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

    
81
import edu.ucsb.nceas.metacat.EventLog;
82
import edu.ucsb.nceas.metacat.IdentifierManager;
83
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
84

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

    
95
  /* the logger instance */
96
  private Logger logMetacat = null;
97

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

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

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

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

    
232
		// get the subject
233
		Subject subject = session.getSubject();
234

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

    
247
		}
248

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

    
255
			try {
256
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
257
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
258
				}
259

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

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

    
274
				}
275

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

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

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

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

    
320
		return true;	  
321
	  
322
  }
323
  
324
  /**
325
   * Deletes an object from the Coordinating Node, where the object is a 
326
   * a science metadata object.
327
   * 
328
   * @param session - the Session object containing the credentials for the Subject
329
   * @param pid - The object identifier to be deleted
330
   * 
331
   * @return pid - the identifier of the object used for the deletion
332
   * 
333
   * @throws InvalidToken
334
   * @throws ServiceFailure
335
   * @throws NotAuthorized
336
   * @throws NotFound
337
   * @throws NotImplemented
338
   * @throws InvalidRequest
339
   */
340
  @Override
341
  public Identifier delete(Session session, Identifier pid) 
342
      throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
343

    
344
	  // check that it is CN/admin
345
	  boolean allowed = isAdminAuthorized(session);
346
	  
347
	  if (!allowed) {
348
		  String msg = "The subject is not allowed to call delete() on a Coordinating Node.";
349
		  logMetacat.info(msg);
350
		  throw new NotAuthorized("1320", msg);
351
	  }
352
	  
353
	  // defer to superclass implementation
354
	  Identifier retId =  super.delete(session, pid);
355
      
356
	  // notify the replicas
357
	  SystemMetadata systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
358
	  if (systemMetadata.getReplicaList() != null) {
359
		  for (Replica replica: systemMetadata.getReplicaList()) {
360
			  NodeReference replicaNode = replica.getReplicaMemberNode();
361
			  try {
362
				  Identifier mnRetId = D1Client.getMN(replicaNode).delete(null, pid);
363
			  } catch (Exception e) {
364
				  // all we can really do is log errors and carry on with life
365
				  logMetacat.error("Error deleting pid: " +  pid.getValue() + " from replica MN: " + replicaNode.getValue(), e);
366
			}
367
			  
368
		  }
369
	  }
370
	  
371
	  return retId;
372
      
373
  }
374
  
375
  /**
376
   * Deletes an object from the Coordinating Node, where the object is a 
377
   * a science metadata object.
378
   * 
379
   * @param session - the Session object containing the credentials for the Subject
380
   * @param pid - The object identifier to be deleted
381
   * 
382
   * @return pid - the identifier of the object used for the deletion
383
   * 
384
   * @throws InvalidToken
385
   * @throws ServiceFailure
386
   * @throws NotAuthorized
387
   * @throws NotFound
388
   * @throws NotImplemented
389
   * @throws InvalidRequest
390
   */
391
  @Override
392
  public Identifier archive(Session session, Identifier pid) 
393
      throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
394

    
395
	  // check that it is CN/admin
396
	  boolean allowed = isAdminAuthorized(session);
397
	  
398
	  if (!allowed) {
399
		  String msg = "The subject is not allowed to call delete() on a Coordinating Node.";
400
		  logMetacat.info(msg);
401
		  throw new NotAuthorized("1320", msg);
402
	  }
403
	  
404
	  // defer to superclass implementation
405
	  Identifier retId =  super.archive(session, pid);
406
      
407
	  // notify the replicas
408
	  SystemMetadata systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
409
	  if (systemMetadata.getReplicaList() != null) {
410
		  for (Replica replica: systemMetadata.getReplicaList()) {
411
			  NodeReference replicaNode = replica.getReplicaMemberNode();
412
			  try {
413
				  // TODO: implement in the clients
414
				  //Identifier mnRetId = D1Client.getMN(replicaNode).archive(null, pid);
415
			  } catch (Exception e) {
416
				  // all we can really do is log errors and carry on with life
417
				  logMetacat.error("Error archiving pid: " +  pid.getValue() + " from replica MN: " + replicaNode.getValue(), e);
418
			}
419
			  
420
		  }
421
	  }
422
	  
423
	  return retId;
424
      
425
  }
426
  
427
  /**
428
   * Set the obsoletedBy attribute in System Metadata
429
   * @param session
430
   * @param pid
431
   * @param obsoletedByPid
432
   * @param serialVersion
433
   * @return
434
   * @throws NotImplemented
435
   * @throws NotFound
436
   * @throws NotAuthorized
437
   * @throws ServiceFailure
438
   * @throws InvalidRequest
439
   * @throws InvalidToken
440
   * @throws VersionMismatch
441
   */
442
  @Override
443
  public boolean setObsoletedBy(Session session, Identifier pid,
444
			Identifier obsoletedByPid, long serialVersion)
445
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
446
			InvalidRequest, InvalidToken, VersionMismatch {
447

    
448
		// The lock to be used for this identifier
449
		Lock lock = null;
450

    
451
		// get the subject
452
		Subject subject = session.getSubject();
453

    
454
		// are we allowed to do this?
455
		if (!isAuthorized(session, pid, Permission.WRITE)) {
456
			throw new NotAuthorized("4881", Permission.WRITE
457
					+ " not allowed by " + subject.getValue() + " on "
458
					+ pid.getValue());
459

    
460
		}
461

    
462

    
463
		SystemMetadata systemMetadata = null;
464
		try {
465
			lock = HazelcastService.getInstance().getLock(pid.getValue());
466
			lock.lock();
467
			logMetacat.debug("Locked identifier " + pid.getValue());
468

    
469
			try {
470
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
471
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
472
				}
473

    
474
				// did we get it correctly?
475
				if (systemMetadata == null) {
476
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
477
				}
478

    
479
				// does the request have the most current system metadata?
480
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
481
					String msg = "The requested system metadata version number "
482
							+ serialVersion
483
							+ " differs from the current version at "
484
							+ systemMetadata.getSerialVersion().longValue()
485
							+ ". Please get the latest copy in order to modify it.";
486
					throw new VersionMismatch("4886", msg);
487

    
488
				}
489

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

    
493
			}
494

    
495
			// set the new policy
496
			systemMetadata.setObsoletedBy(obsoletedByPid);
497

    
498
			// update the metadata
499
			try {
500
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
501
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
502
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
503
			} catch (RuntimeException e) {
504
				throw new ServiceFailure("4882", e.getMessage());
505
			}
506

    
507
		} catch (RuntimeException e) {
508
			throw new ServiceFailure("4882", e.getMessage());
509
		} finally {
510
			lock.unlock();
511
			logMetacat.debug("Unlocked identifier " + pid.getValue());
512
		}
513

    
514
		return true;
515
	}
516
  
517
  
