Project

General

Profile

1 6177 cjones
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000-2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author:  $'
7
 *     '$Date:  $'
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 */
23
24
package edu.ucsb.nceas.metacat.dataone;
25
26
import java.util.Date;
27 6220 leinfelder
import java.util.List;
28 6177 cjones
29 6178 cjones
import org.apache.log4j.Logger;
30 6366 leinfelder
import org.dataone.service.cn.v1.CNAuthorization;
31
import org.dataone.service.cn.v1.CNCore;
32
import org.dataone.service.cn.v1.CNRead;
33
import org.dataone.service.cn.v1.CNReplication;
34 6177 cjones
import org.dataone.service.exceptions.IdentifierNotUnique;
35
import org.dataone.service.exceptions.InsufficientResources;
36
import org.dataone.service.exceptions.InvalidRequest;
37
import org.dataone.service.exceptions.InvalidSystemMetadata;
38
import org.dataone.service.exceptions.InvalidToken;
39
import org.dataone.service.exceptions.NotAuthorized;
40
import org.dataone.service.exceptions.NotFound;
41
import org.dataone.service.exceptions.NotImplemented;
42
import org.dataone.service.exceptions.ServiceFailure;
43 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
44
import org.dataone.service.types.v1.Identifier;
45
import org.dataone.service.types.v1.NodeList;
46
import org.dataone.service.types.v1.ObjectFormat;
47
import org.dataone.service.types.v1.ObjectFormatIdentifier;
48
import org.dataone.service.types.v1.ObjectFormatList;
49
import org.dataone.service.types.v1.ObjectList;
50
import org.dataone.service.types.v1.ObjectLocationList;
51
import org.dataone.service.types.v1.Permission;
52
import org.dataone.service.types.v1.Replica;
53
import org.dataone.service.types.v1.ReplicationPolicy;
54
import org.dataone.service.types.v1.ReplicationStatus;
55
import org.dataone.service.types.v1.Session;
56
import org.dataone.service.types.v1.Subject;
57
import org.dataone.service.types.v1.SystemMetadata;
58 6177 cjones
59 6188 leinfelder
import edu.ucsb.nceas.metacat.EventLog;
60
import edu.ucsb.nceas.metacat.IdentifierManager;
61 6194 leinfelder
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
62 6188 leinfelder
import edu.ucsb.nceas.metacat.replication.ForceReplicationSystemMetadataHandler;
63
64 6177 cjones
/**
65
 * Represents Metacat's implementation of the DataONE Coordinating Node
66 6179 cjones
 * service API. Methods implement the various CN* interfaces, and methods common
67 6177 cjones
 * to both Member Node and Coordinating Node interfaces are found in the
68
 * D1NodeService super class.
69
 *
70
 */
71
public class CNodeService extends D1NodeService implements CNAuthorization,
72 6235 leinfelder
    CNCore, CNRead, CNReplication {
73 6177 cjones
74 6178 cjones
	/* the instance of the CNodeService object */
75
  private static CNodeService instance = null;
76
77
  /* the logger instance */
78
  private Logger logMetacat = null;
79 6177 cjones
80 6178 cjones
  /**
81
   * singleton accessor
82
   */
83 6241 cjones
  public static CNodeService getInstance() {
84 6178 cjones
    if (instance == null) {
85 6241 cjones
86 6254 cjones
      instance = new CNodeService();
87 6241 cjones
88 6178 cjones
    }
89 6241 cjones
90 6178 cjones
    return instance;
91
  }
92
93
  /**
94
   * Constructor, private for singleton access
95
   */
96 6254 cjones
  private CNodeService() {
97
  	super();
98 6178 cjones
    logMetacat = Logger.getLogger(CNodeService.class);
99
100
  }
101
102 6177 cjones
	/**
103
	 * Set the replication policy for an object given the object identifier
104
	 *
105
	 * @param session - the Session object containing the credentials for the Subject
106
	 * @param pid - the object identifier for the given object
107
	 * @param policy - the replication policy to be applied
108
	 *
109
	 * @return true or false
110
	 *
111
	 * @throws NotImplemented
112
	 * @throws NotAuthorized
113
	 * @throws ServiceFailure
114
	 * @throws InvalidRequest
115
	 *
116
	 */
117
	@Override
118
	public boolean setReplicationPolicy(Session session, Identifier pid,
119
	  ReplicationPolicy policy)
120 6219 leinfelder
	  throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, InvalidRequest, InvalidToken {
121 6177 cjones
122 6219 leinfelder
		// get the subject
123
		Subject subject = session.getSubject();
124
		// get the system metadata
125
		String guid = pid.getValue();
126
127
		// are we allowed to do this?
128 6225 leinfelder
		if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
129 6221 leinfelder
			throw new NotAuthorized("4881", Permission.CHANGE_PERMISSION + " not allowed by " + subject.getValue() + " on " + guid);
130 6219 leinfelder
		}
131
132
		SystemMetadata systemMetadata = null;
133
		try {
134
			systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
135
		} catch (McdbDocNotFoundException e) {
136
			throw new NotFound("4884", "No record found for: " + guid);
137
		}
138
139
		// set the new policy
140
		systemMetadata.setReplicationPolicy(policy);
141
142
		// update the metadata
143
		try {
144
			IdentifierManager.getInstance().updateSystemMetadata(systemMetadata);
145
		} catch (McdbDocNotFoundException e) {
146
			throw new ServiceFailure("4882", e.getMessage());
147
		}
148
149
		return true;
150 6177 cjones
	}
