source: branches/ant-install-branch/gsdl3/src/java/org/greenstone/gsdl3/gs3build/classifier/AbstractHierarchyNode.java@ 9858

Last change on this file since 9858 was 9858, checked in by kjdon, 19 years ago

OK, changed my mind about making SQLConnection kill off the previous statement.
To make it more transparent what is happening, you now have to create a Statement (connection.createStatement()), then use the Statement to execute the query. This means that the thing doing the query owns the Statement, and can kill it off when finished with it, and nothing else can kill it off unexpectedly. The previous way this was all implemented meant that there was a large memory leak, and some functionality actually relied on this. A newer version of the mysql connector/J has fixed the bug where the statement wasn't closed on garbage collection, but it still seems better to close it explicitly.
Hopefully I have got it all back to working as well as it was bfore, and haven't introduced any bugs :-)

  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1package org.greenstone.gsdl3.gs3build.classifier;
2
3import java.util.List;
4import java.util.ArrayList;
5import java.util.Iterator;
6
7import java.sql.ResultSet;
8import java.sql.SQLException;
9import java.sql.Statement;
10
11import org.greenstone.gsdl3.gs3build.doctypes.DocumentID;
12
13import org.greenstone.gsdl3.gs3build.database.*;
14
15public abstract class AbstractHierarchyNode
16{
17 String prefix; // a basic prefix used in this hierarchy
18 String descriptor; // the textual descriptor used on screen or long-hand
19 String name; // the index number, letter assignment or other item
20 // used to identify the position of the item in the
21 // hierarchy
22 String id; // an identifier used by the GLI for maintenance
23 // purposes; this plays no active role in the
24 // rebuilding process (at the moment)
25 List childNodes; // the child classification nodes of this node
26 List childDocs; // the child documents of this node
27 List matches; // the other metadata values that may be matched
28 // against the classifier
29 AbstractHierarchyNode parent; // the parent of the node
30
31 class AbstractHierarchyDocument
32 { DocumentID documentId;
33 String sortKey;
34
35 public AbstractHierarchyDocument(DocumentID documentId, String sortKey)
36 { this.documentId = documentId;
37 this.sortKey = sortKey;
38 }
39
40 public DocumentID getID()
41 { return this.documentId;
42 }
43
44 public String toString()
45 { return this.sortKey;
46 }
47 }
48
49 /**
50 * Simple node
51 */
52 public AbstractHierarchyNode()
53 { this.descriptor = "";
54 this.name = "";
55 this.id = "";
56 this.prefix = "";
57 this.childNodes = new ArrayList();
58 this.childDocs = new ArrayList();
59 this.parent = null;
60 this.matches = new ArrayList();
61 }
62
63 public AbstractHierarchyNode(String prefix, String name, String id, String descriptor)
64 { this.descriptor = descriptor;
65 this.name = name;
66 this.id = id;
67 this.prefix = prefix;
68 this.childNodes = new ArrayList();
69 this.childDocs = new ArrayList();
70 this.parent = null;
71 this.matches = new ArrayList();
72 this.matches.add(this.id);
73 this.matches.add(this.name);
74 }
75
76 public void addChild(AbstractHierarchyNode child)
77 { this.childNodes.add(child);
78 child.setParent(this);
79
80 /**
81 if (this.id == null) {
82 System.out.println(child.id.toString() + " added to root");
83 }
84 else {
85 System.out.println(child.id.toString() + " added to " + this.id);
86 }
87 */
88 }
89
90 public boolean add(AbstractHierarchyNode child)
91 { if (this.id != null && this.id.length() > 0 &&
92 !child.id.startsWith(this.id + "."))
93 { return false;
94 }
95
96 Iterator subNodes = this.childNodes.iterator();
97 while (subNodes.hasNext()) {
98 AbstractHierarchyNode subNode = (AbstractHierarchyNode) subNodes.next();
99
100 if (subNode.add(child)) {
101 return true;
102 }
103 }
104
105 this.addChild(child);
106 return true;
107 }
108
109 public void addDocument(DocumentID document, String sortKey)
110 { if (sortKey == null && false) {
111 System.err.println("attempt to classify by an unset key");
112 return;
113 }
114 this.childDocs.add(new AbstractHierarchyDocument(document, sortKey));
115
116 System.out.println("Adding " + document.toString() + " to " + this.name + " " + this.childDocs.size());
117 if (sortKey != null) {
118 int first = 0;
119 int last = this.childDocs.size() - 1;
120
121 while (first != last) {
122 int at = (first + last) / 2;
123
124 System.out.println(this.name + " " + at + " " + this.childDocs.size() + " " + this.childDocs.get(at) + " " + sortKey);
125 if (this.childDocs.get(at) == null ||
126 this.childDocs.get(at).toString() == null) {
127 last = at;
128 System.out.println("COntinuing");
129 continue;
130 }
131
132 if (this.childDocs.get(at).toString().compareTo(sortKey) > 0) {
133 last = at;
134 }
135 else {
136 first = at + 1;
137 }
138 }
139
140 Object newItem = this.childDocs.get(this.childDocs.size() - 1);
141 last = this.childDocs.size() - 1;
142 while (last > first) {
143 this.childDocs.set(last, this.childDocs.get(last-1));
144 last --;
145 }
146 this.childDocs.set(first, newItem);
147 }
148
149 // System.out.println("Added " + document.toString() + " to " + this.name + " " + this.childDocs.size());
150 // for (int a = 0; a < this.childDocs.size(); a ++) {
151 //System.out.println(this.childDocs.get(a));
152 //}
153 }
154
155 public void setParent(AbstractHierarchyNode parent)
156 { this.parent = parent;
157 }
158
159 public AbstractHierarchyNode getParent()
160 { return this.parent;
161 }
162
163 public String getParentId()
164 {
165 if (this.id == null) {
166 return "";
167 }
168
169 int dotAt = this.id.lastIndexOf('.');
170 if (dotAt < 0) {
171 return "";
172 }
173 return this.id.substring(0, dotAt);
174 }
175
176 public void setDescriptor(String descriptor)
177 { this.descriptor = descriptor;
178 }
179
180 public void setID(String id)
181 { this.id = id;
182 this.matches.add(id);
183 }
184
185 public String getID()
186 { return this.id;
187 }
188
189 public int noOfChildDocs()
190 { return this.childDocs.size();
191 }
192
193 public int noOfLeafDocs()
194 { int total = this.childDocs.size();
195
196 Iterator iterator = this.childNodes.iterator();
197 while (iterator.hasNext()) {
198 AbstractHierarchyNode childNode = (AbstractHierarchyNode) iterator.next();
199
200 total += childNode.noOfLeafDocs();
201 }
202
203 return total;
204 }
205
206 /**
207 * Set the name for this hierarchy node - i.e. its brief description
208 *
209 * @param <code>String</code> the new node name.
210 */
211 public void setName(String name)
212 { this.name = name;
213 this.matches.add(name);
214 }
215
216 /**
217 * Get the name for this hierarchy node - i.e. its brief description
218 *
219 * @return <code>String</code> the node's name.
220 */
221 public String getName()
222 { return this.name;
223 }
224
225 /**
226 * Add another string which can be used to describe this hierarchy node - i.e. one which if
227 * found in a document would indicate that that document belongs to this hierarchy node.
228 *
229 * @param <code>String</code> the string to match.
230 */
231 public void addMatch(String match)
232 { this.matches.add(match);
233 }
234
235 /**
236 * Check if a given string matches any of the values given for this hierarchy node...
237 *
238 * @param <code>String</code> the descriptive string to be compared against the hierarchy
239 * @return <code>boolean</code> <code>true</code> whether the string matches this hierarchy
240 */
241 public boolean isMatch (String toMatch)
242 { Iterator thisMatch = this.matches.iterator();
243
244 while (thisMatch.hasNext())
245 { String thisMatchText = thisMatch.next().toString();
246
247 if (thisMatchText.equals(toMatch))
248 { return true;
249 }
250 }
251 return false;
252 }
253
254 /**
255 * Take a document, and find the classifications that it matches against in
256 * the current hierarchy.
257 *
258 * @param <code>DocumentID</code> the id of the document being classified
259 * @param <code>List</code> the values against which the classifier should
260 * test for the document being a match - i.e. the pertinent document
261 * property values.
262 * @param <code>ClassifierObserverInterface</code>
263 * object modifies the document with information about the
264 * classifications that it fell within.
265 */
266 abstract public void getClassifications(DocumentID documentID, List values, String sortKey,
267 ClassifierObserverInterface observer);
268
269 public boolean writeSQL(GS3SQLConnection connection)
270 {
271 int classifyRef;
272 GS3SQLAction action = null;
273 GS3SQLSelect select;
274 GS3SQLInsert insert;
275
276 Statement statement;
277 // can we connect to the database?
278 try {
279 statement = connection.createStatement();
280 } catch (SQLException e) {
281 System.err.println("AbstractHierarchyNode.writeSQL(): "+e);
282 return false;
283 }
284
285 // Get own full id
286 String fullId = this.id.length() > 0 ? this.prefix+"."+this.id : this.prefix;
287
288 // check for an existing instance of this classifier
289 select = new GS3SQLSelect("classifiers");
290 select.addField("ClassifyRef");
291 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ClassifyID", "=", fullId);
292 GS3SQLWhere where = new GS3SQLWhere(whereItem);
293 select.setWhere(where);
294
295
296 // update or insert the classifier as required
297 try {
298 ResultSet results = statement.executeQuery(select.toString());
299 if (results.first()) {
300 GS3SQLUpdate update = new GS3SQLUpdate("classifiers");
301 update.setWhere(where);
302 action = update;
303
304 classifyRef = results.getInt("ClassifyRef");
305 }
306 else {
307 insert = new GS3SQLInsert("classifiers");
308
309 if (this.id == null || this.id.length() == 0) {
310 insert.addValue("ParentID", "");
311 }
312 else {
313 String parentId = this.getParentId();
314
315 if (parentId.length() > 0) {
316 insert.addValue("ParentID", this.prefix+"."+this.getParentId());
317 }
318 else {
319 insert.addValue("ParentID", this.prefix);
320 }
321 }
322
323 action = insert;
324 classifyRef = -1;
325 }
326 action.addValue("ClassifyID", fullId);
327 action.addValue("Name", this.name);
328 action.addValue("Description", this.descriptor);
329
330 String tailId = "0";
331 if (this.id.length() > 0) {
332 int lastDot = this.id.lastIndexOf('.');
333 if (lastDot >= 0) {
334 tailId = this.id.substring(lastDot+1);
335 }
336 else {
337 tailId = this.id;
338 }
339 }
340 action.addValue("ClassifyOrder", tailId, GS3SQLField.INTEGER_TYPE);
341 action.addValue("NumLeafDocs", Integer.toString(this.noOfLeafDocs()), GS3SQLField.INTEGER_TYPE);
342
343 statement.execute(action.toString());
344 }
345 catch (SQLException sqlEx) {
346 if (action == null) {
347 System.err.println("AbstractHierarchyNode.writeSQL(): "+sqlEx);
348 }
349 else {
350 System.err.println("AbstractHierarchyNode.writeSQL(): "+sqlEx + " " + action.toString());
351 }
352 return false;
353 }
354
355 // get the ClassifyRef if we don't already have it (have done a
356 // insert action above)...
357 if (classifyRef == -1) {
358 try {
359 ResultSet results = statement.executeQuery(select.toString());
360 if (!results.first()) {
361 statement.close();
362 return false;
363 }
364
365 classifyRef = results.getInt("ClassifyRef");
366
367 }
368 catch (SQLException sqlEx) {
369 System.err.println("AbstractHierarchyNode.writeSQL(): "+sqlEx);
370 return false;
371 }
372 }
373 else {
374 // TODO: clear 'dead' child classifications
375
376 // delete child documents
377 GS3SQLDelete delete = new GS3SQLDelete("classdocuments");
378 delete.setWhere(where);
379 try {
380 statement.execute(delete.toString());
381 } catch (SQLException e) {
382 System.err.println("AbstractHierarchyNode.writeSQL(): "+e);
383 return false;
384 }
385 }
386
387 // post the child nodes...
388 Iterator iterator = this.childNodes.iterator();
389 while (iterator.hasNext()) {
390 AbstractHierarchyNode childNode = (AbstractHierarchyNode) iterator.next();
391
392 if (!childNode.writeSQL(connection)) {
393 System.out.println("Failed to write " );
394 return false;
395 }
396 }
397
398 // note the child documents...
399 iterator = this.childDocs.iterator();
400 int order = 1;
401 while (iterator.hasNext()) {
402 AbstractHierarchyDocument hierarchyDoc = (AbstractHierarchyDocument) iterator.next();
403 DocumentID docId = hierarchyDoc.getID();
404
405 insert = new GS3SQLInsert("classdocuments");
406 insert.addValue("ClassifyRef", Integer.toString(classifyRef), GS3SQLField.INTEGER_TYPE);
407 insert.addValue("DocID", docId.toString());
408 insert.addValue("DocOrder", Integer.toString(order), GS3SQLField.INTEGER_TYPE);
409 try {
410 statement.execute(insert.toString());
411 } catch (SQLException e) {
412 System.err.println("AbstractHierarchyNode.writeSQL(): "+e);
413 return false;
414 }
415 order ++;
416 }
417 // close the statment
418 try {
419 statement.close();
420 } catch (SQLException e) {
421 System.err.println("AbstractHierarchyNode.writeSQL(): "+e);
422 }
423
424 return true;
425 }
426}
427
428
Note: See TracBrowser for help on using the repository browser.