518
  /**
519
   * Set the replication status for an object given the object identifier
520
   * 
521
   * @param session - the Session object containing the credentials for the Subject
522
   * @param pid - the object identifier for the given object
523
   * @param status - the replication status to be applied
524
   * 
525
   * @return true or false
526
   * 
527
   * @throws NotImplemented
528
   * @throws NotAuthorized
529
   * @throws ServiceFailure
530
   * @throws InvalidRequest
531
   * @throws InvalidToken
532
   * @throws NotFound
533
   * 
534
   */
535
  @Override
536
  public boolean setReplicationStatus(Session session, Identifier pid,
537
      NodeReference targetNode, ReplicationStatus status, BaseException failure) 
538
      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
539
      InvalidRequest, NotFound {
540
	  
541
	  // cannot be called by public
542
	  if (session == null) {
543
		  throw new NotAuthorized("4720", "Session cannot be null");
544
	  }
545
      
546
      // The lock to be used for this identifier
547
      Lock lock = null;
548
      
549
      boolean allowed = false;
550
      int replicaEntryIndex = -1;
551
      List<Replica> replicas = null;
552
      // get the subject
553
      Subject subject = session.getSubject();
554
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
555
          " is " + status.toString());
556
      
557
      SystemMetadata systemMetadata = null;
558

    
559
      try {
560
          lock = HazelcastService.getInstance().getLock(pid.getValue());
561
          lock.lock();
562
          logMetacat.debug("Locked identifier " + pid.getValue());
563

    
564
          try {      
565
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
566

    
567
              // did we get it correctly?
568
              if ( systemMetadata == null ) {
569
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
570
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
571
                  
572
              }
573
              replicas = systemMetadata.getReplicaList();
574
              int count = 0;
575
              
576
              // was there a failure? log it
577
              if ( failure != null && status == ReplicationStatus.FAILED ) {
578
                 String msg = "The replication request of the object identified by " + 
579
                     pid.getValue() + " failed.  The error message was " +
580
                     failure.getMessage() + ".";
581
              }
582
              
583
              if (replicas.size() > 0 && replicas != null) {
584
                  // find the target replica index in the replica list
585
                  for (Replica replica : replicas) {
586
                      String replicaNodeStr = replica.getReplicaMemberNode()
587
                              .getValue();
588
                      String targetNodeStr = targetNode.getValue();
589
                      logMetacat.debug("Comparing " + replicaNodeStr + " to "
590
                              + targetNodeStr);
591
                  
592
                      if (replicaNodeStr.equals(targetNodeStr)) {
593
                          replicaEntryIndex = count;
594
                          logMetacat.debug("replica entry index is: "
595
                                  + replicaEntryIndex);
596
                          break;
597
                      }
598
                      count++;
599
                  
600
                  }
601
              }
602
              // are we allowed to do this? only CNs and target MNs are allowed
603
              CNode cn = D1Client.getCN();
604
              List<Node> nodes = cn.listNodes().getNodeList();
605
              
606
              // find the node in the node list
607
              for ( Node node : nodes ) {
608
                  
609
                  NodeReference nodeReference = node.getIdentifier();
610
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " + nodeReference.getValue());
611
                  
612
                  // allow target MN certs
613
                  if (targetNode.getValue().equals(nodeReference.getValue()) &&
614
                      node.getType() == NodeType.MN) {
615
                      List<Subject> nodeSubjects = node.getSubjectList();
616
                      
617
                      // check if the session subject is in the node subject list
618
                      for (Subject nodeSubject : nodeSubjects) {
619
                          logMetacat.debug("In setReplicationStatus(), comparing subjects: " +
620
                                  nodeSubject.getValue() + " and " + subject.getValue());
621
                          if ( nodeSubject.equals(subject) ) { // subject of session == target node subject
622
                              
623
                              // lastly limit to COMPLETED, INVALIDATED,
624
                              // and FAILED status updates from MNs only
625
                              if ( status == ReplicationStatus.COMPLETED ||
626
                                   status == ReplicationStatus.INVALIDATED ||
627
                                   status == ReplicationStatus.FAILED) {
628
                                  allowed = true;
629
                                  break;
630
                                  
631
                              }                              
632
                          }
633
                      }                 
634
                  }
635
              }
636

    
637
              if ( !allowed ) {
638
                  //check for CN admin access
639
                  allowed = isAuthorized(session, pid, Permission.WRITE);
640
                  
641
              }              
642
              
643
              if ( !allowed ) {
644
                  String msg = "The subject identified by "
645
                          + subject.getValue()
646
                          + " does not have permission to set the replication status for "
647
                          + "the replica identified by "
648
                          + targetNode.getValue() + ".";
649
                  logMetacat.info(msg);
650
                  throw new NotAuthorized("4720", msg);
651
                  
652
              }
653

    
654
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
655
            throw new NotFound("4740", "No record found for: " + pid.getValue() +
656
                " : " + e.getMessage());
657
            
658
          }
659
          
660
          Replica targetReplica = new Replica();
661
          // set the status for the replica
662
          if ( replicaEntryIndex != -1 ) {
663
              targetReplica = replicas.get(replicaEntryIndex);
664
              
665
              // don't allow status to change from COMPLETED to anything other
666
              // than INVALIDATED: prevents overwrites from race conditions
667
              if ( targetReplica.getReplicationStatus() == ReplicationStatus.COMPLETED &&
668
            	   status != ReplicationStatus.INVALIDATED) {
669
            	  throw new InvalidRequest("4730", "Status state change from " +
670
            			  targetReplica.getReplicationStatus() + " to " +
671
            			  status.toString() + "is prohibited for identifier " +
672
            			  pid.getValue() + " and target node " + 
673
            			  targetReplica.getReplicaMemberNode().getValue());
674
              }
675
              
676
              targetReplica.setReplicationStatus(status);
677
              logMetacat.debug("Set the replication status for " + 
678
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
679
                  targetReplica.getReplicationStatus() + " for identifier " +
680
                  pid.getValue());
681
              
682
          } else {
683
              // this is a new entry, create it
684
              targetReplica.setReplicaMemberNode(targetNode);
685
              targetReplica.setReplicationStatus(status);
686
              targetReplica.setReplicaVerified(Calendar.getInstance().getTime());
687
              replicas.add(targetReplica);
688
              
689
          }
690
          
691
          systemMetadata.setReplicaList(replicas);
692
                
693
          // update the metadata
694
          try {
695
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
696
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
697
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
698

    
699
              if ( status != ReplicationStatus.QUEUED && status != ReplicationStatus.REQUESTED) {
700
                  
701
                logMetacat.trace("METRICS:\tREPLICATION:\tEND REQUEST:\tPID:\t" + pid.getValue() + 
702
                          "\tNODE:\t" + targetNode.getValue() + 
703
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
704
                
705
                logMetacat.trace("METRICS:\tREPLICATION:\t" + status.toString().toUpperCase() +
706
                          "\tPID:\t"  + pid.getValue() + 
707
                          "\tNODE:\t" + targetNode.getValue() + 
708
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
709
              }
710

    
711
              if ( status == ReplicationStatus.FAILED && failure != null ) {
712
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
713
                      " on target node " + targetNode + ". The exception was: " +
714
                      failure.getMessage());
715
              }
716
          } catch (RuntimeException e) {
717
              throw new ServiceFailure("4700", e.getMessage());
718
          
719
          }
720
          
721
    } catch (RuntimeException e) {
722
        String msg = "There was a RuntimeException getting the lock for " +
723
            pid.getValue();
724
        logMetacat.info(msg);
725
        
726
    } finally {
727
        lock.unlock();
728
        logMetacat.debug("Unlocked identifier " + pid.getValue());
729
        
730
    }
731
      
732
      return true;
733
  }
