Project

General

Profile

1
/**
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.io.InputStream;
27
import java.math.BigInteger;
28
import java.util.ArrayList;
29
import java.util.Calendar;
30
import java.util.Date;
31
import java.util.List;
32
import java.util.concurrent.locks.Lock;
33

    
34
import javax.servlet.http.HttpServletRequest;
35

    
36
import org.apache.log4j.Logger;
37
import org.dataone.client.CNode;
38
import org.dataone.client.D1Client;
39
import org.dataone.client.MNode;
40
import org.dataone.service.cn.v1.CNAuthorization;
41
import org.dataone.service.cn.v1.CNCore;
42
import org.dataone.service.cn.v1.CNRead;
43
import org.dataone.service.cn.v1.CNReplication;
44
import org.dataone.service.exceptions.BaseException;
45
import org.dataone.service.exceptions.IdentifierNotUnique;
46
import org.dataone.service.exceptions.InsufficientResources;
47
import org.dataone.service.exceptions.InvalidRequest;
48
import org.dataone.service.exceptions.InvalidSystemMetadata;
49
import org.dataone.service.exceptions.InvalidToken;
50
import org.dataone.service.exceptions.NotAuthorized;
51
import org.dataone.service.exceptions.NotFound;
52
import org.dataone.service.exceptions.NotImplemented;
53
import org.dataone.service.exceptions.ServiceFailure;
54
import org.dataone.service.exceptions.UnsupportedType;
55
import org.dataone.service.exceptions.VersionMismatch;
56
import org.dataone.service.types.v1.AccessPolicy;
57
import org.dataone.service.types.v1.Checksum;
58
import org.dataone.service.types.v1.ChecksumAlgorithmList;
59
import org.dataone.service.types.v1.DescribeResponse;
60
import org.dataone.service.types.v1.Event;
61
import org.dataone.service.types.v1.Identifier;
62
import org.dataone.service.types.v1.Log;
63
import org.dataone.service.types.v1.Node;
64
import org.dataone.service.types.v1.NodeList;
65
import org.dataone.service.types.v1.NodeReference;
66
import org.dataone.service.types.v1.NodeType;
67
import org.dataone.service.types.v1.ObjectFormat;
68
import org.dataone.service.types.v1.ObjectFormatIdentifier;
69
import org.dataone.service.types.v1.ObjectFormatList;
70
import org.dataone.service.types.v1.ObjectList;
71
import org.dataone.service.types.v1.ObjectLocationList;
72
import org.dataone.service.types.v1.Permission;
73
import org.dataone.service.types.v1.Replica;
74
import org.dataone.service.types.v1.ReplicationPolicy;
75
import org.dataone.service.types.v1.ReplicationStatus;
76
import org.dataone.service.types.v1.Session;
77
import org.dataone.service.types.v1.Subject;
78
import org.dataone.service.types.v1.SystemMetadata;
79
import org.dataone.service.types.v1.util.ServiceMethodRestrictionUtil;
80
import org.dataone.service.types.v1_1.QueryEngineDescription;
81
import org.dataone.service.types.v1_1.QueryEngineList;
82

    
83
import edu.ucsb.nceas.metacat.EventLog;
84
import edu.ucsb.nceas.metacat.IdentifierManager;
85
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
86
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
87

    
88
/**
89
 * Represents Metacat's implementation of the DataONE Coordinating Node 
90
 * service API. Methods implement the various CN* interfaces, and methods common
91
 * to both Member Node and Coordinating Node interfaces are found in the
92
 * D1NodeService super class.
93
 *
94
 */
95
public class CNodeService extends D1NodeService implements CNAuthorization,
96
    CNCore, CNRead, CNReplication {
97

    
98
  /* the logger instance */
99
  private Logger logMetacat = null;
100

    
101
  /**
102
   * singleton accessor
103
   */
104
  public static CNodeService getInstance(HttpServletRequest request) { 
105
    return new CNodeService(request);
106
  }
107
  
108
  /**
109
   * Constructor, private for singleton access
110
   */
111
  private CNodeService(HttpServletRequest request) {
112
    super(request);
113
    logMetacat = Logger.getLogger(CNodeService.class);
114
        
115
  }
116
    
117
  /**
118
   * Set the replication policy for an object given the object identifier
119
   * 
120
   * @param session - the Session object containing the credentials for the Subject
121
   * @param pid - the object identifier for the given object
122
   * @param policy - the replication policy to be applied
123
   * 
124
   * @return true or false
125
   * 
126
   * @throws NotImplemented
127
   * @throws NotAuthorized
128
   * @throws ServiceFailure
129
   * @throws InvalidRequest
130
   * @throws VersionMismatch
131
   * 
132
   */
133
  @Override
134
  public boolean setReplicationPolicy(Session session, Identifier pid,
135
      ReplicationPolicy policy, long serialVersion) 
136
      throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, 
137
      InvalidRequest, InvalidToken, VersionMismatch {
138
      
139
      // The lock to be used for this identifier
140
      Lock lock = null;
141
      
142
      // get the subject
143
      Subject subject = session.getSubject();
144
      
145
      // are we allowed to do this?
146
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
147
          throw new NotAuthorized("4881", Permission.CHANGE_PERMISSION
148
                  + " not allowed by " + subject.getValue() + " on "
149
                  + pid.getValue());
150
          
151
      }
152
      
153
      SystemMetadata systemMetadata = null;
154
      try {
155
          lock = HazelcastService.getInstance().getLock(pid.getValue());
156
          lock.lock();
157
          logMetacat.debug("Locked identifier " + pid.getValue());
158

    
159
          try {
160
              if ( HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid) ) {
161
                  systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
162
                  
163
              }
164
              
165
              // did we get it correctly?
166
              if ( systemMetadata == null ) {
167
                  throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
168
                  
169
              }
170

    
171
              // does the request have the most current system metadata?
172
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
173
                 String msg = "The requested system metadata version number " + 
174
                     serialVersion + " differs from the current version at " +
175
                     systemMetadata.getSerialVersion().longValue() +
176
                     ". Please get the latest copy in order to modify it.";
177
                 throw new VersionMismatch("4886", msg);
178
                 
179
              }
180
              
181
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
182
              throw new NotFound("4884", "No record found for: " + pid.getValue());
183
            
184
          }
185
          
186
          // set the new policy
187
          systemMetadata.setReplicationPolicy(policy);
188
          
189
          // update the metadata
190
          try {
191
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
192
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
193
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
194
              notifyReplicaNodes(systemMetadata);
195
              
196
          } catch (RuntimeException e) {
197
              throw new ServiceFailure("4882", e.getMessage());
198
          
199
          }
200
          
201
      } catch (RuntimeException e) {
202
          throw new ServiceFailure("4882", e.getMessage());
203
          
204
      } finally {
205
          lock.unlock();
206
          logMetacat.debug("Unlocked identifier " + pid.getValue());
207
          
208
      }
209
    
210
      return true;
211
  }
212

    
213
  /**
214
   * Deletes the replica from the given Member Node
215
   * NOTE: MN.delete() may be an "archive" operation. TBD.
216
   * @param session
217
   * @param pid
218
   * @param nodeId
219
   * @param serialVersion
220
   * @return
221
   * @throws InvalidToken
222
   * @throws ServiceFailure
223
   * @throws NotAuthorized
224
   * @throws NotFound
225
   * @throws NotImplemented
226
   * @throws VersionMismatch
227
   */
228
  @Override
229
  public boolean deleteReplicationMetadata(Session session, Identifier pid, NodeReference nodeId, long serialVersion) 
230
  	throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, VersionMismatch {
231
	  
232
	  	// The lock to be used for this identifier
233
		Lock lock = null;
234

    
235
		// get the subject
236
		Subject subject = session.getSubject();
237

    
238
		// are we allowed to do this?
239
		boolean isAuthorized = false;
240
		try {
241
			isAuthorized = isAuthorized(session, pid, Permission.WRITE);
242
		} catch (InvalidRequest e) {
243
			throw new ServiceFailure("4882", e.getDescription());
244
		}
245
		if (!isAuthorized) {
246
			throw new NotAuthorized("4881", Permission.WRITE
247
					+ " not allowed by " + subject.getValue() + " on "
248
					+ pid.getValue());
249

    
250
		}
251

    
252
		SystemMetadata systemMetadata = null;
253
		try {
254
			lock = HazelcastService.getInstance().getLock(pid.getValue());
255
			lock.lock();
256
			logMetacat.debug("Locked identifier " + pid.getValue());
257

    
258
			try {
259
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
260
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
261
				}
262

    
263
				// did we get it correctly?
264
				if (systemMetadata == null) {
265
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
266
				}
267

    
268
				// does the request have the most current system metadata?
269
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
270
					String msg = "The requested system metadata version number "
271
							+ serialVersion
272
							+ " differs from the current version at "
273
							+ systemMetadata.getSerialVersion().longValue()
274
							+ ". Please get the latest copy in order to modify it.";
275
					throw new VersionMismatch("4886", msg);
276

    
277
				}
278

    
279
			} catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
