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.setSerialVersion(sysMeta.getSerialVersion().add(BigInteger.ONE));
400
				sysMeta.setArchived(true);
401
				sysMeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
402
				HazelcastService.getInstance().getSystemMetadataMap().put(pid, sysMeta);
403
				
404
			  } else {
405
				  throw new ServiceFailure("4962", "Couldn't delete the object " + pid.getValue() +
406
					  ". Couldn't obtain the system metadata record.");
407
				  
408
			  }
409
			  
410
		  } catch (RuntimeException re) {
411
			  throw new ServiceFailure("4962", "Couldn't delete " + pid.getValue() + 
412
				  ". The error message was: " + re.getMessage());
413
			  
414
		  } finally {
415
			  lock.unlock();
416
			  logMetacat.debug("Unlocked identifier " + pid.getValue());
417

    
418
		  }
419

    
420
          // NOTE: cannot log the delete without localId
421
//          EventLog.getInstance().log(request.getRemoteAddr(), 
422
//                  request.getHeader("User-Agent"), session.getSubject().getValue(), 
423
//                  pid.getValue(), Event.DELETE.xmlValue());
424

    
425
      }
426

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

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

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

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

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

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

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

    
563
		  }
564

    
565
          // NOTE: cannot log the archive without localId
566
//          EventLog.getInstance().log(request.getRemoteAddr(), 
567
//                  request.getHeader("User-Agent"), session.getSubject().getValue(), 
568
//                  pid.getValue(), Event.DELETE.xmlValue());
569

    
570
      }
571

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

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

    
642
		// The lock to be used for this identifier
643
		Lock lock = null;
644

    
645
		// get the subject
646
		Subject subject = session.getSubject();
647

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

    
654
		}
655

    
656

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

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

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

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

    
682
				}
683

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

    
687
			}
688

    
689
			// set the new policy
690
			systemMetadata.setObsoletedBy(obsoletedByPid);
691

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

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

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

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

    
758
          try {      
759
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
760

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

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

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

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

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

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

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

    
1004
    throw new NotImplemented("4131", "resolve not implemented");
1005

    
1006
  }
1007

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

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

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

    
1074
    return ObjectFormatService.getInstance().listFormats();
1075
  }
1076

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

    
1089
    throw new NotImplemented("4800", "listNodes not implemented");
1090
  }
1091

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

    
1114
      // The lock to be used for this identifier
1115
      Lock lock = null;
1116

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

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

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

    
1220
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1221
  }
1222
  
1223
  @Override
1224
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1225
  throws InvalidToken, ServiceFailure,
1226
        NotAuthorized, NotImplemented, InvalidRequest {
1227
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
1228
  }
1229
  
1230
  /**
1231
    * Checks whether the pid is reserved by the subject in the session param
1232
    * If the reservation is held on the pid by the subject, we return true.
1233
    * 
1234
   * @param session - the Session object containing the Subject
1235
   * @param pid - The identifier to check
1236
   * 
1237
   * @return true if the reservation exists for the subject/pid
1238
   * 
1239
   * @throws InvalidToken
1240
   * @throws ServiceFailure
1241
   * @throws NotFound - when the pid is not found (in use or in reservation)
1242
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
1243
   * @throws IdentifierNotUnique - when the pid is in use
1244
   * @throws NotImplemented
1245
   */
1246

    
1247
  @Override
1248
  public boolean hasReservation(Session session, Subject subject, Identifier pid) 
1249
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique, 
1250
      NotImplemented, InvalidRequest {
1251
  
1252
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1253
  }
