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

Last change on this file since 7466 was 6738, checked in by cs025, 20 years ago

Added remove function, or tidied as appropriate.

  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 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 * Remove the metadata for a particular label.
127 *
128 * @param <code>String</code> the namespace in which the metadata occurs
129 * @param <code>String</code> the label of the metadata
130 */
131 public void removeMetadata(String namespace, String label)
132 { METSNamespace namespaceData = this.getOpenNamespace(namespace);
133
134 if (namespaceData != null && namespaceData.isEditable() == true)
135 { namespaceData.removeMetadata(label);
136 }
137 }
138
139 /**
140 * Fetch a <code>List</code> of the values matching the given label in
141 * the requisite namespace.
142 *
143 * @param <code>String</code> namespace
144 * @param <code>String</code> label of metadata to match
145 *
146 * @return <code>List</code> the corresponding values found.
147 */
148 public List getMetadata(String namespace, String label)
149 {
150 // Simple case - no metadata
151 if (!this.map.containsKey(namespace))
152 { return null;
153 }
154
155 // if there's just one instance of the requisite namespace,
156 // then again it is a simple case
157 if (this.map.getAll(namespace).size() == 1)
158 { return this.getNamespace(namespace).getMetadata(label);
159 }
160
161 // otherwise, step through and accumulate
162 List accumulatedValues = new ArrayList();
163 Iterator namespaceIterator = this.map.getAll(namespace).iterator();
164 while (namespaceIterator.hasNext())
165 { METSNamespace localNamespace = (METSNamespace) namespaceIterator.next();
166
167 List localList = localNamespace.getMetadata(label);
168 if (localList != null && localList.size() > 0)
169 { accumulatedValues.addAll(localList);
170 }
171 }
172
173 // if the result of the accumulation is empty, return a null item
174 if (accumulatedValues.size() == 0)
175 { return null;
176 }
177
178 return accumulatedValues;
179 }
180
181 /**
182 * Parse an XML Element as a METS Descriptive Metadata section
183 *
184 * @param <code>Element</code> the XML element which represents the dmdSec itself
185 */
186 public static METSDescriptive parseXML(Element element)
187 { // Note: no parsing of attributes required, we just move onto the metadata
188 // namespaces/sections themselves
189 String ID = element.getAttribute("ID");
190 String label = element.getAttribute("GROUPID");
191 METSDescriptive thisDescriptive = new METSDescriptive(ID, label);
192
193 NodeList children = element.getChildNodes();
194
195 for (int c = 0; c < children.getLength(); c ++)
196 { if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
197 continue;
198 }
199
200 Element childElement = (Element) children.item(c);
201 if (childElement.getNodeName().equals("mets:mdRef"))
202 { METSNamespace namespace = NamespaceFactory.parseXML(element);
203 }
204 else if (childElement.getNodeName().equals("mets:mdWrap"))
205 { METSNamespace namespace = NamespaceFactory.parseXML(element);
206 }
207 else
208 { // TODO: raise an error!
209 }
210 }
211 return thisDescriptive;
212 }
213
214
215 /**
216 * Write the document metadata to a <code>PrintWriter</code> in METS
217 * XML format.
218 *
219 * @param <code>PrintWriter</code> the writer to use for output
220 */
221 public void write(PrintWriter output)
222 { String tag = XMLTools.getOpenTag("mets", "dmdSec");
223 tag = XMLTools.addAttribute(tag, "ID", this.ID);
224 tag = XMLTools.addAttribute(tag, "GROUPID", this.name);
225 output.println(tag);
226
227 Iterator keys = this.map.keySet().iterator();
228
229 // get the keys one by one
230 while (keys.hasNext())
231 { Object nextKey = keys.next();
232 if (nextKey == null)
233 { continue;
234 }
235 String key = nextKey.toString();
236
237 // get every copy of the current namespace name - namespaces may
238 // occur more than once, so this is a List
239 Iterator namespaces = this.map.getAll(key).iterator();
240
241 // namespaces will write themselves...
242 while (namespaces.hasNext())
243 { METSNamespace namespace = (METSNamespace) namespaces.next();
244
245 namespace.write(output);
246 }
247 }
248
249 tag = XMLTools.getCloseTag("mets", "dmdSec");
250 output.println(tag);
251 }
252
253 public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
254 { // check if this node is in the
255 int sqlId = -1;
256
257 // System.out.println("Writing " + connection.toString());
258
259 GS3SQLSelect select = new GS3SQLSelect("metadata");
260 select.addField("*");
261 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetaID", "=", this.ID);
262 GS3SQLWhereItem item = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
263 GS3SQLWhere where = new GS3SQLWhere(whereItem);
264 where.add(item);
265 select.setWhere(where);
266
267 connection.execute(select.toString());
268
269 try {
270 GS3SQLAction action;
271
272 ResultSet resultSet = connection.getResultSet();
273
274 if (resultSet != null &&
275 resultSet.first()) {
276 // the node already exists - no need to do anything as such
277 GS3SQLUpdate update = new GS3SQLUpdate("metadata");
278 update.setWhere(where);
279 action = update;
280 }
281 else
282 { // Set result set to null, just in case next() didn't work above...
283 resultSet = null;
284
285 // It is a new node and needs writing
286 action = new GS3SQLInsert("metadata");
287
288 action.addValue("DocID", document.getID().toString());
289 action.addValue("MetaID", this.ID);
290 }
291
292 // always set the group identifier
293 action.addValue("GroupID", this.name);
294
295 // execute the action as required
296 connection.execute(action.toString());
297
298 // create a new resultset if necessary
299 if (resultSet == null) {
300 // now execute the select statement again to get the new identifier
301 // 'MetadataRef'
302 // System.out.println(select.toString());
303 connection.execute(select.toString());
304
305 resultSet = connection.getResultSet();
306 resultSet.first();
307 }
308
309 // get the reference for this item...
310 sqlId = resultSet.getInt("MetadataRef");
311 }
312 catch (SQLException sql)
313 { System.out.println(sql);
314 }
315
316 Iterator keys = this.map.keySet().iterator();
317
318 // get the keys one by one
319 while (keys.hasNext())
320 { Object nextKey = keys.next();
321 if (nextKey == null)
322 { continue;
323 }
324 String key = nextKey.toString();
325
326 // get every current namespace - namespaces may
327 // occur more than once, so this is a List
328 Iterator namespaces = this.map.getAll(key).iterator();
329
330 // namespaces will write themselves...
331 while (namespaces.hasNext())
332 { METSNamespace namespace = (METSNamespace) namespaces.next();
333
334 if (!namespace.writeSQL(sqlId, connection))
335 { return false;
336 }
337 }
338 }
339 return true;
340 }
341
342 public static METSDescriptive readSQL(DocumentInterface document, GS3SQLConnection connection,
343 ResultSet resultSet)
344 {
345 try {
346 String ID = resultSet.getString("MetaID");
347 String name = resultSet.getString("GroupID");
348
349 // create the metadata block object
350 METSDescriptive descriptive = new METSDescriptive(ID, name);
351
352 // get its metadata reference to retrieve namespaces
353 int metadataRef = resultSet.getInt("MetadataRef");
354
355 // query the database for matching namespaces for this metadata block
356 GS3SQLSelect select = new GS3SQLSelect("namespaces");
357 select.addField("*");
358 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(metadataRef),
359 GS3SQLField.INTEGER_TYPE);
360 GS3SQLWhere where = new GS3SQLWhere(whereItem);
361 select.setWhere(where);
362
363 connection.execute(select.toString());
364
365 // parse through the namespaces, calling the namespace class to create instances
366 // as it will
367 ResultSet namespaceSet = connection.getResultSet();
368 if (namespaceSet != null && namespaceSet.first()) {
369 do {
370 METSNamespace namespace = METSNamespace.readSQL(connection, namespaceSet);
371 if (namespace != null) {
372 descriptive.addNamespace(namespace);
373 }
374 else {
375 System.out.println("Null namespace output");
376 }
377 }
378 while (namespaceSet.next());
379 }
380
381 return descriptive;
382 }
383 catch (SQLException sqlEx)
384 { System.out.println(sqlEx);
385 System.exit(1);
386 }
387 return null;
388 }
389}
Note: See TracBrowser for help on using the repository browser.