280
				throw new NotFound("4884", "No record found for: " + pid.getValue());
281

    
282
			}
283
			  
284
			// check permissions
285
			// TODO: is this necessary?
286
			List<Node> nodeList = D1Client.getCN().listNodes().getNodeList();
287
			boolean isAllowed = ServiceMethodRestrictionUtil.isMethodAllowed(session.getSubject(), nodeList, "CNReplication", "deleteReplicationMetadata");
288
			if (!isAllowed) {
289
				throw new NotAuthorized("4881", "Caller is not authorized to deleteReplicationMetadata");
290
			}
291
			  
292
			// delete the replica from the given node
293
			// CSJ: use CN.delete() to truly delete a replica, semantically
294
			// deleteReplicaMetadata() only modifies the sytem metadata entry.
295
			//D1Client.getMN(nodeId).delete(session, pid);
296
			  
297
			// reflect that change in the system metadata
298
			List<Replica> updatedReplicas = new ArrayList<Replica>(systemMetadata.getReplicaList());
299
			for (Replica r: systemMetadata.getReplicaList()) {
300
				  if (r.getReplicaMemberNode().equals(nodeId)) {
301
					  updatedReplicas.remove(r);
302
					  break;
303
				  }
304
			}
305
			systemMetadata.setReplicaList(updatedReplicas);
306

    
307
			// update the metadata
308
			try {
309
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
310
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
311
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
312
			} catch (RuntimeException e) {
313
				throw new ServiceFailure("4882", e.getMessage());
314
			}
315

    
316
		} catch (RuntimeException e) {
317
			throw new ServiceFailure("4882", e.getMessage());
318
		} finally {
319
			lock.unlock();
320
			logMetacat.debug("Unlocked identifier " + pid.getValue());
321
		}
322

    
323
		return true;	  
324
	  
325
  }
326
  
327
  /**
328
   * Deletes an object from the Coordinating Node
329
   * 
330
   * @param session - the Session object containing the credentials for the Subject
331
   * @param pid - The object identifier to be deleted
332
   * 
333
   * @return pid - the identifier of the object used for the deletion
334
   * 
335
   * @throws InvalidToken
336
   * @throws ServiceFailure
337
   * @throws NotAuthorized
338
   * @throws NotFound
339
   * @throws NotImplemented
340
   * @throws InvalidRequest
341
   */
342
  @Override
343
  public Identifier delete(Session session, Identifier pid) 
344
      throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
345
      
346
      String localId = null;      // The corresponding docid for this pid
347
	  Lock lock = null;           // The lock to be used for this identifier
348
      CNode cn = null;            // a reference to the CN to get the node list    
349
      NodeType nodeType = null;   // the nodeType of the replica node being contacted
350
      List<Node> nodeList = null; // the list of nodes in this CN environment
351

    
352
      // check for a valid session
353
      if (session == null) {
354
        	throw new InvalidToken("4963", "No session has been provided");
355
        	
356
      }
357

    
358
      // do we have a valid pid?
359
      if (pid == null || pid.getValue().trim().equals("")) {
360
          throw new ServiceFailure("4960", "The provided identifier was invalid.");
361
          
362
      }
363

    
364
	  // check that it is CN/admin
365
	  boolean allowed = isAdminAuthorized(session);
366
	  
367
	  // additional check if it is the authoritative node if it is not the admin
368
      if(!allowed) {
369
          allowed = isAuthoritativeMNodeAdmin(session, pid);
370
          
371
      }
372
	  
373
	  if (!allowed) {
374
		  String msg = "The subject " + session.getSubject().getValue() + 
375
			  " is not allowed to call delete() on a Coordinating Node.";
376
		  logMetacat.info(msg);
377
		  throw new NotAuthorized("4960", msg);
378
		  
379
	  }
380
	  
381
	  // Don't defer to superclass implementation without a locally registered identifier
382
	  
383
      // Check for the existing identifier
384
      try {
385
          localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
386
          super.delete(session, pid);
387
          
388
      } catch (McdbDocNotFoundException e) {
389
          // This object is not registered in the identifier table. Assume it is of formatType DATA,
390
    	  // and set the archive flag. (i.e. the *object* doesn't exist on the CN)
391
    	  
392
          try {
393
  			  lock = HazelcastService.getInstance().getLock(pid.getValue());
394
  			  lock.lock();
395
  			  logMetacat.debug("Locked identifier " + pid.getValue());
396

    
397
			  SystemMetadata sysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
398
			  if ( sysMeta != null ) {
399
				sysMeta.setArchived(true);
400
				sysMeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
401
				HazelcastService.getInstance().getSystemMetadataMap().put(pid, sysMeta);
402
				
403
			  } else {
404
				  throw new ServiceFailure("4962", "Couldn't delete the object " + pid.getValue() +
405
					  ". Couldn't obtain the system metadata record.");
406
				  
407
			  }
408
			  
409
		  } catch (RuntimeException re) {
410
			  throw new ServiceFailure("4962", "Couldn't delete " + pid.getValue() + 
411
				  ". The error message was: " + re.getMessage());
412
			  
413
		  } finally {
414
			  lock.unlock();
415
			  logMetacat.debug("Unlocked identifier " + pid.getValue());
416

    
417
		  }
418

    
419
          // Log the delete
420
          EventLog.getInstance().log(request.getRemoteAddr(), 
421
                  request.getHeader("User-Agent"), session.getSubject().getValue(), 
422
                  pid.getValue(), Event.DELETE.xmlValue());
423

    
424
      }
425

    
426
      // get the node list
427
      try {
428
          cn = D1Client.getCN();
429
          nodeList = cn.listNodes().getNodeList();
430
          
431
      } catch (Exception e) { // handle BaseException and other I/O issues
432
          
433
          // swallow errors since the call is not critical
434
          logMetacat.error("Can't inform MNs of the deletion of " + pid.getValue() + 
435
              " due to communication issues with the CN: " + e.getMessage());
436
          
437
      }
438

    
439
	  // notify the replicas
440
	  SystemMetadata systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
441
	  if (systemMetadata.getReplicaList() != null) {
442
		  for (Replica replica: systemMetadata.getReplicaList()) {
443
			  NodeReference replicaNode = replica.getReplicaMemberNode();
444
			  try {
445
                  if (nodeList != null) {
446
                      // find the node type
447
                      for (Node node : nodeList) {
448
                          if ( node.getIdentifier().getValue().equals(replicaNode.getValue()) ) {
449
                              nodeType = node.getType();
450
                              break;
451
              
452
                          }
453
                      }
454
                  }
455
                  
456
                  // only send call MN.delete() to avoid an infinite loop with the CN
457
                  if (nodeType != null && nodeType == NodeType.MN) {
458
				      Identifier mnRetId = D1Client.getMN(replicaNode).delete(null, pid);
459
                  }
460
                  
461
			  } catch (Exception e) {
462
				  // all we can really do is log errors and carry on with life
463
				  logMetacat.error("Error deleting pid: " +  pid.getValue() + 
464
					  " from replica MN: " + replicaNode.getValue(), e);
465
			}
466
			  
467
		  }
468
	  }
469
	  
470
	  return pid;
471
      
472
  }
473
  
474
  /**
475
   * Archives an object from the Coordinating Node
476
   * 
477
   * @param session - the Session object containing the credentials for the Subject
478
   * @param pid - The object identifier to be deleted
479
   * 
480
   * @return pid - the identifier of the object used for the deletion
481
   * 
482
   * @throws InvalidToken
483
   * @throws ServiceFailure
484
   * @throws NotAuthorized
485
   * @throws NotFound
486
   * @throws NotImplemented
487
   * @throws InvalidRequest
488
   */
489
  @Override
490
  public Identifier archive(Session session, Identifier pid) 
491
      throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
492

    
493
      String localId = null; // The corresponding docid for this pid
494
	  Lock lock = null;      // The lock to be used for this identifier
495
      CNode cn = null;            // a reference to the CN to get the node list    
496
      NodeType nodeType = null;   // the nodeType of the replica node being contacted
497
      List<Node> nodeList = null; // the list of nodes in this CN environment
498
      
499

    
500
      // check for a valid session
501
      if (session == null) {
502
        	throw new InvalidToken("4973", "No session has been provided");
503
        	
504
      }
505

    
506
      // do we have a valid pid?
507
      if (pid == null || pid.getValue().trim().equals("")) {
508
          throw new ServiceFailure("4972", "The provided identifier was invalid.");
509
          
510
      }
511

    
512
	  // check that it is CN/admin
513
	  boolean allowed = isAdminAuthorized(session);
514
	  
515
	  //check if it is the authoritative member node
516
	  if(!allowed) {
517
	      allowed = isAuthoritativeMNodeAdmin(session, pid);
518
	  }
519
	  
