source: branches/ant-install-branch/gsdl3/src/java/org/greenstone/gsdl3/gs3build/doctypes/AbstractDocument.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.8 KB
Line 
1package org.greenstone.gsdl3.gs3build.doctypes;
2
3import java.util.List;
4import java.util.ArrayList;
5import java.util.Iterator;
6import java.util.HashMap;
7import java.util.Map;
8import java.util.Date;
9
10import java.sql.SQLException;
11import java.sql.Statement;
12import java.sql.ResultSet;
13import java.sql.Timestamp;
14
15import java.net.URL;
16
17import org.greenstone.gsdl3.gs3build.metadata.NamespaceFactory;
18import org.greenstone.gsdl3.gs3build.metadata.StructureIdentifierFactory;
19import org.greenstone.gsdl3.gs3build.metadata.GSDL3Namespace;
20import org.greenstone.gsdl3.gs3build.metadata.METSDescriptiveSet;
21import org.greenstone.gsdl3.gs3build.metadata.METSFile;
22import org.greenstone.gsdl3.gs3build.metadata.METSFileSet;
23import org.greenstone.gsdl3.gs3build.metadata.METSHeader;
24import org.greenstone.gsdl3.gs3build.metadata.METSStructure;
25import org.greenstone.gsdl3.gs3build.metadata.METSStructureSet;
26import org.greenstone.gsdl3.gs3build.metadata.METSDivision;
27import org.greenstone.gsdl3.gs3build.metadata.METSNamespace;
28import org.greenstone.gsdl3.gs3build.metadata.MetadataLabel;
29
30import org.greenstone.gsdl3.gs3build.util.MultiMap;
31import org.greenstone.gsdl3.gs3build.database.GS3SQLConnection;
32
33/**
34 * Provide a base-line functionality for the <code>DocumentInterface</code>
35 * class.
36 */
37
38public abstract class AbstractDocument implements DocumentInterface
39{
40 METSFileSet fileSet;
41 METSDescriptiveSet metadata;
42 METSStructureSet structureSet;
43 METSHeader header;
44 DocumentID id;
45 boolean isModified;
46 StructureIdentifierFactory structureIdFactory;
47 java.sql.Timestamp firstDate;
48 java.sql.Timestamp indexDate;
49 java.sql.Timestamp modifiedDate;
50
51 /**
52 * <p>Create a very vanilla document with a given document identifier.</p>
53 * <p>Most commonly used in dealing with loading files using DocumentFactory
54 * or similar.</p>
55 *
56 * @param <code>DocumentID</code> the document identifier
57 */
58 public AbstractDocument(DocumentID id)
59 { this.fileSet = new METSFileSet();
60 this.metadata = new METSDescriptiveSet();
61 this.header = new METSHeader();
62 this.structureSet = new METSStructureSet();
63 this.id = id;
64 this.structureIdFactory = new StructureIdentifierFactory();
65
66 java.util.Date thisDate = new java.util.Date();
67 this.firstDate = new java.sql.Timestamp(thisDate.getTime());
68 this.indexDate = new java.sql.Timestamp(thisDate.getTime());
69 this.modifiedDate = null; // as a signature that the modified date needs finding...
70 }
71
72 /**
73 * Create a basic document from a given <code>URL</code. This is usually the form
74 * called through the recognisers.
75 *
76 * @param <code>URL</code> the URL of the first file in the document package
77 */
78 public AbstractDocument(URL url)
79 { this.fileSet = new METSFileSet();
80 METSFile metsFile = this.fileSet.addFile(url);
81 this.metadata = new METSDescriptiveSet();
82 this.header = new METSHeader();
83 this.structureSet = new METSStructureSet();
84 this.id = null;
85
86 java.util.Date thisDate = new java.util.Date();
87 this.firstDate = new java.sql.Timestamp(thisDate.getTime());
88 this.indexDate = new java.sql.Timestamp(thisDate.getTime());
89
90 METSStructure structure = new METSStructure("All", "All", "Whole Document");
91 METSDivision documentBody = new METSDivision("All", "All", "All", "Whole Document", "Document");
92 structure.addDivision(documentBody);
93 this.structureSet.addStructure(structure);
94 documentBody.addFileReference(metsFile.getID());
95 documentBody.addMetadataReference("DM1");
96 }
97
98 /**
99 * Set the identified for the document. Every document should have
100 * a document number set on its accession, either through metadata
101 * placed upon it internally or externally, or by assignment through
102 * a <code>DocumentIDFactory</code>. Each identifier should be
103 * unique.
104 *
105 * @param <code>DocumentID</code> the document identifier - in XML
106 * terms, the gsdl3:id element.
107 */
108 public void setID(DocumentID id)
109 { this.id = id;
110 this.isModified = true;
111 }
112
113 /**
114 * Get the document identifier - this should be unique to the document,
115 * but care must be taken in the configuration of the collection to
116 * ensure that this is the case.
117 *
118 * @return <code>DocumentID</code> the identifer
119 */
120 public DocumentID getID()
121 { return this.id;
122 }
123
124 /**
125 * Indicate whether this document is indexed.
126 *
127 * @see: DocumentInterface.isIndexed
128 */
129 public boolean isIndexed()
130 { return true;
131 }
132
133 /**
134 * Get the date that this file was modified
135 */
136 public long getFilesDatestamp()
137 { return this.fileSet.getModifiedDatestamp();
138 }
139
140 /**
141 * Get the date that this file was modified
142 */
143 public long getModifiedDatestamp()
144 { if (this.modifiedDate == null) {
145 this.setModifiedDatestamp();
146 }
147 return this.modifiedDate.getTime();
148 }
149
150 /**
151 * Update/set the date of the most recent file modification
152 */
153 public void setModifiedDatestamp()
154 { this.modifiedDate = new java.sql.Timestamp(this.fileSet.getModifiedDatestamp());
155 }
156
157 /**
158 * Get the date that this document was first indexed
159 */
160 public long getAccessionDate()
161 { return this.firstDate.getTime();
162 }
163
164 /**
165 * Get the date that this document was last indexed
166 */
167 public long getLastIndexedDate()
168 { return this.indexDate.getTime();
169 }
170
171 /**
172 * Set the last indexed date for this document;
173 */
174 public void setLastIndexedDate(long timestamp)
175 { this.indexDate = new java.sql.Timestamp(timestamp);
176 }
177
178 /**
179 * Check if this document is in the database already.
180 *
181 * In this simple implementation, the first file in the document's "default"
182 * filegroup is taken to be the canonical file for this document - any document
183 * of the same type with the same canonical file is taken to be a match.
184 *
185 * @return <code>boolean</code> - if a matching document is found in the
186 * database.
187 */
188 public String getDuplicateID(GS3SQLConnection connection)
189 { //String query = "SELECT * FROM document INNER JOIN filegroups ON document.docId=filegroups.docId WHERE DocType=\"" + HTML_DOCUMENT_TYPE + "\"";
190
191 // Query for documents using the same file...
192 String query = "SELECT DocID FROM files INNER JOIN filegroups ON files.FileGroupRef=filegroups.FileGroupRef WHERE (filegroups.FileGroupId=\"default\" AND files.FileLocation=\"" + this.fileSet.getFile(0).getLocation().toString() + "\")";
193 try {
194 Statement statement = connection.createStatement();
195 ResultSet results = statement.executeQuery(query);
196
197 List docs = new ArrayList();
198
199 if (results.first()) {
200 do {
201 String value = results.getString("DocID");
202 docs.add(value);
203 } while (results.next());
204
205 Iterator docIterator = docs.iterator();
206 while (docIterator.hasNext()) {
207 String docId = docIterator.next().toString();
208 String innerQuery = "SELECT * FROM document WHERE DocID=\"" + docId + "\"";
209 results = statement.executeQuery(innerQuery);
210 if (results.first()) {
211 String docType = results.getString("DocType");
212 if (docType.equals(this.getDocumentType())) {
213 return docId;
214 }
215 }
216 }
217 }
218 statement.close();
219 }
220 catch (java.sql.SQLException sqlEx) {
221 System.err.println("AbstractDocument.getDuplicateID(): "+sqlEx);
222 }
223
224 return "";
225 }
226
227 /**
228 * Obtain the METS header of this document
229 *
230 * @return <code>METSHeader</code> the header
231 */
232 public METSHeader getHeader()
233 { return this.header;
234 }
235
236 /**
237 * Set the METS header for this document.
238 *
239 * @param <code>METSHeader</code> the header
240 */
241 public void setHeader(METSHeader header)
242 { this.header = header;
243 }
244
245 /**
246 * A simple implementation of the isDocumentType function that does <b>not</b> consider
247 * inheritance - it <code>must</code> be extended as required.
248 */
249 public boolean isDocumentType(String type)
250 { return type.equals(this.getDocumentType());
251 }
252
253 public abstract String getDocumentType();
254
255 public abstract String getDocumentText();
256
257 public abstract String getSectionText(String sectionId);
258
259 public String getMETSType()
260 { return "document";
261 }
262
263 /**
264 * @see DocumentInterface:addDocumentMetadata
265 */
266 public void addDocumentMetadata(MetadataLabel label, String value)
267 { // no need to set isModified, as the following call will do it anyway!
268 this.addDocumentMetadata(label.getNamespace(), label.getLabel(), value);
269 }
270
271 /**
272 * @see DocumentInterface:addDocumentMetadata
273 */
274 public void setDocumentMetadata(MetadataLabel label, String value)
275 { // no need to set isModified, as the following call will do it anyway!
276 this.setDocumentMetadata(label.getNamespace(), label.getLabel(), value);
277 }
278
279 /**
280 * @see DocumentInterface:addDocumentMetadata
281 */
282 public void addDocumentMetadata(String namespace, String label, String value)
283 { this.metadata.addMetadata("default", namespace, label, value);
284 this.isModified = true;
285 }
286
287 /**
288 * @see DocumentInterface:addDocumentMetadata
289 */
290 public void setDocumentMetadata(String namespace, String label, String value)
291 { this.metadata.setMetadata("default", namespace, label, value);
292 this.isModified = true;
293 }
294
295 /**
296 * @see DocumentInterface:removeDocumentMetadata
297 */
298 public void removeDocumentMetadata(String namespace, String label)
299 { this.metadata.removeMetadata("default", namespace, label);
300 this.isModified = true;
301 }
302
303 /**
304 *
305 */
306 public void removeAllMetadata(String namespace, String label)
307 { this.metadata.removeAllMetadata(namespace, label);
308 this.isModified = true;
309 }
310
311 /**
312 * Post metadata to a file in this document - the appropriate changes
313 * should be made...
314 */
315 public void postFileMetadata(URL fileLocation, String namespace, String label, String value)
316 {
317 // First get the list of file groups, etc. that this file is associated with...
318 List fileGroups = this.fileSet.findGroups(fileLocation);
319
320 // Next, get the METS divisions associated with each file group...
321 List divisions = this.structureSet.findDivisionsForFiles(fileGroups);
322
323 // Finally, post the metadata to the metadata group associated with each structure
324 Iterator divisionIter = divisions.iterator();
325 while (divisionIter.hasNext())
326 { METSDivision division = (METSDivision) divisionIter.next();
327
328 // get the open namespace for this division
329 METSNamespace namespaceMetadata = division.findNamespace(namespace, true, this.metadata);
330
331 // then post the metadata to it...
332 namespaceMetadata.addMetadata(label, value);
333 }
334 }
335
336 /**
337 * Get the metadata structure of the document
338 *
339 * @return <code>METSDescriptive</code> the metadata holder for the document.
340 */
341 public METSDescriptiveSet getDocumentMetadata()
342 { return this.metadata;
343 }
344
345 /**
346 * Set the metadata structure for this document
347 *
348 * @param <code>METSDescriptive</code> the new metadata holder for the document.
349 */
350 public void setDocumentMetadata(METSDescriptiveSet metadata)
351 { this.metadata = metadata;
352 this.isModified = true;
353 }
354
355 /**
356 * Get the metadata structure of the document
357 *
358 * @return <code>METSStructureSet</code> the metadata holder for the document.
359 */
360 public METSStructureSet getDocumentStructure()
361 { return this.structureSet;
362 }
363
364 public void setDocumentStructure(METSStructureSet structureSet)
365 { this.structureSet = structureSet;
366 }
367
368 /**
369 * Get the values associated with a particular metadata value.
370 *
371 * @param <code>String</code> the namespace to find the values in.
372 * @param <code>String</code> the label to match to find the values.
373 *
374 * @return <code>List</code> the values.
375 */
376 public List getDocumentMetadataItem(String namespace, String label)
377 { return this.metadata.getMetadata("default", namespace, label);
378 }
379
380 /**
381 * Get the values associated with a particular metadata value.
382 *
383 * @param <code>String</code> the namespace and label separated by a
384 * colon.
385 *
386 * @return <code>List</code> the values.
387 */
388 public List getDocumentMetadataItem(String namespaceLabel)
389 { String namespace, label;
390
391 int colonAt = namespaceLabel.indexOf(':');
392 if (colonAt < 0)
393 { namespace = GSDL3Namespace.GSDL3_NAMESPACE_ID;
394 label = namespaceLabel;
395 }
396 else
397 { namespace = namespaceLabel.substring(0, colonAt);
398 label = namespaceLabel.substring(colonAt+1);
399 }
400 return this.metadata.getMetadata("default", namespace, label);
401 }
402
403 /**
404 * @see DocumentInterface:getDocumentFiles
405 */
406 public METSFileSet getDocumentFiles()
407 { return this.fileSet;
408 }
409
410 public void setDocumentFiles(METSFileSet fileSet)
411 { this.fileSet = fileSet;
412 }
413
414 /**
415 * This is just a dummy function that does nothing at this level...
416 */
417 public org.w3c.dom.Document getDOMDocument()
418 { return null;
419 }
420
421 /**
422 * @see DocumentInterface:isMETSCompatible
423 */
424 public boolean isMETSCompatible()
425 { return true;
426 }
427
428 /**
429 * Use a default document writer - this may be overridden for subclasses...
430 *
431 * @see DocumentInterface:writeMETSObject
432 */
433 public DocumentWriter getMETSWriter()
434 { return new DocumentWriter();
435 }
436
437 /**
438 * Use a default SQL document writer - this may be overridden for subclasses...
439 *
440 */
441 public DocumentSQLWriter getSQLWriter()
442 { return new DocumentSQLWriter();
443 }
444
445 /**
446 * Obtain a document from the SQL database
447 */
448 public static AbstractDocument readSQL(GS3SQLConnection connection, ResultSet sqlResult)
449 { try {
450 DocumentID id = new DocumentID(sqlResult.getString("DocID"));
451 String type = sqlResult.getString("docType");
452
453 // Use a factory method to create the correct subtype...
454 AbstractDocument document = DocumentFactory.createDocument(type, id);
455 // Append the document date information
456 document.indexDate = sqlResult.getTimestamp("IndexedDate");
457 document.firstDate = sqlResult.getTimestamp("AccessionDate");
458 document.modifiedDate = sqlResult.getTimestamp("ModifiedDate");
459
460 // Get the individual components of the document
461 METSFileSet fileSet = METSFileSet.readSQL(document, connection);
462 document.setDocumentFiles(fileSet);
463 METSDescriptiveSet descriptiveSet = METSDescriptiveSet.readSQL(document, connection);
464 document.setDocumentMetadata(descriptiveSet);
465 METSStructureSet structureSet = METSStructureSet.readSQL(document, connection);
466 document.setDocumentStructure(structureSet);
467
468 // indicate that the document is not currently modified
469 document.setChanged(false);
470 return document;
471 }
472 catch (SQLException sqlEx) {
473 System.err.println("AbstractDocument.readSQL(): Failure to load document: " + sqlEx);
474 }
475 return null;
476 }
477
478 /**
479 *
480 */
481 public boolean isChanged()
482 { return this.isModified;
483 }
484
485 public void setChanged(boolean isModified)
486 { this.isModified = isModified;
487 }
488}
Note: See TracBrowser for help on using the repository browser.