734
  
735
  /**
736
   * Return the checksum of the object given the identifier 
737
   * 
738
   * @param session - the Session object containing the credentials for the Subject
739
   * @param pid - the object identifier for the given object
740
   * 
741
   * @return checksum - the checksum of the object
742
   * 
743
   * @throws InvalidToken
744
   * @throws ServiceFailure
745
   * @throws NotAuthorized
746
   * @throws NotFound
747
   * @throws NotImplemented
748
   */
749
  @Override
750
  public Checksum getChecksum(Session session, Identifier pid)
751
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
752
    NotImplemented {
753
    
754
	boolean isAuthorized = false;
755
	try {
756
		isAuthorized = isAuthorized(session, pid, Permission.READ);
757
	} catch (InvalidRequest e) {
758
		throw new ServiceFailure("1410", e.getDescription());
759
	}  
760
    if (!isAuthorized) {
761
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());  
762
    }
763
    
764
    SystemMetadata systemMetadata = null;
765
    Checksum checksum = null;
766
    
767
    try {
768
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);        
769

    
770
        if (systemMetadata == null ) {
771
            throw new NotFound("1420", "Couldn't find an object identified by " + pid.getValue());
772
        }
773
        checksum = systemMetadata.getChecksum();
774
        
775
    } catch (RuntimeException e) {
776
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " + 
777
            pid.getValue() + ". The error message was: " + e.getMessage());
778
      
779
    }
780
    
781
    return checksum;
782
  }
783

    
784
  /**
785
   * Resolve the location of a given object
786
   * 
787
   * @param session - the Session object containing the credentials for the Subject
788
   * @param pid - the object identifier for the given object
789
   * 
790
   * @return objectLocationList - the list of nodes known to contain the object
791
   * 
792
   * @throws InvalidToken
793
   * @throws ServiceFailure
794
   * @throws NotAuthorized
795
   * @throws NotFound
796
   * @throws NotImplemented
797
   */
798
  @Override
799
  public ObjectLocationList resolve(Session session, Identifier pid)
800
    throws InvalidToken, ServiceFailure, NotAuthorized,
801
    NotFound, NotImplemented {
802

    
803
    throw new NotImplemented("4131", "resolve not implemented");
804

    
805
  }
806

    
807
  /**
808
   * Search the metadata catalog for identifiers that match the criteria
809
   * 
810
   * @param session - the Session object containing the credentials for the Subject
811
   * @param queryType - An identifier for the type of query expression 
812
   *                    provided in the query
813
   * @param query -  The criteria for matching the characteristics of the 
814
   *                 metadata objects of interest
815
   * 
816
   * @return objectList - the list of objects matching the criteria
817
   * 
818
   * @throws InvalidToken
819
   * @throws ServiceFailure
820
   * @throws NotAuthorized
821
   * @throws InvalidRequest
822
   * @throws NotImplemented
823
   */
824
  @Override
825
  public ObjectList search(Session session, String queryType, String query)
826
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
827
    NotImplemented {
828

    
829
    ObjectList objectList = null;
830
    try {
831
        objectList = 
832
          IdentifierManager.getInstance().querySystemMetadata(
833
              null, //startTime, 
834
              null, //endTime,
835
              null, //objectFormat, 
836
              false, //replicaStatus, 
837
              0, //start, 
838
              -1 //count
839
              );
840
        
841
    } catch (Exception e) {
842
      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
843
    }
844

    
845
      return objectList;
846
      
847
    //throw new NotImplemented("4281", "search not implemented");
848
    
849
    // the code block below is from an older implementation
850
    
851
    /*  This block commented out because of the EcoGrid circular dependency.
852
         *  For now, query will not be supported until the circularity can be
853
         *  resolved, probably by moving the ecogrid query syntax transformers
854
         *  directly into the Metacat codebase.  MBJ 2010-02-03
855
         
856
        try {
857
            EcogridQueryParser parser = new EcogridQueryParser(request
858
                    .getReader());
859
            parser.parseXML();
860
            QueryType queryType = parser.getEcogridQuery();
861
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
862
                new EcogridJavaToMetacatJavaQueryTransformer();
863
            QuerySpecification metacatQuery = queryTransformer
864
                    .transform(queryType);
865

    
866
            DBQuery metacat = new DBQuery();
867

    
868
            boolean useXMLIndex = (new Boolean(PropertyService
869
                    .getProperty("database.usexmlindex"))).booleanValue();
870
            String xmlquery = "query"; // we don't care the query in resultset,
871
            // the query can be anything
872
            PrintWriter out = null; // we don't want metacat result, so set out null
873

    
874
            // parameter: queryspecification, user, group, usingIndexOrNot
875
            StringBuffer result = metacat.createResultDocument(xmlquery,
876
                    metacatQuery, out, username, groupNames, useXMLIndex);
877

    
878
            // create result set transfer       
879
            String saxparser = PropertyService.getProperty("xml.saxparser");
880
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
881
                    new StringReader(result.toString()), saxparser, queryType
882
                            .getNamespace().get_value());
883
            ResultsetType records = metacatResultsetParser.getEcogridResult();
884

    
885
            System.out
886
                    .println(EcogridResultsetTransformer.toXMLString(records));
887
            response.setContentType("text/xml");
888
            out = response.getWriter();
889
            out.print(EcogridResultsetTransformer.toXMLString(records));
890

    
891
        } catch (Exception e) {
892
            e.printStackTrace();
893
        }*/
894
    
895

    
896
  }
897
  
898
  /**
899
   * Returns the object format registered in the DataONE Object Format 
900
   * Vocabulary for the given format identifier
901
   * 
902
   * @param fmtid - the identifier of the format requested
903
   * 
904
   * @return objectFormat - the object format requested
905
   * 
906
   * @throws ServiceFailure
907
   * @throws NotFound
908
   * @throws InsufficientResources
909
   * @throws NotImplemented
910
   */
911
  @Override
912
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
913
    throws ServiceFailure, NotFound, NotImplemented {
914
     
915
      return ObjectFormatService.getInstance().getFormat(fmtid);
916
      
917
  }