520
	  if (!allowed) {
521
		  String msg = "The subject " + session.getSubject().getValue() + 
522
				  " is not allowed to call archive() on a Coordinating Node.";
523
		  logMetacat.info(msg);
524
		  throw new NotAuthorized("4970", msg);
525
	  }
526
	  
527
      // Check for the existing identifier
528
      try {
529
          localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
530
          super.archive(session, pid);
531
          
532
      } catch (McdbDocNotFoundException e) {
533
          // This object is not registered in the identifier table. Assume it is of formatType DATA,
534
    	  // and set the archive flag. (i.e. the *object* doesn't exist on the CN)
535
    	  
536
          try {
537
  			  lock = HazelcastService.getInstance().getLock(pid.getValue());
538
  			  lock.lock();
539
  			  logMetacat.debug("Locked identifier " + pid.getValue());
540

    
541
			  SystemMetadata sysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
542
			  if ( sysMeta != null ) {
543
				sysMeta.setArchived(true);
544
				sysMeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
545
				HazelcastService.getInstance().getSystemMetadataMap().put(pid, sysMeta);
546
				
547
			  } else {
548
				  throw new ServiceFailure("4972", "Couldn't archive the object " + pid.getValue() +
549
					  ". Couldn't obtain the system metadata record.");
550
				  
551
			  }
552
			  
553
		  } catch (RuntimeException re) {
554
			  throw new ServiceFailure("4972", "Couldn't archive " + pid.getValue() + 
555
				  ". The error message was: " + re.getMessage());
556
			  
557
		  } finally {
558
			  lock.unlock();
559
			  logMetacat.debug("Unlocked identifier " + pid.getValue());
560

    
561
		  }
562

    
563
          // Log the archive
564
          EventLog.getInstance().log(request.getRemoteAddr(), 
565
                  request.getHeader("User-Agent"), session.getSubject().getValue(), 
566
                  pid.getValue(), Event.DELETE.xmlValue());
567

    
568
      }
569

    
570
      // get the node list
571
      try {
572
          cn = D1Client.getCN();
573
          nodeList = cn.listNodes().getNodeList();
574
          
575
      } catch (Exception e) { // handle BaseException and other I/O issues
576
          
577
          // swallow errors since the call is not critical
578
          logMetacat.error("Can't inform MNs of the archive of " + pid.getValue() + 
579
              " due to communication issues with the CN: " + e.getMessage());
580
          
581
      }
582

    
583
	  // notify the replicas
584
	  SystemMetadata systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
585
	  if (systemMetadata.getReplicaList() != null) {
586
		  for (Replica replica: systemMetadata.getReplicaList()) {
587
			  NodeReference replicaNode = replica.getReplicaMemberNode();
588
			  try {
589
                  if (nodeList != null) {
590
                      // find the node type
591
                      for (Node node : nodeList) {
592
                          if ( node.getIdentifier().getValue().equals(replicaNode.getValue()) ) {
593
                              nodeType = node.getType();
594
                              break;
595
              
596
                          }
597
                      }
598
                  }
599
                  
600
                  // only send call MN.archive() to avoid an infinite loop with the CN
601
                  if (nodeType != null && nodeType == NodeType.MN) {
602
				      Identifier mnRetId = D1Client.getMN(replicaNode).archive(null, pid);
603
				      
604
                  }
605
                  
606
			  } catch (Exception e) {
607
				  // all we can really do is log errors and carry on with life
608
				  logMetacat.error("Error archiving pid: " +  pid.getValue() + 
609
					  " from replica MN: " + replicaNode.getValue(), e);
610
			}
611
			  
612
		  }
613
	  }
614
	  
615
	  return pid;
616
      
617
  }
618
  
619
  /**
620
   * Set the obsoletedBy attribute in System Metadata
621
   * @param session
622
   * @param pid
623
   * @param obsoletedByPid
624
   * @param serialVersion
625
   * @return
626
   * @throws NotImplemented
627
   * @throws NotFound
628
   * @throws NotAuthorized
629
   * @throws ServiceFailure
630
   * @throws InvalidRequest
631
   * @throws InvalidToken
632
   * @throws VersionMismatch
633
   */
634
  @Override
635
  public boolean setObsoletedBy(Session session, Identifier pid,
636
			Identifier obsoletedByPid, long serialVersion)
637
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
638
			InvalidRequest, InvalidToken, VersionMismatch {
639

    
640
		// The lock to be used for this identifier
641
		Lock lock = null;
642

    
643
		// get the subject
644
		Subject subject = session.getSubject();
645

    
646
		// are we allowed to do this?
647
		if (!isAuthorized(session, pid, Permission.WRITE)) {
648
			throw new NotAuthorized("4881", Permission.WRITE
649
					+ " not allowed by " + subject.getValue() + " on "
650
					+ pid.getValue());
651

    
652
		}
653

    
654

    
655
		SystemMetadata systemMetadata = null;
656
		try {
657
			lock = HazelcastService.getInstance().getLock(pid.getValue());
658
			lock.lock();
659
			logMetacat.debug("Locked identifier " + pid.getValue());
660

    
661
			try {
662
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
663
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
664
				}
665

    
666
				// did we get it correctly?
667
				if (systemMetadata == null) {
668
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
669
				}
670

    
671
				// does the request have the most current system metadata?
672
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
673
					String msg = "The requested system metadata version number "
674
							+ serialVersion
675
							+ " differs from the current version at "
676
							+ systemMetadata.getSerialVersion().longValue()
677
							+ ". Please get the latest copy in order to modify it.";
678
					throw new VersionMismatch("4886", msg);
679

    
680
				}
681

    
682
			} catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
683
				throw new NotFound("4884", "No record found for: " + pid.getValue());
684

    
685
			}
686

    
687
			// set the new policy
688
			systemMetadata.setObsoletedBy(obsoletedByPid);
689

    
690
			// update the metadata
691
			try {
692
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
693
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
694
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
695
			} catch (RuntimeException e) {
696
				throw new ServiceFailure("4882", e.getMessage());
697
			}
698

    
699
		} catch (RuntimeException e) {
700
			throw new ServiceFailure("4882", e.getMessage());
701
		} finally {
702
			lock.unlock();
703
			logMetacat.debug("Unlocked identifier " + pid.getValue());
704
		}
705

    
706
		return true;
707
	}
708
  
709
  
710
  /**
711
   * Set the replication status for an object given the object identifier
712
   * 
713
   * @param session - the Session object containing the credentials for the Subject
714
   * @param pid - the object identifier for the given object
715
   * @param status - the replication status to be applied
716
   * 
717
   * @return true or false
718
   * 
719
   * @throws NotImplemented
720
   * @throws NotAuthorized
721
   * @throws ServiceFailure
722
   * @throws InvalidRequest
723
   * @throws InvalidToken
724
   * @throws NotFound
725
   * 
726
   */
727
  @Override
728
  public boolean setReplicationStatus(Session session, Identifier pid,
729
      NodeReference targetNode, ReplicationStatus status, BaseException failure) 
730
      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
731
      InvalidRequest, NotFound {
732
	  
733
	  // cannot be called by public
734
	  if (session == null) {
735
		  throw new NotAuthorized("4720", "Session cannot be null");
736
	  }
737
      
738
      // The lock to be used for this identifier
739
      Lock lock = null;
740
      
741
      boolean allowed = false;
742
      int replicaEntryIndex = -1;
743
      List<Replica> replicas = null;
744
      // get the subject
745
      Subject subject = session.getSubject();
746
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
747
          " is " + status.toString());
748
      
749
      SystemMetadata systemMetadata = null;