151
152
	/**
153
	 * Set the replication status for an object given the object identifier
154
	 *
155
	 * @param session - the Session object containing the credentials for the Subject
156
	 * @param pid - the object identifier for the given object
157
	 * @param status - the replication status to be applied
158
	 *
159
	 * @return true or false
160
	 *
161
	 * @throws NotImplemented
162
	 * @throws NotAuthorized
163
	 * @throws ServiceFailure
164
	 * @throws InvalidRequest
165
	 * @throws InvalidToken
166
	 * @throws NotFound
167
	 *
168
	 */
169
	@Override
170
	public boolean setReplicationStatus(Session session, Identifier pid,
171
	  ReplicationStatus status)
172
	  throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized,
173
	  InvalidRequest, NotFound {
174
175 6220 leinfelder
		// get the subject
176
		Subject subject = session.getSubject();
177
		// get the system metadata
178
		String guid = pid.getValue();
179
180
		// are we allowed to do this?
181 6225 leinfelder
		if (!isAuthorized(session, pid, Permission.WRITE)) {
182 6221 leinfelder
			throw new NotAuthorized("4720", Permission.WRITE + " not allowed by " + subject.getValue() + " on " + guid);
183 6220 leinfelder
		}
184
185
		SystemMetadata systemMetadata = null;
186
		try {
187
			systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
188
		} catch (McdbDocNotFoundException e) {
189
			throw new NotFound("4740", "No record found for: " + guid);
190
		}
191
192
		// set the status for each replica
193
		// TODO: should this method select a certain replica?
194
		List<Replica> replicas = systemMetadata.getReplicaList();
195
		for (Replica replica: replicas) {
196
			replica.setReplicationStatus(status);
197
		}
198
199
		// [re]set the list -- redundant?
200
		systemMetadata.setReplicaList(replicas);
201
202
		// update the metadata
203
		try {
204
			IdentifierManager.getInstance().updateSystemMetadata(systemMetadata);
205
		} catch (McdbDocNotFoundException e) {
206
			throw new ServiceFailure("4700", e.getMessage());
207
		}
208
209
		return true;
210 6177 cjones
	}
211
212
	/**
213
	 * Test that the specified relationship between pidOfSubject and pidOfObject exists
214
	 *
215
	 * @param session - the Session object containing the credentials for the Subject
216
	 * @param node - the node information for the given node be modified
217
	 *
218
	 * @return true if the relationship exists
219
	 *
220
	 * @throws InvalidToken
221
	 * @throws ServiceFailure
222
	 * @throws NotAuthorized
223
	 * @throws NotFound
224
	 * @throws InvalidRequest
225
	 * @throws NotImplemented
226
	 */
227
	@Override
228 6221 leinfelder
	public boolean assertRelation(Session session, Identifier pidOfSubject,
229 6177 cjones
		String relationship, Identifier pidOfObject)