918

    
919
  /**
920
   * Returns a list of all object formats registered in the DataONE Object 
921
   * Format Vocabulary
922
    * 
923
   * @return objectFormatList - The list of object formats registered in 
924
   *                            the DataONE Object Format Vocabulary
925
   * 
926
   * @throws ServiceFailure
927
   * @throws NotImplemented
928
   * @throws InsufficientResources
929
   */
930
  @Override
931
  public ObjectFormatList listFormats() 
932
    throws ServiceFailure, NotImplemented {
933

    
934
    return ObjectFormatService.getInstance().listFormats();
935
  }
936

    
937
  /**
938
   * Returns a list of nodes that have been registered with the DataONE infrastructure
939
    * 
940
   * @return nodeList - List of nodes from the registry
941
   * 
942
   * @throws ServiceFailure
943
   * @throws NotImplemented
944
   */
945
  @Override
946
  public NodeList listNodes() 
947
    throws NotImplemented, ServiceFailure {
948

    
949
    throw new NotImplemented("4800", "listNodes not implemented");
950
  }
951

    
952
  /**
953
   * Provides a mechanism for adding system metadata independently of its 
954
   * associated object, such as when adding system metadata for data objects.
955
    * 
956
   * @param session - the Session object containing the credentials for the Subject
957
   * @param pid - The identifier of the object to register the system metadata against
958
   * @param sysmeta - The system metadata to be registered
959
   * 
960
   * @return true if the registration succeeds
961
   * 
962
   * @throws NotImplemented
963
   * @throws NotAuthorized
964
   * @throws ServiceFailure
965
   * @throws InvalidRequest
966
   * @throws InvalidSystemMetadata
967
   */
968
  @Override
969
  public Identifier registerSystemMetadata(Session session, Identifier pid,
970
      SystemMetadata sysmeta) 
971
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
972
      InvalidSystemMetadata {
973

    
974
      // The lock to be used for this identifier
975
      Lock lock = null;
976

    
977
      // TODO: control who can call this?
978
      if (session == null) {
979
          //TODO: many of the thrown exceptions do not use the correct error codes
980
          //check these against the docs and correct them
981
          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
982
                  "  If you are not logged in, please do so and retry the request.");
983
      }
984
      
985
      // verify that guid == SystemMetadata.getIdentifier()
986
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() + 
987
          "|" + sysmeta.getIdentifier().getValue());
988
      if (!pid.getValue().equals(sysmeta.getIdentifier().getValue())) {
989
          throw new InvalidRequest("4863", 
990
              "The identifier in method call (" + pid.getValue() + 
991
              ") does not match identifier in system metadata (" +
992
              sysmeta.getIdentifier().getValue() + ").");
993
      }
994

    
995
      try {
996
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
997
          lock.lock();
998
          logMetacat.debug("Locked identifier " + pid.getValue());
999
          logMetacat.debug("Checking if identifier exists...");
1000
          // Check that the identifier does not already exist
1001
          if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
1002
              throw new InvalidRequest("4863", 
1003
                  "The identifier is already in use by an existing object.");
1004
          
1005
          }
1006
          
1007
          // insert the system metadata into the object store
1008
          logMetacat.debug("Starting to insert SystemMetadata...");
1009
          try {
1010
              sysmeta.setSerialVersion(BigInteger.ONE);
1011
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1012
              HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
1013
              
1014
          } catch (RuntimeException e) {
1015
            logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
1016
              throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1017
                  e.getClass() + ": " + e.getMessage());
1018
              
1019
          }
1020
          
1021
      } catch (RuntimeException e) {
1022
          throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1023
                  e.getClass() + ": " + e.getMessage());
1024
          
1025
      }  finally {
1026
          lock.unlock();
1027
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1028
          
1029
      }
1030

    
1031
      
1032
      logMetacat.debug("Returning from registerSystemMetadata");
1033
      EventLog.getInstance().log(request.getRemoteAddr(), 
1034
          request.getHeader("User-Agent"), session.getSubject().getValue(), 
1035
          pid.getValue(), "registerSystemMetadata");
1036
      return pid;
1037
  }
1038
  
1039
  /**
1040
   * Given an optional scope and format, reserves and returns an identifier 
1041
   * within that scope and format that is unique and will not be 
1042
   * used by any other sessions. 
1043
    * 
1044
   * @param session - the Session object containing the credentials for the Subject
1045
   * @param pid - The identifier of the object to register the system metadata against
1046
   * @param scope - An optional string to be used to qualify the scope of 
1047
   *                the identifier namespace, which is applied differently 
1048
   *                depending on the format requested. If scope is not 
1049
   *                supplied, a default scope will be used.
1050
   * @param format - The optional name of the identifier format to be used, 
1051
   *                  drawn from a DataONE-specific vocabulary of identifier 
1052
   *                 format names, including several common syntaxes such 
1053
   *                 as DOI, LSID, UUID, and LSRN, among others. If the 
1054
   *                 format is not supplied by the caller, the CN service 
1055
   *                 will use a default identifier format, which may change 
1056
   *                 over time.
1057
   * 
1058
   * @return true if the registration succeeds
1059
   * 
1060
   * @throws InvalidToken
1061
   * @throws ServiceFailure
1062
   * @throws NotAuthorized
1063
   * @throws IdentifierNotUnique
1064
   * @throws NotImplemented
1065
   */
1066
  @Override
1067
  public Identifier reserveIdentifier(Session session, Identifier pid)
1068
  throws InvalidToken, ServiceFailure,
1069
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
1070

    
1071
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1072
  }
1073
  
1074
  @Override
1075
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1076
  throws InvalidToken, ServiceFailure,
1077
        NotAuthorized, NotImplemented, InvalidRequest {
1078
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
1079
  }
1080
  
1081
  /**
1082
    * Checks whether the pid is reserved by the subject in the session param
1083
    * If the reservation is held on the pid by the subject, we return true.
1084
    * 
1085
   * @param session - the Session object containing the Subject
1086
   * @param pid - The identifier to check
1087
   * 
1088
   * @return true if the reservation exists for the subject/pid
1089
   * 
1090
   * @throws InvalidToken
1091
   * @throws ServiceFailure
1092
   * @throws NotFound - when the pid is not found (in use or in reservation)
1093
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
1094
   * @throws IdentifierNotUnique - when the pid is in use
1095
   * @throws NotImplemented
1096
   */
1097

    
1098
  @Override
1099
  public boolean hasReservation(Session session, Subject subject, Identifier pid) 
1100
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique, 
1101
      NotImplemented, InvalidRequest {
1102
  
1103
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1104
  }