750

    
751
      try {
752
          lock = HazelcastService.getInstance().getLock(pid.getValue());
753
          lock.lock();
754
          logMetacat.debug("Locked identifier " + pid.getValue());
755

    
756
          try {      
757
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
758

    
759
              // did we get it correctly?
760
              if ( systemMetadata == null ) {
761
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
762
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
763
                  
764
              }
765
              replicas = systemMetadata.getReplicaList();
766
              int count = 0;
767
              
768
              // was there a failure? log it
769
              if ( failure != null && status.equals(ReplicationStatus.FAILED) ) {
770
                 String msg = "The replication request of the object identified by " + 
771
                     pid.getValue() + " failed.  The error message was " +
772
                     failure.getMessage() + ".";
773
              }
774
              
775
              if (replicas.size() > 0 && replicas != null) {
776
                  // find the target replica index in the replica list
777
                  for (Replica replica : replicas) {
778
                      String replicaNodeStr = replica.getReplicaMemberNode().getValue();
779
                      String targetNodeStr = targetNode.getValue();
780
                      logMetacat.debug("Comparing " + replicaNodeStr + " to " + targetNodeStr);
781
                  
782
                      if (replicaNodeStr.equals(targetNodeStr)) {
783
                          replicaEntryIndex = count;
784
                          logMetacat.debug("replica entry index is: "
785
                                  + replicaEntryIndex);
786
                          break;
787
                      }
788
                      count++;
789
                  
790
                  }
791
              }
792
              // are we allowed to do this? only CNs and target MNs are allowed
793
              CNode cn = D1Client.getCN();
794
              List<Node> nodes = cn.listNodes().getNodeList();
795
              
796
              // find the node in the node list
797
              for ( Node node : nodes ) {
798
                  
799
                  NodeReference nodeReference = node.getIdentifier();
800
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " + 
801
                      nodeReference.getValue());
802
                  
803
                  // allow target MN certs
804
                  if ( targetNode.getValue().equals(nodeReference.getValue() ) &&
805
                      node.getType().equals(NodeType.MN)) {
806
                      List<Subject> nodeSubjects = node.getSubjectList();
807
                      
808
                      // check if the session subject is in the node subject list
809
                      for (Subject nodeSubject : nodeSubjects) {
810
                          logMetacat.debug("In setReplicationStatus(), comparing subjects: " +
811
                                  nodeSubject.getValue() + " and " + subject.getValue());
812
                          if ( nodeSubject.equals(subject) ) { // subject of session == target node subject
813
                              
814
                              // lastly limit to COMPLETED, INVALIDATED,
815
                              // and FAILED status updates from MNs only
816
                              if ( status.equals(ReplicationStatus.COMPLETED) ||
817
                                   status.equals(ReplicationStatus.INVALIDATED) ||
818
                                   status.equals(ReplicationStatus.FAILED)) {
819
                                  allowed = true;
820
                                  break;
821
                                  
822
                              }                              
823
                          }
824
                      }                 
825
                  }
826
              }
827

    
828
              if ( !allowed ) {
829
                  //check for CN admin access
830
                  allowed = isAuthorized(session, pid, Permission.WRITE);
831
                  
832
              }              
833
              
834
              if ( !allowed ) {
835
                  String msg = "The subject identified by "
836
                          + subject.getValue()
837
                          + " does not have permission to set the replication status for "
838
                          + "the replica identified by "
839
                          + targetNode.getValue() + ".";
840
                  logMetacat.info(msg);
841
                  throw new NotAuthorized("4720", msg);
842
                  
843
              }
844

    
845
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
846
            throw new NotFound("4740", "No record found for: " + pid.getValue() +
847
                " : " + e.getMessage());
848
            
849
          }
850
          
851
          Replica targetReplica = new Replica();
852
          // set the status for the replica
853
          if ( replicaEntryIndex != -1 ) {
854
              targetReplica = replicas.get(replicaEntryIndex);
855
              
856
              // don't allow status to change from COMPLETED to anything other
857
              // than INVALIDATED: prevents overwrites from race conditions
858
              if ( targetReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
859
            	   !status.equals(ReplicationStatus.INVALIDATED)) {
860
            	  throw new InvalidRequest("4730", "Status state change from " +
861
            			  targetReplica.getReplicationStatus() + " to " +
862
            			  status.toString() + "is prohibited for identifier " +
863
            			  pid.getValue() + " and target node " + 
864
            			  targetReplica.getReplicaMemberNode().getValue());
865
              }
866
              
867
              targetReplica.setReplicationStatus(status);
868
              
869
              logMetacat.debug("Set the replication status for " + 
870
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
871
                  targetReplica.getReplicationStatus() + " for identifier " +
872
                  pid.getValue());
873
              
874
          } else {
875
              // this is a new entry, create it
876
              targetReplica.setReplicaMemberNode(targetNode);
877
              targetReplica.setReplicationStatus(status);
878
              targetReplica.setReplicaVerified(Calendar.getInstance().getTime());
879
              replicas.add(targetReplica);
880
              
881
          }
882
          
883
          systemMetadata.setReplicaList(replicas);
884
                
885
          // update the metadata
886
          try {
887
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
888
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
889
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
890

    
891
              if ( !status.equals(ReplicationStatus.QUEUED) && 
892
            	   !status.equals(ReplicationStatus.REQUESTED)) {
893
                  
894
                logMetacat.trace("METRICS:\tREPLICATION:\tEND REQUEST:\tPID:\t" + pid.getValue() + 
895
                          "\tNODE:\t" + targetNode.getValue() + 
896
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
897
                
898
                logMetacat.trace("METRICS:\tREPLICATION:\t" + status.toString().toUpperCase() +
899
                          "\tPID:\t"  + pid.getValue() + 
900
                          "\tNODE:\t" + targetNode.getValue() + 
901
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
902
              }
903

    
904
              if ( status.equals(ReplicationStatus.FAILED) && failure != null ) {
905
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
906
                      " on target node " + targetNode + ". The exception was: " +
907
                      failure.getMessage());
908
              }
909
              
910
			  // update the replica nodes about the completed replica when complete
911
              if (status.equals(ReplicationStatus.COMPLETED)) {
912
				notifyReplicaNodes(systemMetadata);
913
			}
914
          
915
          } catch (RuntimeException e) {
916
              throw new ServiceFailure("4700", e.getMessage());
917
          
918
          }
919
          
920
    } catch (RuntimeException e) {
921
        String msg = "There was a RuntimeException getting the lock for " +
922
            pid.getValue();
923
        logMetacat.info(msg);
924
        
925
    } finally {
926
        lock.unlock();
927
        logMetacat.debug("Unlocked identifier " + pid.getValue());
928
        
929
    }
930
      
931
      return true;
932
  }
933
  
934
/**
935
   * Return the checksum of the object given the identifier 
936
   * 
937
   * @param session - the Session object containing the credentials for the Subject
938
   * @param pid - the object identifier for the given object
939
   * 
940
   * @return checksum - the checksum of the object
941
   * 
942
   * @throws InvalidToken
943
   * @throws ServiceFailure
944
   * @throws NotAuthorized
945
   * @throws NotFound
946
   * @throws NotImplemented
947
   */
948
  @Override
949
  public Checksum getChecksum(Session session, Identifier pid)
950
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
951
    NotImplemented {
952
    
953
	boolean isAuthorized = false;
954
	try {
955
		isAuthorized = isAuthorized(session, pid, Permission.READ);
956
	} catch (InvalidRequest e) {
957
		throw new ServiceFailure("1410", e.getDescription());
958
	}  
959
    if (!isAuthorized) {
960
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());  
961
    }
962
    
963
    SystemMetadata systemMetadata = null;
964
    Checksum checksum = null;
965
    
966
    try {
967
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);        
968

    
969
        if (systemMetadata == null ) {
970
            throw new NotFound("1420", "Couldn't find an object identified by " + pid.getValue());
971
        }
972
        checksum = systemMetadata.getChecksum();
973
        
974
    } catch (RuntimeException e) {
975
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " + 
976
            pid.getValue() + ". The error message was: " + e.getMessage());
977
      
978
    }
979
    
980
    return checksum;
981
  }
982

    
983
  /**
984
   * Resolve the location of a given object
985
   * 
986
   * @param session - the Session object containing the credentials for the Subject
987
   * @param pid - the object identifier for the given object
988
   * 
989
   * @return objectLocationList - the list of nodes known to contain the object
990
   * 
991
   * @throws InvalidToken
992
   * @throws ServiceFailure
993
   * @throws NotAuthorized
994
   * @throws NotFound
995
   * @throws NotImplemented
996
   */
997
  @Override
998
  public ObjectLocationList resolve(Session session, Identifier pid)
999
    throws InvalidToken, ServiceFailure, NotAuthorized,
1000
    NotFound, NotImplemented {
1001

    
1002
    throw new NotImplemented("4131", "resolve not implemented");
1003

    
1004
  }
1005

    
1006
  /**
1007
   * Metacat does not implement this method at the CN level
1008
   */
1009
  @Override
1010
  public ObjectList search(Session session, String queryType, String query)
1011
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
1012
    NotImplemented {
1013

    
1014
		  throw new NotImplemented("4281", "Metacat does not implement CN.search");
1015
	  
1016
//    ObjectList objectList = null;
1017
//    try {
1018
//        objectList = 
1019
//          IdentifierManager.getInstance().querySystemMetadata(
1020
//              null, //startTime, 
1021
//              null, //endTime,
1022
//              null, //objectFormat, 
1023
//              false, //replicaStatus, 
1024
//              0, //start, 
1025
//              1000 //count
1026
//              );
1027
//        
1028
//    } catch (Exception e) {
1029
//      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
1030
//    }
1031
//
1032
//      return objectList;
1033
		  
1034
  }
1035
  
1036
  /**
1037
   * Returns the object format registered in the DataONE Object Format 
1038
   * Vocabulary for the given format identifier
1039
   * 
1040
   * @param fmtid - the identifier of the format requested
1041
   * 
1042
   * @return objectFormat - the object format requested
1043
   * 
1044
   * @throws ServiceFailure
1045
   * @throws NotFound
1046
   * @throws InsufficientResources
1047
   * @throws NotImplemented
1048
   */
1049
  @Override
1050
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
1051
    throws ServiceFailure, NotFound, NotImplemented {
1052
     
1053
      return ObjectFormatService.getInstance().getFormat(fmtid);
1054
      
1055
  }
