source: branches/ant-install-branch/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptive.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: 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.