1105

    
1106
  /**
1107
   * Changes ownership (RightsHolder) of the specified object to the 
1108
   * subject specified by userId
1109
    * 
1110
   * @param session - the Session object containing the credentials for the Subject
1111
   * @param pid - Identifier of the object to be modified
1112
   * @param userId - The subject that will be taking ownership of the specified object.
1113
   *
1114
   * @return pid - the identifier of the modified object
1115
   * 
1116
   * @throws ServiceFailure
1117
   * @throws InvalidToken
1118
   * @throws NotFound
1119
   * @throws NotAuthorized
1120
   * @throws NotImplemented
1121
   * @throws InvalidRequest
1122
   */  
1123
  @Override
1124
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1125
      long serialVersion)
1126
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1127
      NotImplemented, InvalidRequest, VersionMismatch {
1128
      
1129
      // The lock to be used for this identifier
1130
      Lock lock = null;
1131

    
1132
      // get the subject
1133
      Subject subject = session.getSubject();
1134
      
1135
      // are we allowed to do this?
1136
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1137
          throw new NotAuthorized("4440", "not allowed by "
1138
                  + subject.getValue() + " on " + pid.getValue());
1139
          
1140
      }
1141
      
1142
      SystemMetadata systemMetadata = null;
1143
      try {
1144
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1145
          logMetacat.debug("Locked identifier " + pid.getValue());
1146

    
1147
          try {
1148
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1149
              
1150
              // does the request have the most current system metadata?
1151
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1152
                 String msg = "The requested system metadata version number " + 
1153
                     serialVersion + " differs from the current version at " +
1154
                     systemMetadata.getSerialVersion().longValue() +
1155
                     ". Please get the latest copy in order to modify it.";
1156
                 throw new VersionMismatch("4443", msg);
1157
              }
1158
              
1159
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1160
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1161
              
1162
          }
1163
              
1164
          // set the new rights holder
1165
          systemMetadata.setRightsHolder(userId);
1166
          
1167
          // update the metadata
1168
          try {
1169
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1170
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1171
              HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
1172
              notifyReplicaNodes(systemMetadata);
1173
              
1174
          } catch (RuntimeException e) {
1175
              throw new ServiceFailure("4490", e.getMessage());
1176
          
1177
          }
1178
          
1179
      } catch (RuntimeException e) {
1180
          throw new ServiceFailure("4490", e.getMessage());
1181
          
1182
      } finally {
1183
          lock.unlock();
1184
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1185
      
1186
      }
1187
      
1188
      return pid;
1189
  }
1190

    
1191
  /**
1192
   * Verify that a replication task is authorized by comparing the target node's
1193
   * Subject (from the X.509 certificate-derived Session) with the list of 
1194
   * subjects in the known, pending replication tasks map.
1195
   * 
1196
   * @param originatingNodeSession - Session information that contains the 
1197
   *                                 identity of the calling user
1198
   * @param targetNodeSubject - Subject identifying the target node
1199
   * @param pid - the identifier of the object to be replicated
1200
   * @param replicatePermission - the execute permission to be granted
1201
   * 
1202
   * @throws ServiceFailure
1203
   * @throws NotImplemented
1204
   * @throws InvalidToken
1205
   * @throws NotAuthorized
1206
   * @throws InvalidRequest
1207
   * @throws NotFound
1208
   */
1209
  @Override
1210
  public boolean isNodeAuthorized(Session originatingNodeSession, 
1211
    Subject targetNodeSubject, Identifier pid) 
1212
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure, 
1213
    NotFound, InvalidRequest {
1214
    
1215
    boolean isAllowed = false;
1216
    SystemMetadata sysmeta = null;
1217
    NodeReference targetNode = null;
1218
    
1219
    try {
1220
      // get the target node reference from the nodes list
1221
      CNode cn = D1Client.getCN();
1222
      List<Node> nodes = cn.listNodes().getNodeList();
1223
      
1224
      if ( nodes != null ) {
1225
        for (Node node : nodes) {
1226
            
1227
        	if (node.getSubjectList() != null) {
1228
        		
1229
	            for (Subject nodeSubject : node.getSubjectList()) {
1230
	            	
1231
	                if ( nodeSubject.equals(targetNodeSubject) ) {
1232
	                    targetNode = node.getIdentifier();
1233
	                    logMetacat.debug("targetNode is : " + targetNode.getValue());
1234
	                    break;
1235
	                }
1236
	            }
1237
        	}
1238
            
1239
            if ( targetNode != null) { break; }
1240
        }
1241
        
1242
      } else {
1243
          String msg = "Couldn't get the node list from the CN";
1244
          logMetacat.debug(msg);
1245
          throw new ServiceFailure("4872", msg);
1246
          
1247
      }
1248
      
1249
      // can't find a node listed with the given subject
1250
      if ( targetNode == null ) {
1251
          String msg = "There is no Member Node registered with a node subject " +
1252
              "matching " + targetNodeSubject.getValue();
1253
          logMetacat.info(msg);
1254
          throw new NotAuthorized("4871", msg);
1255
          
1256
      }
1257
      
1258
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1259
      
1260
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1261

    
1262
      if ( sysmeta != null ) {
1263
          
1264
          List<Replica> replicaList = sysmeta.getReplicaList();
1265
          
1266
          if ( replicaList != null ) {
1267
              
1268
              // find the replica with the status set to 'requested'
1269
              for (Replica replica : replicaList) {
1270
                  ReplicationStatus status = replica.getReplicationStatus();
1271
                  NodeReference listedNode = replica.getReplicaMemberNode();
1272
                  if ( listedNode != null && targetNode != null ) {
1273
                      logMetacat.debug("Comparing " + listedNode.getValue()
1274
                              + " to " + targetNode.getValue());
1275
                      
1276
                      if (listedNode.getValue().equals(targetNode.getValue())
1277
                              && status.equals(ReplicationStatus.REQUESTED)) {
1278
                          isAllowed = true;
1279
                          break;
1280

    
1281
                      }
1282
                  }
1283
              }
1284
          }
1285
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1286
              "to replicate: " + isAllowed + " for " + pid.getValue());
1287

    
1288
          
1289
      } else {
1290
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1291
          " is null.");          
1292
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue());
1293
          
1294
      }
1295

    
1296
    } catch (RuntimeException e) {
1297
    	  ServiceFailure sf = new ServiceFailure("4872", 
1298
                "Runtime Exception: Couldn't determine if node is allowed: " + 
1299
                e.getMessage());
1300
    	  sf.initCause(e);
1301
        throw sf;
1302
        
1303
    }
1304
      
1305
    return isAllowed;
1306
    
1307
  }
1308

    
1309
  /**
1310
   * Adds a new object to the Node, where the object is a science metadata object.
1311
   * 
1312
   * @param session - the Session object containing the credentials for the Subject
1313
   * @param pid - The object identifier to be created
1314
   * @param object - the object bytes
1315
   * @param sysmeta - the system metadata that describes the object  
1316
   * 
1317
   * @return pid - the object identifier created
1318
   * 
1319
   * @throws InvalidToken
1320
   * @throws ServiceFailure
1321
   * @throws NotAuthorized
1322
   * @throws IdentifierNotUnique
1323
   * @throws UnsupportedType
1324
   * @throws InsufficientResources
1325
   * @throws InvalidSystemMetadata
1326
   * @throws NotImplemented
1327
   * @throws InvalidRequest
1328
   */