1056

    
1057
  /**
1058
   * Returns a list of all object formats registered in the DataONE Object 
1059
   * Format Vocabulary
1060
    * 
1061
   * @return objectFormatList - The list of object formats registered in 
1062
   *                            the DataONE Object Format Vocabulary
1063
   * 
1064
   * @throws ServiceFailure
1065
   * @throws NotImplemented
1066
   * @throws InsufficientResources
1067
   */
1068
  @Override
1069
  public ObjectFormatList listFormats() 
1070
    throws ServiceFailure, NotImplemented {
1071

    
1072
    return ObjectFormatService.getInstance().listFormats();
1073
  }
1074

    
1075
  /**
1076
   * Returns a list of nodes that have been registered with the DataONE infrastructure
1077
    * 
1078
   * @return nodeList - List of nodes from the registry
1079
   * 
1080
   * @throws ServiceFailure
1081
   * @throws NotImplemented
1082
   */
1083
  @Override
1084
  public NodeList listNodes() 
1085
    throws NotImplemented, ServiceFailure {
1086

    
1087
    throw new NotImplemented("4800", "listNodes not implemented");
1088
  }
1089

    
1090
  /**
1091
   * Provides a mechanism for adding system metadata independently of its 
1092
   * associated object, such as when adding system metadata for data objects.
1093
    * 
1094
   * @param session - the Session object containing the credentials for the Subject
1095
   * @param pid - The identifier of the object to register the system metadata against
1096
   * @param sysmeta - The system metadata to be registered
1097
   * 
1098
   * @return true if the registration succeeds
1099
   * 
1100
   * @throws NotImplemented
1101
   * @throws NotAuthorized
1102
   * @throws ServiceFailure
1103
   * @throws InvalidRequest
1104
   * @throws InvalidSystemMetadata
1105
   */
1106
  @Override
1107
  public Identifier registerSystemMetadata(Session session, Identifier pid,
1108
      SystemMetadata sysmeta) 
1109
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
1110
      InvalidSystemMetadata {
1111

    
1112
      // The lock to be used for this identifier
1113
      Lock lock = null;
1114

    
1115
      // TODO: control who can call this?
1116
      if (session == null) {
1117
          //TODO: many of the thrown exceptions do not use the correct error codes
1118
          //check these against the docs and correct them
1119
          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
1120
                  "  If you are not logged in, please do so and retry the request.");
1121
      }
1122
      
1123
      // verify that guid == SystemMetadata.getIdentifier()
1124
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() + 
1125
          "|" + sysmeta.getIdentifier().getValue());
1126
      if (!pid.getValue().equals(sysmeta.getIdentifier().getValue())) {
1127
          throw new InvalidRequest("4863", 
1128
              "The identifier in method call (" + pid.getValue() + 
1129
              ") does not match identifier in system metadata (" +
1130
              sysmeta.getIdentifier().getValue() + ").");
1131
      }
1132

    
1133
      try {
1134
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
1135
          lock.lock();
1136
          logMetacat.debug("Locked identifier " + pid.getValue());
1137
          logMetacat.debug("Checking if identifier exists...");
1138
          // Check that the identifier does not already exist
1139
          if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
1140
              throw new InvalidRequest("4863", 
1141
                  "The identifier is already in use by an existing object.");
1142
          
1143
          }
1144
          
1145
          // insert the system metadata into the object store
1146
          logMetacat.debug("Starting to insert SystemMetadata...");
1147
          try {
1148
              sysmeta.setSerialVersion(BigInteger.ONE);
1149
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1150
              HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
1151
              
1152
          } catch (RuntimeException e) {
1153
            logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
1154
              throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1155
                  e.getClass() + ": " + e.getMessage());
1156
              
1157
          }
1158
          
1159
      } catch (RuntimeException e) {
1160
          throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1161
                  e.getClass() + ": " + e.getMessage());
1162
          
1163
      }  finally {
1164
          lock.unlock();
1165
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1166
          
1167
      }
1168

    
1169
      
1170
      logMetacat.debug("Returning from registerSystemMetadata");
1171
      EventLog.getInstance().log(request.getRemoteAddr(), 
1172
          request.getHeader("User-Agent"), session.getSubject().getValue(), 
1173
          pid.getValue(), "registerSystemMetadata");
1174
      return pid;
1175
  }
1176
  
1177
  /**
1178
   * Given an optional scope and format, reserves and returns an identifier 
1179
   * within that scope and format that is unique and will not be 
1180
   * used by any other sessions. 
1181
    * 
1182
   * @param session - the Session object containing the credentials for the Subject
1183
   * @param pid - The identifier of the object to register the system metadata against
1184
   * @param scope - An optional string to be used to qualify the scope of 
1185
   *                the identifier namespace, which is applied differently 
1186
   *                depending on the format requested. If scope is not 
1187
   *                supplied, a default scope will be used.
1188
   * @param format - The optional name of the identifier format to be used, 
1189
   *                  drawn from a DataONE-specific vocabulary of identifier 
1190
   *                 format names, including several common syntaxes such 
1191
   *                 as DOI, LSID, UUID, and LSRN, among others. If the 
1192
   *                 format is not supplied by the caller, the CN service 
1193
   *                 will use a default identifier format, which may change 
1194
   *                 over time.
1195
   * 
1196
   * @return true if the registration succeeds
1197
   * 
1198
   * @throws InvalidToken
1199
   * @throws ServiceFailure
1200
   * @throws NotAuthorized
1201
   * @throws IdentifierNotUnique
1202
   * @throws NotImplemented
1203
   */
1204
  @Override
1205
  public Identifier reserveIdentifier(Session session, Identifier pid)
1206
  throws InvalidToken, ServiceFailure,
1207
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
1208

    
1209
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1210
  }
1211
  
1212
  @Override
1213
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1214
  throws InvalidToken, ServiceFailure,
1215
        NotAuthorized, NotImplemented, InvalidRequest {
1216
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
1217
  }
1218
  
1219
  /**
1220
    * Checks whether the pid is reserved by the subject in the session param
1221
    * If the reservation is held on the pid by the subject, we return true.
1222
    * 
1223
   * @param session - the Session object containing the Subject
1224
   * @param pid - The identifier to check
1225
   * 
1226
   * @return true if the reservation exists for the subject/pid
1227
   * 
1228
   * @throws InvalidToken
1229
   * @throws ServiceFailure
1230
   * @throws NotFound - when the pid is not found (in use or in reservation)
1231
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
1232
   * @throws IdentifierNotUnique - when the pid is in use
1233
   * @throws NotImplemented
1234
   */
1235

    
1236
  @Override
1237
  public boolean hasReservation(Session session, Subject subject, Identifier pid) 
1238
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique, 
1239
      NotImplemented, InvalidRequest {
1240
  
1241
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1242
  }
1243

    
1244
  /**
1245
   * Changes ownership (RightsHolder) of the specified object to the 
1246
   * subject specified by userId
1247
    * 
1248
   * @param session - the Session object containing the credentials for the Subject
1249
   * @param pid - Identifier of the object to be modified
1250
   * @param userId - The subject that will be taking ownership of the specified object.
1251
   *
1252
   * @return pid - the identifier of the modified object
1253
   * 
1254
   * @throws ServiceFailure
1255
   * @throws InvalidToken
1256
   * @throws NotFound
1257
   * @throws NotAuthorized
1258
   * @throws NotImplemented
1259
   * @throws InvalidRequest
1260
   */  
1261
  @Override
1262
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1263
      long serialVersion)
1264
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1265
      NotImplemented, InvalidRequest, VersionMismatch {
1266
      
1267
      // The lock to be used for this identifier
1268
      Lock lock = null;
1269

    
1270
      // get the subject
1271
      Subject subject = session.getSubject();
1272
      
1273
      // are we allowed to do this?
1274
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1275
          throw new NotAuthorized("4440", "not allowed by "
1276
                  + subject.getValue() + " on " + pid.getValue());
1277
          
1278
      }
1279
      
1280
      SystemMetadata systemMetadata = null;
1281
      try {
1282
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1283
          lock.lock();
1284
          logMetacat.debug("Locked identifier " + pid.getValue());
1285

    
1286
          try {
1287
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1288
              
1289
              // does the request have the most current system metadata?
1290
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1291
                 String msg = "The requested system metadata version number " + 
1292
                     serialVersion + " differs from the current version at " +
1293
                     systemMetadata.getSerialVersion().longValue() +
1294
                     ". Please get the latest copy in order to modify it.";
1295
                 throw new VersionMismatch("4443", msg);
1296
              }
1297
              
1298
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1299
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1300
              
1301
          }
1302
              
1303
          // set the new rights holder
1304
          systemMetadata.setRightsHolder(userId);
1305
          
1306
          // update the metadata
1307
          try {
1308
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1309
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1310
              HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
1311
              notifyReplicaNodes(systemMetadata);
1312
              
1313
          } catch (RuntimeException e) {
1314
              throw new ServiceFailure("4490", e.getMessage());
1315
          
1316
          }
1317
          
