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