Project

General

Profile

1
/**
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: leinfelder $'
9
 *     '$Date: 2012-02-01 15:52:51 -0800 (Wed, 01 Feb 2012) $'
10
 * '$Revision: 6970 $'
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.File;
29
import java.io.IOException;
30
import java.io.InputStream;
31
import java.math.BigInteger;
32
import java.net.URL;
33
import java.net.URLConnection;
34
import java.security.NoSuchAlgorithmException;
35
import java.sql.SQLException;
36
import java.util.ArrayList;
37
import java.util.Collections;
38
import java.util.Date;
39
import java.util.HashMap;
40
import java.util.Hashtable;
41
import java.util.List;
42
import java.util.Map;
43
import java.util.Vector;
44

    
45
import javax.xml.parsers.ParserConfigurationException;
46
import javax.xml.xpath.XPathExpressionException;
47

    
48
import org.apache.commons.beanutils.BeanUtils;
49
import org.apache.commons.io.IOUtils;
50
import org.apache.log4j.Logger;
51
import org.apache.wicket.protocol.http.MockHttpServletRequest;
52
import org.dataone.client.ObjectFormatCache;
53
import org.dataone.eml.DataoneEMLParser;
54
import org.dataone.eml.EMLDocument;
55
import org.dataone.eml.EMLDocument.DistributionMetadata;
56
import org.dataone.ore.ResourceMapFactory;
57
import org.dataone.service.exceptions.BaseException;
58
import org.dataone.service.exceptions.NotFound;
59
import org.dataone.service.types.v1.AccessPolicy;
60
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
import org.dataone.service.types.v1.Session;
65
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
import org.dataone.service.util.DateTimeMarshaller;
69
import org.dspace.foresite.ResourceMap;
70
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
import edu.ucsb.nceas.metacat.DBUtil;
76
import edu.ucsb.nceas.metacat.DocumentImpl;
77
import edu.ucsb.nceas.metacat.IdentifierManager;
78
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
79
import edu.ucsb.nceas.metacat.McdbException;
80
import edu.ucsb.nceas.metacat.MetaCatServlet;
81
import edu.ucsb.nceas.metacat.MetacatHandler;
82
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
83
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
import edu.ucsb.nceas.metacat.replication.ReplicationService;
87
import edu.ucsb.nceas.metacat.shared.AccessException;
88
import edu.ucsb.nceas.metacat.shared.HandlerException;
89
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

    
95
	private static final String resourceMapPrefix = "resourceMap_";
96
	private static Logger logMetacat = Logger.getLogger(SystemMetadataFactory.class);
97
	/**
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
	
102
	/**
103
	 * 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
	 * @throws SAXException 
114
	 * @throws HandlerException 
115
	 * @throws AccessControlException 
116
	 * @throws AccessException 
117
	 */
118
	public static SystemMetadata createSystemMetadata(String localId, boolean includeORE, boolean downloadData)
119
			throws McdbException, McdbDocNotFoundException, SQLException,
120
			IOException, AccessionNumberException, ClassNotFoundException,
121
			InsufficientKarmaException, ParseLSIDException,
122
			PropertyNotFoundException, BaseException, NoSuchAlgorithmException,
123
			JiBXException, AccessControlException, HandlerException, SAXException, AccessException {
124
		
125
		logMetacat.debug("createSystemMetadata() called for localId " + localId);
126

    
127
		// check for system metadata
128
		SystemMetadata sysMeta = null;
129
		
130
		AccessionNumber accNum = new AccessionNumber(localId, "NONE");
131
		int rev = Integer.valueOf(accNum.getRev());
132
		
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
			logMetacat.debug("No guid found in the identifier table.  Creating mapping for " + localId);
141
			IdentifierManager.getInstance().createMapping(localId, localId);
142
			guid = IdentifierManager.getInstance().getGUID(accNum.getDocid(), rev);			
143
		}
144
		
145
		// look up existing system metadata if it exists
146
		Identifier identifier = new Identifier();
147
		identifier.setValue(guid);
148
		try {
149
			logMetacat.debug("Using hazelcast to get system metadata");
150
			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
			logMetacat.debug("No system metadata found in hz: " + e.getMessage());
157

    
158
		}