1254

    
1255
  /**
1256
   * Changes ownership (RightsHolder) of the specified object to the 
1257
   * subject specified by userId
1258
    * 
1259
   * @param session - the Session object containing the credentials for the Subject
1260
   * @param pid - Identifier of the object to be modified
1261
   * @param userId - The subject that will be taking ownership of the specified object.
1262
   *
1263
   * @return pid - the identifier of the modified object
1264
   * 
1265
   * @throws ServiceFailure
1266
   * @throws InvalidToken
1267
   * @throws NotFound
1268
   * @throws NotAuthorized
1269
   * @throws NotImplemented
1270
   * @throws InvalidRequest
1271
   */  
1272
  @Override
1273
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1274
      long serialVersion)
1275
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1276
      NotImplemented, InvalidRequest, VersionMismatch {
1277
      
1278
      // The lock to be used for this identifier
1279
      Lock lock = null;
1280

    
1281
      // get the subject
1282
      Subject subject = session.getSubject();
1283
      
1284
      // are we allowed to do this?
1285
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1286
          throw new NotAuthorized("4440", "not allowed by "
1287
                  + subject.getValue() + " on " + pid.getValue());
1288
          
1289
      }
1290
      
1291
      SystemMetadata systemMetadata = null;
1292
      try {
1293
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1294
          lock.lock();
1295
          logMetacat.debug("Locked identifier " + pid.getValue());
1296

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

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

    
1412
      if ( sysmeta != null ) {
1413
          
1414
          List<Replica> replicaList = sysmeta.getReplicaList();
1415
          
1416
          if ( replicaList != null ) {
1417
              
1418
              // find the replica with the status set to 'requested'
1419
              for (Replica replica : replicaList) {
1420
                  ReplicationStatus status = replica.getReplicationStatus();
1421
                  NodeReference listedNode = replica.getReplicaMemberNode();
1422
                  if ( listedNode != null && targetNode != null ) {
1423
                      logMetacat.debug("Comparing " + listedNode.getValue()
1424
                              + " to " + targetNode.getValue());
1425
                      
1426
                      if (listedNode.getValue().equals(targetNode.getValue())
1427
                              && status.equals(ReplicationStatus.REQUESTED)) {
1428
                          isAllowed = true;
1429
                          break;
1430

    
1431
                      }
1432
                  }
1433
              }
1434
          }
1435
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1436
              "to replicate: " + isAllowed + " for " + pid.getValue());
1437

    
1438
          
1439
      } else {
1440
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1441
          " is null.");          
1442
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue());
1443
          
1444
      }
1445

    
1446
    } catch (RuntimeException e) {
1447
    	  ServiceFailure sf = new ServiceFailure("4872", 
1448
                "Runtime Exception: Couldn't determine if node is allowed: " + 
1449
                e.getMessage());
1450
    	  sf.initCause(e);
1451
        throw sf;
1452
        
1453
    }
1454
      
1455
    return isAllowed;
1456
    
1457
  }
1458

    
1459
  /**
1460
   * Adds a new object to the Node, where the object is a science metadata object.
1461
   * 
1462
   * @param session - the Session object containing the credentials for the Subject
1463
   * @param pid - The object identifier to be created
1464
   * @param object - the object bytes
1465
   * @param sysmeta - the system metadata that describes the object  
1466
   * 
1467
   * @return pid - the object identifier created
1468
   * 
1469
   * @throws InvalidToken
1470
   * @throws ServiceFailure
1471
   * @throws NotAuthorized
1472
   * @throws IdentifierNotUnique
1473
   * @throws UnsupportedType
1474
   * @throws InsufficientResources
1475
   * @throws InvalidSystemMetadata
1476
   * @throws NotImplemented
1477
   * @throws InvalidRequest
1478
   */
1479
  public Identifier create(Session session, Identifier pid, InputStream object,
1480
    SystemMetadata sysmeta) 
1481
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
1482
    UnsupportedType, InsufficientResources, InvalidSystemMetadata, 