1318
      } catch (RuntimeException e) {
1319
          throw new ServiceFailure("4490", e.getMessage());
1320
          
1321
      } finally {
1322
          lock.unlock();
1323
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1324
      
1325
      }
1326
      
1327
      return pid;
1328
  }
1329

    
1330
  /**
1331
   * Verify that a replication task is authorized by comparing the target node's
1332
   * Subject (from the X.509 certificate-derived Session) with the list of 
1333
   * subjects in the known, pending replication tasks map.
1334
   * 
1335
   * @param originatingNodeSession - Session information that contains the 
1336
   *                                 identity of the calling user
1337
   * @param targetNodeSubject - Subject identifying the target node
1338
   * @param pid - the identifier of the object to be replicated
1339
   * @param replicatePermission - the execute permission to be granted
1340
   * 
1341
   * @throws ServiceFailure
1342
   * @throws NotImplemented
1343
   * @throws InvalidToken
1344
   * @throws NotAuthorized
1345
   * @throws InvalidRequest
1346
   * @throws NotFound
1347
   */
1348
  @Override
1349
  public boolean isNodeAuthorized(Session originatingNodeSession, 
1350
    Subject targetNodeSubject, Identifier pid) 
1351
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure, 
1352
    NotFound, InvalidRequest {
1353
    
1354
    boolean isAllowed = false;
1355
    SystemMetadata sysmeta = null;
1356
    NodeReference targetNode = null;
1357
    
1358
    try {
1359
      // get the target node reference from the nodes list
1360
      CNode cn = D1Client.getCN();
1361
      List<Node> nodes = cn.listNodes().getNodeList();
1362
      
1363
      if ( nodes != null ) {
1364
        for (Node node : nodes) {
1365
            
1366
        	if (node.getSubjectList() != null) {
1367
        		
1368
	            for (Subject nodeSubject : node.getSubjectList()) {
1369
	            	
1370
	                if ( nodeSubject.equals(targetNodeSubject) ) {
1371
	                    targetNode = node.getIdentifier();
1372
	                    logMetacat.debug("targetNode is : " + targetNode.getValue());
1373
	                    break;
1374
	                }
1375
	            }
1376
        	}
1377
            
1378
            if ( targetNode != null) { break; }
1379
        }
1380
        
1381
      } else {
1382
          String msg = "Couldn't get the node list from the CN";
1383
          logMetacat.debug(msg);
1384
          throw new ServiceFailure("4872", msg);
1385
          
1386
      }
1387
      
1388
      // can't find a node listed with the given subject
1389
      if ( targetNode == null ) {
1390
          String msg = "There is no Member Node registered with a node subject " +
1391
              "matching " + targetNodeSubject.getValue();
1392
          logMetacat.info(msg);
1393
          throw new NotAuthorized("4871", msg);
1394
          
1395
      }
1396
      
1397
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1398
      
1399
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1400

    
1401
      if ( sysmeta != null ) {
1402
          
1403
          List<Replica> replicaList = sysmeta.getReplicaList();
1404
          
1405
          if ( replicaList != null ) {
1406
              
1407
              // find the replica with the status set to 'requested'
1408
              for (Replica replica : replicaList) {
1409
                  ReplicationStatus status = replica.getReplicationStatus();
1410
                  NodeReference listedNode = replica.getReplicaMemberNode();
1411
                  if ( listedNode != null && targetNode != null ) {
1412
                      logMetacat.debug("Comparing " + listedNode.getValue()
1413
                              + " to " + targetNode.getValue());
1414
                      
1415
                      if (listedNode.getValue().equals(targetNode.getValue())
1416
                              && status.equals(ReplicationStatus.REQUESTED)) {
1417
                          isAllowed = true;
1418
                          break;
1419

    
1420
                      }
1421
                  }
1422
              }
1423
          }
1424
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1425
              "to replicate: " + isAllowed + " for " + pid.getValue());
1426

    
1427
          
1428
      } else {
1429
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1430
          " is null.");          
1431
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue());
1432
          
1433
      }
1434

    
1435
    } catch (RuntimeException e) {
1436
    	  ServiceFailure sf = new ServiceFailure("4872", 
1437
                "Runtime Exception: Couldn't determine if node is allowed: " + 
1438
                e.getMessage());
1439
    	  sf.initCause(e);
1440
        throw sf;
1441
        
1442
    }
1443
      
1444
    return isAllowed;
1445
    
1446
  }
1447

    
1448
  /**
1449
   * Adds a new object to the Node, where the object is a science metadata object.
1450
   * 
1451
   * @param session - the Session object containing the credentials for the Subject
1452
   * @param pid - The object identifier to be created
1453
   * @param object - the object bytes
1454
   * @param sysmeta - the system metadata that describes the object  
1455
   * 
1456
   * @return pid - the object identifier created
1457
   * 
1458
   * @throws InvalidToken
1459
   * @throws ServiceFailure
1460
   * @throws NotAuthorized
1461
   * @throws IdentifierNotUnique
1462
   * @throws UnsupportedType
1463
   * @throws InsufficientResources
1464
   * @throws InvalidSystemMetadata
1465
   * @throws NotImplemented
1466
   * @throws InvalidRequest
1467
   */
1468
  public Identifier create(Session session, Identifier pid, InputStream object,
1469
    SystemMetadata sysmeta) 
1470
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
1471
    UnsupportedType, InsufficientResources, InvalidSystemMetadata, 
1472
    NotImplemented, InvalidRequest {
1473
                  
1474
      // The lock to be used for this identifier
1475
      Lock lock = null;
1476

    
1477
      try {
1478
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1479
          // are we allowed?
1480
          boolean isAllowed = false;
1481
          isAllowed = isAdminAuthorized(session);
1482
          
1483
          // additional check if it is the authoritative node if it is not the admin
1484
          if(!isAllowed) {
1485
              isAllowed = isAuthoritativeMNodeAdmin(session, pid);
1486
          }
1487

    
1488
          // proceed if we're called by a CN
1489
          if ( isAllowed ) {
1490
              // create the coordinating node version of the document      
1491
              lock.lock();
1492
              logMetacat.debug("Locked identifier " + pid.getValue());
1493
              sysmeta.setSerialVersion(BigInteger.ONE);
1494
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1495
              sysmeta.setArchived(false); // this is a create op, not update
1496
              
1497
              // the CN should have set the origin and authoritative member node fields
1498
              try {
1499
                  sysmeta.getOriginMemberNode().getValue();
1500
                  sysmeta.getAuthoritativeMemberNode().getValue();
1501
                  
1502
              } catch (NullPointerException npe) {
1503
                  throw new InvalidSystemMetadata("4896", 
1504
                      "Both the origin and authoritative member node identifiers need to be set.");
1505
                  
1506
              }
1507
              pid = super.create(session, pid, object, sysmeta);
1508

    
1509
          } else {
1510
              String msg = "The subject listed as " + session.getSubject().getValue() + 
1511
                  " isn't allowed to call create() on a Coordinating Node.";
1512
              logMetacat.info(msg);
1513
              throw new NotAuthorized("1100", msg);
1514
          }
1515
          
1516
      } catch (RuntimeException e) {
1517
          // Convert Hazelcast runtime exceptions to service failures
1518
          String msg = "There was a problem creating the object identified by " +
1519
              pid.getValue() + ". There error message was: " + e.getMessage();
1520
          throw new ServiceFailure("4893", msg);
1521
          
1522
      } finally {
1523
    	  if (lock != null) {
1524
	          lock.unlock();
1525
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1526
    	  }
1527
      }
1528
      
1529
      return pid;
1530

    
1531
  }
1532

    
1533
  /**
1534
   * Set access for a given object using the object identifier and a Subject
1535
   * under a given Session.
1536
   * 
1537
   * @param session - the Session object containing the credentials for the Subject
1538
   * @param pid - the object identifier for the given object to apply the policy
1539
   * @param policy - the access policy to be applied
1540
   * 
1541
   * @return true if the application of the policy succeeds
1542
   * @throws InvalidToken
1543
   * @throws ServiceFailure
1544
   * @throws NotFound
1545
   * @throws NotAuthorized
1546
   * @throws NotImplemented
1547
   * @throws InvalidRequest
1548
   */
1549
  public boolean setAccessPolicy(Session session, Identifier pid, 
1550
      AccessPolicy accessPolicy, long serialVersion) 
1551
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, 
1552
      NotImplemented, InvalidRequest, VersionMismatch {
1553
      
1554
      // The lock to be used for this identifier
1555
      Lock lock = null;
1556
      SystemMetadata systemMetadata = null;
1557
      
1558
      boolean success = false;
1559
      
1560
      // get the subject
1561
      Subject subject = session.getSubject();
1562
      
1563
      // are we allowed to do this?
1564
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1565
          throw new NotAuthorized("4420", "not allowed by "
1566
                  + subject.getValue() + " on " + pid.getValue());
1567
      }
1568
      
