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