230
	  throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
231
	  InvalidRequest, NotImplemented {
232
233 6221 leinfelder
234
		// get the system metadata
235
		String guid1 = pidOfSubject.getValue();
236
		// are we allowed to do this?
237 6225 leinfelder
		if (!isAuthorized(session, pidOfSubject, Permission.READ)) {
238 6221 leinfelder
			throw new NotAuthorized("4881", Permission.READ + " not allowed on " + guid1);
239
		}
240
241
		SystemMetadata systemMetadata = null;
242
		try {
243
			systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid1);
244
		} catch (McdbDocNotFoundException e) {
245
			throw new NotFound("4884", "No record found for: " + guid1);
246
		}
247
248
		// check relationships
249 6366 leinfelder
		// TODO: use ORE map
250 6221 leinfelder
		if (relationship.equalsIgnoreCase("describes")) {
251 6366 leinfelder
252 6221 leinfelder
		}
253
		if (relationship.equalsIgnoreCase("describedBy")) {
254 6366 leinfelder
255 6221 leinfelder
		}
256
		if (relationship.equalsIgnoreCase("derivedFrom")) {
257 6366 leinfelder
258 6221 leinfelder
		}
259
		if (relationship.equalsIgnoreCase("obsoletes")) {
260 6366 leinfelder
			Identifier pid = systemMetadata.getObsoletes();
261
			if (pid.getValue().equals(pidOfObject.getValue())) {
262
				return true;
263 6294 leinfelder
			}
264
			//return systemMetadata.getObsoleteList().contains(pidOfObject);
265 6221 leinfelder
		}
266
		if (relationship.equalsIgnoreCase("obsoletedBy")) {
267 6366 leinfelder
			Identifier pid = systemMetadata.getObsoletedBy();
268
			if (pid.getValue().equals(pidOfObject.getValue())) {
269
				return true;
270 6294 leinfelder
			}
271
			//return systemMetadata.getObsoletedByList().contains(pidOfObject);
272 6221 leinfelder
		}
273
274 6177 cjones
		return false;
275
	}
276
277
	/**
278 6218 leinfelder
	 * Return the checksum of the object given the identifier
279 6177 cjones
	 *
280
	 * @param session - the Session object containing the credentials for the Subject
281
	 * @param pid - the object identifier for the given object
282
	 *
283
	 * @return checksum - the checksum of the object
284
	 *
285
	 * @throws InvalidToken
286
	 * @throws ServiceFailure
287
	 * @throws NotAuthorized
288
	 * @throws NotFound
289
	 * @throws InvalidRequest
290
	 * @throws NotImplemented
291
	 */
292
	@Override
293
	public Checksum getChecksum(Session session, Identifier pid)
294
	  throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
295
	  InvalidRequest, NotImplemented {
296
297 6216 leinfelder
		if (!isAuthorized(session, pid, Permission.READ)) {
298
			throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());
299
		}
300
		SystemMetadata systemMetadata = null;
301
		try {
302
			systemMetadata = IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
303
		} catch (McdbDocNotFoundException e) {
304
			throw new NotFound("1420", "No record found for: " + pid.getValue());
305
		}
306
		Checksum checksum = systemMetadata.getChecksum();
307
308
		return checksum;
309 6177 cjones
	}
310
311
	/**
312
	 * Resolve the location of a given object
313
	 *
314
	 * @param session - the Session object containing the credentials for the Subject
315
	 * @param pid - the object identifier for the given object
316
	 *
317
	 * @return objectLocationList - the list of nodes known to contain the object
318
	 *
319
	 * @throws InvalidRequest
320
	 * @throws InvalidToken
321
	 * @throws ServiceFailure
322
	 * @throws NotAuthorized
323
	 * @throws NotFound
324
	 * @throws NotImplemented
325
	 */
326
	@Override
327
	public ObjectLocationList resolve(Session session, Identifier pid)
328
	  throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized,
329
	  NotFound, NotImplemented {
330
331 6303 leinfelder
		throw new NotImplemented("4131", "resolve not implemented");
332
333 6177 cjones
	}
