source: trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptive.java@ 9874

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

merged from branch ant-install-branch: merge 1

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