1329
  public Identifier create(Session session, Identifier pid, InputStream object,
1330
    SystemMetadata sysmeta) 
1331
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
1332
    UnsupportedType, InsufficientResources, InvalidSystemMetadata, 
1333
    NotImplemented, InvalidRequest {
1334
                  
1335
      // The lock to be used for this identifier
1336
      Lock lock = null;
1337

    
1338
      try {
1339
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1340
          // are we allowed?
1341
          boolean isAllowed = false;
1342
          isAllowed = isAdminAuthorized(session);
1343

    
1344
          // proceed if we're called by a CN
1345
          if ( isAllowed ) {
1346
              // create the coordinating node version of the document      
1347
              lock.lock();
1348
              logMetacat.debug("Locked identifier " + pid.getValue());
1349
              sysmeta.setSerialVersion(BigInteger.ONE);
1350
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1351
              sysmeta.setArchived(false); // this is a create op, not update
1352
              
1353
              // the CN should have set the origin and authoritative member node fields
1354
              try {
1355
                  sysmeta.getOriginMemberNode().getValue();
1356
                  sysmeta.getAuthoritativeMemberNode().getValue();
1357
                  
1358
              } catch (NullPointerException npe) {
1359
                  throw new InvalidSystemMetadata("4896", 
1360
                      "Both the origin and authoritative member node identifiers need to be set.");
1361
                  
1362
              }
1363
              pid = super.create(session, pid, object, sysmeta);
1364

    
1365
          } else {
1366
              String msg = "The subject listed as " + session.getSubject().getValue() + 
1367
                  " isn't allowed to call create() on a Coordinating Node.";
1368
              logMetacat.info(msg);
1369
              throw new NotAuthorized("1100", msg);
1370
          }
1371
          
1372
      } catch (RuntimeException e) {
1373
          // Convert Hazelcast runtime exceptions to service failures
1374
          String msg = "There was a problem creating the object identified by " +
1375
              pid.getValue() + ". There error message was: " + e.getMessage();
1376
          throw new ServiceFailure("4893", msg);
1377
          
1378
      } finally {
1379
    	  if (lock != null) {
1380
	          lock.unlock();
1381
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1382
    	  }
1383
      }
1384
      
1385
      return pid;
1386

    
1387
  }
1388

    
1389
  /**
1390
   * Set access for a given object using the object identifier and a Subject
1391
   * under a given Session.
1392
   * 
1393
   * @param session - the Session object containing the credentials for the Subject
1394
   * @param pid - the object identifier for the given object to apply the policy
1395
   * @param policy - the access policy to be applied
1396
   * 
1397
   * @return true if the application of the policy succeeds
1398
   * @throws InvalidToken
1399
   * @throws ServiceFailure
1400
   * @throws NotFound
1401
   * @throws NotAuthorized
1402
   * @throws NotImplemented
1403
   * @throws InvalidRequest
1404
   */
1405
  public boolean setAccessPolicy(Session session, Identifier pid, 
1406
      AccessPolicy accessPolicy, long serialVersion) 
1407
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, 
1408
      NotImplemented, InvalidRequest, VersionMismatch {
1409
      
1410
      // The lock to be used for this identifier
1411
      Lock lock = null;
1412
      SystemMetadata systemMetadata = null;
1413
      
1414
      boolean success = false;
1415
      
1416
      // get the subject
1417
      Subject subject = session.getSubject();
1418
      
1419
      // are we allowed to do this?
1420
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1421
          throw new NotAuthorized("4420", "not allowed by "
1422
                  + subject.getValue() + " on " + pid.getValue());
1423
      }
1424
      
1425
      try {
1426
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1427
          lock.lock();
1428
          logMetacat.debug("Locked identifier " + pid.getValue());
1429

    
1430
          try {
1431
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1432

    
1433
              if ( systemMetadata == null ) {
1434
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1435
                  
1436
              }
1437
              // does the request have the most current system metadata?
1438
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1439
                 String msg = "The requested system metadata version number " + 
1440
                     serialVersion + " differs from the current version at " +
1441
                     systemMetadata.getSerialVersion().longValue() +
1442
                     ". Please get the latest copy in order to modify it.";
1443
                 throw new VersionMismatch("4402", msg);
1444
                 
1445
              }
1446
              
1447
          } catch (RuntimeException e) {
1448
              // convert Hazelcast RuntimeException to NotFound
1449
              throw new NotFound("4400", "No record found for: " + pid);
1450
            
1451
          }
1452
              
1453
          // set the access policy
1454
          systemMetadata.setAccessPolicy(accessPolicy);
1455
          
1456
          // update the system metadata
1457
          try {
1458
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1459
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1460
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1461
              notifyReplicaNodes(systemMetadata);
1462
              
1463
          } catch (RuntimeException e) {
1464
              // convert Hazelcast RuntimeException to ServiceFailure
1465
              throw new ServiceFailure("4430", e.getMessage());
1466
            
1467
          }
1468
          
1469
      } catch (RuntimeException e) {
1470
          throw new ServiceFailure("4430", e.getMessage());
1471
          
1472
      } finally {
1473
          lock.unlock();
1474
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1475
        
1476
      }
1477

    
1478
    
1479
    // TODO: how do we know if the map was persisted?
1480
    success = true;
1481
    
1482
    return success;
1483
  }
1484

    
1485
  /**
1486
   * Full replacement of replication metadata in the system metadata for the 
1487
   * specified object, changes date system metadata modified
1488
   * 
1489
   * @param session - the Session object containing the credentials for the Subject
1490
   * @param pid - the object identifier for the given object to apply the policy
1491
   * @param replica - the replica to be updated
1492
   * @return
1493
   * @throws NotImplemented
1494
   * @throws NotAuthorized
1495
   * @throws ServiceFailure
1496
   * @throws InvalidRequest
1497
   * @throws NotFound
1498
   * @throws VersionMismatch
1499
   */
1500
  @Override
1501
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1502
      Replica replica, long serialVersion) 
1503
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1504
      NotFound, VersionMismatch {
1505
      
1506
      // The lock to be used for this identifier
1507
      Lock lock = null;
1508
      
1509
      // get the subject
1510
      Subject subject = session.getSubject();
1511
      
1512
      // are we allowed to do this?
1513
      try {
1514

    
1515
          // what is the controlling permission?
1516
          if (!isAuthorized(session, pid, Permission.WRITE)) {
1517
              throw new NotAuthorized("4851", "not allowed by "
1518
                      + subject.getValue() + " on " + pid.getValue());
1519
          }
1520

    
1521
        
1522
      } catch (InvalidToken e) {
1523
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() + 
1524
                  " on " + pid.getValue());  
1525
          
1526
      }