334
335
	/**
336
	 * Search the metadata catalog for identifiers that match the criteria
337
	 *
338
	 * @param session - the Session object containing the credentials for the Subject
339
	 * @param queryType - An identifier for the type of query expression
340
	 *                    provided in the query
341
	 * @param query -  The criteria for matching the characteristics of the
342
	 *                 metadata objects of interest
343
	 *
344
	 * @return objectList - the list of objects matching the criteria
345
	 *
346
	 * @throws InvalidToken
347
	 * @throws ServiceFailure
348
	 * @throws NotAuthorized
349
	 * @throws InvalidRequest
350
	 * @throws NotImplemented
351
	 */
352
	@Override
353 6397 leinfelder
	public ObjectList search(Session session, String queryType, String query)
354 6177 cjones
	  throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
355
	  NotImplemented {
356
357 6300 leinfelder
		ObjectList objectList = null;
358
		try {
359
		    objectList =
360
		    	IdentifierManager.getInstance().querySystemMetadata(
361
		    			null, //startTime,
362
		    			null, //endTime,
363
		    			null, //objectFormat,
364
		    			false, //replicaStatus,
365
		    			0, //start,
366
		    			-1 //count
367
		    			);
368
369
		} catch (Exception e) {
370
			throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
371
		}
372
373 6286 leinfelder
	    return objectList;
374
375
		//throw new NotImplemented("4281", "search not implemented");
376 6281 leinfelder
377
		// the code block below is from an older implementation
378
379
		/*  This block commented out because of the EcoGrid circular dependency.
380
         *  For now, query will not be supported until the circularity can be
381
         *  resolved, probably by moving the ecogrid query syntax transformers
382
         *  directly into the Metacat codebase.  MBJ 2010-02-03
383
384
        try {
385
            EcogridQueryParser parser = new EcogridQueryParser(request
386
                    .getReader());
387
            parser.parseXML();
388
            QueryType queryType = parser.getEcogridQuery();
389
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer =
390
                new EcogridJavaToMetacatJavaQueryTransformer();
391
            QuerySpecification metacatQuery = queryTransformer
392
                    .transform(queryType);
393 6223 leinfelder
394 6281 leinfelder
            DBQuery metacat = new DBQuery();
395
396
            boolean useXMLIndex = (new Boolean(PropertyService
397
                    .getProperty("database.usexmlindex"))).booleanValue();
398
            String xmlquery = "query"; // we don't care the query in resultset,
399
            // the query can be anything
400
            PrintWriter out = null; // we don't want metacat result, so set out null
401
402
            // parameter: queryspecification, user, group, usingIndexOrNot
403
            StringBuffer result = metacat.createResultDocument(xmlquery,
404
                    metacatQuery, out, username, groupNames, useXMLIndex);
405
406
            // create result set transfer
407
            String saxparser = PropertyService.getProperty("xml.saxparser");
408
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
409
                    new StringReader(result.toString()), saxparser, queryType
410
                            .getNamespace().get_value());
411
            ResultsetType records = metacatResultsetParser.getEcogridResult();
412
413
            System.out
414
                    .println(EcogridResultsetTransformer.toXMLString(records));
415
            response.setContentType("text/xml");
416
            out = response.getWriter();
417
            out.print(EcogridResultsetTransformer.toXMLString(records));
418
419
        } catch (Exception e) {
420
            e.printStackTrace();
421
        }*/
422
423
424 6177 cjones
	}
425
426
	/**
427
	 * Returns the object format registered in the DataONE Object Format
428
	 * Vocabulary for the given format identifier
429
	 *
430
	 * @param fmtid - the identifier of the format requested
431
	 *
432
	 * @return objectFormat - the object format requested
433
	 *
434
	 * @throws InvalidRequest
435
	 * @throws ServiceFailure
436
	 * @throws NotFound
437
	 * @throws InsufficientResources
438
	 * @throws NotImplemented
439
	 */
440
	@Override
441
	public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
442
	  throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources,
443
	  NotImplemented {
444 6187 leinfelder
445
	  	return ObjectFormatService.getInstance().getFormat(fmtid);
446
447 6177 cjones
	}