1569
      try {
1570
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1571
          lock.lock();
1572
          logMetacat.debug("Locked identifier " + pid.getValue());
1573

    
1574
          try {
1575
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1576

    
1577
              if ( systemMetadata == null ) {
1578
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1579
                  
1580
              }
1581
              // does the request have the most current system metadata?
1582
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1583
                 String msg = "The requested system metadata version number " + 
1584
                     serialVersion + " differs from the current version at " +
1585
                     systemMetadata.getSerialVersion().longValue() +
1586
                     ". Please get the latest copy in order to modify it.";
1587
                 throw new VersionMismatch("4402", msg);
1588
                 
1589
              }
1590
              
1591
          } catch (RuntimeException e) {
1592
              // convert Hazelcast RuntimeException to NotFound
1593
              throw new NotFound("4400", "No record found for: " + pid);
1594
            
1595
          }
1596
              
1597
          // set the access policy
1598
          systemMetadata.setAccessPolicy(accessPolicy);
1599
          
1600
          // update the system metadata
1601
          try {
1602
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1603
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1604
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1605
              notifyReplicaNodes(systemMetadata);
1606
              
1607
          } catch (RuntimeException e) {
1608
              // convert Hazelcast RuntimeException to ServiceFailure
1609
              throw new ServiceFailure("4430", e.getMessage());
1610
            
1611
          }
1612
          
1613
      } catch (RuntimeException e) {
1614
          throw new ServiceFailure("4430", e.getMessage());
1615
          
1616
      } finally {
1617
          lock.unlock();
1618
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1619
        
1620
      }
1621

    
1622
    
1623
    // TODO: how do we know if the map was persisted?
1624
    success = true;
1625
    
1626
    return success;
1627
  }
1628

    
1629
  /**
1630
   * Full replacement of replication metadata in the system metadata for the 
1631
   * specified object, changes date system metadata modified
1632
   * 
1633
   * @param session - the Session object containing the credentials for the Subject
1634
   * @param pid - the object identifier for the given object to apply the policy
1635
   * @param replica - the replica to be updated
1636
   * @return
1637
   * @throws NotImplemented
1638
   * @throws NotAuthorized
1639
   * @throws ServiceFailure
1640
   * @throws InvalidRequest
1641
   * @throws NotFound
1642
   * @throws VersionMismatch
1643
   */
1644
  @Override
1645
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1646
      Replica replica, long serialVersion) 
1647
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1648
      NotFound, VersionMismatch {
1649
      
1650
      // The lock to be used for this identifier
1651
      Lock lock = null;
1652
      
1653
      // get the subject
1654
      Subject subject = session.getSubject();
1655
      
1656
      // are we allowed to do this?
1657
      try {
1658

    
1659
          // what is the controlling permission?
1660
          if (!isAuthorized(session, pid, Permission.WRITE)) {
1661
              throw new NotAuthorized("4851", "not allowed by "
1662
                      + subject.getValue() + " on " + pid.getValue());
1663
          }
1664

    
1665
        
1666
      } catch (InvalidToken e) {
1667
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() + 
1668
                  " on " + pid.getValue());  
1669
          
1670
      }
1671

    
1672
      SystemMetadata systemMetadata = null;
1673
      try {
1674
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1675
          lock.lock();
1676
          logMetacat.debug("Locked identifier " + pid.getValue());
1677

    
1678
          try {      
1679
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1680

    
1681
              // does the request have the most current system metadata?
1682
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1683
                 String msg = "The requested system metadata version number " + 
1684
                     serialVersion + " differs from the current version at " +
1685
                     systemMetadata.getSerialVersion().longValue() +
1686
                     ". Please get the latest copy in order to modify it.";
1687
                 throw new VersionMismatch("4855", msg);
1688
              }
1689
              
1690
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1691
              throw new NotFound("4854", "No record found for: " + pid.getValue() +
1692
                  " : " + e.getMessage());
1693
            
1694
          }
1695
              
1696
          // set the status for the replica
1697
          List<Replica> replicas = systemMetadata.getReplicaList();
1698
          NodeReference replicaNode = replica.getReplicaMemberNode();
1699
          ReplicationStatus replicaStatus = replica.getReplicationStatus();
1700
          int index = 0;
1701
          for (Replica listedReplica: replicas) {
1702
              
1703
              // remove the replica that we are replacing
1704
              if ( replicaNode.getValue().equals(listedReplica.getReplicaMemberNode().getValue())) {
1705
                      // don't allow status to change from COMPLETED to anything other
1706
                      // than INVALIDATED: prevents overwrites from race conditions
1707
                	  if ( !listedReplica.getReplicationStatus().equals(replicaStatus) && 
1708
                	       listedReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
1709
            		       !replicaStatus.equals(ReplicationStatus.INVALIDATED) ) {
1710
                	  throw new InvalidRequest("4853", "Status state change from " +
1711
                			  listedReplica.getReplicationStatus() + " to " +
1712
                			  replicaStatus.toString() + "is prohibited for identifier " +
1713
                			  pid.getValue() + " and target node " + 
1714
                			  listedReplica.getReplicaMemberNode().getValue());
1715

    
1716
            	  }
1717
                  replicas.remove(index);
1718
                  break;
1719
                  
1720
              }
1721
              index++;
1722
          }
1723
          
1724
          // add the new replica item
1725
          replicas.add(replica);
1726
          systemMetadata.setReplicaList(replicas);
1727
          
1728
          // update the metadata
1729
          try {
1730
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1731
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1732
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1733
              
1734
              // inform replica nodes of the change if the status is complete
1735
              if ( replicaStatus.equals(ReplicationStatus.COMPLETED) ) {
1736
            	  notifyReplicaNodes(systemMetadata);
1737
            	  
1738
              }
1739
          } catch (RuntimeException e) {
1740
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1741
              throw new ServiceFailure("4852", e.getMessage());
1742
          
1743
          }
1744
          
1745
      } catch (RuntimeException e) {
1746
          logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1747
          throw new ServiceFailure("4852", e.getMessage());
1748
      
1749
      } finally {
1750
          lock.unlock();
1751
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1752
          
1753
      }
1754
    
1755
      return true;
1756
      
1757
  }
1758
  
1759
  /**
1760
   * 
1761
   */
1762
  @Override
1763
  public ObjectList listObjects(Session session, Date startTime, 
1764
      Date endTime, ObjectFormatIdentifier formatid, Boolean replicaStatus,
1765
      Integer start, Integer count)
1766
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1767
      ServiceFailure {
1768
      
1769
      ObjectList objectList = null;
1770
        try {
1771
        	if (count == null || count > MAXIMUM_DB_RECORD_COUNT) {
1772
            	count = MAXIMUM_DB_RECORD_COUNT;
1773
            }
1774
            objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, formatid, replicaStatus, start, count);
1775
        } catch (Exception e) {
1776
            throw new ServiceFailure("1580", "Error querying system metadata: " + e.getMessage());
1777
        }
1778

    
1779
        return objectList;
1780
  }
1781

    
1782
  
1783
 	/**
1784
 	 * Returns a list of checksum algorithms that are supported by DataONE.
1785
 	 * @return cal  the list of checksum algorithms
1786
 	 * 
1787
 	 * @throws ServiceFailure
1788
 	 * @throws NotImplemented
1789
 	 */
1790
  @Override
1791
  public ChecksumAlgorithmList listChecksumAlgorithms()
1792
			throws ServiceFailure, NotImplemented {
1793
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
1794
		cal.addAlgorithm("MD5");
1795
		cal.addAlgorithm("SHA-1");
1796
		return cal;
1797
		
1798
	}
1799

    
1800
  /**
1801
   * Notify replica Member Nodes of system metadata changes for a given pid
1802
   * 
1803
   * @param currentSystemMetadata - the up to date system metadata
1804
   */
1805
  public void notifyReplicaNodes(SystemMetadata currentSystemMetadata) {
1806
      
1807
      Session session = null;
1808
      List<Replica> replicaList = currentSystemMetadata.getReplicaList();
1809
      MNode mn = null;
1810
      NodeReference replicaNodeRef = null;
1811
      CNode cn = null;
1812
      NodeType nodeType = null;
1813
      List<Node> nodeList = null;
1814
      
1815
      try {
1816
          cn = D1Client.getCN();
1817
          nodeList = cn.listNodes().getNodeList();
1818
          
1819
      } catch (Exception e) { // handle BaseException and other I/O issues
1820
          
1821
          // swallow errors since the call is not critical
1822
          logMetacat.error("Can't inform MNs of system metadata changes due " +
1823
              "to communication issues with the CN: " + e.getMessage());
1824
          
1825
      }
1826
      
1827
      if ( replicaList != null ) {
1828
          
1829
          // iterate through the replicas and inform  MN replica nodes
1830
          for (Replica replica : replicaList) {
1831
              
1832
              replicaNodeRef = replica.getReplicaMemberNode();
1833
              try {
1834
                  if (nodeList != null) {
1835
                      // find the node type
1836
                      for (Node node : nodeList) {
1837
                          if ( node.getIdentifier().getValue().equals(replicaNodeRef.getValue()) ) {
1838
                              nodeType = node.getType();
1839
                              break;
1840
              
1841
                          }
1842
                      }
1843
                  }
1844
              
1845
                  // notify only MNs
1846
                  if (nodeType != null && nodeType == NodeType.MN) {
1847
                      mn = D1Client.getMN(replicaNodeRef);
1848
                      mn.systemMetadataChanged(session, 
1849
                          currentSystemMetadata.getIdentifier(), 
1850
                          currentSystemMetadata.getSerialVersion().longValue(),
1851
                          currentSystemMetadata.getDateSysMetadataModified());
1852
                  }
1853
              
1854
              } catch (Exception e) { // handle BaseException and other I/O issues
1855
              
1856
                  // swallow errors since the call is not critical
1857
                  logMetacat.error("Can't inform "
1858
                          + replicaNodeRef.getValue()
1859
                          + " of system metadata changes due "
1860
                          + "to communication issues with the CN: "
1861
                          + e.getMessage());
1862
              
1863
              }
1864
          }
1865
      }
1866
  }