1527

    
1528
      SystemMetadata systemMetadata = null;
1529
      try {
1530
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1531
          lock.lock();
1532
          logMetacat.debug("Locked identifier " + pid.getValue());
1533

    
1534
          try {      
1535
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1536

    
1537
              // does the request have the most current system metadata?
1538
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1539
                 String msg = "The requested system metadata version number " + 
1540
                     serialVersion + " differs from the current version at " +
1541
                     systemMetadata.getSerialVersion().longValue() +
1542
                     ". Please get the latest copy in order to modify it.";
1543
                 throw new VersionMismatch("4855", msg);
1544
              }
1545
              
1546
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1547
              throw new NotFound("4854", "No record found for: " + pid.getValue() +
1548
                  " : " + e.getMessage());
1549
            
1550
          }
1551
              
1552
          // set the status for the replica
1553
          List<Replica> replicas = systemMetadata.getReplicaList();
1554
          NodeReference replicaNode = replica.getReplicaMemberNode();
1555
          ReplicationStatus replicaStatus = replica.getReplicationStatus();
1556
          int index = 0;
1557
          for (Replica listedReplica: replicas) {
1558
              
1559
              // remove the replica that we are replacing
1560
              if ( replicaNode.getValue().equals(listedReplica.getReplicaMemberNode().getValue())) {
1561
                      // don't allow status to change from COMPLETED to anything other
1562
                      // than INVALIDATED: prevents overwrites from race conditions
1563
                	  if ( listedReplica.getReplicationStatus() == ReplicationStatus.COMPLETED &&
1564
            		    replicaStatus != ReplicationStatus.INVALIDATED ) {
1565
                	  throw new InvalidRequest("4853", "Status state change from " +
1566
                			  listedReplica.getReplicationStatus() + " to " +
1567
                			  replicaStatus.toString() + "is prohibited for identifier " +
1568
                			  pid.getValue() + " and target node " + 
1569
                			  listedReplica.getReplicaMemberNode().getValue());
1570

    
1571
            	  }
1572
                  replicas.remove(index);
1573
                  break;
1574
                  
1575
              }
1576
              index++;
1577
          }
1578
          
1579
          // add the new replica item
1580
          replicas.add(replica);
1581
          systemMetadata.setReplicaList(replicas);
1582
          
1583
          // update the metadata
1584
          try {
1585
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1586
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1587
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1588
            
1589
          } catch (RuntimeException e) {
1590
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1591
              throw new ServiceFailure("4852", e.getMessage());
1592
          
1593
          }
1594
          
1595
      } catch (RuntimeException e) {
1596
          logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1597
          throw new ServiceFailure("4852", e.getMessage());
1598
      
1599
      } finally {
1600
          lock.unlock();
1601
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1602
          
1603
      }
1604
    
1605
      return true;
1606
      
1607
  }
1608
  
1609
  /**
1610
   * 
1611
   */
1612
  @Override
1613
  public ObjectList listObjects(Session session, Date startTime, 
1614
      Date endTime, ObjectFormatIdentifier formatid, Boolean replicaStatus,
1615
      Integer start, Integer count)
1616
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1617
      ServiceFailure {
1618
      
1619
      ObjectList objectList = null;
1620
        try {
1621
            objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, formatid, replicaStatus, start, count);
1622
        } catch (Exception e) {
1623
            throw new ServiceFailure("1580", "Error querying system metadata: " + e.getMessage());
1624
        }
1625

    
1626
        return objectList;
1627
  }
1628

    
1629
  
1630
 	/**
1631
 	 * Returns a list of checksum algorithms that are supported by DataONE.
1632
 	 * @return cal  the list of checksum algorithms
1633
 	 * 
1634
 	 * @throws ServiceFailure
1635
 	 * @throws NotImplemented
1636
 	 */
1637
  @Override
1638
  public ChecksumAlgorithmList listChecksumAlgorithms()
1639
			throws ServiceFailure, NotImplemented {
1640
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
1641
		cal.addAlgorithm("MD5");
1642
		cal.addAlgorithm("SHA-1");
1643
		return cal;
1644
		
1645
	}
1646

    
1647
  /**
1648
   * Notify replica Member Nodes of system metadata changes for a given pid
1649
   * 
1650
   * @param currentSystemMetadata - the up to date system metadata
1651
   */
1652
  public void notifyReplicaNodes(SystemMetadata currentSystemMetadata) {
1653
      
1654
      Session session = null;
1655
      List<Replica> replicaList = currentSystemMetadata.getReplicaList();
1656
      MNode mn = null;
1657
      NodeReference replicaNodeRef = null;
1658
      CNode cn = null;
1659
      NodeType nodeType = null;
1660
      List<Node> nodeList = null;
1661
      
1662
      try {
1663
          cn = D1Client.getCN();
1664
          nodeList = cn.listNodes().getNodeList();
1665
          
1666
      } catch (Exception e) { // handle BaseException and other I/O issues
1667
          
1668
          // swallow errors since the call is not critical
1669
          logMetacat.error("Can't inform MNs of system metadata changes due " +
1670
              "to communication issues with the CN: " + e.getMessage());
1671
          
1672
      }
1673
      
1674
      if ( replicaList != null ) {
1675
          
1676
          // iterate through the replicas and inform  MN replica nodes
1677
          for (Replica replica : replicaList) {
1678
              
1679
              replicaNodeRef = replica.getReplicaMemberNode();
1680
              try {
1681
                  if (nodeList != null) {
1682
                      // find the node type
1683
                      for (Node node : nodeList) {
1684
                          if (node.getIdentifier().getValue() == 
1685
                              replicaNodeRef.getValue()) {
1686
                              nodeType = node.getType();
1687
                              break;
1688
              
1689
                          }
1690
                      }
1691
                  }
1692
              
1693
                  // notify only MNs
1694
                  if (nodeType != null && nodeType == NodeType.MN) {
1695
                      mn = D1Client.getMN(replicaNodeRef);
1696
                      mn.systemMetadataChanged(session, 
1697
                          currentSystemMetadata.getIdentifier(), 
1698
                          currentSystemMetadata.getSerialVersion().longValue(),
1699
                          currentSystemMetadata.getDateSysMetadataModified());
1700
                  }
1701
              
1702
              } catch (Exception e) { // handle BaseException and other I/O issues
1703
              
1704
                  // swallow errors since the call is not critical
1705
                  logMetacat.error("Can't inform "
1706
                          + replicaNodeRef.getValue()
1707
                          + " of system metadata changes due "
1708
                          + "to communication issues with the CN: "
1709
                          + e.getMessage());
1710
              
1711
              }
1712
          }
1713
      }
1714
  }
1715

    
1716
	@Override
1717
	public boolean isAuthorized(Identifier pid, Permission permission)
1718
			throws ServiceFailure, InvalidToken, NotFound, NotAuthorized,