1483
    NotImplemented, InvalidRequest {
1484
                  
1485
      // The lock to be used for this identifier
1486
      Lock lock = null;
1487

    
1488
      try {
1489
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1490
          // are we allowed?
1491
          boolean isAllowed = false;
1492
          isAllowed = isAdminAuthorized(session);
1493
          
1494
          // additional check if it is the authoritative node if it is not the admin
1495
          if(!isAllowed) {
1496
              isAllowed = isAuthoritativeMNodeAdmin(session, pid);
1497
          }
1498

    
1499
          // proceed if we're called by a CN
1500
          if ( isAllowed ) {
1501
              // create the coordinating node version of the document      
1502
              lock.lock();
1503
              logMetacat.debug("Locked identifier " + pid.getValue());
1504
              sysmeta.setSerialVersion(BigInteger.ONE);
1505
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1506
              sysmeta.setArchived(false); // this is a create op, not update
1507
              
1508
              // the CN should have set the origin and authoritative member node fields
1509
              try {
1510
                  sysmeta.getOriginMemberNode().getValue();
1511
                  sysmeta.getAuthoritativeMemberNode().getValue();
1512
                  
1513
              } catch (NullPointerException npe) {
1514
                  throw new InvalidSystemMetadata("4896", 
1515
                      "Both the origin and authoritative member node identifiers need to be set.");
1516
                  
1517
              }
1518
              pid = super.create(session, pid, object, sysmeta);
1519

    
1520
          } else {
1521
              String msg = "The subject listed as " + session.getSubject().getValue() + 
1522
                  " isn't allowed to call create() on a Coordinating Node.";
1523
              logMetacat.info(msg);
1524
              throw new NotAuthorized("1100", msg);
1525
          }
1526
          
1527
      } catch (RuntimeException e) {
1528
          // Convert Hazelcast runtime exceptions to service failures
1529
          String msg = "There was a problem creating the object identified by " +
1530
              pid.getValue() + ". There error message was: " + e.getMessage();
1531
          throw new ServiceFailure("4893", msg);
1532
          
1533
      } finally {
1534
    	  if (lock != null) {
1535
	          lock.unlock();
1536
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1537
    	  }
1538
      }
1539
      
1540
      return pid;
1541

    
1542
  }
1543

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

    
1585
          try {
1586
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1587

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

    
1633
    
1634
    // TODO: how do we know if the map was persisted?
1635
    success = true;
1636
    
1637
    return success;
1638
  }
1639

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

    
1670
          // what is the controlling permission?
1671
          if (!isAuthorized(session, pid, Permission.WRITE)) {
1672
              throw new NotAuthorized("4851", "not allowed by "
1673
                      + subject.getValue() + " on " + pid.getValue());
1674
          }
1675

    
1676
        
1677
      } catch (InvalidToken e) {
1678
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() + 
1679
                  " on " + pid.getValue());  
1680
          
1681
      }
1682

    
1683
      SystemMetadata systemMetadata = null;