448
449
	/**
450
   * Returns a list of all object formats registered in the DataONE Object
451
   * Format Vocabulary
452
 	 *
453
	 * @return objectFormatList - The list of object formats registered in
454
	 *                            the DataONE Object Format Vocabulary
455
	 *
456
	 * @throws InvalidRequest
457
	 * @throws ServiceFailure
458
	 * @throws NotImplemented
459
	 * @throws NotFound
460
	 * @throws InsufficientResources
461
	 */
462
	@Override
463
	public ObjectFormatList listFormats()
464
	  throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources,
465
	  NotImplemented {
466
467 6187 leinfelder
		return ObjectFormatService.getInstance().listFormats();
468 6177 cjones
	}
469
470
	/**
471
   * Returns a list of nodes that have been registered with the DataONE infrastructure
472
 	 *
473
	 * @return nodeList - List of nodes from the registry
474
	 *
475
	 * @throws ServiceFailure
476
	 * @throws NotImplemented
477
	 */
478
	@Override
479
	public NodeList listNodes()
480
	  throws NotImplemented, ServiceFailure {
481
482 6223 leinfelder
		throw new NotImplemented("4800", "listNodes not implemented");
483 6177 cjones
	}
484
485
	/**
486
   * Provides a mechanism for adding system metadata independently of its
487
   * associated object, such as when adding system metadata for data objects.
488
 	 *
489
	 * @param session - the Session object containing the credentials for the Subject
490
	 * @param pid - The identifier of the object to register the system metadata against
491
	 * @param sysmeta - The system metadata to be registered
492
	 *
493
	 * @return true if the registration succeeds
494
	 *
495
	 * @throws NotImplemented
496
	 * @throws NotAuthorized
497
	 * @throws ServiceFailure
498
	 * @throws InvalidRequest
499
	 * @throws InvalidSystemMetadata
500
	 */
501
	@Override
502 6397 leinfelder
	public Identifier registerSystemMetadata(Session session, Identifier guid,
503 6177 cjones
	  SystemMetadata sysmeta)
504
	  throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
505
	  InvalidSystemMetadata {
506
507 6188 leinfelder
		// TODO: control who can call this?
508
	      if (session == null) {
509
	          //TODO: many of the thrown exceptions do not use the correct error codes
510
	          //check these against the docs and correct them
511 6189 leinfelder
	          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
512 6188 leinfelder
	                  "  If you are not logged in, please do so and retry the request.");
513
	      }
514
515
	      // verify that guid == SystemMetadata.getIdentifier()
516
	      logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
517
	      if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
518
	          throw new InvalidRequest("4863",
519
	              "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
520
	              sysmeta.getIdentifier().getValue() + ").");
521
	      }
522
523
	      logMetacat.debug("Checking if identifier exists...");
524
	      // Check that the identifier does not already exist
525 6278 leinfelder
	      if (IdentifierManager.getInstance().identifierExists(guid.getValue())) {
526 6188 leinfelder
	          throw new InvalidRequest("4863",
527
	              "GUID is already in use by an existing object.");
528 6337 leinfelder
529 6188 leinfelder
	      }
530
531
	      // insert the system metadata into the object store
532
	      logMetacat.debug("Starting to insert SystemMetadata...");
533
	      sysmeta.setDateSysMetadataModified(new Date());
534
	      try {
535
			    IdentifierManager.getInstance().createSystemMetadata(sysmeta);
536
			    // force replication of this record
537
			    ForceReplicationSystemMetadataHandler forceReplication =
538
			    	new ForceReplicationSystemMetadataHandler(guid.getValue(), null);
539
		    } catch (Exception e) {
540
	          throw new ServiceFailure("4862", "Error inserting system metadata: " + e.getClass() + ": " + e.getMessage());
541
		    }
542
543
	      logMetacat.debug("Returning from registerSystemMetadata");
544
	      EventLog.getInstance().log(null, session.getSubject().getValue(), guid.getValue(), "registerSystemMetadata");
545 6397 leinfelder
	      return guid;
546 6177 cjones
	}