1867

    
1868
	@Override
1869
	public boolean isAuthorized(Identifier pid, Permission permission)
1870
			throws ServiceFailure, InvalidToken, NotFound, NotAuthorized,
1871
			NotImplemented, InvalidRequest {
1872
		
1873
		return isAuthorized(null, pid, permission);
1874
	}
1875
	
1876
	@Override
1877
	public boolean setAccessPolicy(Identifier pid, AccessPolicy accessPolicy, long serialVersion)
1878
			throws InvalidToken, NotFound, NotImplemented, NotAuthorized,
1879
			ServiceFailure, InvalidRequest, VersionMismatch {
1880
		
1881
		return setAccessPolicy(null, pid, accessPolicy, serialVersion);
1882
	}
1883
	
1884
	@Override
1885
	public Identifier setRightsHolder(Identifier pid, Subject userId, long serialVersion)
1886
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1887
			NotImplemented, InvalidRequest, VersionMismatch {
1888
		
1889
		return setRightsHolder(null, pid, userId, serialVersion);
1890
	}
1891
	
1892
	@Override
1893
	public Identifier create(Identifier pid, InputStream object, SystemMetadata sysmeta)
1894
			throws InvalidToken, ServiceFailure, NotAuthorized,
1895
			IdentifierNotUnique, UnsupportedType, InsufficientResources,
1896
			InvalidSystemMetadata, NotImplemented, InvalidRequest {
1897

    
1898
		return create(null, pid, object, sysmeta);
1899
	}
1900
	
1901
	@Override
1902
	public Identifier delete(Identifier pid) throws InvalidToken, ServiceFailure,
1903
			NotAuthorized, NotFound, NotImplemented {
1904

    
1905
		return delete(null, pid);
1906
	}
1907
	
1908
	@Override
1909
	public Identifier generateIdentifier(String scheme, String fragment)
1910
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
1911
			InvalidRequest {
1912

    
1913
		return generateIdentifier(null, scheme, fragment);
1914
	}
1915
	
1916
	@Override
1917
	public Log getLogRecords(Date fromDate, Date toDate, Event event, String pidFilter,
1918
			Integer start, Integer count) throws InvalidToken, InvalidRequest,
1919
			ServiceFailure, NotAuthorized, NotImplemented, InsufficientResources {
1920

    
1921
		return getLogRecords(null, fromDate, toDate, event, pidFilter, start, count);
1922
	}
1923
	
1924
	@Override
1925
	public boolean hasReservation(Subject subject, Identifier pid)
1926
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1927
			NotImplemented, InvalidRequest, IdentifierNotUnique {
1928

    
1929
		return hasReservation(null, subject, pid);
1930
	}
1931
	
1932
	@Override
1933
	public Identifier registerSystemMetadata(Identifier pid, SystemMetadata sysmeta)
1934
			throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1935
			InvalidSystemMetadata, InvalidToken {
1936

    
1937
		return registerSystemMetadata(null, pid, sysmeta);
1938
	}
1939
	
1940
	@Override
1941
	public Identifier reserveIdentifier(Identifier pid) throws InvalidToken,
1942
			ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented,
1943
			InvalidRequest {
1944

    
1945
		return reserveIdentifier(null, pid);
1946
	}
1947
	
1948
	@Override
1949
	public boolean setObsoletedBy(Identifier pid, Identifier obsoletedByPid, long serialVersion)
1950
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1951
			InvalidRequest, InvalidToken, VersionMismatch {
1952

    
1953
		return setObsoletedBy(null, pid, obsoletedByPid, serialVersion);
1954
	}
1955
	
1956
	@Override
1957
	public DescribeResponse describe(Identifier pid) throws InvalidToken,
1958
			NotAuthorized, NotImplemented, ServiceFailure, NotFound {
1959

    
1960
		return describe(null, pid);
1961
	}
1962
	
1963
	@Override
1964
	public InputStream get(Identifier pid) throws InvalidToken, ServiceFailure,
1965
			NotAuthorized, NotFound, NotImplemented {
1966

    
1967
		return get(null, pid);
1968
	}
1969
	
1970
	@Override
1971
	public Checksum getChecksum(Identifier pid) throws InvalidToken,
1972
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1973

    
1974
		return getChecksum(null, pid);
1975
	}
1976
	
1977
	@Override
1978
	public SystemMetadata getSystemMetadata(Identifier pid) throws InvalidToken,
1979
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1980

    
1981
		return getSystemMetadata(null, pid);
1982
	}
1983
	
1984
	@Override
1985
	public ObjectList listObjects(Date startTime, Date endTime,
1986
			ObjectFormatIdentifier formatid, Boolean replicaStatus, Integer start, Integer count)
1987
			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1988
			ServiceFailure {
1989

    
1990
		return listObjects(null, startTime, endTime, formatid, replicaStatus, start, count);
1991
	}
1992
	
1993
	@Override
1994
	public ObjectLocationList resolve(Identifier pid) throws InvalidToken,
1995
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1996

    
1997
		return resolve(null, pid);
1998
	}
1999
	
2000
	@Override
2001
	public ObjectList search(String queryType, String query) throws InvalidToken,
2002
			ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented {
2003

    
2004
		return search(null, queryType, query);
2005
	}
2006
	
2007
	@Override
2008
	public boolean deleteReplicationMetadata(Identifier pid, NodeReference nodeId,
2009
			long serialVersion) throws InvalidToken, InvalidRequest, ServiceFailure,
2010
			NotAuthorized, NotFound, NotImplemented, VersionMismatch {
2011

    
2012
		return deleteReplicationMetadata(null, pid, nodeId, serialVersion);
2013
	}
2014
	
2015
	@Override
2016
	public boolean isNodeAuthorized(Subject targetNodeSubject, Identifier pid)
2017
			throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
2018
			NotFound, InvalidRequest {
2019

    
2020
		return isNodeAuthorized(null, targetNodeSubject, pid);
2021
	}
2022
	
2023
	@Override
2024
	public boolean setReplicationPolicy(Identifier pid, ReplicationPolicy policy,
2025
			long serialVersion) throws NotImplemented, NotFound, NotAuthorized,
2026
			ServiceFailure, InvalidRequest, InvalidToken, VersionMismatch {
2027

    
2028
		return setReplicationPolicy(null, pid, policy, serialVersion);
2029
	}
2030
	
2031
	@Override
2032
	public boolean setReplicationStatus(Identifier pid, NodeReference targetNode,
2033
			ReplicationStatus status, BaseException failure) throws ServiceFailure,
2034
			NotImplemented, InvalidToken, NotAuthorized, InvalidRequest, NotFound {
2035

    
2036
		return setReplicationStatus(null, pid, targetNode, status, failure);
2037
	}
2038
	
2039
	@Override
2040
	public boolean updateReplicationMetadata(Identifier pid, Replica replica,
2041
			long serialVersion) throws NotImplemented, NotAuthorized, ServiceFailure,
2042
			NotFound, InvalidRequest, InvalidToken, VersionMismatch {
2043

    
2044
		return updateReplicationMetadata(null, pid, replica, serialVersion);
2045
	}
2046

    
2047
  @Override
2048
  public QueryEngineDescription getQueryEngineDescription(String arg0)
2049
          throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
2050
          NotFound {
2051
      throw new NotImplemented("4410", "getQueryEngineDescription not implemented");
2052
      
2053
  }
2054

    
2055
  @Override
2056
  public QueryEngineList listQueryEngines() throws InvalidToken, ServiceFailure,
2057
          NotAuthorized, NotImplemented {
2058
      throw new NotImplemented("4420", "listQueryEngines not implemented");
2059
      
2060
  }
2061

    
2062
  @Override
2063
  public InputStream query(String arg0, String arg1) throws InvalidToken,
2064
          ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, NotFound {
2065
      throw new NotImplemented("4324", "query not implemented");
2066
      
2067
  }
2068
}
(1-1/7)