1684
      try {
1685
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1686
          lock.lock();
1687
          logMetacat.debug("Locked identifier " + pid.getValue());
1688

    
1689
          try {      
1690
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1691

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

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

    
1790
        return objectList;
1791
  }
1792

    
1793
  
1794
 	/**
1795
 	 * Returns a list of checksum algorithms that are supported by DataONE.
1796
 	 * @return cal  the list of checksum algorithms
1797
 	 * 
1798
 	 * @throws ServiceFailure
1799
 	 * @throws NotImplemented
1800
 	 */
1801
  @Override
1802
  public ChecksumAlgorithmList listChecksumAlgorithms()
1803
			throws ServiceFailure, NotImplemented {
1804
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
1805
		cal.addAlgorithm("MD5");
1806
		cal.addAlgorithm("SHA-1");
1807
		return cal;
1808
		
1809
	}
1810

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

    
1879
	@Override
1880
	public boolean isAuthorized(Identifier pid, Permission permission)
1881
			throws ServiceFailure, InvalidToken, NotFound, NotAuthorized,
1882
			NotImplemented, InvalidRequest {
1883
		
1884
		return isAuthorized(null, pid, permission);
1885
	}
1886
	
1887
	@Override
1888
	public boolean setAccessPolicy(Identifier pid, AccessPolicy accessPolicy, long serialVersion)
1889
			throws InvalidToken, NotFound, NotImplemented, NotAuthorized,
1890
			ServiceFailure, InvalidRequest, VersionMismatch {
1891
		
1892
		return setAccessPolicy(null, pid, accessPolicy, serialVersion);
1893
	}
1894
	
1895
	@Override
1896
	public Identifier setRightsHolder(Identifier pid, Subject userId, long serialVersion)
1897
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1898
			NotImplemented, InvalidRequest, VersionMismatch {
1899
		
1900
		return setRightsHolder(null, pid, userId, serialVersion);
1901
	}
1902
	
1903
	@Override
1904
	public Identifier create(Identifier pid, InputStream object, SystemMetadata sysmeta)
1905
			throws InvalidToken, ServiceFailure, NotAuthorized,
1906
			IdentifierNotUnique, UnsupportedType, InsufficientResources,
1907
			InvalidSystemMetadata, NotImplemented, InvalidRequest {
1908

    
1909
		return create(null, pid, object, sysmeta);
1910
	}
1911
	
1912
	@Override
1913
	public Identifier delete(Identifier pid) throws InvalidToken, ServiceFailure,
1914
			NotAuthorized, NotFound, NotImplemented {
1915

    
1916
		return delete(null, pid);
1917
	}
1918
	
1919
	@Override
1920
	public Identifier generateIdentifier(String scheme, String fragment)
1921
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
1922
			InvalidRequest {
1923

    
1924
		return generateIdentifier(null, scheme, fragment);
1925
	}
1926
	
1927
	@Override
1928
	public Log getLogRecords(Date fromDate, Date toDate, Event event, String pidFilter,
1929
			Integer start, Integer count) throws InvalidToken, InvalidRequest,
1930
			ServiceFailure, NotAuthorized, NotImplemented, InsufficientResources {
1931

    
1932
		return getLogRecords(null, fromDate, toDate, event, pidFilter, start, count);
1933
	}
1934
	
1935
	@Override
1936
	public boolean hasReservation(Subject subject, Identifier pid)
1937
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1938
			NotImplemented, InvalidRequest, IdentifierNotUnique {
1939

    
1940
		return hasReservation(null, subject, pid);
1941
	}
1942
	
1943
	@Override
1944
	public Identifier registerSystemMetadata(Identifier pid, SystemMetadata sysmeta)
1945
			throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1946
			InvalidSystemMetadata, InvalidToken {
1947

    
1948
		return registerSystemMetadata(null, pid, sysmeta);
1949
	}
1950
	
1951
	@Override
1952
	public Identifier reserveIdentifier(Identifier pid) throws InvalidToken,
1953
			ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented,
1954
			InvalidRequest {
1955

    
1956
		return reserveIdentifier(null, pid);
1957
	}
1958
	
1959
	@Override
1960
	public boolean setObsoletedBy(Identifier pid, Identifier obsoletedByPid, long serialVersion)
1961
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1962
			InvalidRequest, InvalidToken, VersionMismatch {
1963

    
1964
		return setObsoletedBy(null, pid, obsoletedByPid, serialVersion);
1965
	}
1966
	
1967
	@Override
1968
	public DescribeResponse describe(Identifier pid) throws InvalidToken,
1969
			NotAuthorized, NotImplemented, ServiceFailure, NotFound {
1970

    
1971
		return describe(null, pid);
1972
	}
1973
	
1974
	@Override
1975
	public InputStream get(Identifier pid) throws InvalidToken, ServiceFailure,
1976
			NotAuthorized, NotFound, NotImplemented {
1977

    
1978
		return get(null, pid);
1979
	}
1980
	
1981
	@Override
1982
	public Checksum getChecksum(Identifier pid) throws InvalidToken,
1983
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1984

    
1985
		return getChecksum(null, pid);
1986
	}