547
548
	/**
549 6378 leinfelder
	 * Provides a mechanism for updating system metadata independently of its
550
	 * associated object
551
 	 *
552
	 * @param session - the Session object containing the credentials for the Subject
553
	 * @param pid - The identifier of the system metadata
554
	 * @param sysmeta - The system metadata to be registered
555
	 *
556
	 * @return true if the update succeeds
557
	 *
558
	 * @throws NotImplemented
559
	 * @throws NotAuthorized
560
	 * @throws ServiceFailure
561
	 * @throws InvalidRequest
562
	 * @throws InvalidSystemMetadata
563
	 * @throws NotFound
564
	 */
565
	@Override
566
	public boolean updateSystemMetadata(Session session, Identifier guid,
567
	  SystemMetadata sysmeta)
568
	  throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
569
	  InvalidSystemMetadata, NotFound {
570
571
		// TODO: control who can call this?
572
	      if (session == null) {
573
	          //TODO: many of the thrown exceptions do not use the correct error codes
574
	          //check these against the docs and correct them
575
	          throw new NotAuthorized("4861", "No Session - could not authorize for update." +
576
	                  "  If you are not logged in, please do so and retry the request.");
577
	      }
578
579
	      // verify that guid == SystemMetadata.getIdentifier()
580
	      logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
581
	      if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
582
	          throw new InvalidRequest("4863",
583
	              "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
584
	              sysmeta.getIdentifier().getValue() + ").");
585
	      }
586
587
	      logMetacat.debug("Checking if identifier exists...");
588
	      // Check that the identifier exists
589
	      if (!IdentifierManager.getInstance().identifierExists(guid.getValue())) {
590
	          throw new NotFound("000",
591
	              "GUID does not exist");
592
	      }
593
594
	      // update the system metadata into the object store
595
	      logMetacat.debug("Starting to update SystemMetadata...");
596
	      sysmeta.setDateSysMetadataModified(new Date());
597
	      try {
598
			    IdentifierManager.getInstance().updateSystemMetadata(sysmeta);
599
			    // force replication of this record
600
			    ForceReplicationSystemMetadataHandler forceReplication =
601
			    	new ForceReplicationSystemMetadataHandler(guid.getValue(), null);
602
		    } catch (Exception e) {
603
	          throw new ServiceFailure("4862", "Error updating system metadata: " + e.getClass() + ": " + e.getMessage());
604
		    }
605
606
	      logMetacat.debug("Returning from updateSystemMetadata");
607
	      EventLog.getInstance().log(null, session.getSubject().getValue(), guid.getValue(), "updateSystemMetadata");
608
	      return true;
609
	}
610
611
	/**
612 6177 cjones
   * Given an optional scope and format, reserves and returns an identifier
613
   * within that scope and format that is unique and will not be
614
   * used by any other sessions.
615
 	 *
616
	 * @param session - the Session object containing the credentials for the Subject
617
	 * @param pid - The identifier of the object to register the system metadata against
618
	 * @param scope - An optional string to be used to qualify the scope of
619
	 *                the identifier namespace, which is applied differently
620
	 *                depending on the format requested. If scope is not
621
	 *                supplied, a default scope will be used.
622
	 * @param format - The optional name of the identifier format to be used,
623
	 * 								 drawn from a DataONE-specific vocabulary of identifier
624
	 *                 format names, including several common syntaxes such
625
	 *                 as DOI, LSID, UUID, and LSRN, among others. If the
626
	 *                 format is not supplied by the caller, the CN service
627
	 *                 will use a default identifier format, which may change
628
	 *                 over time.
629
	 *
630
	 * @return true if the registration succeeds
631
	 *
632
	 * @throws InvalidToken
633
	 * @throws ServiceFailure
634
	 * @throws NotAuthorized
635
	 * @throws IdentifierNotUnique
636
	 * @throws NotImplemented
637
	 */
638
	@Override
639 6378 leinfelder
	public boolean reserveIdentifier(Session session, Identifier pid)
640
	throws InvalidToken, ServiceFailure,
641
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
642 6177 cjones
643 6337 leinfelder
		throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
644 6177 cjones
	}
645 6339 leinfelder
646 6378 leinfelder
	@Override
647
	public Identifier generateIdentifier(Session session, String scheme, String fragment)
648
	throws InvalidToken, ServiceFailure,