159

    
160
		if (sysMeta == null) {
161
			// create system metadata
162
			sysMeta = new SystemMetadata();
163
			sysMeta.setIdentifier(identifier);
164
			sysMeta.setSerialVersion(BigInteger.valueOf(1));
165
			sysMeta.setArchived(false);
166
		}
167
		
168
		// get additional docinfo
169
		Hashtable<String, String> docInfo = ReplicationService.getDocumentInfoMap(localId);
170
		// set the default object format
171
		String doctype = docInfo.get("doctype");
172
		ObjectFormatIdentifier fmtid = null;
173

    
174
		// set the object format, fall back to defaults
175
		try {
176
			fmtid = ObjectFormatCache.getInstance().getFormat(doctype).getFormatId();
177
		} catch (NotFound nfe) {
178
			// 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
			}
184
		}
185

    
186
		sysMeta.setFormatId(fmtid);
187
		logMetacat.debug("The ObjectFormat for " + localId + " is " + fmtid.getValue());
188

    
189
		// for retrieving the actual object
190
		InputStream inputStream = null;
191
		inputStream = MetacatHandler.read(localId);
192

    
193
		// create the checksum
194
		String algorithm = "MD5";
195
		Checksum checksum = ChecksumUtil.checksum(inputStream, algorithm);
196
		sysMeta.setChecksum(checksum);
197
		
198
		// 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
		
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
		// ensure this ordering since processing depends on it
230
		Collections.sort(revisions);
231
		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
		// set them on our object
248
		sysMeta.setObsoletedBy(obsoletedBy);
249
		sysMeta.setObsoletes(obsoletes);
250
		
251
		// update the system metadata for the object[s] we are revising
252
		if (obsoletedBy != null) {
253
			//SystemMetadata obsoletedBySysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletedBy);
254
			SystemMetadata obsoletedBySysMeta = IdentifierManager.getInstance().getSystemMetadata(obsoletedBy.getValue());
255
			if (obsoletedBySysMeta != null) {
256
				obsoletedBySysMeta.setObsoletes(identifier);
257
				HazelcastService.getInstance().getSystemMetadataMap().put(obsoletedBy, obsoletedBySysMeta);
258
			}
259
		}
260
		if (obsoletes != null) {
261
			//SystemMetadata obsoletesSysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletes);
262
			SystemMetadata obsoletesSysMeta = IdentifierManager.getInstance().getSystemMetadata(obsoletes.getValue());
263
			if (obsoletesSysMeta != null) {
264
				obsoletesSysMeta.setObsoletedBy(identifier);
265
				obsoletesSysMeta.setArchived(true);
266
				HazelcastService.getInstance().getSystemMetadataMap().put(obsoletes, obsoletesSysMeta);
267
			}
268
		}
269
		
270
		// look up the access control policy we have in metacat
271
		AccessPolicy accessPolicy = IdentifierManager.getInstance().getAccessPolicy(guid);
272
		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
		// 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
				
293
				// get it again to parse the document
294
				logMetacat.debug("Re-reading document inputStream");
295
				inputStream = MetacatHandler.read(localId);
296
				
297
				DataoneEMLParser emlParser = DataoneEMLParser.getInstance();
298
		        EMLDocument emlDocument = emlParser.parseDocument(inputStream);
299
				
300
				// iterate through the data objects in the EML doc and add sysmeta
301
				logMetacat.debug("In createSystemMetadata() the number of data "
302
								+ "entities is: "
303
								+ emlDocument.distributionMetadata);
304

    
305
				// 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
				// iterate through data objects described by the EML
310
	            if (emlDocument.distributionMetadata != null) {
311
					for (int j = 0; j < emlDocument.distributionMetadata.size(); j++) {
312
	
313
						DistributionMetadata distMetadata = emlDocument.distributionMetadata.elementAt(j);
314
				        String dataDocUrl = distMetadata.url;
315
				        String dataDocMimeType = distMetadata.mimeType;
316
						// default to binary
317
						if (dataDocMimeType == null) {
318
							dataDocMimeType = ObjectFormatCache.getInstance()
319
									.getFormat("application/octet-stream")
320
									.getFormatId().getValue();
321
						}
322

    
323
						// process the data
324
						boolean remoteData = false;
325
						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
									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
								} 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
									
381
									remoteData = true;
382
								}
