source: trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptive.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: 14.0 KB
Line 
1package org.greenstone.gsdl3.gs3build.metadata;
2
3import java.util.List;
4import java.util.ArrayList;
5import java.util.Iterator;
6
7import java.io.PrintWriter;
8
9import java.sql.SQLException;
10import java.sql.ResultSet;
11
12import org.w3c.dom.Document;
13import org.w3c.dom.Element;
14import org.w3c.dom.NamedNodeMap;
15import org.w3c.dom.Node;
16import org.w3c.dom.NodeList;
17import org.w3c.dom.Text;
18
19import org.greenstone.gsdl3.gs3build.doctypes.DocumentInterface;
20
21import org.greenstone.gsdl3.gs3build.util.XMLTools;
22import org.greenstone.gsdl3.gs3build.database.*;
23
24/**
25 * Support the descriptive metadata of a given document
26 *
27 * The descriptive metadata can occur multiple times, so this 'wrapper' is
28 * in fact a holder for a number of individual metadata sets. Individual
29 * metadata groups are found in METSNamespace items.
30 *
31 *
32 */
33
34import org.greenstone.gsdl3.gs3build.util.MultiMap;
35
36public class METSDescriptive
37{
38 MultiMap map;
39 String ID;
40 String name;
41
42 public METSDescriptive(String ID, String name)
43 {
44 this.map = new MultiMap();
45 this.ID = ID;
46 this.name = name;
47 }
48
49 public String getID()
50 {
51 return this.ID;
52 }
53
54 public String getName()
55 {
56 return this.name;
57 }
58
59 public void addNamespace(METSNamespace namespace)
60 {
61 this.map.put(namespace.getName(), namespace);
62 }
63
64 public METSNamespace getNamespace(String namespace)
65 {
66 return (METSNamespace) this.map.get(namespace);
67 }
68
69 /**
70 * Get the version of a metadata namespace that can be used for
71 * adding new values to the document. Remember, each namespace may
72 * occur more than once, but only one of the occurrences can be 'open'.
73 *
74 * @param <code>String</code> the name of the namespace
75 */
76 public METSNamespace getOpenNamespace(String namespace)
77 {
78 if (this.map.getAll(namespace) == null) {
79 return null;
80 }
81
82 Iterator namespaces = ((List) this.map.getAll(namespace)).iterator();
83
84 while (namespaces.hasNext()) {
85 METSNamespace namespaceData = (METSNamespace) namespaces.next();
86
87 if (namespaceData.isEditable()){
88 return namespaceData;
89 }
90 }
91 return null;
92 }
93
94 /**
95 * Add a piece of metadata to this document. Existing values are preserved.
96 *
97 * @param <code>String</code> the namespace in which the metadata occurs
98 * @param <code>String</code> the label of the metadata
99 * @param <code>String</code> the value of the metadata
100 */
101 public void addMetadata(String namespace, String label, String value)
102 {
103 METSNamespace namespaceData = this.getOpenNamespace(namespace);
104
105 if (namespaceData == null ||
106 namespaceData.isEditable() == false) {
107 namespaceData = NamespaceFactory.initNamespace(namespace);
108 this.addNamespace(namespaceData);
109 }
110 namespaceData.addMetadata(label, value);
111 }
112
113 /**
114 * Add a piece of metadata to this document. Existing values in editable
115 * parts of the document's metadata are destroyed.
116 *
117 * @param <code>String</code> the namespace in which the metadata occurs
118 * @param <code>String</code> the label of the metadata
119 * @param <code>String</code> the value of the metadata
120 */
121 public void setMetadata(String namespace, String label, String value)
122 {
123 METSNamespace namespaceData = this.getOpenNamespace(namespace);
124
125 if (namespaceData == null ||
126 namespaceData.isEditable() == false) {
127 namespaceData = NamespaceFactory.initNamespace(namespace);
128 this.addNamespace(namespaceData);
129 }
130 namespaceData.setMetadata(label, value);
131 }
132
133 /**
134 * Remove the metadata for a particular label.
135 *
136 * @param <code>String</code> the namespace in which the metadata occurs
137 * @param <code>String</code> the label of the metadata
138 */
139 public void removeMetadata(String namespace, String label)
140 {
141 METSNamespace namespaceData = this.getOpenNamespace(namespace);
142
143 if (namespaceData != null && namespaceData.isEditable() == true) {
144 namespaceData.removeMetadata(label);
145 }
146 }
147
148 /**
149 * Fetch a <code>List</code> of the values matching the given label in
150 * the requisite namespace.
151 *
152 * @param <code>String</code> namespace
153 * @param <code>String</code> label of metadata to match
154 *
155 * @return <code>List</code> the corresponding values found.
156 */
157 public List getMetadata(String namespace, String label)
158 {
159 // Simple case - no metadata
160 if (!this.map.containsKey(namespace)){
161 return null;
162 }
163
164 // if there's just one instance of the requisite namespace,
165 // then again it is a simple case
166 if (this.map.getAll(namespace).size() == 1){
167 return this.getNamespace(namespace).getMetadata(label);
168 }
169
170 // otherwise, step through and accumulate
171 List accumulatedValues = new ArrayList();
172 Iterator namespaceIterator = this.map.getAll(namespace).iterator();
173 while (namespaceIterator.hasNext()){
174 METSNamespace localNamespace = (METSNamespace) namespaceIterator.next();
175
176 List localList = localNamespace.getMetadata(label);
177 if (localList != null && localList.size() > 0){
178 accumulatedValues.addAll(localList);
179 }
180 }
181
182 // if the result of the accumulation is empty, return a null item
183 if (accumulatedValues.size() == 0){
184 return null;
185 }
186
187 return accumulatedValues;
188 }
189
190 protected void parse_xmlData(METSNamespace namespace, Element element)
191 {
192 if (namespace==null) {
193 System.err.println("namespace is null!!!!");
194 }
195 NodeList children = element.getChildNodes();
196
197 for (int c = 0; c < children.getLength(); c++) {
198 if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
199 continue;
200 }
201
202 Element child = (Element) children.item(c);
203 String childName = child.getNodeName();
204
205 // if (childName.equals("gsdl2:Metadata")) {
206 if (childName.equals("gsdl3:Metadata")) {
207 String metaName = child.getAttribute("name");
208 Text text = (Text) child.getFirstChild();
209 String metaValue = text.getData();
210
211 addMetadata(namespace.getName(),metaName, metaValue);
212 }
213 }
214 }
215
216 public void parse_mdWrap(Element element)
217 {
218 // deal with mets:mdWrap
219
220 METSNamespace namespace = NamespaceFactory.parseXML(element);
221
222 NodeList children = element.getChildNodes();
223
224 for (int c = 0; c < children.getLength(); c ++) {
225 if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
226 continue;
227 }
228
229 Element child = (Element) children.item(c);
230 String childName = child.getNodeName();
231
232 if (childName.equals("mets:xmlData")) {
233 parse_xmlData(namespace, child);
234 } else {
235 System.err.println("Warning: unrecognised tag " + childName
236 + "in mets:mdWrap");
237 }
238 }
239 }
240
241 /**
242 * Parse an XML Element as a METS Descriptive Metadata section
243 *
244 * @param <code>Element</code> the XML element which represents the dmdSec itself
245 */
246 public static METSDescriptive parseXML(Element element)
247 {
248 // Note: no parsing of attributes required, we just move onto
249 // the metadata namespaces/sections themselves
250
251 // deal with mets:dmdSec
252 String ID = element.getAttribute("ID");
253 String label = element.getAttribute("GROUPID");
254
255 METSDescriptive thisDescriptive = new METSDescriptive(ID, label);
256
257 //thisDescriptive = new METSDescriptive(ID, label);
258
259 NodeList children = element.getChildNodes();
260
261 for (int c = 0; c < children.getLength(); c ++) {
262 if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
263 continue;
264 }
265
266 Element child = (Element) children.item(c);
267 String childName = child.getNodeName();
268
269 if (childName.equals("mets:mdRef")) {
270 //for External Descriptive Metadata
271 METSNamespace namespace = NamespaceFactory.parseXML(element);
272 System.err.println("*** mets::mdRef does not appear to be implemented yet");
273 } else if (childName.equals("mets:mdWrap")) {
274 thisDescriptive.parse_mdWrap(child);
275 } else {
276 // TODO: raise an error!
277 System.out.println("Error: METSDescriiptive: unrecognised tag "+childName);
278 }
279 }
280 return thisDescriptive;
281 }
282 /**
283 * Write the document metadata to a <code>PrintWriter</code> in METS
284 * XML format.
285 *
286 * @param <code>PrintWriter</code> the writer to use for output
287 */
288 public void write(PrintWriter output)
289 {
290 String tag = XMLTools.getOpenTag("mets", "dmdSec");
291 tag = XMLTools.addAttribute(tag, "ID", this.ID);
292 tag = XMLTools.addAttribute(tag, "GROUPID", this.name);
293 output.println(tag);
294
295 Iterator keys = this.map.keySet().iterator();
296
297 // get the keys one by one
298 while (keys.hasNext()){
299 Object nextKey = keys.next();
300 if (nextKey == null){
301 continue;
302 }
303 String key = nextKey.toString();
304
305 // get every copy of the current namespace name - namespaces may
306 // occur more than once, so this is a List
307 Iterator namespaces = this.map.getAll(key).iterator();
308
309 // namespaces will write themselves...
310 while (namespaces.hasNext()){
311 METSNamespace namespace = (METSNamespace) namespaces.next();
312
313 namespace.write(output);
314 }
315 }
316
317 tag = XMLTools.getCloseTag("mets", "dmdSec");
318 output.println(tag);
319 }
320
321 public void copy_metadata(METSDescriptive dst)
322 {
323 Iterator keys = this.map.keySet().iterator();
324
325 // get the keys one by one
326 while (keys.hasNext()) {
327 Object nextKey = keys.next();
328 if (nextKey == null) {
329 continue;
330 }
331 String key = nextKey.toString();
332
333 // get every copy of the current namespace name - namespaces may
334 // occur more than once, so this is a List
335 Iterator namespaces = this.map.getAll(key).iterator();
336
337 while (namespaces.hasNext()) {
338 METSNamespace namespace = (METSNamespace) namespaces.next();
339
340 // for each metadata name
341
342 Iterator mdnIter = namespace.getMetadataNames();
343 while (mdnIter.hasNext()) {
344
345 String md_name = mdnIter.next().toString();
346
347 List values = getMetadata(key, md_name);
348
349 if (values != null) {
350 Iterator valueIter = values.iterator();
351 while (valueIter.hasNext()) {
352 String value = valueIter.next().toString();
353 dst.addMetadata("gsdl3",md_name,value);
354 }
355 }
356 }
357 }
358 }
359 }
360
361
362 public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
363 {
364 // check if this node is in the
365 int sqlId = -1;
366
367 // System.out.println("Writing " + connection.toString());
368
369 GS3SQLSelect select = new GS3SQLSelect("metadata");
370 select.addField("*");
371 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetaID", "=", this.ID);
372 GS3SQLWhereItem item = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
373 GS3SQLWhere where = new GS3SQLWhere(whereItem);
374 where.add(item);
375 select.setWhere(where);
376
377 connection.execute(select.toString());
378
379 try {
380 GS3SQLAction action;
381
382 ResultSet resultSet = connection.getResultSet();
383
384 if (resultSet != null &&
385 resultSet.first()) {
386 // the node already exists - no need to do anything as such
387 GS3SQLUpdate update = new GS3SQLUpdate("metadata");
388 update.setWhere(where);
389 action = update;
390 }
391 else
392 { // Set result set to null, just in case next() didn't work above...
393 resultSet = null;
394
395 // It is a new node and needs writing
396 action = new GS3SQLInsert("metadata");
397
398 action.addValue("DocID", document.getID().toString());
399 action.addValue("MetaID", this.ID);
400 }
401
402 // always set the group identifier
403 action.addValue("GroupID", this.name);
404
405 // execute the action as required
406 connection.execute(action.toString());
407
408 // create a new resultset if necessary
409 if (resultSet == null) {
410 // now execute the select statement again to get the new identifier
411 // 'MetadataRef'
412 // System.out.println(select.toString());
413 connection.execute(select.toString());
414
415 resultSet = connection.getResultSet();
416 resultSet.first();
417 }
418
419 // get the reference for this item...
420 sqlId = resultSet.getInt("MetadataRef");
421 }
422 catch (SQLException sql){
423 System.out.println(sql);
424 }
425
426 Iterator keys = this.map.keySet().iterator();
427
428 // get the keys one by one
429 while (keys.hasNext()){
430 Object nextKey = keys.next();
431 if (nextKey == null){
432 continue;
433 }
434 String key = nextKey.toString();
435
436 // get every current namespace - namespaces may
437 // occur more than once, so this is a List
438 Iterator namespaces = this.map.getAll(key).iterator();
439
440 // namespaces will write themselves...
441 while (namespaces.hasNext()){
442 METSNamespace namespace = (METSNamespace) namespaces.next();
443
444 if (!namespace.writeSQL(sqlId, connection)){
445 return false;
446 }
447 }
448 }
449 return true;
450 }
451
452 public static METSDescriptive readSQL(DocumentInterface document, GS3SQLConnection connection,
453 ResultSet resultSet)
454 {
455 try {
456 String ID = resultSet.getString("MetaID");
457 String name = resultSet.getString("GroupID");
458
459 // create the metadata block object
460 METSDescriptive descriptive = new METSDescriptive(ID, name);
461
462 // get its metadata reference to retrieve namespaces
463 int metadataRef = resultSet.getInt("MetadataRef");
464
465 // query the database for matching namespaces for this metadata block
466 GS3SQLSelect select = new GS3SQLSelect("namespaces");
467 select.addField("*");
468 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(metadataRef),
469 GS3SQLField.INTEGER_TYPE);
470 GS3SQLWhere where = new GS3SQLWhere(whereItem);
471 select.setWhere(where);
472
473 connection.execute(select.toString());
474
475 // parse through the namespaces, calling the namespace class to create instances
476 // as it will
477 ResultSet namespaceSet = connection.getResultSet();
478 if (namespaceSet != null && namespaceSet.first()) {
479 do {
480 METSNamespace namespace = METSNamespace.readSQL(connection, namespaceSet);
481 if (namespace != null) {
482 descriptive.addNamespace(namespace);
483 }
484 else {
485 System.out.println("Null namespace output");
486 }
487 }
488 while (namespaceSet.next());
489 }
490
491 return descriptive;
492 }
493 catch (SQLException sqlEx){
494 System.out.println(sqlEx);
495 System.exit(1);
496 }
497 return null;
498 }
499}
Note: See TracBrowser for help on using the repository browser.