1719
			NotImplemented, InvalidRequest {
1720
		
1721
		return isAuthorized(null, pid, permission);
1722
	}
1723
	
1724
	@Override
1725
	public boolean setAccessPolicy(Identifier pid, AccessPolicy accessPolicy, long serialVersion)
1726
			throws InvalidToken, NotFound, NotImplemented, NotAuthorized,
1727
			ServiceFailure, InvalidRequest, VersionMismatch {
1728
		
1729
		return setAccessPolicy(null, pid, accessPolicy, serialVersion);
1730
	}
1731
	
1732
	@Override
1733
	public Identifier setRightsHolder(Identifier pid, Subject userId, long serialVersion)
1734
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1735
			NotImplemented, InvalidRequest, VersionMismatch {
1736
		
1737
		return setRightsHolder(null, pid, userId, serialVersion);
1738
	}
1739
	
1740
	@Override
1741
	public Identifier create(Identifier pid, InputStream object, SystemMetadata sysmeta)
1742
			throws InvalidToken, ServiceFailure, NotAuthorized,
1743
			IdentifierNotUnique, UnsupportedType, InsufficientResources,
1744
			InvalidSystemMetadata, NotImplemented, InvalidRequest {
1745

    
1746
		return create(null, pid, object, sysmeta);
1747
	}
1748
	
1749
	@Override
1750
	public Identifier delete(Identifier pid) throws InvalidToken, ServiceFailure,
1751
			NotAuthorized, NotFound, NotImplemented {
1752

    
1753
		return delete(null, pid);
1754
	}
1755
	
1756
	@Override
1757
	public Identifier generateIdentifier(String scheme, String fragment)
1758
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
1759
			InvalidRequest {
1760

    
1761
		return generateIdentifier(null, scheme, fragment);
1762
	}
1763
	
1764
	@Override
1765
	public Log getLogRecords(Date fromDate, Date toDate, Event event, String pidFilter,
1766
			Integer start, Integer count) throws InvalidToken, InvalidRequest,
1767
			ServiceFailure, NotAuthorized, NotImplemented, InsufficientResources {
1768

    
1769
		return getLogRecords(null, fromDate, toDate, event, pidFilter, start, count);
1770
	}
1771
	
1772
	@Override
1773
	public boolean hasReservation(Subject subject, Identifier pid)
1774
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1775
			NotImplemented, InvalidRequest, IdentifierNotUnique {
1776

    
1777
		return hasReservation(null, subject, pid);
1778
	}
1779
	
1780
	@Override
1781
	public Identifier registerSystemMetadata(Identifier pid, SystemMetadata sysmeta)
1782
			throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1783
			InvalidSystemMetadata, InvalidToken {
1784

    
1785
		return registerSystemMetadata(null, pid, sysmeta);
1786
	}
1787
	
1788
	@Override
1789
	public Identifier reserveIdentifier(Identifier pid) throws InvalidToken,
1790
			ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented,
1791
			InvalidRequest {
1792

    
1793
		return reserveIdentifier(null, pid);
1794
	}
1795
	
1796
	@Override
1797
	public boolean setObsoletedBy(Identifier pid, Identifier obsoletedByPid, long serialVersion)
1798
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1799
			InvalidRequest, InvalidToken, VersionMismatch {
1800

    
1801
		return setObsoletedBy(null, pid, obsoletedByPid, serialVersion);
1802
	}
1803
	
1804
	@Override
1805
	public DescribeResponse describe(Identifier pid) throws InvalidToken,
1806
			NotAuthorized, NotImplemented, ServiceFailure, NotFound {
1807

    
1808
		return describe(null, pid);
1809
	}
1810
	
1811
	@Override
1812
	public InputStream get(Identifier pid) throws InvalidToken, ServiceFailure,
1813
			NotAuthorized, NotFound, NotImplemented {
1814

    
1815
		return get(null, pid);
1816
	}
1817
	
1818
	@Override
1819
	public Checksum getChecksum(Identifier pid) throws InvalidToken,
1820
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1821

    
1822
		return getChecksum(null, pid);
1823
	}
1824
	
1825
	@Override
1826
	public SystemMetadata getSystemMetadata(Identifier pid) throws InvalidToken,
1827
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1828

    
1829
		return getSystemMetadata(null, pid);
1830
	}
1831
	
1832
	@Override
1833
	public ObjectList listObjects(Date startTime, Date endTime,
1834
			ObjectFormatIdentifier formatid, Boolean replicaStatus, Integer start, Integer count)
1835
			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1836
			ServiceFailure {
1837

    
1838
		return listObjects(null, startTime, endTime, formatid, replicaStatus, start, count);
1839
	}
1840
	
1841
	@Override
1842
	public ObjectLocationList resolve(Identifier pid) throws InvalidToken,
1843
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1844

    
1845
		return resolve(null, pid);
1846
	}
1847
	
1848
	@Override
1849
	public ObjectList search(String queryType, String query) throws InvalidToken,
1850
			ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented {
1851

    
1852
		return search(null, queryType, query);
1853
	}
1854
	
1855
	@Override
1856
	public boolean deleteReplicationMetadata(Identifier pid, NodeReference nodeId,
1857
			long serialVersion) throws InvalidToken, InvalidRequest, ServiceFailure,
1858
			NotAuthorized, NotFound, NotImplemented, VersionMismatch {
1859

    
1860
		return deleteReplicationMetadata(null, pid, nodeId, serialVersion);
1861
	}
1862
	
1863
	@Override
1864
	public boolean isNodeAuthorized(Subject targetNodeSubject, Identifier pid)
1865
			throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
1866
			NotFound, InvalidRequest {
1867

    
1868
		return isNodeAuthorized(null, targetNodeSubject, pid);
1869
	}
1870
	
1871
	@Override
1872
	public boolean setReplicationPolicy(Identifier pid, ReplicationPolicy policy,
1873
			long serialVersion) throws NotImplemented, NotFound, NotAuthorized,
1874
			ServiceFailure, InvalidRequest, InvalidToken, VersionMismatch {
1875

    
1876
		return setReplicationPolicy(null, pid, policy, serialVersion);
1877
	}
1878
	
1879
	@Override
1880
	public boolean setReplicationStatus(Identifier pid, NodeReference targetNode,
1881
			ReplicationStatus status, BaseException failure) throws ServiceFailure,
1882
			NotImplemented, InvalidToken, NotAuthorized, InvalidRequest, NotFound {
1883

    
1884
		return setReplicationStatus(null, pid, targetNode, status, failure);
1885
	}
1886
	
1887
	@Override
1888
	public boolean updateReplicationMetadata(Identifier pid, Replica replica,
1889
			long serialVersion) throws NotImplemented, NotAuthorized, ServiceFailure,
1890
			NotFound, InvalidRequest, InvalidToken, VersionMismatch {
1891

    
1892
		return updateReplicationMetadata(null, pid, replica, serialVersion);
1893
	}
1894
}
(1-1/5)