source: branches/ant-install-branch/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/SimpleNamespace.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: 10.7 KB
Line 
1package org.greenstone.gsdl3.gs3build.metadata;
2
3import java.io.PrintWriter;
4import java.util.Iterator;
5import java.util.List;
6import java.util.Map;
7import java.util.ArrayList;
8import java.util.HashMap;
9
10import java.sql.SQLException;
11import java.sql.Statement;
12import java.sql.ResultSet;
13
14import org.w3c.dom.Document;
15import org.w3c.dom.Element;
16import org.w3c.dom.NamedNodeMap;
17import org.w3c.dom.Node;
18import org.w3c.dom.NodeList;
19import org.w3c.dom.Text;
20
21import org.greenstone.gsdl3.gs3build.util.MultiMap;
22import org.greenstone.gsdl3.gs3build.util.XMLTools;
23import org.greenstone.gsdl3.gs3build.database.*;
24
25/**
26 * Implement a simple, unordered, namespace in METS.
27 *
28 * @see: org.greenstone.gsdl3.gs3build.metadata.METSNamespace
29 */
30
31public class SimpleNamespace extends METSNamespace
32{
33 MultiMap metadataMap;
34
35 public SimpleNamespace(String name)
36 {
37 super(name);
38 this.metadataMap = new MultiMap();
39 }
40
41 public SimpleNamespace(String name, METSLocation location)
42 {
43 super(name, location);
44 this.metadataMap = new MultiMap();
45 }
46
47 public SimpleNamespace(String name, Element mdWrapTag)
48 {
49 super(name);
50 this.metadataMap = new MultiMap();
51
52 NodeList childNodes = mdWrapTag.getChildNodes();
53 for (int c = 0; c < childNodes.getLength(); c ++) {
54 // a metadata node
55 if (childNodes.item(c).getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
56 // get the name of the metadata from the node
57 String metadataLabel = childNodes.item(c).getNodeName();
58
59 // skip blank labels
60 // TODO: raise an error: metadata item without metadata label set
61 if (metadataLabel == null || metadataLabel.length() == 0) {
62 continue;
63 }
64
65 // build the value
66 String metadataValue = "";
67
68 Element childElement = (Element) childNodes.item(c);
69 for (int i = 0; i < childElement.getChildNodes().getLength(); i ++) {
70 metadataValue = metadataValue + childElement.getChildNodes().item(i).toString();
71 }
72
73 // trim any leading namespace identifiers in "namespace:label" metadata
74 if (metadataLabel.startsWith(this.name + ":")) {
75 metadataLabel = metadataLabel.substring(this.name.length() + 1);
76 }
77
78 this.addMetadata(metadataLabel, metadataValue);
79 }
80 }
81 }
82
83 public boolean validate(String field, String value)
84 {
85 return true;
86 }
87
88 /**
89 * Add a metadata item. Whether the field and value validate for this
90 * schema will also be tested.
91 *
92 * @param <code>String</code> the name of the field to be given the value
93 * @param <code>String</code> the value to be assigned
94 *
95 * @return <code>boolean</code> whether the field value was added. This
96 * would return <code>false</code> if the values did not validate,
97 * for example.
98 */
99 public boolean addMetadata(String label, String value)
100 {
101 if (!this.validate(label, value)) {
102 return false;
103 }
104
105 this.metadataMap.put(label, value);
106 return true;
107 }
108
109 /**
110 * Assign a metadata item. Whether the field and value validate for this
111 * schema will also be tested. Any existing metadata for that field will
112 * be destroyed if the new value validates.
113 *
114 * @param <code>String</code> the name of the field to be given the value
115 * @param <code>String</code> the value to be assigned
116 *
117 * @return <code>boolean</code> whether the field value was added. This
118 * would return <code>false</code> if the values did not validate,
119 * for example.
120 */
121 public boolean setMetadata(String label, String value)
122 {
123 if (!this.validate(label, value)) {
124 return false;
125 }
126
127 this.metadataMap.setOnly(label, value);
128 return true;
129 }
130
131 /**
132 * Remove all metadata values for a given field name
133 *
134 * @param <code>String</code> the field to delete
135 *
136 * @return <code>boolean</code> whether the field was actually deleted;
137 * will return <code>true</code> if the field was already empty.
138 */
139 public boolean removeMetadata(String label)
140 {
141 this.metadataMap.remove(label);
142 return true;
143 }
144
145 /**
146 * Remove a particular incidence of a given metadata field for a document.
147 * If an exact match for the given value is not found, nothing changes.
148 * N.B. if a value occurs twice, only the first incidence of it will be
149 * deleted from the list.
150 *
151 * @param <code>String</code> the field to have the value removed
152 * @param <code>String</code> the value to be removed from a given field
153 *
154 * @return <code>boolean</code> <code>true</code> if an actual metadata text
155 * is matched against the given value and is thus deleted.
156 */
157 public boolean removeMetadata(String label, String value)
158 {
159 return this.metadataMap.remove(label, value);
160 }
161
162 /**
163 * Get the metadata items for a particular label
164 *
165 * @param <code>String</code> the label to fetch values for
166 *
167 * @return <code>List</code> the list of corresponding values. May be
168 * <code>null</code>
169 */
170 public List getMetadata(String label)
171 {
172 return this.metadataMap.getAll(label);
173 }
174
175 public Iterator getMetadataNames()
176 {
177 return this.metadataMap.keySet().iterator();
178 }
179
180 /**
181 * Write out the metadata to an XML file through a <code>PrintWriter</code>.
182 *
183 * @param <code>PrintWriter</code> the writer to use.
184 */
185 public boolean write(PrintWriter writer)
186 {
187 // if this is a non-file block of metadata, write it out in long hand
188 if (this.location == null){
189 String tag = XMLTools.getOpenTag("mets", "mdWrap");
190
191 tag = XMLTools.addAttribute(tag, "MDTYPE", "OTHER");
192 tag = XMLTools.addAttribute(tag, "OTHERMDTYPE", this.name);
193 if (this.id != null) {
194 this.id = "gsdl"+this.id;
195 tag = XMLTools.addAttribute(tag, "ID", this.id);
196 }
197 writer.print(" "); //indentation
198 writer.println(tag);
199
200 tag = XMLTools.getOpenTag("mets", "xmlData");
201 writer.print(" "); //indentation
202 writer.println(tag);
203
204 Iterator keys = this.metadataMap.keySet().iterator();
205 while (keys.hasNext()){
206 String thisKey = keys.next().toString();
207 writer.print(" "); //indentation
208 this.writeItem(writer, thisKey);
209 }
210
211 writer.print(" "); //indentation
212 writer.println(XMLTools.getCloseTag("mets", "xmlData"));
213
214 writer.print(" "); //indentation
215 writer.println(XMLTools.getCloseTag("mets", "mdWrap"));
216 }
217 // otherwise, drop the metadata out in a simplified file-reference
218 // form only
219 else
220 {
221 String tag = XMLTools.getOpenTag("mets","mdRef");
222 tag = XMLTools.addAttribute(tag, "LOCTYPE", "URL");
223 tag = XMLTools.addAttribute(tag, "xlink:href", location.getLocation().toString());
224 //tag = XMLTools.addAttribute(tag, "MDTYPE", "OTHER");
225 //tag = XMLTools.addAttribute(tag, "OTHERMDTYPE", this.name);
226 tag = XMLTools.addAttribute(tag, "MDTYPE", this.name);
227 if (this.id != null) {
228 tag = XMLTools.addAttribute(tag, "ID", this.id);
229 }
230 writer.println(tag);
231 writer.print(" "); //indentation
232 writer.println("</mets:mdRef>");
233 }
234 return true;
235 }
236
237 /**
238 * Write out a single element - this may be overloaded to provide for the
239 * appropriate formatting for this metadata.
240 */
241 protected boolean writeItem(PrintWriter writer, String label)
242 {
243 if (this.location == null) {
244 // just place the metadata in a simple wrapper
245 Iterator values = this.metadataMap.getAll(label).iterator();
246
247 while (values.hasNext()) {
248 String value = values.next().toString();
249 String metaTagName = "Metadata name=" +'"'+ label +'"';
250 //writer.write(XMLTools.getOpenTag(this.name, label));
251 writer.write(XMLTools.getOpenTag(this.name, metaTagName));
252 writer.write(value);
253
254 //writer.println(XMLTools.getCloseTag(this.name, label));
255 writer.println(XMLTools.getCloseTag(this.name, "Metadata"));
256 }
257 }
258 else {
259 String tag = XMLTools.getOpenTag("mets", "mdRef");
260 tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
261 tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
262 tag = XMLTools.addAttribute(tag, "MDTYPE", this.getName());
263 tag = XMLTools.makeSingleton(tag);
264 writer.print(" "); //indentation
265 writer.println(tag);
266 }
267 return true;
268 }
269
270 /**
271 * Write out the metadata to an SQL database through a <code>GS3SQLConnection</code>.
272 *
273 * @param <code>GS3SQLConnection</code> the SQL database to use.
274 */
275 public boolean writeSQL(int parentId, GS3SQLConnection connection)
276 {
277 // write the general stuff
278 String sqlId;
279
280 if (!super.writeSQL(parentId, connection)) {
281 return false;
282 }
283
284 Statement statement = null;
285 ResultSet results = null;
286 try {
287 statement = connection.createStatement();
288 if (this.id == null) {
289 GS3SQLSelect select = new GS3SQLSelect("namespaces");
290 select.setWhere(new GS3SQLWhere(new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(parentId), GS3SQLField.INTEGER_TYPE)));
291 select.addField("NamespaceRef");
292 results = statement.executeQuery(select.toString());
293 if (results.first()) {
294 sqlId = Integer.toString(results.getInt("NamespaceRef"));
295 } else {
296 statement.close();
297 return false;
298 }
299 }
300 else {
301 sqlId = this.id;
302 }
303
304 // clear all the existing metadata items for this namespace
305 GS3SQLDelete delete = new GS3SQLDelete("mdvalues");
306 GS3SQLWhere where = new GS3SQLWhere(new GS3SQLWhereItem("NamespaceRef", "=", sqlId, GS3SQLField.INTEGER_TYPE));
307 delete.setWhere(where);
308 statement.execute(delete.toString());
309
310 // write out the metadata for this namespace
311 Iterator keys = this.metadataMap.keySet().iterator();
312 while (keys.hasNext()){
313 String thisKey = keys.next().toString();
314
315 Iterator values = this.metadataMap.getAll(thisKey).iterator();
316
317 while (values.hasNext()){
318 String value = values.next().toString();
319
320 GS3SQLInsert insert = new GS3SQLInsert("mdvalues");
321 insert.addValue("NamespaceRef", sqlId, GS3SQLField.INTEGER_TYPE);
322 insert.addValue("Label", thisKey);
323 insert.addValue("Value", value);
324 statement.execute(insert.toString());
325 }
326 }
327 statement.close();
328 }
329 catch (SQLException sql) {
330 System.out.println("SimpleNamespace.writeSQL(): "+sql);
331 }
332 return true;
333 }
334
335
336 /**
337 * <p>Indicate whether this metadata is open to being changed or not.</p>
338 * <p>Metadata which is created from a distinct file cannot be changed,
339 * only those which have no associated file can be modified.
340 *
341 * @return <code>boolean</code> whether this namespace can be altered.
342 */
343 public boolean isEditable()
344 {
345 return (this.location == null);
346 }
347}
Note: See TracBrowser for help on using the repository browser.