Project

General

Profile

1 6705 leinfelder
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class for upgrading the database to version 1.5
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Saurabh Garg
7
 *
8
 *   '$Author$'
9
 *     '$Date$'
10
 * '$Revision$'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26
package edu.ucsb.nceas.metacat.dataone;
27
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.math.BigInteger;
31 6852 leinfelder
import java.net.URL;
32 6873 leinfelder
import java.net.URLConnection;
33 6705 leinfelder
import java.security.NoSuchAlgorithmException;
34
import java.sql.SQLException;
35 6712 leinfelder
import java.util.ArrayList;
36 6727 leinfelder
import java.util.Collections;
37 6705 leinfelder
import java.util.Date;
38 6712 leinfelder
import java.util.HashMap;
39 6705 leinfelder
import java.util.Hashtable;
40 6712 leinfelder
import java.util.List;
41
import java.util.Map;
42 6709 leinfelder
import java.util.Vector;
43 6705 leinfelder
44
import javax.xml.parsers.ParserConfigurationException;
45
import javax.xml.xpath.XPathExpressionException;
46
47 6712 leinfelder
import org.apache.commons.beanutils.BeanUtils;
48
import org.apache.commons.io.IOUtils;
49 6705 leinfelder
import org.apache.log4j.Logger;
50 6721 leinfelder
import org.apache.wicket.protocol.http.MockHttpServletRequest;
51 6705 leinfelder
import org.dataone.client.ObjectFormatCache;
52 6712 leinfelder
import org.dataone.ore.ResourceMapFactory;
53 6705 leinfelder
import org.dataone.service.exceptions.BaseException;
54 6911 leinfelder
import org.dataone.service.exceptions.InvalidRequest;
55
import org.dataone.service.exceptions.InvalidSystemMetadata;
56
import org.dataone.service.exceptions.InvalidToken;
57
import org.dataone.service.exceptions.NotAuthorized;
58 6705 leinfelder
import org.dataone.service.exceptions.NotFound;
59 6911 leinfelder
import org.dataone.service.exceptions.NotImplemented;
60
import org.dataone.service.exceptions.ServiceFailure;
61 6721 leinfelder
import org.dataone.service.types.v1.AccessPolicy;
62 6705 leinfelder
import org.dataone.service.types.v1.Checksum;
63
import org.dataone.service.types.v1.Identifier;
64
import org.dataone.service.types.v1.NodeReference;
65
import org.dataone.service.types.v1.ObjectFormatIdentifier;
66 6721 leinfelder
import org.dataone.service.types.v1.Session;
67 6705 leinfelder
import org.dataone.service.types.v1.Subject;
68
import org.dataone.service.types.v1.SystemMetadata;
69
import org.dataone.service.types.v1.util.ChecksumUtil;
70 6709 leinfelder
import org.dataone.service.util.DateTimeMarshaller;
71 6712 leinfelder
import org.dspace.foresite.ResourceMap;
72 6705 leinfelder
import org.ecoinformatics.datamanager.DataManager;
73
import org.ecoinformatics.datamanager.database.DatabaseConnectionPoolInterface;
74
import org.ecoinformatics.datamanager.parser.DataPackage;
75
import org.jibx.runtime.JiBXException;
76
import org.xml.sax.SAXException;
77
78
import edu.ucsb.nceas.metacat.AccessionNumber;
79
import edu.ucsb.nceas.metacat.AccessionNumberException;
80 6709 leinfelder
import edu.ucsb.nceas.metacat.DBUtil;
81 6705 leinfelder
import edu.ucsb.nceas.metacat.IdentifierManager;
82
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
83
import edu.ucsb.nceas.metacat.McdbException;
84 6712 leinfelder
import edu.ucsb.nceas.metacat.MetaCatServlet;
85 6705 leinfelder
import edu.ucsb.nceas.metacat.MetacatHandler;
86 6708 leinfelder
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
87 6705 leinfelder
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
88
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
89
import edu.ucsb.nceas.metacat.dataquery.MetacatDatabaseConnectionPoolFactory;
90
import edu.ucsb.nceas.metacat.properties.PropertyService;
91 6708 leinfelder
import edu.ucsb.nceas.metacat.replication.ReplicationService;
92 6721 leinfelder
import edu.ucsb.nceas.metacat.shared.AccessException;
93 6708 leinfelder
import edu.ucsb.nceas.metacat.shared.HandlerException;
94 6705 leinfelder
import edu.ucsb.nceas.metacat.util.DocumentUtil;
95
import edu.ucsb.nceas.utilities.ParseLSIDException;
96
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
97
98
public class SystemMetadataFactory {
99 6706 leinfelder
100 6800 leinfelder
	private static final String resourceMapPrefix = "resourceMap_";
101 6707 leinfelder
	private static Logger logMetacat = Logger.getLogger(SystemMetadataFactory.class);
102 6712 leinfelder
103 6705 leinfelder
	/**
104 6706 leinfelder
	 * Creates a system metadata object for insertion into metacat
105
	 *
106
	 * @param localId
107
	 *            The local document identifier
108
	 * @param user
109
	 *            The user submitting the system metadata document
110
	 * @param groups
111
	 *            The groups the user belongs to
112
	 *
113
	 * @return sysMeta The system metadata object created
114 6708 leinfelder
	 * @throws SAXException
115
	 * @throws HandlerException
116
	 * @throws AccessControlException
117 6721 leinfelder
	 * @throws AccessException
118 6706 leinfelder
	 */
119 6852 leinfelder
	public static SystemMetadata createSystemMetadata(String localId, boolean includeORE, boolean downloadData)
120 6706 leinfelder
			throws McdbException, McdbDocNotFoundException, SQLException,
121
			IOException, AccessionNumberException, ClassNotFoundException,
122
			InsufficientKarmaException, ParseLSIDException,
123
			PropertyNotFoundException, BaseException, NoSuchAlgorithmException,
124 6721 leinfelder
			JiBXException, AccessControlException, HandlerException, SAXException, AccessException {
125 6707 leinfelder
126 6706 leinfelder
		logMetacat.debug("MetacatHandler.createSystemMetadata() called.");
127
		logMetacat.debug("provided localId: " + localId);
128 6705 leinfelder
129 6706 leinfelder
		// create system metadata for the document
130
		SystemMetadata sysMeta = new SystemMetadata();
131
		sysMeta.setSerialVersion(BigInteger.valueOf(1));
132 6910 cjones
		sysMeta.setArchived(false);
133 6706 leinfelder
		AccessionNumber accNum = new AccessionNumber(localId, "NONE");
134 6808 leinfelder
		int rev = Integer.valueOf(accNum.getRev());
135
136 6706 leinfelder
		// get the data or metadata object
137
		InputStream inputStream;
138
		try {
139
			inputStream = MetacatHandler.read(localId);
140
		} catch (ParseLSIDException ple) {
141
			logMetacat.debug("There was a problem parsing the LSID from "
142
					+ localId + ". The error message was: " + ple.getMessage());
143
			throw ple;
144 6705 leinfelder
145 6706 leinfelder
		} catch (PropertyNotFoundException pnfe) {
146
			logMetacat.debug("There was a problem finding a property. "
147
					+ "The error message was: " + pnfe.getMessage());
148
			throw pnfe;
149
150
		} catch (McdbException me) {
151
			logMetacat.debug("There was a Metacat problem. "
152
					+ "The error message was: " + me.getMessage());
153
			throw me;
154
155
		} catch (SQLException sqle) {
156
			logMetacat.debug("There was a SQL problem. "
157
					+ "The error message was: " + sqle.getMessage());
158
			throw sqle;
159
160
		} catch (ClassNotFoundException cnfe) {
161
			logMetacat.debug("There was a problem finding a class. "
162
					+ "The error message was: " + cnfe.getMessage());
163
			throw cnfe;
164
165
		} catch (IOException ioe) {
166
			logMetacat.debug("There was an I/O exception. "
167
					+ "The error message was: " + ioe.getMessage());
168
			throw ioe;
169
170 6931 leinfelder
		}
171
172
		// get/make the guid
173
		String guid = null;
174
		try {
175
			// get the guid if it exists
176
			guid = IdentifierManager.getInstance().getGUID(accNum.getDocid(), rev);
177
		} catch (McdbDocNotFoundException dnfe) {
178
			// otherwise create the mapping
179
			logMetacat.debug("There was a problem getting the guid from "
180
							+ "the given localId (docid and revision). The error message was: "
181
							+ dnfe.getMessage());
182
			logMetacat.debug("No guid in the identifier table.  adding it for " + localId);
183
			IdentifierManager.getInstance().createMapping(localId, localId);
184
			logMetacat.debug("Mapping created for " + localId);
185
			logMetacat.debug("accessionNumber: " + accNum);
186
			guid = IdentifierManager.getInstance().getGUID(accNum.getDocid(), rev);
187
		}
188
		Identifier identifier = new Identifier();
189
		identifier.setValue(guid);
190 6706 leinfelder
191 6931 leinfelder
		// set the id
192
		sysMeta.setIdentifier(identifier);
193
194 6706 leinfelder
		// get additional docinfo
195 6708 leinfelder
		Hashtable<String, String> docInfo = ReplicationService.getDocumentInfoMap(localId);
196 6706 leinfelder
		// set the default object format
197 6708 leinfelder
		String doctype = docInfo.get("doctype");
198 6706 leinfelder
		ObjectFormatIdentifier fmtid = null;
199
200
		// set the object format, fall back to defaults
201
		try {
202 6707 leinfelder
			fmtid = ObjectFormatCache.getInstance().getFormat(doctype).getFormatId();
203 6706 leinfelder
		} catch (NotFound nfe) {
204
205
			try {
206
				// format is not registered, use default
207
				if (doctype.trim().equals("BIN")) {
208
					fmtid = ObjectFormatCache.getInstance().getFormat(
209
							"application/octet-stream").getFormatId();
210
211
				} else {
212
					fmtid = ObjectFormatCache.getInstance().getFormat(
213
							"text/plain").getFormatId();
214
				}
215
216
			} catch (NotFound nf) {
217 6707 leinfelder
				logMetacat.error("There was a problem getting the default format "
218 6706 leinfelder
								+ "from the ObjectFormatCache: "
219
								+ nf.getMessage());
220
				throw nf;
221
			}
222
223
		}
224
225
		sysMeta.setFormatId(fmtid);
226 6707 leinfelder
		logMetacat.debug("The ObjectFormat for " + localId + " is " + fmtid.getValue());
227 6706 leinfelder
228 6721 leinfelder
		// create the checksum
229
		inputStream = MetacatHandler.read(localId);
230
		String algorithm = "MD5";
231
		Checksum checksum = ChecksumUtil.checksum(inputStream, algorithm);
232
		sysMeta.setChecksum(checksum);
233
234
		// set the size
235
		inputStream = MetacatHandler.read(localId);
236
		String sizeStr = new Long(sizeOfStream(inputStream)).toString();
237
		sysMeta.setSize(new BigInteger(sizeStr));
238
239
		// submitter
240
		Subject submitter = new Subject();
241
		submitter.setValue(docInfo.get("user_updated"));
242
		sysMeta.setSubmitter(submitter);
243
244
		// rights holder
245
		Subject owner = new Subject();
246
		owner.setValue(docInfo.get("user_owner"));
247
		sysMeta.setRightsHolder(owner);
248
249
		// dates
250
		String createdDateString = docInfo.get("date_created");
251
		String updatedDateString = docInfo.get("date_updated");
252
		Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
253
		Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
254
		sysMeta.setDateUploaded(createdDate);
255
		sysMeta.setDateSysMetadataModified(updatedDate);
256
257
		// set the revision history
258
		String docidWithoutRev = accNum.getDocid();
259
		Identifier obsoletedBy = null;
260
		Identifier obsoletes = null;
261
		Vector<Integer> revisions = DBUtil.getRevListFromRevisionTable(docidWithoutRev);
262 6727 leinfelder
		// ensure this ordering since processing depends on it
263
		Collections.sort(revisions);
264 6721 leinfelder
		for (int existingRev: revisions) {
265
			// use the docid+rev as the guid
266
			String existingPid = docidWithoutRev + "." + existingRev;
267
			if (existingRev < rev) {
268
				// it's the old docid, until it's not
269
				obsoletes = new Identifier();
270
				obsoletes.setValue(existingPid);
271
			}
272
			if (existingRev > rev) {
273
				// it's the newer docid
274
				obsoletedBy = new Identifier();
275
				obsoletedBy.setValue(existingPid);
276
				// only want the version just after it
277
				break;
278
			}
279
		}
280 6725 leinfelder
		// set them on our object
281 6721 leinfelder
		sysMeta.setObsoletedBy(obsoletedBy);
282
		sysMeta.setObsoletes(obsoletes);
283
284 6725 leinfelder
		// update the system metadata for the object[s] we are revising
285
		if (obsoletedBy != null) {
286 6747 leinfelder
			//SystemMetadata obsoletedBySysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletedBy);
287
			SystemMetadata obsoletedBySysMeta = IdentifierManager.getInstance().getSystemMetadata(obsoletedBy.getValue());
288 6725 leinfelder
			if (obsoletedBySysMeta != null) {
289
				obsoletedBySysMeta.setObsoletes(identifier);
290
				HazelcastService.getInstance().getSystemMetadataMap().put(obsoletedBy, obsoletedBySysMeta);
291
			}
292
		}
293
		if (obsoletes != null) {
294 6747 leinfelder
			//SystemMetadata obsoletesSysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletes);
295
			SystemMetadata obsoletesSysMeta = IdentifierManager.getInstance().getSystemMetadata(obsoletes.getValue());
296 6725 leinfelder
			if (obsoletesSysMeta != null) {
297
				obsoletesSysMeta.setObsoletedBy(identifier);
298 6911 leinfelder
				obsoletesSysMeta.setArchived(true);
299
				HazelcastService.getInstance().getSystemMetadataMap().put(obsoletes, obsoletesSysMeta);
300 6725 leinfelder
			}
301
		}
302
303 6744 leinfelder
		// look up the access control policy we have in metacat
304
		AccessPolicy accessPolicy = IdentifierManager.getInstance().getAccessPolicy(guid);
305 6721 leinfelder
		sysMeta.setAccessPolicy(accessPolicy);
306
307
		// authoritative node
308
		NodeReference nr = new NodeReference();
309
		nr.setValue(PropertyService.getProperty("dataone.memberNodeId"));
310
		sysMeta.setOriginMemberNode(nr);
311
		sysMeta.setAuthoritativeMemberNode(nr);
312
313 6706 leinfelder
		// further parse EML documents to get data object format,
314
		// describes and describedBy information
315
		if (fmtid == ObjectFormatCache.getInstance().getFormat(
316
				"eml://ecoinformatics.org/eml-2.0.0").getFormatId()
317
				|| fmtid == ObjectFormatCache.getInstance().getFormat(
318
						"eml://ecoinformatics.org/eml-2.0.1").getFormatId()
319
				|| fmtid == ObjectFormatCache.getInstance().getFormat(
320
						"eml://ecoinformatics.org/eml-2.1.0").getFormatId()
321
				|| fmtid == ObjectFormatCache.getInstance().getFormat(
322
						"eml://ecoinformatics.org/eml-2.1.1").getFormatId()) {
323
324
			try {
325 6721 leinfelder
				inputStream = MetacatHandler.read(localId);
326 6707 leinfelder
				DatabaseConnectionPoolInterface connectionPool =
327
					MetacatDatabaseConnectionPoolFactory.getDatabaseConnectionPoolInterface();
328
				DataManager dataManager =
329
					DataManager.getInstance(connectionPool, connectionPool.getDBAdapterName());
330
				DataPackage dataPackage = dataManager.parseMetadata(inputStream);
331 6706 leinfelder
332 6721 leinfelder
				// iterate through the data objects in the EML doc and add sysmeta
333 6707 leinfelder
				logMetacat.debug("In createSystemMetadata() the number of data "
334 6706 leinfelder
								+ "entities is: "
335
								+ dataPackage.getEntityNumber());
336
337 6712 leinfelder
				// for generating the ORE map
338
	            Map<Identifier, List<Identifier>> idMap = new HashMap<Identifier, List<Identifier>>();
339
	            List<Identifier> dataIds = new ArrayList<Identifier>();
340
341 6706 leinfelder
				// iterate through data objects described by the EML
342 6744 leinfelder
	            if (dataPackage.getEntityList() != null) {
343
					for (int j = 0; j < dataPackage.getEntityList().length; j++) {
344
345
						String dataDocUrl = dataPackage.getEntityList()[j].getURL();
346
						String dataDocMimeType = dataPackage.getEntityList()[j].getDataFormat();
347
						// default to binary
348
						if (dataDocMimeType == null) {
349
							dataDocMimeType = ObjectFormatCache.getInstance()
350
									.getFormat("application/octet-stream")
351
									.getFormatId().getValue();
352 6721 leinfelder
						}
353 6852 leinfelder
354
						// process the data
355 6855 leinfelder
						boolean remoteData = false;
356 6852 leinfelder
						String dataDocLocalId = null;
357
						Identifier dataGuid = new Identifier();
358
359
						// handle ecogrid, or downloadable data
360
						String ecogridPrefix = "ecogrid://knb/";
361
						if (dataDocUrl.trim().startsWith(ecogridPrefix)) {
362
							dataDocLocalId = dataDocUrl.substring(dataDocUrl.indexOf(ecogridPrefix) + ecogridPrefix.length());
363
						} else {
364
							// should we try downloading the remote data?
365
							if (downloadData) {
366
								InputStream dataObject = null;
367
								try {
368
									// download the data from the URL
369
									URL dataURL = new URL(dataDocUrl);
370 6873 leinfelder
									URLConnection dataConnection = dataURL.openConnection();
371
372
									// default is to download the data
373
									dataObject = dataConnection.getInputStream();
374
375
									String detectedContentType = dataConnection.getContentType();
376
									logMetacat.info("Detected content type: " + detectedContentType);
377
378
									if (detectedContentType != null) {
379
										// seems to be HTML from the remote location
380
										if (detectedContentType.contains("html")) {
381
											// if we are not expecting it, we skip it
382
											if (!dataDocMimeType.contains("html")) {
383
												// set to null so we don't download it
384
												dataObject = null;
385
												logMetacat.warn("Skipping remote resource, unexpected HTML content type at: " + dataDocUrl);
386
											}
387
										}
388
389
										// TODO: any other special processing (csv, images, etc)?
390
									} else {
391
										// if we don't know what it is, should we skip it?
392
										dataObject = null;
393
										logMetacat.warn("Skipping remote resource, unknown content type at: " + dataDocUrl);
394
									}
395
396 6852 leinfelder
								} catch (Exception e) {
397
									// error with the download
398
									logMetacat.warn("Error downloading remote data. " + e.getMessage());
399
								}
400
401
								if (dataObject != null) {
402
									// create the local version of it
403
									dataDocLocalId = DocumentUtil.generateDocumentId(1);
404
									IdentifierManager.getInstance().createMapping(dataDocLocalId, dataDocLocalId);
405
									dataGuid.setValue(dataDocLocalId);
406
407
									// save it locally
408
									Session session = new Session();
409
									session.setSubject(submitter);
410
									MockHttpServletRequest request = new MockHttpServletRequest(null, null, null);
411
									MNodeService.getInstance(request).insertDataObject(dataObject, dataGuid, session);
412 6855 leinfelder
413
									remoteData = true;
414 6852 leinfelder
								}
415
							}
416
417
						}
418
419 6744 leinfelder
						logMetacat.debug("Data local ID: " + dataDocLocalId);
420
						logMetacat.debug("Data URL     : " + dataDocUrl);
421
						logMetacat.debug("Data mime    : " + dataDocMimeType);
422 6852 leinfelder
423
						// now we have a local id for the data
424
						if (dataDocLocalId != null) {
425
426 6744 leinfelder
							// look up the guid for the data
427
							String dataDocid = DocumentUtil.getSmartDocId(dataDocLocalId);
428
							int dataRev = DocumentUtil.getRevisionFromAccessionNumber(dataDocLocalId);
429
430
							// check if data system metadata exists already
431
							SystemMetadata dataSysMeta = null;
432
							String dataGuidString = null;
433 6706 leinfelder
							try {
434 6744 leinfelder
								// look for the identifier
435 6707 leinfelder
								dataGuidString = IdentifierManager.getInstance().getGUID(dataDocid, dataRev);
436 6744 leinfelder
								// set it
437 6706 leinfelder
								dataGuid.setValue(dataGuidString);
438 6744 leinfelder
								// look up the system metadata
439 6706 leinfelder
								try {
440 6744 leinfelder
									dataSysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(dataGuid);
441
								} catch (Exception e) {
442
									// probably not in the system
443
									dataSysMeta = null;
444 6706 leinfelder
								}
445 6744 leinfelder
								//dataSysMeta = IdentifierManager.getInstance().getSystemMetadata(dataGuidString);
446
							} catch (McdbDocNotFoundException nf) {
447
								// we didn't find it
448
								dataSysMeta = null;
449
							}
450 6712 leinfelder
451 6744 leinfelder
							// we'll have to generate it
452
							if (dataSysMeta == null) {
453
								// System metadata for data doesn't exist yet, so create it
454
								logMetacat.debug("There was not an existing system metadata document for " + dataDocLocalId);
455
								try {
456
									logMetacat.debug("Creating a system metadata " + "document for " + dataDocLocalId);
457 6852 leinfelder
									dataSysMeta = createSystemMetadata(dataDocLocalId, includeORE, false);
458 6744 leinfelder
459
									// now look it up again
460
									dataGuidString = IdentifierManager.getInstance().getGUID(dataDocid, dataRev);
461
462
									// set the guid
463
									dataGuid.setValue(dataGuidString);
464
465
									// set object format
466
									logMetacat.debug("Updating system metadata for "
467
													+ dataGuid.getValue() + " to "
468
													+ dataDocMimeType);
469
									try {
470
										ObjectFormatIdentifier fmt =
471
											ObjectFormatCache.getInstance().getFormat(dataDocMimeType).getFormatId();
472
										dataSysMeta.setFormatId(fmt);
473
									} catch (NotFound nfe) {
474
										logMetacat.debug("Couldn't find format identifier for: "
475
														+ dataDocMimeType
476
														+ ". Setting it to application/octet-stream.");
477
										ObjectFormatIdentifier newFmtid = new ObjectFormatIdentifier();
478
										newFmtid.setValue("application/octet-stream");
479
									}
480 6855 leinfelder
481
									// inherit access rules from metadata, if we don't have our own
482
									if (remoteData) {
483
										dataSysMeta.setAccessPolicy(sysMeta.getAccessPolicy());
484
										// TODO: use access rules defined in EML, per data file
485
									}
486
487 6744 leinfelder
									// update the values
488
									HazelcastService.getInstance().getSystemMetadataMap().put(dataSysMeta.getIdentifier(), dataSysMeta);
489
490
491
								} catch (McdbDocNotFoundException mdnf) {
492
									mdnf.printStackTrace();
493
									throw mdnf;
494
								} catch (NumberFormatException nfe) {
495
									nfe.printStackTrace();
496
									throw nfe;
497
								} catch (AccessionNumberException ane) {
498
									ane.printStackTrace();
499
									throw ane;
500
								} catch (SQLException sqle) {
501
									sqle.printStackTrace();
502
									throw sqle;
503
								} catch (NoSuchAlgorithmException nsae) {
504
									nsae.printStackTrace();
505
									throw nsae;
506
								} catch (IOException ioe) {
507
									ioe.printStackTrace();
508
									throw ioe;
509
								} catch (PropertyNotFoundException pnfe) {
510
									pnfe.printStackTrace();
511
									throw pnfe;
512
								} catch (BaseException be) {
513
									be.printStackTrace();
514
									throw be;
515
								}
516
517
							}
518 6721 leinfelder
519 6744 leinfelder
							// part of the ORE package
520
							dataIds.add(dataGuid);
521
522
						} // end if (EML package)
523
524
					} // end for (data entities)
525
526
	            } // data entities not null
527
528 6712 leinfelder
				// ORE map
529 6713 leinfelder
				if (includeORE) {
530 6800 leinfelder
					// can we generate them?
531 6713 leinfelder
			        if (!dataIds.isEmpty()) {
532 6800 leinfelder
			        	// it doesn't exist in the system?
533
			        	if (!oreExistsFor(sysMeta.getIdentifier())) {
534
535
				            // generate the ORE map for this datapackage
536
				            Identifier resourceMapId = new Identifier();
537
				            // want to be able to run this over and over again for now
538
				            resourceMapId.setValue(resourceMapPrefix + sysMeta.getIdentifier().getValue());
539
				            idMap.put(sysMeta.getIdentifier(), dataIds);
540
				            ResourceMap rm = ResourceMapFactory.getInstance().createResourceMap(resourceMapId, idMap);
541
				            String resourceMapXML = ResourceMapFactory.getInstance().serializeResourceMap(rm);
542
				            // copy most of the same system metadata as the packaging metadata
543
				            SystemMetadata resourceMapSysMeta = new SystemMetadata();
544
				            BeanUtils.copyProperties(resourceMapSysMeta, sysMeta);
545
				            resourceMapSysMeta.setIdentifier(resourceMapId);
546
				            Checksum oreChecksum = ChecksumUtil.checksum(IOUtils.toInputStream(resourceMapXML, MetaCatServlet.DEFAULT_ENCODING), "MD5");
547
							resourceMapSysMeta.setChecksum(oreChecksum);
548
				            ObjectFormatIdentifier formatId = ObjectFormatCache.getInstance().getFormat("http://www.openarchives.org/ore/terms").getFormatId();
549
							resourceMapSysMeta.setFormatId(formatId);
550
							resourceMapSysMeta.setSize(BigInteger.valueOf(sizeOfStream(IOUtils.toInputStream(resourceMapXML, MetaCatServlet.DEFAULT_ENCODING))));
551
552
							// set the revision graph
553
							resourceMapSysMeta.setObsoletes(null);
554
							resourceMapSysMeta.setObsoletedBy(null);
555
							// look up the resource map that this one obsoletes
556
							if (sysMeta.getObsoletes() != null) {
557
								Identifier resourceMapObsoletes = new Identifier();
558
								resourceMapObsoletes.setValue(resourceMapPrefix + sysMeta.getObsoletes().getValue());
559
								resourceMapSysMeta.setObsoletes(resourceMapObsoletes);
560
								SystemMetadata resourceMapObsoletesSystemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(resourceMapObsoletes);
561
								if (resourceMapObsoletesSystemMetadata != null) {
562
									resourceMapObsoletesSystemMetadata.setObsoletedBy(resourceMapId);
563
									HazelcastService.getInstance().getSystemMetadataMap().put(resourceMapObsoletes, resourceMapObsoletesSystemMetadata);
564
								}
565
							}
566
							// look up the resource map that this one is obsoletedBy
567
							if (sysMeta.getObsoletedBy() != null) {
568
								Identifier resourceMapObsoletedBy = new Identifier();
569
								resourceMapObsoletedBy.setValue(resourceMapPrefix + sysMeta.getObsoletedBy().getValue());
570
								resourceMapSysMeta.setObsoletedBy(resourceMapObsoletedBy);
571
								SystemMetadata resourceMapObsoletedBySystemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(resourceMapObsoletedBy);
572
								if (resourceMapObsoletedBySystemMetadata != null) {
573
									resourceMapObsoletedBySystemMetadata.setObsoletes(resourceMapId);
574
									HazelcastService.getInstance().getSystemMetadataMap().put(resourceMapObsoletedBy, resourceMapObsoletedBySystemMetadata);
575
								}
576
							}
577
578 6907 leinfelder
							// save it locally, if it doesn't already exist
579
							if (!IdentifierManager.getInstance().identifierExists(resourceMapId.getValue())) {
580
								Session session = new Session();
581
								session.setSubject(submitter);
582
								MockHttpServletRequest request = new MockHttpServletRequest(null, null, null);
583
								MNodeService.getInstance(request).insertDataObject(IOUtils.toInputStream(resourceMapXML, MetaCatServlet.DEFAULT_ENCODING), resourceMapId, session);
584
								MNodeService.getInstance(request).insertSystemMetadata(resourceMapSysMeta);
585
								logMetacat.info("Inserted ORE package: " + resourceMapId.getValue());
586
							}
587 6800 leinfelder
			        	}
588 6713 leinfelder
			        }
589
				}
590 6706 leinfelder
591
			} catch (ParserConfigurationException pce) {
592 6707 leinfelder
				logMetacat.debug("There was a problem parsing the EML document. "
593 6706 leinfelder
								+ "The error message was: " + pce.getMessage());
594
595
			} catch (SAXException saxe) {
596 6707 leinfelder
				logMetacat.debug("There was a problem traversing the EML document. "
597 6706 leinfelder
								+ "The error message was: " + saxe.getMessage());
598
599
			} catch (XPathExpressionException xpee) {
600 6707 leinfelder
				logMetacat.debug("There was a problem searching the EML document. "
601 6706 leinfelder
								+ "The error message was: " + xpee.getMessage());
602
			} catch (Exception e) {
603 6707 leinfelder
				logMetacat.debug("There was a problem creating System Metadata. "
604 6706 leinfelder
								+ "The error message was: " + e.getMessage());
605 6721 leinfelder
				e.printStackTrace();
606 6706 leinfelder
			} // end try()
607
608
		} // end if()
609
610
		return sysMeta;
611
	}
612 6800 leinfelder
613
	/**
614 6911 leinfelder
     * Generate SystemMetadata for any object in the object store that does
615
     * not already have it.  SystemMetadata documents themselves, are, of course,
616
     * exempt.  This is a utility method for migration of existing object
617
     * stores to DataONE where SystemMetadata is required for all objects.
618
     * @param idList
619
     * @param includeOre
620
     * @param downloadData
621
     * @throws ServiceFailure
622
     * @throws McdbDocNotFoundException
623
     * @throws PropertyNotFoundException
624
     * @throws InvalidToken
625
     * @throws NotAuthorized
626
     * @throws NotFound
627
     * @throws NotImplemented
628
     * @throws InvalidRequest
629
     * @throws NoSuchAlgorithmException
630
     * @throws AccessionNumberException
631
     * @throws SQLException
632
     */
633
    public static void generateSystemMetadata(List<String> idList, boolean includeOre, boolean downloadData)
634
    throws ServiceFailure, McdbDocNotFoundException, PropertyNotFoundException, InvalidToken, NotAuthorized,
635
    NotFound, NotImplemented, InvalidRequest, NoSuchAlgorithmException, AccessionNumberException, SQLException
636
    {
637
638
        for (String localId : idList) {
639
            //for each id, add a system metadata doc
640
        	try {
641
        		logMetacat.debug("generating system metadata for " + localId);
642
        		generateSystemMetadata(localId, includeOre, downloadData);
643
        	} catch (Exception e) {
644
        		logMetacat.error("Error generating system metadata for: " + localId, e);
645
			}
646
        }
647
        logMetacat.info("done generating system metadata");
648
    }
649
650
651
    /**
652
     * Generate SystemMetadata for a particular object with identifier localId.
653
     * This is a utility method for migration of existing objects
654
     * to DataONE where SystemMetadata is required for all objects.
655
     * @param localId
656
     * @param includeOre
657
     * @param downloadData
658
     * @throws ServiceFailure
659
     * @throws McdbDocNotFoundException
660
     * @throws PropertyNotFoundException
661
     * @throws InvalidToken
662
     * @throws NotAuthorized
663
     * @throws NotFound
664
     * @throws NotImplemented
665
     * @throws InvalidRequest
666
     * @throws NoSuchAlgorithmException
667
     * @throws AccessionNumberException
668
     * @throws SQLException
669
     * @throws InvalidSystemMetadata
670
     */
671
    protected static void generateSystemMetadata(String localId, boolean includeOre, boolean downloadData)
672
    throws ServiceFailure, McdbDocNotFoundException, PropertyNotFoundException, InvalidToken, NotAuthorized,
673
    NotFound, NotImplemented, InvalidRequest, NoSuchAlgorithmException, AccessionNumberException, SQLException, InvalidSystemMetadata
674
    {
675
    	logMetacat.debug("generateSystemMetadata() called.");
676
    	logMetacat.debug("Creating SystemMetadata for localId " + localId);
677
        SystemMetadata sm = null;
678
679
        //generate required system metadata fields from the document
680
        try {
681
        	sm = SystemMetadataFactory.createSystemMetadata(localId, includeOre, downloadData);
682
        } catch (Exception e1) {
683
        	e1.printStackTrace();
684
        	ServiceFailure sf = new ServiceFailure("00","Exception in generateSystemMetadata: " +
685
        			e1.getMessage());
686
        	sf.setStackTrace(e1.getStackTrace());
687
        	throw sf;
688
        }
689
690
        //insert the systemmetadata object or just update it as needed
691
        boolean exists = IdentifierManager.getInstance().systemMetadataExists(sm.getIdentifier().getValue());
692
        if (!exists) {
693
        	IdentifierManager.getInstance().createSystemMetadata(sm);
694
        	logMetacat.info("Generated SystemMetadata for " + localId);
695
        } else {
696
        	IdentifierManager.getInstance().updateSystemMetadata(sm);
697
        	logMetacat.info("Updated SystemMetadata for " + localId);
698
        }
699
    }
700
701
	/**
702 6800 leinfelder
	 * Determines if we already have registered an ORE map for this package
703
	 * @param guid of the EML/packaging object
704
	 * @return true if there is an ORE map for the given package
705
	 */
706
	private static boolean oreExistsFor(Identifier guid) {
707
		// TODO: implement call to CN.search()
708
		return false;
709
	}
710 6706 leinfelder
711 6707 leinfelder
	/**
712 6706 leinfelder
	 * Find the size (in bytes) of a stream. Note: This needs to refactored out
713
	 * of MetacatHandler and into a utility when stream i/o in Metacat is
714
	 * evaluated.
715
	 *
716
	 * @param is The InputStream of bytes
717
	 *
718
	 * @return size The size in bytes of the input stream as a long
719
	 *
720
	 * @throws IOException
721
	 */
722
	private static long sizeOfStream(InputStream is) throws IOException {
723
724
		long size = 0;
725
		byte[] b = new byte[1024];
726
		int numread = is.read(b, 0, 1024);
727
		while (numread != -1) {
728
			size += numread;
729
			numread = is.read(b, 0, 1024);
730
		}
731
		return size;
732
733
	}
734 6705 leinfelder
}