source: branches/ant-install-branch/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDivision.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: 19.9 KB
Line 
1package org.greenstone.gsdl3.gs3build.metadata;
2
3import java.io.PrintWriter;
4
5import java.util.Iterator;
6import java.util.List;
7import java.util.ArrayList;
8import java.util.Map;
9import java.util.LinkedHashMap;
10
11import java.sql.SQLException;
12import java.sql.Statement;
13import java.sql.ResultSet;
14
15import org.w3c.dom.Element;
16import org.w3c.dom.NodeList;
17
18import org.greenstone.gsdl3.gs3build.doctypes.DocumentID;
19import org.greenstone.gsdl3.gs3build.util.XMLTools;
20import org.greenstone.gsdl3.gs3build.database.*;
21
22public class METSDivision extends AbstractStructure
23{
24 String order; // see the METS documentation for the meaning of the different
25 String orderLabel; // label types.
26 String userLabel;
27 String type; // e.g. section, chapter, physical or logical, etc.
28 List metadataRefs;
29 List adminRefs;
30 List fileRefs;
31
32 public static final String DIVISION_TYPE = "Division";
33 public static final String DIVISION_TAG = "div";
34 public static final String FPTR_TAG = "fptr";
35
36 public METSDivision(String ID, String order, String orderLabel, String userLabel, String type)
37 {
38 super(ID);
39
40 this.order = order;
41 this.orderLabel = orderLabel;
42 this.userLabel = userLabel;
43 this.type = type;
44 this.fileRefs = new ArrayList();
45 this.metadataRefs = new ArrayList();
46 }
47
48 public String getStructureType()
49 {
50 return DIVISION_TYPE;
51 }
52
53 public String getLabel()
54 {
55 return this.orderLabel;
56 }
57
58 /**
59 * Find all the divisions that match a given list of file group
60 * identifiers...
61 *
62 * @param <code>List</code> the list of identifiers to find
63 * @param <code>List</code> the list into which to place any
64 * matching divisions.
65 */
66 public void findDivisionsForFiles(List listOfFileIdentifiers, List resultList)
67 {
68 Iterator iterator = this.fileRefs.iterator();
69
70 // get the references on this division, and mark if necessary
71 while (iterator.hasNext()) {
72 String reference = iterator.next().toString();
73
74 Iterator fileIterator = listOfFileIdentifiers.iterator();
75 while (fileIterator.hasNext()){
76 String fileRef = fileIterator.next().toString();
77
78 if (fileRef.equals(reference)){
79 resultList.add(this);
80 }
81 }
82 }
83
84 // get the child groups, and check each in turn...
85 Iterator groups = this.children.values().iterator();
86 while (groups.hasNext()){
87 METSDivision group = (METSDivision) groups.next();
88
89 group.findDivisionsForFiles(listOfFileIdentifiers, resultList);
90 }
91 }
92
93 /**
94 * Get the namespace from the given set of descriptive blocks...
95 */
96 public METSNamespace findNamespace(String namespaceName, boolean isOpenNamespace,
97 METSDescriptiveSet descriptiveSet)
98 {
99 METSNamespace namespace = null;
100
101 // Special case - no existing metadata references
102 if (this.metadataRefs.size() == 0) {
103 // Create new Descriptive and add it to the descriptive set
104 METSDescriptive descriptive = new METSDescriptive("DM"+this.ID, this.orderLabel);
105 descriptiveSet.addDescriptive(descriptive);
106
107 // Create the namespace and add it to the Descriptive
108 namespace = NamespaceFactory.initNamespace(namespaceName);
109 if (namespace != null){
110 descriptive.addNamespace(namespace);
111 }
112
113 return namespace;
114 }
115
116 Iterator descriptiveIterator = this.metadataRefs.iterator();
117
118 while (descriptiveIterator.hasNext()){
119 String descriptiveRef = descriptiveIterator.next().toString();
120
121 METSDescriptive descriptive = descriptiveSet.getDescriptiveById(descriptiveRef);
122
123 if (isOpenNamespace) {
124 namespace = descriptive.getOpenNamespace(namespaceName);
125 }
126 else {
127 namespace = descriptive.getNamespace(namespaceName);
128 }
129
130 if (namespace != null)
131 break;
132 }
133
134 // Special case - no such namespace in any descriptive list...
135 if (namespace == null){
136 // take the first descriptive area...
137 METSDescriptive descriptive = descriptiveSet.getDescriptiveById(this.metadataRefs.get(0).toString());
138
139 // create the namespace, and add it to the METSDescriptive
140 namespace = NamespaceFactory.initNamespace(namespaceName);
141 if (namespace != null){
142 descriptive.addNamespace(namespace);
143 }
144 }
145
146 return namespace;
147 }
148
149 /**
150 * Add a new file reference to the structure
151 *
152 * @param <code>METSFileID</code> the file to be referenced.
153 */
154 public void addFileReference(METSFileID fileRef)
155 {
156 this.addFileReference(fileRef.toString());
157 }
158
159 public void addFileReference(String fileRef)
160 {
161 this.fileRefs.add(fileRef);
162 }
163
164 /**
165 * Add a new metadata reference to the structure
166 */
167 public void addMetadataReference(String metadataRef)
168 {
169 // TODO: correct the type
170 this.metadataRefs.add(metadataRef);
171 }
172
173 /**
174 * Get all the metadata references
175 *
176 * @return <code>List</code> containing all the references
177 */
178 public List getMetadataReferences()
179 {
180 return this.metadataRefs;
181 }
182
183 /**
184 * Get all the default (first) metadata reference...
185 *
186 * @return <code>List</code> containing all the references
187 */
188 //TODO: check for this first *open* metadata item...
189 public String getDefaultMetadataReference()
190 {
191 if (this.metadataRefs.size() == 0) {
192 return null;
193 }
194 return this.metadataRefs.get(0).toString();
195 }
196
197 /**
198 * Get all the default (first) first filegroup reference...
199 *
200 * @return <code>List</code> containing all the references
201 */
202 public String getDefaultFileReference()
203 {
204 if (this.fileRefs.size() == 0) {
205 return null;
206 }
207 return this.fileRefs.get(0).toString();
208 }
209
210 /**
211 * Get a child or descendant division
212 *
213 * @param <code>String</code> the path to the child division
214 * @return <code>METSDivision</code> the division found.
215 */
216 public METSDivision getDivision(String divisionLabel)
217 {
218 // if the division ID equals this, then process it
219 if (divisionLabel.equals(this.orderLabel)) {
220 return this;
221 }
222
223 // if we just shouldn't be here, then error...
224 if (!divisionLabel.startsWith(this.orderLabel + ".")) {
225 return null;
226 }
227
228 // get the next division in the division path...
229 String subdivisionPath = divisionLabel.substring(this.orderLabel.length() + 1);
230 String nextDivision = getTopDivisionName(subdivisionPath);
231 String nextLabel;
232
233 // first try the current division name with an appended '.' and the next child id...
234 METSDivision child = (METSDivision) this.children.get(this.orderLabel + "." + nextDivision);
235 if (child == null){
236 // if that didn't work, try the next division on its own
237 child = (METSDivision) this.children.get(nextDivision);
238
239 // if neither worked, then abort...
240 if (child == null) {
241 return null;
242 }
243 else {
244 // set the next identifier
245 nextLabel = METSDivision.getSubDivisionName(divisionLabel);
246 }
247 }
248 else {
249 // set the next identifier...
250 nextLabel = divisionLabel;
251 }
252
253 return child.getDivision(nextLabel);
254 }
255
256 /**
257 * A convenience method for splitting a division name - this gives the name
258 * without the leading division label... To be used when division identifiers
259 * are given as '.' separated paths and division names do not contain the
260 * full path of their parents.
261 *
262 * @return <code>String</code>
263 */
264 public static String getSubDivisionName(String divisionName)
265 {
266 int at = divisionName.indexOf('.');
267
268 if (at >= 0){
269 return divisionName.substring(at+1);
270 }
271 else {
272 return null;
273 }
274 }
275
276 /**
277 * Get the parent division name. Division identifiers
278 * concatenate the ancestor's names with intervening
279 * '.' characters.
280 *
281 * @return <code>String</code> the division name
282 */
283 public static String getParentName(String divisionName)
284 {
285 int at = divisionName.lastIndexOf('.');
286
287 if (at >= 0) {
288 return divisionName.substring(0, at);
289 }
290 return "";
291 }
292
293 /**
294 * Get the top division name.
295 *
296 * @return <code>String</code> the division name
297 */
298 public static String getTopDivisionName(String divisionName)
299 {
300 int at = divisionName.indexOf('.');
301
302 if (at >= 0){
303 return divisionName.substring(0, at);
304 }
305 else {
306 return divisionName;
307 }
308 }
309
310 /* Parse an XML Element as a METSDivision section
311 *
312 * @param <code>Element</code> the XML element which represents
313 * the mets:div itself
314 */
315
316 public static METSDivision parseXML(Element element)
317 {
318 METSDivision thisDivision = null;
319
320 String divId = element.getAttribute("ID");
321 String divType = element.getAttribute("TYPE");
322 String divOrder = element.getAttribute("ORDER");
323 String divOrderLabel = element.getAttribute("ORDERLABEL");
324 String divUserLabel = element.getAttribute("LABEL");
325 String divMetaRef = element.getAttribute("DMDID");
326
327 thisDivision = new METSDivision(divId, divOrder,divOrderLabel, divUserLabel, divType);
328
329 thisDivision.addMetadataReference(divMetaRef);
330
331 NodeList children = element.getChildNodes();
332
333 for (int c = 0; c < children.getLength(); c++){
334 if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE){
335 continue;
336 }
337 Element child = (Element) children.item(c);
338 String childName = child.getNodeName();
339
340 if (childName.equals("mets:fptr")) {
341
342 METSDivision.fptr_parseXML(thisDivision, child);
343 } else if (childName.equals("mets:div")) {
344 METSDivision division = METSDivision.parseXML(child);
345 thisDivision.addDivision(division);
346 } else {
347 System.err.println("Error: mets:div expected mets:div or mets:fptr, but got " + childName);
348 }
349 }
350 return thisDivision;
351 }
352
353
354 /**
355 * Parse an XML element as a METSFptr Section
356 * @param <code>Element</code> the XML element which represents the mets:fptr itself
357 */
358 private static void fptr_parseXML(METSDivision thisDivision, Element element)
359 {
360 String fileRef = element.getAttribute("FILEID");
361 thisDivision.addFileReference(fileRef);
362 }
363
364 /**
365
366
367 /**
368 * Write the METS file in an XML to a text-output sink.
369 *
370 * @param <code>PrintWriter</code> the destination of the output
371 */
372 public boolean write(PrintWriter writer)
373 {
374 // Get the main tag for the division
375 String tag = XMLTools.getOpenTag("mets", DIVISION_TAG);
376 tag = XMLTools.addAttribute(tag, "ID", this.ID.toString());
377 tag = XMLTools.addAttribute(tag, "TYPE", this.type);
378 tag = XMLTools.addAttribute(tag, "ORDER", this.order);
379 if (this.orderLabel != null){
380 tag = XMLTools.addAttribute(tag, "ORDERLABEL", this.orderLabel);
381 }
382 if (this.userLabel != null){
383 tag = XMLTools.addAttribute(tag, "LABEL", this.userLabel);
384 }
385
386 // Add a metadata reference attribute
387 if (this.metadataRefs.size() > 0){
388 String metaList = this.writeList(this.metadataRefs);
389 tag = XMLTools.addAttribute(tag, "DMDID", metaList);
390 }
391
392 // write the central tag
393 writer.print(" "); //indentation
394 writer.println(tag);
395
396 // write the list of file pointers for this structural element
397 if (this.fileRefs.size() > 0) {
398 String fileList = this.writeTagList("mets", "fptr", "FILEID", this.fileRefs);
399 writer.print(" "); //indentation
400 writer.println(fileList);
401 }
402
403 // write out any children in turn
404 Iterator groups = this.children.values().iterator();
405
406 while (groups.hasNext()){
407 METSDivision group = (METSDivision) groups.next();
408
409 if (!group.write(writer)) {
410 return false;
411 }
412 }
413
414 // close the div element
415 writer.print(" "); //indentation
416 writer.println(XMLTools.getCloseTag("mets", DIVISION_TAG));
417
418 return true;
419 }
420
421 /**
422 * A convenience method for writing a <code>List</code> as a series of tags...
423 */
424 private String writeTagList(String namespace, String tagname,
425 String attribute, List list)
426 {
427 StringBuffer listString = new StringBuffer();
428
429 Iterator iterator = list.iterator();
430 while (iterator.hasNext()){
431 String item = iterator.next().toString();
432
433 String tag = XMLTools.getOpenTag(namespace, tagname);
434 tag = XMLTools.addAttribute(tag, attribute, item);
435 tag = XMLTools.makeSingleton(tag);
436
437 listString.append(tag);
438 }
439 return listString.toString();
440 }
441
442 /**
443 * A convenience method for writing a <code>List</code> as a space-separated <code>String</code>.
444 */
445 private String writeList(List list)
446 {
447 StringBuffer listString = new StringBuffer();
448
449 Iterator iterator = list.iterator();
450 while (iterator.hasNext()){
451 String item = iterator.next().toString();
452
453 if (listString.length() > 0) {
454 listString.append(" ");
455 }
456
457 listString.append(item);
458 }
459 return listString.toString();
460 }
461
462 public boolean writeSQL(DocumentID docId, int parentRef, boolean parentIsStructure,
463 GS3SQLConnection connection)
464 {
465 int sqlRef = -1;
466
467 // set the "where" to find the reference for this division
468 GS3SQLSelect select = new GS3SQLSelect("divisions");
469 select.addField("DivisionRef");
470 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(parentRef), GS3SQLField.INTEGER_TYPE);
471 GS3SQLWhereItem parentItem = new GS3SQLWhereItem("ParentType", "=", parentIsStructure ? METSStructure.STRUCTURE_TYPE : METSDivision.DIVISION_TYPE);
472 GS3SQLWhereItem item = new GS3SQLWhereItem("SectionID", "=", this.ID.toString());
473 GS3SQLWhere where = new GS3SQLWhere(whereItem);
474 where.add(parentItem);
475 where.add(item);
476 select.setWhere(where);
477
478 Statement statement = null;
479 ResultSet resultSet = null;
480
481 // Do the actual writing
482 GS3SQLAction action;
483
484 try {
485 statement = connection.createStatement();
486 resultSet = statement.executeQuery(select.toString());
487 if (!resultSet.first()) {
488
489 GS3SQLInsert insert = new GS3SQLInsert("divisions");
490 insert.addValue("DocID", docId.toString());
491 insert.addValue("SectionID", this.ID.toString());
492 insert.addValue("ParentRef", Integer.toString(parentRef));
493 insert.addValue("ParentType", parentIsStructure == true ? METSStructure.STRUCTURE_TYPE : METSDivision.DIVISION_TYPE);
494
495 action = insert;
496 }
497 else {
498 sqlRef = resultSet.getInt("DivisionRef");
499
500 GS3SQLUpdate update = new GS3SQLUpdate("divisions");
501 GS3SQLWhere updateWhere =
502 new GS3SQLWhere(new GS3SQLWhereItem("DivisionRef", "=", Integer.toString(sqlRef), GS3SQLField.INTEGER_TYPE));
503 update.setWhere(updateWhere);
504 action = update;
505 }
506 }
507 catch (SQLException sql) {
508 System.err.println(sql + " " + select.toString());
509 return false;
510 }
511
512 action.addValue("DivisionType", this.type.toString());
513 action.addValue("LabelOrder", this.order);
514 action.addValue("ShortLabel", this.orderLabel);
515 action.addValue("UserLabel", this.userLabel);
516
517 try {
518 statement.execute(action.toString());
519 } catch (SQLException e) {
520 System.err.println("METSDivision.writeSQL(): "+e);
521 return false;
522 }
523
524 // if doing a fresh item, get the new structure reference...
525 if (sqlRef == -1){
526 // get the new structure reference
527 try {
528 // read in the structure reference
529 resultSet = statement.executeQuery(select.toString());
530 if (resultSet.first()) {
531 sqlRef = resultSet.getInt("DivisionRef");
532 }
533 }
534 catch (SQLException sqlex) {
535 System.err.println("METSDIVISION.writeSQL(): Unable to retrieve reference for Division " + sqlex);
536 return false;
537 }
538 }
539
540 // delete the old file/metadata references
541 try {
542 GS3SQLWhere referenceWhere =
543 new GS3SQLWhere(new GS3SQLWhereItem("DivisionRef", "=", Integer.toString(sqlRef),
544 GS3SQLField.INTEGER_TYPE));
545
546 GS3SQLDelete delete = new GS3SQLDelete("divisionfilerefs");
547 delete.setWhere(referenceWhere);
548
549 statement.execute(delete.toString());
550
551 delete = new GS3SQLDelete("divisionmetarefs");
552 delete.setWhere(referenceWhere);
553 statement.execute(delete.toString());
554
555 // write the new file references
556 if (this.fileRefs.size() > 0){
557 Iterator iterator = this.fileRefs.iterator();
558
559 while (iterator.hasNext()) {
560 GS3SQLInsert fileinsert = new GS3SQLInsert("divisionfilerefs");
561 fileinsert.addValue("DocID", docId.toString());
562 fileinsert.addValue("DivisionRef", Integer.toString(sqlRef), GS3SQLField.INTEGER_TYPE);
563 fileinsert.addValue("DivisionType", "Group");
564 fileinsert.addValue("FileID", iterator.next().toString());
565 statement.execute(fileinsert.toString());
566 }
567 }
568
569 // write the metadata references
570 if (this.metadataRefs.size() > 0){
571 Iterator iterator = this.metadataRefs.iterator();
572
573 while (iterator.hasNext()) {
574 GS3SQLInsert metainsert = new GS3SQLInsert("divisionmetarefs");
575 metainsert.addValue("DocID", docId.toString());
576 metainsert.addValue("DivisionRef", Integer.toString(sqlRef), GS3SQLField.INTEGER_TYPE);
577 metainsert.addValue("DivisionType", "Group");
578 metainsert.addValue("MetaID", iterator.next().toString());
579 statement.execute(metainsert.toString());
580 }
581 }
582 statement.close();
583 } catch (SQLException e) {
584 System.err.println("METSDIVISION.writeSQL(): "+e);
585 return false;
586 }
587 // write out any children in turn
588 Iterator groups = this.children.values().iterator();
589
590 while (groups.hasNext()){
591 METSDivision group = (METSDivision) groups.next();
592
593 if (!group.writeSQL(docId, sqlRef, false, connection)) {
594 return false;
595 }
596 }
597 return true;
598 }
599
600 public static METSDivision readSQL(GS3SQLConnection connection, ResultSet resultSet)
601 {
602 METSLocation metsLocation = null;
603
604 GS3SQLSelect select = null;
605 try {
606 // read the basic information
607 String ID = resultSet.getString("SectionID");
608 String type = resultSet.getString("DivisionType");
609 String order = resultSet.getString("LabelOrder");
610 String orderLabel = resultSet.getString("ShortLabel");
611 String userLabel = resultSet.getString("UserLabel");
612
613 // construct the division object
614 METSDivision division = new METSDivision(ID, order, orderLabel, userLabel, type);
615
616 // obtain a list of child divisions
617 int divisionRef = resultSet.getInt("DivisionRef");
618
619 select = new GS3SQLSelect("divisions");
620 select.addField("*");
621 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(divisionRef),
622 GS3SQLField.INTEGER_TYPE);
623 GS3SQLWhere where = new GS3SQLWhere(whereItem);
624 whereItem = new GS3SQLWhereItem("ParentType", "=", METSDivision.DIVISION_TYPE);
625 where.add(whereItem);
626 select.setWhere(where);
627
628 Statement statement = connection.createStatement();
629 ResultSet childSet = statement.executeQuery(select.toString());
630
631 // circulate through to obtain further children
632 if (childSet.first())
633 {
634 do {
635 METSDivision childDivision = METSDivision.readSQL(connection, childSet);
636 division.addDivision(childDivision);
637 }
638 while (childSet.next());
639 }
640 select = new GS3SQLSelect("divisionfilerefs");
641 select.addField("*");
642 where = new GS3SQLWhere(new GS3SQLWhereItem("DivisionRef", "=", Integer.toString(divisionRef),
643 GS3SQLField.INTEGER_TYPE));
644 select.setWhere(where);
645
646 ResultSet fileSet = statement.executeQuery(select.toString());
647
648 if (fileSet.first()){
649 do {
650 String reference = fileSet.getString("FileID");
651 division.fileRefs.add(reference);
652 }
653 while (fileSet.next());
654 }
655
656 select = new GS3SQLSelect("divisionmetarefs");
657 select.addField("*");
658 where = new GS3SQLWhere(new GS3SQLWhereItem("DivisionRef", "=", Integer.toString(divisionRef),
659 GS3SQLField.INTEGER_TYPE));
660 select.setWhere(where);
661
662 ResultSet metaSet = statement.executeQuery(select.toString());
663
664 if (metaSet.first()){
665 do {
666 String reference = metaSet.getString("MetaID");
667 division.metadataRefs.add(reference);
668 }
669 while (metaSet.next());
670 }
671
672 statement.close();
673 return division;
674 }
675 catch (SQLException sqlEx){
676 System.out.println(sqlEx + " " +select.toString());
677 }
678 return null;
679 }
680}
681
Note: See TracBrowser for help on using the repository browser.