383
							}
384
							
385
						}
386
						
387
						logMetacat.debug("Data local ID: " + dataDocLocalId);
388
						logMetacat.debug("Data URL     : " + dataDocUrl);
389
						logMetacat.debug("Data mime    : " + dataDocMimeType);
390
						
391
						// now we have a local id for the data
392
						if (dataDocLocalId != null) {
393
							
394
							// 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
							try {
402
								// look for the identifier
403
								dataGuidString = IdentifierManager.getInstance().getGUID(dataDocid, dataRev);
404
								// set it
405
								dataGuid.setValue(dataGuidString);
406
								// look up the system metadata
407
								try {
408
									dataSysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(dataGuid);
409
								} catch (Exception e) {
410
									// probably not in the system
411
									dataSysMeta = null;
412
								}
413
								//dataSysMeta = IdentifierManager.getInstance().getSystemMetadata(dataGuidString);
414
							} catch (McdbDocNotFoundException nf) {
415
								// we didn't find it
416
								dataSysMeta = null;
417
							}
418
								
419
							// we'll have to generate it	
420
							if (dataSysMeta == null) {
421
								// System metadata for data doesn't exist yet, so create it
422
								logMetacat.debug("No exisiting SystemMetdata found, creating for: " + dataDocLocalId);
423
								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
	
437
							}
438
							
439
							// set object format for the data file
440
							logMetacat.debug("Updating system metadata for " + dataGuid.getValue() + " to " + dataDocMimeType);
441
							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
							dataIds.add(dataGuid);
458
	
459
						} // end if (EML package)
460
	
461
					} // end for (data entities)
462
					
463
	            } // data entities not null
464
	            
465
				// ORE map
466
				if (includeORE) {
467
					// can we generate them?
468
			        if (!dataIds.isEmpty()) {
469
			        	// 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
							// 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
			        	}
525
			        }
526
				}
527

    
528
			} catch (ParserConfigurationException pce) {
529
				logMetacat.debug("There was a problem parsing the EML document. "
530
								+ "The error message was: " + pce.getMessage());
531

    
532
			} catch (SAXException saxe) {
533
				logMetacat.debug("There was a problem traversing the EML document. "
534
								+ "The error message was: " + saxe.getMessage());
535

    
536
			} catch (XPathExpressionException xpee) {
537
				logMetacat.debug("There was a problem searching the EML document. "
538
								+ "The error message was: " + xpee.getMessage());
539
			} catch (Exception e) {
540
				logMetacat.debug("There was a problem creating System Metadata. "
541
								+ "The error message was: " + e.getMessage());
542
				e.printStackTrace();
543
			} // end try()
544

    
545
		} // end if()
546

    
547
		return sysMeta;
548
	}
549
	
550
	/**
551
     * 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
	 * @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
     */
574
    public static void generateSystemMetadata(List<String> idList, boolean includeOre, boolean downloadData) 
575
    throws PropertyNotFoundException, NoSuchAlgorithmException, AccessionNumberException, SQLException, AccessControlException, AccessException, McdbException, IOException, ClassNotFoundException, InsufficientKarmaException, ParseLSIDException, BaseException, JiBXException, HandlerException, SAXException 
576
    {
577
        
578
        for (String localId : idList) { 
579
            //for each id, add a system metadata doc
580
        	generateSystemMetadata(localId, includeOre, downloadData);
581
        }
582
        logMetacat.info("done generating system metadata for given list");
583
    }
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
     * @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
     */
609
    protected static void generateSystemMetadata(String localId, boolean includeOre, boolean downloadData) 
610
    throws PropertyNotFoundException, NoSuchAlgorithmException, AccessionNumberException, SQLException, AccessControlException, AccessException, McdbException, IOException, ClassNotFoundException, InsufficientKarmaException, ParseLSIDException, BaseException, JiBXException, HandlerException, SAXException 
611
    {
612
    	logMetacat.debug("Creating SystemMetadata for localId " + localId);
613
        SystemMetadata sm = null;
614

    
615
        //generate required system metadata fields from the document
616
    	sm = SystemMetadataFactory.createSystemMetadata(localId, includeOre, downloadData);
617
    	
618
        //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
	 * 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

    
639
	/**
640
	 * 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
	
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
}
(5-5/5)