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

Last change on this file since 6103 was 5945, checked in by cs025, 21 years ago

Extensive additions to metadata

  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 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.util.GS3SQLConnection;
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{ MultiMap map;
39 String ID;
40 String name;
41
42 public METSDescriptive(String ID, String name)
43 { this.map = new MultiMap();
44 this.ID = ID;
45 this.name = name;
46 }
47
48 public String getID()
49 { return this.ID;
50 }
51
52 public String getName()
53 { return this.name;
54 }
55
56 public void addNamespace(METSNamespace namespace)
57 { this.map.put(namespace.getName(), namespace);
58 }
59
60 public METSNamespace getNamespace(String namespace)
61 { return (METSNamespace) this.map.get(namespace);
62 }
63
64 /**
65 * Get the version of a metadata namespace that can be used for
66 * adding new values to the document. Remember, each namespace may
67 * occur more than once, but only one of the occurrences can be 'open'.
68 *
69 * @param <code>String</code> the name of the namespace
70 */
71 public METSNamespace getOpenNamespace(String namespace)
72 { if (this.map.getAll(namespace) == null)
73 { return null;
74 }
75
76 Iterator namespaces = ((List) this.map.getAll(namespace)).iterator();
77
78 while (namespaces.hasNext())
79 { METSNamespace namespaceData = (METSNamespace) namespaces.next();
80
81 if (namespaceData.isEditable())
82 { return namespaceData;
83 }
84 }
85 return null;
86 }
87
88 /**
89 * Add a piece of metadata to this document. Existing values are preserved.
90 *
91 * @param <code>String</code> the namespace in which the metadata occurs
92 * @param <code>String</code> the label of the metadata
93 * @param <code>String</code> the value of the metadata
94 */
95 public void addMetadata(String namespace, String label, String value)
96 { METSNamespace namespaceData = this.getOpenNamespace(namespace);
97
98 if (namespaceData == null ||
99 namespaceData.isEditable() == false)
100 { namespaceData = NamespaceFactory.initNamespace(namespace);
101 this.addNamespace(namespaceData);
102 }
103 namespaceData.addMetadata(label, value);
104 }
105
106 /**
107 * Add a piece of metadata to this document. Existing values in editable
108 * parts of the document's metadata are destroyed.
109 *
110 * @param <code>String</code> the namespace in which the metadata occurs
111 * @param <code>String</code> the label of the metadata
112 * @param <code>String</code> the value of the metadata
113 */
114 public void setMetadata(String namespace, String label, String value)
115 { METSNamespace namespaceData = this.getOpenNamespace(namespace);
116
117 if (namespaceData == null ||
118 namespaceData.isEditable() == false)
119 { namespaceData = NamespaceFactory.initNamespace(namespace);
120 this.addNamespace(namespaceData);
121 }
122 namespaceData.setMetadata(label, value);
123 }
124
125 /**
126 * Fetch a <code>List</code> of the values matching the given label in
127 * the requisite namespace.
128 *
129 * @param <code>String</code> namespace
130 * @param <code>String</code> label of metadata to match
131 *
132 * @return <code>List</code> the corresponding values found.
133 */
134 public List getMetadata(String namespace, String label)
135 {
136 // Simple case - no metadata
137 if (!this.map.containsKey(namespace))
138 { return null;
139 }
140
141 // if there's just one instance of the requisite namespace,
142 // then again it is a simple case
143 if (this.map.getAll(namespace).size() == 1)
144 { return this.getNamespace(namespace).getMetadata(label);
145 }
146
147 // otherwise, step through and accumulate
148 List accumulatedValues = new ArrayList();
149 Iterator namespaceIterator = this.map.getAll(namespace).iterator();
150 while (namespaceIterator.hasNext())
151 { METSNamespace localNamespace = (METSNamespace) namespaceIterator.next();
152
153 List localList = localNamespace.getMetadata(label);
154 if (localList != null && localList.size() > 0)
155 { accumulatedValues.addAll(localList);
156 }
157 }
158
159 // if the result of the accumulation is empty, return a null item
160 if (accumulatedValues.size() == 0)
161 { return null;
162 }
163
164 return accumulatedValues;
165 }
166
167 /**
168 * Parse an XML Element as a METS Descriptive Metadata section
169 *
170 * @param <code>Element</code> the XML element which represents the dmdSec itself
171 */
172 public static METSDescriptive parseXML(Element element)
173 { // Note: no parsing of attributes required, we just move onto the metadata
174 // namespaces/sections themselves
175 String ID = element.getAttribute("ID");
176 String label = element.getAttribute("GROUPID");
177 METSDescriptive thisDescriptive = new METSDescriptive(ID, label);
178
179 NodeList children = element.getChildNodes();
180
181 for (int c = 0; c < children.getLength(); c ++)
182 { if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
183 continue;
184 }
185
186 Element childElement = (Element) children.item(c);
187 if (childElement.getNodeName().equals("mets:mdRef"))
188 { METSNamespace namespace = NamespaceFactory.parseXML(element);
189 }
190 else if (childElement.getNodeName().equals("mets:mdWrap"))
191 { METSNamespace namespace = NamespaceFactory.parseXML(element);
192 }
193 else
194 { // TODO: raise an error!
195 }
196 }
197 return thisDescriptive;
198 }
199
200
201 /**
202 * Write the document metadata to a <code>PrintWriter</code> in METS
203 * XML format.
204 *
205 * @param <code>PrintWriter</code> the writer to use for output
206 */
207 public void write(PrintWriter output)
208 { String tag = XMLTools.getOpenTag("mets", "dmdSec");
209 tag = XMLTools.addAttribute(tag, "ID", this.ID);
210 tag = XMLTools.addAttribute(tag, "GROUPID", this.name);
211 output.println(tag);
212
213 Iterator keys = this.map.keySet().iterator();
214
215 // get the keys one by one
216 while (keys.hasNext())
217 { Object nextKey = keys.next();
218 if (nextKey == null)
219 { continue;
220 }
221 String key = nextKey.toString();
222
223 // get every copy of the current namespace name - namespaces may
224 // occur more than once, so this is a List
225 Iterator namespaces = this.map.getAll(key).iterator();
226
227 // namespaces will write themselves...
228 while (namespaces.hasNext())
229 { METSNamespace namespace = (METSNamespace) namespaces.next();
230
231 namespace.write(output);
232 }
233 }
234
235 tag = XMLTools.getCloseTag("mets", "dmdSec");
236 output.println(tag);
237 }
238
239 public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
240 { // check if this node is in the
241 int sqlId = -1;
242
243 // System.out.println("Writing " + connection.toString());
244
245 GS3SQLSelect select = new GS3SQLSelect("metadata");
246 select.addField("*");
247 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetaID", "=", this.ID);
248 GS3SQLWhereItem item = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
249 GS3SQLWhere where = new GS3SQLWhere(whereItem);
250 where.add(item);
251 select.setWhere(where);
252
253 connection.execute(select.toString());
254
255 try {
256 GS3SQLAction action;
257
258 ResultSet resultSet = connection.getResultSet();
259
260 if (resultSet != null &&
261 resultSet.first()) {
262 // the node already exists - no need to do anything as such
263 GS3SQLUpdate update = new GS3SQLUpdate("metadata");
264 update.setWhere(where);
265 action = update;
266 }
267 else
268 { // Set result set to null, just in case next() didn't work above...
269 resultSet = null;
270
271 // It is a new node and needs writing
272 action = new GS3SQLInsert("metadata");
273
274 action.addValue("DocID", document.getID().toString());
275 action.addValue("MetaID", this.ID);
276 }
277
278 // always set the group identifier
279 action.addValue("GroupID", this.name);
280
281 // execute the action as required
282 connection.execute(action.toString());
283
284 // create a new resultset if necessary
285 if (resultSet == null) {
286 // now execute the select statement again to get the new identifier
287 // 'MetadataRef'
288 // System.out.println(select.toString());
289 connection.execute(select.toString());
290
291 resultSet = connection.getResultSet();
292 resultSet.first();
293 }
294
295 // get the reference for this item...
296 sqlId = resultSet.getInt("MetadataRef");
297 }
298 catch (SQLException sql)
299 { System.out.println(sql);
300 }
301
302 Iterator keys = this.map.keySet().iterator();
303
304 // get the keys one by one
305 while (keys.hasNext())
306 { Object nextKey = keys.next();
307 if (nextKey == null)
308 { continue;
309 }
310 String key = nextKey.toString();
311
312 // get every current namespace - namespaces may
313 // occur more than once, so this is a List
314 Iterator namespaces = this.map.getAll(key).iterator();
315
316 // namespaces will write themselves...
317 while (namespaces.hasNext())
318 { METSNamespace namespace = (METSNamespace) namespaces.next();
319
320 if (!namespace.writeSQL(sqlId, connection))
321 { return false;
322 }
323 }
324 }
325 return true;
326 }
327
328 public static METSDescriptive readSQL(DocumentInterface document, GS3SQLConnection connection,
329 ResultSet resultSet)
330 {
331 try {
332 String ID = resultSet.getString("MetaID");
333 String name = resultSet.getString("GroupID");
334
335 // create the metadata block object
336 METSDescriptive descriptive = new METSDescriptive(ID, name);
337
338 // get its metadata reference to retrieve namespaces
339 int metadataRef = resultSet.getInt("MetadataRef");
340
341 // query the database for matching namespaces for this metadata block
342 GS3SQLSelect select = new GS3SQLSelect("namespaces");
343 select.addField("*");
344 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(metadataRef),
345 GS3SQLField.INTEGER_TYPE);
346 GS3SQLWhere where = new GS3SQLWhere(whereItem);
347 select.setWhere(where);
348
349 connection.execute(select.toString());
350
351 // parse through the namespaces, calling the namespace class to create instances
352 // as it will
353 ResultSet namespaceSet = connection.getResultSet();
354 if (namespaceSet != null && namespaceSet.first()) {
355 do {
356 METSNamespace namespace = METSNamespace.readSQL(connection, namespaceSet);
357 if (namespace != null) {
358 descriptive.addNamespace(namespace);
359 }
360 else {
361 System.out.println("Null namespace output");
362 }
363 }
364 while (namespaceSet.next());
365 }
366
367 return descriptive;
368 }
369 catch (SQLException sqlEx)
370 { System.out.println(sqlEx);
371 System.exit(1);
372 }
373 return null;
374 }
375}
Note: See TracBrowser for help on using the repository browser.