Revision 5329
Added by Matt Jones over 14 years ago
src/edu/ucsb/nceas/metacat/dataone/CrudService.java | ||
---|---|---|
22 | 22 |
*/ |
23 | 23 |
package edu.ucsb.nceas.metacat.dataone; |
24 | 24 |
|
25 |
import java.io.ByteArrayOutputStream; |
|
25 | 26 |
import java.io.File; |
26 | 27 |
import java.io.FileNotFoundException; |
27 | 28 |
import java.io.FileOutputStream; |
28 | 29 |
import java.io.IOException; |
29 | 30 |
import java.io.InputStream; |
30 | 31 |
import java.io.OutputStream; |
32 |
import java.io.PrintWriter; |
|
31 | 33 |
import java.sql.SQLException; |
32 | 34 |
import java.util.Date; |
33 | 35 |
import java.util.Enumeration; |
... | ... | |
57 | 59 |
import org.dataone.service.types.Identifier; |
58 | 60 |
import org.dataone.service.types.LogRecordSet; |
59 | 61 |
import org.dataone.service.types.SystemMetadata; |
62 |
import org.jibx.runtime.BindingDirectory; |
|
63 |
import org.jibx.runtime.IBindingFactory; |
|
64 |
import org.jibx.runtime.IMarshallingContext; |
|
65 |
import org.jibx.runtime.JiBXException; |
|
60 | 66 |
|
61 | 67 |
import com.gc.iotools.stream.is.InputStreamFromOutputStream; |
62 | 68 |
|
... | ... | |
71 | 77 |
import edu.ucsb.nceas.metacat.properties.PropertyService; |
72 | 78 |
import edu.ucsb.nceas.metacat.replication.ForceReplicationHandler; |
73 | 79 |
import edu.ucsb.nceas.metacat.service.SessionService; |
80 |
import edu.ucsb.nceas.metacat.util.DocumentUtil; |
|
74 | 81 |
import edu.ucsb.nceas.metacat.util.SessionData; |
75 | 82 |
import edu.ucsb.nceas.utilities.ParseLSIDException; |
76 | 83 |
import edu.ucsb.nceas.utilities.PropertyNotFoundException; |
... | ... | |
180 | 187 |
|
181 | 188 |
logMetacat.debug("Starting CrudService.create()..."); |
182 | 189 |
|
183 |
// TODO: authenticate & get user info |
|
184 |
String username = "GARBAGETOBEREPLACED"; |
|
185 |
String[] groups = null; |
|
190 |
// authenticate & get user info |
|
191 |
SessionData sessionData = getSessionData(token); |
|
192 |
String username = sessionData.getUserName(); |
|
193 |
String[] groups = sessionData.getGroupNames(); |
|
186 | 194 |
|
187 | 195 |
// verify that guid == SystemMetadata.getIdentifier() |
188 | 196 |
logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue()); |
189 |
// if (!guid.getIdentifier().equals(sysmeta.getIdentifier().getIdentifier())) {
|
|
190 |
// throw new InvalidSystemMetadata(1180,
|
|
191 |
// "GUID in method call does not match GUID in system metadata.");
|
|
192 |
// }
|
|
197 |
if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
|
|
198 |
throw new InvalidSystemMetadata(1180, |
|
199 |
"GUID in method call does not match GUID in system metadata."); |
|
200 |
} |
|
193 | 201 |
|
194 | 202 |
logMetacat.debug("Checking if identifier exists..."); |
195 | 203 |
// Check that the identifier does not already exist |
... | ... | |
203 | 211 |
logMetacat.debug("Generating a guid/localId mapping"); |
204 | 212 |
String localId = im.generateLocalId(guid.getValue(), 1); |
205 | 213 |
|
206 |
// TODO: generate guid/localId pair for sysmeta |
|
207 |
// TODO: update system metadata fields |
|
208 |
// TODO: insert system metadata to metacat (probably at end) |
|
209 |
|
|
210 |
// TODO: Check if we are handling metadata or data |
|
214 |
// Check if we are handling metadata or data |
|
215 |
boolean isScienceMetadata = isScienceMetadata(sysmeta); |
|
211 | 216 |
|
212 |
// TODO: CASE METADATA: |
|
213 |
// Setup and call handleInsertOrUpdate() |
|
217 |
if (isScienceMetadata) { |
|
218 |
// TODO: CASE METADATA: |
|
219 |
// Setup and call handleInsertOrUpdate() |
|
214 | 220 |
|
215 |
// TODO: DEFAULT CASE: DATA |
|
216 |
try { |
|
217 |
logMetacat.debug("Case DATA: starting to write to disk."); |
|
218 |
if (DocumentImpl.getDataFileLockGrant(localId)) { |
|
221 |
} else { |
|
222 |
// TODO: DEFAULT CASE: DATA (needs to be checked and completed) |
|
223 |
try { |
|
224 |
logMetacat.debug("Case DATA: starting to write to disk."); |
|
225 |
if (DocumentImpl.getDataFileLockGrant(localId)) { |
|
219 | 226 |
|
220 |
// Save the data file to disk using "localId" as the name |
|
221 |
try { |
|
222 |
String datafilepath = PropertyService.getProperty("application.datafilepath"); |
|
227 |
// Save the data file to disk using "localId" as the name
|
|
228 |
try {
|
|
229 |
String datafilepath = PropertyService.getProperty("application.datafilepath");
|
|
223 | 230 |
|
224 |
File dataDirectory = new File(datafilepath); |
|
225 |
dataDirectory.mkdirs(); |
|
231 |
File dataDirectory = new File(datafilepath);
|
|
232 |
dataDirectory.mkdirs();
|
|
226 | 233 |
|
227 |
File newFile = writeStreamToFile(dataDirectory, localId, object); |
|
234 |
File newFile = writeStreamToFile(dataDirectory, localId, object);
|
|
228 | 235 |
|
229 |
// TODO: Check that the file size matches SystemMetadata |
|
230 |
// long size = newFile.length(); |
|
231 |
// if (size == 0) { |
|
232 |
// throw new IOException("Uploaded file is 0 bytes!"); |
|
233 |
// } |
|
236 |
// TODO: Check that the file size matches SystemMetadata
|
|
237 |
// long size = newFile.length();
|
|
238 |
// if (size == 0) {
|
|
239 |
// throw new IOException("Uploaded file is 0 bytes!");
|
|
240 |
// }
|
|
234 | 241 |
|
235 |
//register the file in the database (which generates an exception |
|
236 |
// if the docid is not acceptable or other untoward things happen |
|
237 |
try { |
|
238 |
logMetacat.debug("Registering document..."); |
|
239 |
DocumentImpl.registerDocument(localId, "BIN", localId, |
|
240 |
username, groups); |
|
241 |
logMetacat.debug("Registrtion step completed."); |
|
242 |
} catch (SQLException e) { |
|
243 |
//newFile.delete(); |
|
244 |
logMetacat.debug("SQLE: " + e.getMessage()); |
|
245 |
e.printStackTrace(System.out); |
|
246 |
throw new ServiceFailure(1190, "Registration failed: " + e.getMessage()); |
|
247 |
} catch (AccessionNumberException e) { |
|
248 |
//newFile.delete(); |
|
249 |
logMetacat.debug("ANE: " + e.getMessage()); |
|
250 |
e.printStackTrace(System.out); |
|
251 |
throw new ServiceFailure(1190, "Registration failed: " + e.getMessage()); |
|
252 |
} catch (Exception e) { |
|
253 |
//newFile.delete(); |
|
254 |
logMetacat.debug("Exception: " + e.getMessage()); |
|
255 |
e.printStackTrace(System.out); |
|
256 |
throw new ServiceFailure(1190, "Registration failed: " + e.getMessage()); |
|
242 |
//register the file in the database (which generates an exception |
|
243 |
// if the docid is not acceptable or other untoward things happen |
|
244 |
try { |
|
245 |
logMetacat.debug("Registering document..."); |
|
246 |
DocumentImpl.registerDocument(localId, "BIN", localId, |
|
247 |
username, groups); |
|
248 |
logMetacat.debug("Registrtion step completed."); |
|
249 |
} catch (SQLException e) { |
|
250 |
//newFile.delete(); |
|
251 |
logMetacat.debug("SQLE: " + e.getMessage()); |
|
252 |
e.printStackTrace(System.out); |
|
253 |
throw new ServiceFailure(1190, "Registration failed: " + e.getMessage()); |
|
254 |
} catch (AccessionNumberException e) { |
|
255 |
//newFile.delete(); |
|
256 |
logMetacat.debug("ANE: " + e.getMessage()); |
|
257 |
e.printStackTrace(System.out); |
|
258 |
throw new ServiceFailure(1190, "Registration failed: " + e.getMessage()); |
|
259 |
} catch (Exception e) { |
|
260 |
//newFile.delete(); |
|
261 |
logMetacat.debug("Exception: " + e.getMessage()); |
|
262 |
e.printStackTrace(System.out); |
|
263 |
throw new ServiceFailure(1190, "Registration failed: " + e.getMessage()); |
|
264 |
} |
|
265 |
|
|
266 |
logMetacat.debug("Logging the creation event."); |
|
267 |
EventLog.getInstance().log(request.getRemoteAddr(), |
|
268 |
username, localId, "create"); |
|
269 |
|
|
270 |
// Force replication this data file |
|
271 |
// To data file, "insert" and update is same |
|
272 |
// The fourth parameter is null. Because it is notification |
|
273 |
// server and this method is in MetaCatServerlet. It is |
|
274 |
// original command, not get force replication info from |
|
275 |
// another metacat |
|
276 |
// TODO: note that GUID mapping is not being replicated |
|
277 |
logMetacat.debug("Scheduling replication."); |
|
278 |
ForceReplicationHandler frh = new ForceReplicationHandler( |
|
279 |
localId, "insert", false, null); |
|
280 |
|
|
281 |
} catch (PropertyNotFoundException e) { |
|
282 |
throw new ServiceFailure(1190, "Could not lock file for writing:" + e.getMessage()); |
|
257 | 283 |
} |
258 | 284 |
|
259 |
logMetacat.debug("Logging the creation event."); |
|
260 |
EventLog.getInstance().log(request.getRemoteAddr(), |
|
261 |
username, localId, "create"); |
|
262 |
|
|
263 |
// Force replication this data file |
|
264 |
// To data file, "insert" and update is same |
|
265 |
// The fourth parameter is null. Because it is notification |
|
266 |
// server and this method is in MetaCatServerlet. It is |
|
267 |
// original command, not get force replication info from |
|
268 |
// another metacat |
|
269 |
// TODO: note that GUID mapping is not being replicated |
|
270 |
logMetacat.debug("Scheduling replication."); |
|
271 |
ForceReplicationHandler frh = new ForceReplicationHandler( |
|
272 |
localId, "insert", false, null); |
|
273 |
|
|
274 |
} catch (PropertyNotFoundException e) { |
|
275 |
throw new ServiceFailure(1190, "Could not lock file for writing:" + e.getMessage()); |
|
276 | 285 |
} |
277 |
|
|
286 |
} catch (Exception e) { |
|
287 |
// Could not get a lock on the document, so we can not update the file now |
|
288 |
throw new ServiceFailure(1190, "Failed to lock file: " + e.getMessage()); |
|
278 | 289 |
} |
279 |
} catch (Exception e) { |
|
280 |
// Could not get a lock on the document, so we can not update the file now
|
|
281 |
throw new ServiceFailure(1190, "Failed to lock file: " + e.getMessage());
|
|
290 |
|
|
291 |
// Insert the system metadata into the object store
|
|
292 |
insertSystemMetadata(sysmeta, sessionData);
|
|
282 | 293 |
} |
283 | 294 |
|
284 | 295 |
logMetacat.debug("Returning from CrudService.create()"); |
... | ... | |
345 | 356 |
} catch (McdbDocNotFoundException e) { |
346 | 357 |
throw new NotFound(1020, e.getMessage()); |
347 | 358 |
} |
348 |
|
|
349 |
/* |
|
350 |
* Alternative approach that uses Piped streams, but requires thread handling |
|
351 |
* which makes exception handling difficult (because exceptions fall off the |
|
352 |
* calling thread, terminating the thread. |
|
353 |
* |
|
354 |
// Look up the localId for this global identifier |
|
355 |
IdentifierManager im = IdentifierManager.getInstance(); |
|
356 |
try { |
|
357 |
final String localId = im.getLocalId(guid.getIdentifier()); |
|
358 |
|
|
359 |
// Now use that localId to read the object and return it |
|
360 |
params.put("docid", new String[] { localId }); |
|
361 |
final PipedInputStream in = new PipedInputStream(); |
|
362 |
new Thread( |
|
363 |
new Runnable() { |
|
364 |
public void run() { |
|
365 |
try { |
|
366 |
PipedOutputStream out = new PipedOutputStream(in); |
|
367 |
handler.readFromMetacat(request.getRemoteAddr(), null, |
|
368 |
out, localId, "xml", |
|
369 |
username, groupNames, true, params); |
|
370 |
} catch (PropertyNotFoundException e) { |
|
371 |
throw new ServiceFailure(1030, e.getMessage()); |
|
372 |
} catch (ClassNotFoundException e) { |
|
373 |
throw new ServiceFailure(1030, e.getMessage()); |
|
374 |
} catch (IOException e) { |
|
375 |
throw new ServiceFailure(1030, e.getMessage()); |
|
376 |
} catch (SQLException e) { |
|
377 |
throw new ServiceFailure(1030, e.getMessage()); |
|
378 |
} catch (McdbException e) { |
|
379 |
throw new ServiceFailure(1030, e.getMessage()); |
|
380 |
} catch (ParseLSIDException e) { |
|
381 |
throw new NotFound(1020, e.getMessage()); |
|
382 |
} catch (InsufficientKarmaException e) { |
|
383 |
throw new NotAuthorized(1000, "Not authorized for get()."); |
|
384 |
} |
|
385 |
} |
|
386 |
} |
|
387 |
).start(); |
|
388 |
return in; |
|
389 |
} catch (McdbDocNotFoundException e) { |
|
390 |
throw new NotFound(1020, e.getMessage()); |
|
391 |
} |
|
392 |
*/ |
|
393 | 359 |
} |
394 | 360 |
|
395 | 361 |
public Checksum getChecksum(AuthToken token, Identifier guid) |
... | ... | |
414 | 380 |
throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, |
415 | 381 |
InvalidRequest, NotImplemented { |
416 | 382 |
|
417 |
// Look up ID of system metadata based on guid |
|
418 |
// Initially from document, later from entry in table? |
|
383 |
// TODO: Look up ID of system metadata based on guid
|
|
384 |
// TODO: Initially from document, later from entry in table?
|
|
419 | 385 |
|
420 |
// Read system metadata from disk and create SystemMetadata object |
|
421 |
// Follows same implementation plan as get() |
|
386 |
// TODO: Read system metadata from disk and create SystemMetadata object
|
|
387 |
// TODO: Follows same implementation plan as get()
|
|
422 | 388 |
|
423 |
// return it |
|
389 |
// TODO: return it
|
|
424 | 390 |
throw new NotImplemented(1000, "This method not yet implemented."); |
425 | 391 |
} |
426 | 392 |
|
... | ... | |
473 | 439 |
// logMetacat.debug("***********************************************"); |
474 | 440 |
|
475 | 441 |
return newFile; |
476 |
} |
|
442 |
} |
|
443 |
|
|
444 |
/** |
|
445 |
* Determine if a given object should be treated as an XML science metadata |
|
446 |
* object. |
|
447 |
* |
|
448 |
* TODO: This test should be externalized in a configuration dictionary rather than being hardcoded. |
|
449 |
* |
|
450 |
* @param sysmeta the SystemMetadata describig the object |
|
451 |
* @return true if the object should be treated as science metadata |
|
452 |
*/ |
|
453 |
private boolean isScienceMetadata(SystemMetadata sysmeta) { |
|
454 |
boolean scimeta = false; |
|
455 |
switch (sysmeta.getObjectFormat()) { |
|
456 |
case EML_2_1_0: scimeta = true; break; |
|
457 |
case EML_2_0_1: scimeta = true; break; |
|
458 |
case EML_2_0_0: scimeta = true; break; |
|
459 |
case FGDC_STD_001_1_1999: scimeta = true; break; |
|
460 |
case FGDC_STD_001_1998: scimeta = true; break; |
|
461 |
case NCML_2_2: scimeta = true; break; |
|
462 |
} |
|
463 |
|
|
464 |
return scimeta; |
|
465 |
} |
|
466 |
|
|
467 |
private void insertSystemMetadata(SystemMetadata sysmeta, SessionData sessionData) |
|
468 |
throws ServiceFailure { |
|
469 |
logMetacat.debug("Starting to insert SystemMetadata..."); |
|
470 |
IdentifierManager im = IdentifierManager.getInstance(); |
|
471 |
|
|
472 |
// generate guid/localId pair for sysmeta |
|
473 |
String sysMetaGuid = DocumentUtil.generateDocumentId(1); |
|
474 |
sysmeta.setDateSysMetadataModified(new Date()); |
|
475 |
|
|
476 |
String xml = new String(serializeSystemMetadata(sysmeta).toByteArray()); |
|
477 |
insertDocument(xml, sysMetaGuid, sessionData); |
|
478 |
} |
|
479 |
|
|
480 |
private void insertDocument(String xml, String guid, SessionData sessionData) |
|
481 |
throws ServiceFailure { |
|
482 |
logMetacat.debug("Starting to insert xml document..."); |
|
483 |
IdentifierManager im = IdentifierManager.getInstance(); |
|
484 |
|
|
485 |
// generate guid/localId pair for sysmeta |
|
486 |
String localId = im.generateLocalId(guid, 1); |
|
487 |
logMetacat.debug("Metadata guid|localId: " + guid + "|" + |
|
488 |
localId); |
|
489 |
|
|
490 |
// TODO: insert system metadata to metacat (probably at end) |
|
491 |
// TODO: can't pass in the out PrintWriter, as we don't want to write |
|
492 |
// error info on this stream -- need to be able to return to process |
|
493 |
// the real object. So, need to: |
|
494 |
// TODO: refactor handleInsertOrUpdateAction() to not output XML directly |
|
495 |
// onto output stream, or alternatively, capture that and parse it to |
|
496 |
// generate the right exceptions |
|
497 |
String[] action = new String[1]; |
|
498 |
action[0] = "insert"; |
|
499 |
params.put("action", action); |
|
500 |
String[] docid = new String[1]; |
|
501 |
docid[0] = localId; |
|
502 |
params.put("docid", docid); |
|
503 |
String[] doctext = new String[1]; |
|
504 |
doctext[0] = xml; |
|
505 |
logMetacat.debug(doctext[0]); |
|
506 |
params.put("doctext", doctext); |
|
507 |
ByteArrayOutputStream output = new ByteArrayOutputStream(); |
|
508 |
PrintWriter pw = new PrintWriter(output); |
|
509 |
handler.handleInsertOrUpdateAction(request.getRemoteAddr(), response, |
|
510 |
pw, params, sessionData.getUserName(), |
|
511 |
sessionData.getGroupNames()); |
|
512 |
logMetacat.debug(new String(output.toByteArray())); |
|
513 |
logMetacat.debug("Finsihed inserting xml document."); |
|
514 |
} |
|
515 |
|
|
516 |
private ByteArrayOutputStream serializeSystemMetadata(SystemMetadata sysmeta) |
|
517 |
throws ServiceFailure { |
|
518 |
IBindingFactory bfact; |
|
519 |
ByteArrayOutputStream sysmetaOut = null; |
|
520 |
try { |
|
521 |
bfact = BindingDirectory.getFactory(SystemMetadata.class); |
|
522 |
IMarshallingContext mctx = bfact.createMarshallingContext(); |
|
523 |
sysmetaOut = new ByteArrayOutputStream(); |
|
524 |
mctx.marshalDocument(sysmeta, "UTF-8", null, sysmetaOut); |
|
525 |
} catch (JiBXException e) { |
|
526 |
throw new ServiceFailure(1190, "Failed to serialize and insert SystemMetadata: " + e.getMessage()); |
|
527 |
} |
|
528 |
|
|
529 |
return sysmetaOut; |
|
530 |
} |
|
477 | 531 |
} |
Also available in: Unified diff
Modify CrudService to write SystemMetadata to disk with an autogenerated localId and an autogenerated GUID. Validation depends on the DataONE schemas being setup in xml_catalog properly, so still need to check upgrade scripts to be sure these new schemas are added. Still need to handle the metadata document insert, but should be same as system metadata insert.