/edu/uncc/parsets/data/LocalDBDataSet.java

https://code.google.com/p/parsets/ · Java · 275 lines · 188 code · 39 blank · 48 comment · 35 complexity · cb1b33c55bcc1536b9ece44e8c1f7fdf MD5 · raw file

  1. package edu.uncc.parsets.data;
  2. import edu.uncc.parsets.parsets.SelectionChangeEvent;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. import java.util.ArrayList;
  7. import java.util.Iterator;
  8. import java.util.List;
  9. import edu.uncc.parsets.data.LocalDB.DBAccess;
  10. import edu.uncc.parsets.util.PSLogging;
  11. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  12. * Copyright (c) 2009, Robert Kosara, Caroline Ziemkiewicz,
  13. * and others (see Authors.txt for full list)
  14. * All rights reserved.
  15. *
  16. * Redistribution and use in source and binary forms, with or without
  17. * modification, are permitted provided that the following conditions are met:
  18. *
  19. * * Redistributions of source code must retain the above copyright
  20. * notice, this list of conditions and the following disclaimer.
  21. * * Redistributions in binary form must reproduce the above copyright
  22. * notice, this list of conditions and the following disclaimer in the
  23. * documentation and/or other materials provided with the distribution.
  24. * * Neither the name of UNC Charlotte nor the names of its contributors
  25. * may be used to endorse or promote products derived from this software
  26. * without specific prior written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY ITS AUTHORS ''AS IS'' AND ANY
  29. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  30. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  32. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  33. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  35. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  36. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  37. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  39. /**
  40. * A dataset that is backed by a SQLite database.
  41. */
  42. public class LocalDBDataSet extends DataSet {
  43. /**
  44. * Whether to write a timestamp to the DB whenever a dataset is opened.
  45. * This is not very useful for the Java program, but will be important
  46. * on the iPhone.
  47. */
  48. private static final boolean RECORDOPENTIMES = false;
  49. private LocalDB db;
  50. private String dbHandle;
  51. private ArrayList<DimensionHandle> dimHandles;
  52. private int numRecords;
  53. private String url = "";
  54. private String section = "Misc";
  55. private String source = "";
  56. private String srcURL = "";
  57. protected LocalDBDataSet(String dsName, String handle, int count, String remoteURL, String listSection, String dbSource, String dbSrcURL, LocalDB dbHandler) {
  58. name = dsName;
  59. dbHandle = handle;
  60. db = dbHandler;
  61. numRecords = count;
  62. if (remoteURL != null)
  63. url = remoteURL;
  64. if (listSection != null)
  65. section = listSection;
  66. if (dbSource != null)
  67. source = dbSource;
  68. if (dbSrcURL != null)
  69. srcURL = dbSrcURL;
  70. }
  71. public LocalDB getDB() {
  72. return db;
  73. }
  74. @Override
  75. public int getNumRecords() {
  76. return numRecords;
  77. }
  78. @Override
  79. public String toString() {
  80. return name;
  81. }
  82. @Override
  83. public String getURL() {
  84. return url;
  85. }
  86. public String getSection() {
  87. return section;
  88. }
  89. public String getSource() {
  90. return source;
  91. }
  92. public String getSrcURL() {
  93. return srcURL;
  94. }
  95. @Override
  96. public CategoryTree getTree(List<DimensionHandle> dimensions) {
  97. CategoryTree tree = new CategoryTree(dimensions.size()+1);
  98. String dimList = dims2String(dimensions);
  99. StringBuffer query = new StringBuffer("select ");
  100. query.append(dimList);
  101. query.append(", sum(count) from "+dbHandle+"_dims group by ");
  102. query.append(dimList);
  103. query.append(";");
  104. try {
  105. Statement stmt = db.createStatement(DBAccess.FORREADING);
  106. ResultSet rs = stmt.executeQuery(query.toString());
  107. CategoryNode thisLine[] = new CategoryNode[dimensions.size()+1];
  108. CategoryNode previousLine[] = new CategoryNode[dimensions.size()+1];
  109. CategoryNode root = new CategoryNode(null, null, 0);
  110. tree.addtoLevel(0, root);
  111. // this would be much prettier as a recursive function, but the
  112. // semantics and side effects of the ResultSet make that very
  113. // annoying
  114. while (rs.next()) {
  115. int column = 1;
  116. CategoryNode previousNode = root;
  117. for (DimensionHandle dim : dimensions) {
  118. CategoryHandle cat = dim.num2Handle(rs.getInt(column));
  119. CategoryNode node = null;
  120. if (previousLine[column] != null && cat == previousLine[column].getToCategory()) {
  121. node = previousLine[column];
  122. } else {
  123. if (column == dimensions.size())
  124. node = new CategoryNode(previousNode, cat, rs.getInt(column+1));
  125. else {
  126. node = new CategoryNode(previousNode, cat, 0);
  127. for (int i = column+1; i <= dimensions.size(); i++)
  128. previousLine[i] = null;
  129. }
  130. tree.addtoLevel(column, node);
  131. }
  132. previousNode = node;
  133. thisLine[column] = node;
  134. column++;
  135. }
  136. CategoryNode temp[] = thisLine;
  137. thisLine = previousLine;
  138. previousLine = temp;
  139. }
  140. rs.close();
  141. } catch (SQLException e) {
  142. PSLogging.logger.error("SQL error while creating tree.", e);
  143. } finally {
  144. db.releaseReadLock();
  145. }
  146. tree.getRootNode().updateValues();
  147. return tree;
  148. }
  149. /**
  150. * Makes a string from a list of dimensions, with commas in between. Returns
  151. * an empty string for an empty list.
  152. *
  153. * @param dimensions List of dimension handles to put in the string
  154. * @return SQL-ready list of dimension handles
  155. */
  156. public static String dims2String(List<DimensionHandle> dimensions) {
  157. StringBuffer dimList = new StringBuffer();
  158. boolean first = true;
  159. for (DimensionHandle handle : dimensions) {
  160. if (first)
  161. first = false;
  162. else
  163. dimList.append(", ");
  164. dimList.append(handle.getHandle());
  165. }
  166. return dimList.toString();
  167. }
  168. @Override
  169. public Iterator<DimensionHandle> iterator() {
  170. if (dimHandles == null)
  171. loadDimensions();
  172. return dimHandles.iterator();
  173. }
  174. private void loadDimensions() {
  175. try {
  176. Statement stmt = db.createStatement(DBAccess.FORREADING);
  177. dimHandles = new ArrayList<DimensionHandle>();
  178. ResultSet rs = stmt.executeQuery("select name, handle, type from Admin_Dimensions where dataSet = '"+dbHandle+"';");
  179. int dimNum = 0;
  180. while (rs.next()) {
  181. dimHandles.add(new DimensionHandle(rs.getString(1), rs.getString(2), DataType.typeFromString(rs.getString(3)), dimNum, this));
  182. dimNum++;
  183. }
  184. rs.close();
  185. if (RECORDOPENTIMES)
  186. stmt.executeUpdate("update Admin_DataSets set lastOpened=datetime('now') where handle='"+dbHandle+"';");
  187. } catch (SQLException e) {
  188. PSLogging.logger.error("SQL error while loading dimensions.", e);
  189. } finally {
  190. db.releaseReadLock();
  191. }
  192. }
  193. public void deleteFromDB() {
  194. db.deleteFromDB(dbHandle);
  195. }
  196. @Override
  197. public String getName() {
  198. return name;
  199. }
  200. // changed protected to public temporary
  201. @Override
  202. public String getHandle() {
  203. return dbHandle;
  204. }
  205. public int getNumDimensions() {
  206. if (dimHandles == null)
  207. loadDimensions();
  208. return dimHandles.size();
  209. }
  210. public int getNumCategoricalDimensions() {
  211. if (dimHandles == null)
  212. loadDimensions();
  213. int num = 0;
  214. for (DimensionHandle d : dimHandles)
  215. if (d.getDataType() == DataType.categorical)
  216. num++;
  217. return num;
  218. }
  219. public int getNumNumericDimensions() {
  220. return getNumDimensions()-getNumCategoricalDimensions();
  221. }
  222. public DimensionHandle[] getNumericDimensions() {
  223. DimensionHandle handles[] = new DimensionHandle[getNumNumericDimensions()];
  224. int i = 0;
  225. for (DimensionHandle d : dimHandles)
  226. if (d.getDataType() != DataType.categorical)
  227. handles[i++] = d;
  228. return handles;
  229. }
  230. public void selectionChanged(SelectionChangeEvent event) {
  231. }
  232. // new method
  233. public ArrayList<DimensionHandle> getDimensions(){
  234. return dimHandles;
  235. }
  236. }