649
        NotAuthorized, NotImplemented, InvalidRequest {
650
		throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
651
	}
652
653 6339 leinfelder
	/**
654
 	 * Checks whether the pid is reserved by the subject in the session param
655
 	 * If the reservation is held on the pid by the subject, we return true.
656
 	 *
657
	 * @param session - the Session object containing the Subject
658
	 * @param pid - The identifier to check
659
	 *
660
	 * @return true if the reservation exists for the subject/pid
661
	 *
662
	 * @throws InvalidToken
663
	 * @throws ServiceFailure
664
	 * @throws NotFound - when the pid is not found (in use or in reservation)
665
	 * @throws NotAuthorized - when the subject does not hold a reservation on the pid
666
	 * @throws IdentifierNotUnique - when the pid is in use
667
	 * @throws NotImplemented
668
	 */
669 6177 cjones
670 6339 leinfelder
	@Override
671
	public boolean hasReservation(Session session, Identifier pid)
672
		  throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique,
673
		  NotImplemented, InvalidRequest {
674
675
			throw new NotImplemented("4191", "hasReservation not implemented on this node");
676
	}
677
678 6177 cjones
	/**
679
   * Changes ownership (RightsHolder) of the specified object to the
680
   * subject specified by userId
681
 	 *
682
	 * @param session - the Session object containing the credentials for the Subject
683
	 * @param pid - Identifier of the object to be modified
684
	 * @param userId - The subject that will be taking ownership of the specified object.
685
	 *
686
	 * @return pid - the identifier of the modified object
687
	 *
688
	 * @throws ServiceFailure
689
	 * @throws InvalidToken
690
	 * @throws NotFound
691
	 * @throws NotAuthorized
692
	 * @throws NotImplemented
693
	 * @throws InvalidRequest
694
	 */
695
	@Override
696
	public Identifier setOwner(Session session, Identifier pid, Subject userId)
697
	  throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
698
	  NotImplemented, InvalidRequest {
699 6194 leinfelder
700
		// get the subject
701
		Subject subject = session.getSubject();
702
		// get the system metadata
703
		String guid = pid.getValue();
704
705
		// are we allowed to do this?
706 6225 leinfelder
		if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
707 6194 leinfelder
			throw new NotAuthorized("4440", "not allowed by " + subject.getValue() + " on " + guid);
708
		}
709
710
		SystemMetadata systemMetadata = null;
711
		try {
712
			systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
713
		} catch (McdbDocNotFoundException e) {
714
			throw new NotFound("4460", "No record found for: " + guid);
715
		}
716
717
		// set the new rights holder
718
		systemMetadata.setRightsHolder(userId);
719
720
		// update the metadata
721
		try {
722
			IdentifierManager.getInstance().updateSystemMetadata(systemMetadata);
723
		} catch (McdbDocNotFoundException e) {
724
			throw new ServiceFailure("4490", e.getMessage());
725
		}
726 6177 cjones
727 6194 leinfelder
		return pid;
728 6177 cjones
	}
729
730 6384 cjones
	/**
731
	 * Verify that a replication task is authorized by comparing the target node's
732
	 * Subject (from the X.509 certificate-derived Session) with the list of
733
	 * subjects in the known, pending replication tasks map.
734
	 *
735
	 * @param originatingNodeSession - Session information that contains the
736
	 *                                 identity of the calling user
737
	 * @param targetNodeSubject - Subject identifying the target node
738
	 * @param pid - the identifier of the object to be replicated
739
	 * @param replicatePermission - the execute permission to be granted
740
	 *
741
	 * @throws ServiceFailure
742
	 * @throws NotImplemented
743
	 * @throws InvalidToken
744
	 * @throws NotAuthorized
745
	 * @throws InvalidRequest
746
	 * @throws NotFound
747
	 */
748
	@Override
749
  public boolean isReplicationAuthorized(Session originatingNodeSession,
750
    Subject targetNodeSubject, Identifier pid, Permission replicatePermission)
751
	  throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
752
	  NotFound, InvalidRequest {
753
754
		throw new NotImplemented("4870", "isReplicationAuthorized not implemented");
755
756
  }
757
758 6177 cjones
}