1987
	
1988
	@Override
1989
	public SystemMetadata getSystemMetadata(Identifier pid) throws InvalidToken,
1990
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1991

    
1992
		return getSystemMetadata(null, pid);
1993
	}
1994
	
1995
	@Override
1996
	public ObjectList listObjects(Date startTime, Date endTime,
1997
			ObjectFormatIdentifier formatid, Boolean replicaStatus, Integer start, Integer count)
1998
			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1999
			ServiceFailure {
2000

    
2001
		return listObjects(null, startTime, endTime, formatid, replicaStatus, start, count);
2002
	}
2003
	
2004
	@Override
2005
	public ObjectLocationList resolve(Identifier pid) throws InvalidToken,
2006
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
2007

    
2008
		return resolve(null, pid);
2009
	}
2010
	
2011
	@Override
2012
	public ObjectList search(String queryType, String query) throws InvalidToken,
2013
			ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented {
2014

    
2015
		return search(null, queryType, query);
2016
	}
2017
	
2018
	@Override
2019
	public boolean deleteReplicationMetadata(Identifier pid, NodeReference nodeId,
2020
			long serialVersion) throws InvalidToken, InvalidRequest, ServiceFailure,
2021
			NotAuthorized, NotFound, NotImplemented, VersionMismatch {
2022

    
2023
		return deleteReplicationMetadata(null, pid, nodeId, serialVersion);
2024
	}
2025
	
2026
	@Override
2027
	public boolean isNodeAuthorized(Subject targetNodeSubject, Identifier pid)
2028
			throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
2029
			NotFound, InvalidRequest {
2030

    
2031
		return isNodeAuthorized(null, targetNodeSubject, pid);
2032
	}
2033
	
2034
	@Override
2035
	public boolean setReplicationPolicy(Identifier pid, ReplicationPolicy policy,
2036
			long serialVersion) throws NotImplemented, NotFound, NotAuthorized,
2037
			ServiceFailure, InvalidRequest, InvalidToken, VersionMismatch {
2038

    
2039
		return setReplicationPolicy(null, pid, policy, serialVersion);
2040
	}
2041
	
2042
	@Override
2043
	public boolean setReplicationStatus(Identifier pid, NodeReference targetNode,
2044
			ReplicationStatus status, BaseException failure) throws ServiceFailure,
2045
			NotImplemented, InvalidToken, NotAuthorized, InvalidRequest, NotFound {
2046

    
2047
		return setReplicationStatus(null, pid, targetNode, status, failure);
2048
	}
2049
	
2050
	@Override
2051
	public boolean updateReplicationMetadata(Identifier pid, Replica replica,
2052
			long serialVersion) throws NotImplemented, NotAuthorized, ServiceFailure,
2053
			NotFound, InvalidRequest, InvalidToken, VersionMismatch {
2054

    
2055
		return updateReplicationMetadata(null, pid, replica, serialVersion);
2056
	}
2057

    
2058
  @Override
2059
  public QueryEngineDescription getQueryEngineDescription(String arg0)
2060
          throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
2061
          NotFound {
2062
      throw new NotImplemented("4410", "getQueryEngineDescription not implemented");
2063
      
2064
  }
2065

    
2066
  @Override
2067
  public QueryEngineList listQueryEngines() throws InvalidToken, ServiceFailure,
2068
          NotAuthorized, NotImplemented {
2069
      throw new NotImplemented("4420", "listQueryEngines not implemented");
2070
      
2071
  }
2072

    
2073
  @Override
2074
  public InputStream query(String arg0, String arg1) throws InvalidToken,
2075
          ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, NotFound {
2076
      throw new NotImplemented("4324", "query not implemented");
2077
      
2078
  }
2079
}
(1-1/7)