source: trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDivision.java@ 8742

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

changed the import statements for GS3SQLConnection and GS3SQLConnectionFactory to reflect their move to the database package

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