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
			    // notify the replicas
549
				notifyReplicaNodes(sysMeta);
550
				  
551
			  } else {
552
				  throw new ServiceFailure("4972", "Couldn't archive the object " + pid.getValue() +
553
					  ". Couldn't obtain the system metadata record.");
554
				  
555
			  }
556
			  
557
		  } catch (RuntimeException re) {
558
			  throw new ServiceFailure("4972", "Couldn't archive " + pid.getValue() + 
559
				  ". The error message was: " + re.getMessage());
560
			  
561
		  } finally {
562
			  lock.unlock();
563
			  logMetacat.debug("Unlocked identifier " + pid.getValue());
564

    
565
		  }
566

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

    
572
      }
573

    
574
	  return pid;
575
      
576
  }
577
  
578
  /**
579
   * Set the obsoletedBy attribute in System Metadata
580
   * @param session
581
   * @param pid
582
   * @param obsoletedByPid
583
   * @param serialVersion
584
   * @return
585
   * @throws NotImplemented
586
   * @throws NotFound
587
   * @throws NotAuthorized
588
   * @throws ServiceFailure
589
   * @throws InvalidRequest
590
   * @throws InvalidToken
591
   * @throws VersionMismatch
592
   */
593
  @Override
594
  public boolean setObsoletedBy(Session session, Identifier pid,
595
			Identifier obsoletedByPid, long serialVersion)
596
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
597
			InvalidRequest, InvalidToken, VersionMismatch {
598

    
599
		// The lock to be used for this identifier
600
		Lock lock = null;
601

    
602
		// get the subject
603
		Subject subject = session.getSubject();
604

    
605
		// are we allowed to do this?
606
		if (!isAuthorized(session, pid, Permission.WRITE)) {
607
			throw new NotAuthorized("4881", Permission.WRITE
608
					+ " not allowed by " + subject.getValue() + " on "
609
					+ pid.getValue());
610

    
611
		}
612

    
613

    
614
		SystemMetadata systemMetadata = null;
615
		try {
616
			lock = HazelcastService.getInstance().getLock(pid.getValue());
617
			lock.lock();
618
			logMetacat.debug("Locked identifier " + pid.getValue());
619

    
620
			try {
621
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
622
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
623
				}
624

    
625
				// did we get it correctly?
626
				if (systemMetadata == null) {
627
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
628
				}
629

    
630
				// does the request have the most current system metadata?
631
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
632
					String msg = "The requested system metadata version number "
633
							+ serialVersion
634
							+ " differs from the current version at "
635
							+ systemMetadata.getSerialVersion().longValue()
636
							+ ". Please get the latest copy in order to modify it.";
637
					throw new VersionMismatch("4886", msg);
638

    
639
				}
640

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

    
644
			}
645

    
646
			// set the new policy
647
			systemMetadata.setObsoletedBy(obsoletedByPid);
648

    
649
			// update the metadata
650
			try {
651
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
652
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
653
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
654
			} catch (RuntimeException e) {
655
				throw new ServiceFailure("4882", e.getMessage());
656
			}
657

    
658
		} catch (RuntimeException e) {
659
			throw new ServiceFailure("4882", e.getMessage());
660
		} finally {
661
			lock.unlock();
662
			logMetacat.debug("Unlocked identifier " + pid.getValue());
663
		}
664

    
665
		return true;
666
	}
667
  
668
  
669
  /**
670
   * Set the replication status for an object given the object identifier
671
   * 
672
   * @param session - the Session object containing the credentials for the Subject
673
   * @param pid - the object identifier for the given object
674
   * @param status - the replication status to be applied
675
   * 
676
   * @return true or false
677
   * 
678
   * @throws NotImplemented
679
   * @throws NotAuthorized
680
   * @throws ServiceFailure
681
   * @throws InvalidRequest
682
   * @throws InvalidToken
683
   * @throws NotFound
684
   * 
685
   */
686
  @Override
687
  public boolean setReplicationStatus(Session session, Identifier pid,
688
      NodeReference targetNode, ReplicationStatus status, BaseException failure) 
689
      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
690
      InvalidRequest, NotFound {
691
	  
692
	  // cannot be called by public
693
	  if (session == null) {
694
		  throw new NotAuthorized("4720", "Session cannot be null");
695
	  }
696
      
697
      // The lock to be used for this identifier
698
      Lock lock = null;
699
      
700
      boolean allowed = false;
701
      int replicaEntryIndex = -1;
702
      List<Replica> replicas = null;
703
      // get the subject
704
      Subject subject = session.getSubject();
705
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
706
          " is " + status.toString());
707
      
708
      SystemMetadata systemMetadata = null;
709

    
710
      try {
711
          lock = HazelcastService.getInstance().getLock(pid.getValue());
712
          lock.lock();
713
          logMetacat.debug("Locked identifier " + pid.getValue());
714

    
715
          try {      
716
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
717

    
718
              // did we get it correctly?
719
              if ( systemMetadata == null ) {
720
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
721
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
722
                  
723
              }
724
              replicas = systemMetadata.getReplicaList();
725
              int count = 0;
726
              
727
              // was there a failure? log it
728
              if ( failure != null && status.equals(ReplicationStatus.FAILED) ) {
729
                 String msg = "The replication request of the object identified by " + 
730
                     pid.getValue() + " failed.  The error message was " +
731
                     failure.getMessage() + ".";
732
              }
733
              
734
              if (replicas.size() > 0 && replicas != null) {
735
                  // find the target replica index in the replica list
736
                  for (Replica replica : replicas) {
737
                      String replicaNodeStr = replica.getReplicaMemberNode().getValue();
738
                      String targetNodeStr = targetNode.getValue();
739
                      logMetacat.debug("Comparing " + replicaNodeStr + " to " + targetNodeStr);
740
                  
741
                      if (replicaNodeStr.equals(targetNodeStr)) {
742
                          replicaEntryIndex = count;
743
                          logMetacat.debug("replica entry index is: "
744
                                  + replicaEntryIndex);
745
                          break;
746
                      }
747
                      count++;
748
                  
749
                  }
750
              }
751
              // are we allowed to do this? only CNs and target MNs are allowed
752
              CNode cn = D1Client.getCN();
753
              List<Node> nodes = cn.listNodes().getNodeList();
754
              
755
              // find the node in the node list
756
              for ( Node node : nodes ) {
757
                  
758
                  NodeReference nodeReference = node.getIdentifier();
759
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " + 
760
                      nodeReference.getValue());
761
                  
762
                  // allow target MN certs
763
                  if ( targetNode.getValue().equals(nodeReference.getValue() ) &&
764
                      node.getType().equals(NodeType.MN)) {
765
                      List<Subject> nodeSubjects = node.getSubjectList();
766
                      
767
                      // check if the session subject is in the node subject list
768
                      for (Subject nodeSubject : nodeSubjects) {
769
                          logMetacat.debug("In setReplicationStatus(), comparing subjects: " +
770
                                  nodeSubject.getValue() + " and " + subject.getValue());
771
                          if ( nodeSubject.equals(subject) ) { // subject of session == target node subject
772
                              
773
                              // lastly limit to COMPLETED, INVALIDATED,
774
                              // and FAILED status updates from MNs only
775
                              if ( status.equals(ReplicationStatus.COMPLETED) ||
776
                                   status.equals(ReplicationStatus.INVALIDATED) ||
777
                                   status.equals(ReplicationStatus.FAILED)) {
778
                                  allowed = true;
779
                                  break;
780
                                  
781
                              }                              
782
                          }
783
                      }                 
784
                  }
785
              }
786

    
787
              if ( !allowed ) {
788
                  //check for CN admin access
789
                  allowed = isAuthorized(session, pid, Permission.WRITE);
790
                  
791
              }              
792
              
793
              if ( !allowed ) {
794
                  String msg = "The subject identified by "
795
                          + subject.getValue()
796
                          + " does not have permission to set the replication status for "
797
                          + "the replica identified by "
798
                          + targetNode.getValue() + ".";
799
                  logMetacat.info(msg);
800
                  throw new NotAuthorized("4720", msg);
801
                  
802
              }
803

    
804
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
805
            throw new NotFound("4740", "No record found for: " + pid.getValue() +
806
                " : " + e.getMessage());
807
            
808
          }
809
          
810
          Replica targetReplica = new Replica();
811
          // set the status for the replica
812
          if ( replicaEntryIndex != -1 ) {
813
              targetReplica = replicas.get(replicaEntryIndex);
814
              
815
              // don't allow status to change from COMPLETED to anything other
816
              // than INVALIDATED: prevents overwrites from race conditions
817
              if ( targetReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
818
            	   !status.equals(ReplicationStatus.INVALIDATED)) {
819
            	  throw new InvalidRequest("4730", "Status state change from " +
820
            			  targetReplica.getReplicationStatus() + " to " +
821
            			  status.toString() + "is prohibited for identifier " +
822
            			  pid.getValue() + " and target node " + 
823
            			  targetReplica.getReplicaMemberNode().getValue());
824
              }
825
              
826
              targetReplica.setReplicationStatus(status);
827
              
828
              logMetacat.debug("Set the replication status for " + 
829
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
830
                  targetReplica.getReplicationStatus() + " for identifier " +
831
                  pid.getValue());
832
              
833
          } else {
834
              // this is a new entry, create it
835
              targetReplica.setReplicaMemberNode(targetNode);
836
              targetReplica.setReplicationStatus(status);
837
              targetReplica.setReplicaVerified(Calendar.getInstance().getTime());
838
              replicas.add(targetReplica);
839
              
840
          }
841
          
842
          systemMetadata.setReplicaList(replicas);
843
                
844
          // update the metadata
845
          try {
846
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
847
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
848
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
849

    
850
              if ( !status.equals(ReplicationStatus.QUEUED) && 
851
            	   !status.equals(ReplicationStatus.REQUESTED)) {
852
                  
853
                logMetacat.trace("METRICS:\tREPLICATION:\tEND REQUEST:\tPID:\t" + pid.getValue() + 
854
                          "\tNODE:\t" + targetNode.getValue() + 
855
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
856
                
857
                logMetacat.trace("METRICS:\tREPLICATION:\t" + status.toString().toUpperCase() +
858
                          "\tPID:\t"  + pid.getValue() + 
859
                          "\tNODE:\t" + targetNode.getValue() + 
860
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
861
              }
862

    
863
              if ( status.equals(ReplicationStatus.FAILED) && failure != null ) {
864
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
865
                      " on target node " + targetNode + ". The exception was: " +
866
                      failure.getMessage());
867
              }
868
              
869
			  // update the replica nodes about the completed replica when complete
870
              if (status.equals(ReplicationStatus.COMPLETED)) {
871
				notifyReplicaNodes(systemMetadata);
872
			}
873
          
874
          } catch (RuntimeException e) {
875
              throw new ServiceFailure("4700", e.getMessage());
876
          
877
          }
878
          
879
    } catch (RuntimeException e) {
880
        String msg = "There was a RuntimeException getting the lock for " +
881
            pid.getValue();
882
        logMetacat.info(msg);
883
        
884
    } finally {
885
        lock.unlock();
886
        logMetacat.debug("Unlocked identifier " + pid.getValue());
887
        
888
    }
889
      
890
      return true;
891
  }
892
  
893
/**
894
   * Return the checksum of the object given the identifier 
895
   * 
896
   * @param session - the Session object containing the credentials for the Subject
897
   * @param pid - the object identifier for the given object
898
   * 
899
   * @return checksum - the checksum of the object
900
   * 
901
   * @throws InvalidToken
902
   * @throws ServiceFailure
903
   * @throws NotAuthorized
904
   * @throws NotFound
905
   * @throws NotImplemented
906
   */
907
  @Override
908
  public Checksum getChecksum(Session session, Identifier pid)
909
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
910
    NotImplemented {
911
    
912
	boolean isAuthorized = false;
913
	try {
914
		isAuthorized = isAuthorized(session, pid, Permission.READ);
915
	} catch (InvalidRequest e) {
916
		throw new ServiceFailure("1410", e.getDescription());
917
	}  
918
    if (!isAuthorized) {
919
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());  
920
    }
921
    
922
    SystemMetadata systemMetadata = null;
923
    Checksum checksum = null;
924
    
925
    try {
926
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);        
927

    
928
        if (systemMetadata == null ) {
929
            throw new NotFound("1420", "Couldn't find an object identified by " + pid.getValue());
930
        }
931
        checksum = systemMetadata.getChecksum();
932
        
933
    } catch (RuntimeException e) {
934
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " + 
935
            pid.getValue() + ". The error message was: " + e.getMessage());
936
      
937
    }
938
    
939
    return checksum;
940
  }
941

    
942
  /**
943
   * Resolve the location of a given object
944
   * 
945
   * @param session - the Session object containing the credentials for the Subject
946
   * @param pid - the object identifier for the given object
947
   * 
948
   * @return objectLocationList - the list of nodes known to contain the object
949
   * 
950
   * @throws InvalidToken
951
   * @throws ServiceFailure
952
   * @throws NotAuthorized
953
   * @throws NotFound
954
   * @throws NotImplemented
955
   */
956
  @Override
957
  public ObjectLocationList resolve(Session session, Identifier pid)
958
    throws InvalidToken, ServiceFailure, NotAuthorized,
959
    NotFound, NotImplemented {
960

    
961
    throw new NotImplemented("4131", "resolve not implemented");
962

    
963
  }
964

    
965
  /**
966
   * Metacat does not implement this method at the CN level
967
   */
968
  @Override
969
  public ObjectList search(Session session, String queryType, String query)
970
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
971
    NotImplemented {
972

    
973
		  throw new NotImplemented("4281", "Metacat does not implement CN.search");
974
	  
975
//    ObjectList objectList = null;
976
//    try {
977
//        objectList = 
978
//          IdentifierManager.getInstance().querySystemMetadata(
979
//              null, //startTime, 
980
//              null, //endTime,
981
//              null, //objectFormat, 
982
//              false, //replicaStatus, 
983
//              0, //start, 
984
//              1000 //count
985
//              );
986
//        
987
//    } catch (Exception e) {
988
//      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
989
//    }
990
//
991
//      return objectList;
992
		  
993
  }
994
  
995
  /**
996
   * Returns the object format registered in the DataONE Object Format 
997
   * Vocabulary for the given format identifier
998
   * 
999
   * @param fmtid - the identifier of the format requested
1000
   * 
1001
   * @return objectFormat - the object format requested
1002
   * 
1003
   * @throws ServiceFailure
1004
   * @throws NotFound
1005
   * @throws InsufficientResources
1006
   * @throws NotImplemented
1007
   */
1008
  @Override
1009
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
1010
    throws ServiceFailure, NotFound, NotImplemented {
1011
     
1012
      return ObjectFormatService.getInstance().getFormat(fmtid);
1013
      
1014
  }
1015

    
1016
  /**
1017
   * Returns a list of all object formats registered in the DataONE Object 
1018
   * Format Vocabulary
1019
    * 
1020
   * @return objectFormatList - The list of object formats registered in 
1021
   *                            the DataONE Object Format Vocabulary
1022
   * 
1023
   * @throws ServiceFailure
1024
   * @throws NotImplemented
1025
   * @throws InsufficientResources
1026
   */
1027
  @Override
1028
  public ObjectFormatList listFormats() 
1029
    throws ServiceFailure, NotImplemented {
1030

    
1031
    return ObjectFormatService.getInstance().listFormats();
1032
  }
1033

    
1034
  /**
1035
   * Returns a list of nodes that have been registered with the DataONE infrastructure
1036
    * 
1037
   * @return nodeList - List of nodes from the registry
1038
   * 
1039
   * @throws ServiceFailure
1040
   * @throws NotImplemented
1041
   */
1042
  @Override
1043
  public NodeList listNodes() 
1044
    throws NotImplemented, ServiceFailure {
1045

    
1046
    throw new NotImplemented("4800", "listNodes not implemented");
1047
  }
1048

    
1049
  /**
1050
   * Provides a mechanism for adding system metadata independently of its 
1051
   * associated object, such as when adding system metadata for data objects.
1052
    * 
1053
   * @param session - the Session object containing the credentials for the Subject
1054
   * @param pid - The identifier of the object to register the system metadata against
1055
   * @param sysmeta - The system metadata to be registered
1056
   * 
1057
   * @return true if the registration succeeds
1058
   * 
1059
   * @throws NotImplemented
1060
   * @throws NotAuthorized
1061
   * @throws ServiceFailure
1062
   * @throws InvalidRequest
1063
   * @throws InvalidSystemMetadata
1064
   */
1065
  @Override
1066
  public Identifier registerSystemMetadata(Session session, Identifier pid,
1067
      SystemMetadata sysmeta) 
1068
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
1069
      InvalidSystemMetadata {
1070

    
1071
      // The lock to be used for this identifier
1072
      Lock lock = null;
1073

    
1074
      // TODO: control who can call this?
1075
      if (session == null) {
1076
          //TODO: many of the thrown exceptions do not use the correct error codes
1077
          //check these against the docs and correct them
1078
          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
1079
                  "  If you are not logged in, please do so and retry the request.");
1080
      }
1081
      
1082
      // verify that guid == SystemMetadata.getIdentifier()
1083
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() + 
1084
          "|" + sysmeta.getIdentifier().getValue());
1085
      if (!pid.getValue().equals(sysmeta.getIdentifier().getValue())) {
1086
          throw new InvalidRequest("4863", 
1087
              "The identifier in method call (" + pid.getValue() + 
1088
              ") does not match identifier in system metadata (" +
1089
              sysmeta.getIdentifier().getValue() + ").");
1090
      }
1091

    
1092
      try {
1093
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
1094
          lock.lock();
1095
          logMetacat.debug("Locked identifier " + pid.getValue());
1096
          logMetacat.debug("Checking if identifier exists...");
1097
          // Check that the identifier does not already exist
1098
          if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
1099
              throw new InvalidRequest("4863", 
1100
                  "The identifier is already in use by an existing object.");
1101
          
1102
          }
1103
          
1104
          // insert the system metadata into the object store
1105
          logMetacat.debug("Starting to insert SystemMetadata...");
1106
          try {
1107
              sysmeta.setSerialVersion(BigInteger.ONE);
1108
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1109
              HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
1110
              
1111
          } catch (RuntimeException e) {
1112
            logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
1113
              throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1114
                  e.getClass() + ": " + e.getMessage());
1115
              
1116
          }
1117
          
1118
      } catch (RuntimeException e) {
1119
          throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1120
                  e.getClass() + ": " + e.getMessage());
1121
          
1122
      }  finally {
1123
          lock.unlock();
1124
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1125
          
1126
      }
1127

    
1128
      
1129
      logMetacat.debug("Returning from registerSystemMetadata");
1130
      
1131
      try {
1132
    	  String localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1133
    	  EventLog.getInstance().log(request.getRemoteAddr(), 
1134
    	          request.getHeader("User-Agent"), session.getSubject().getValue(), 
1135
    	          localId, "registerSystemMetadata");
1136
      } catch (McdbDocNotFoundException e) {
1137
    	  // do nothing, no localId to log with
1138
    	  logMetacat.warn("Could not log 'registerSystemMetadata' event because no localId was found for pid: " + pid.getValue());
1139
      }
1140
      
1141
      
1142
      return pid;
1143
  }
1144
  
1145
  /**
1146
   * Given an optional scope and format, reserves and returns an identifier 
1147
   * within that scope and format that is unique and will not be 
1148
   * used by any other sessions. 
1149
    * 
1150
   * @param session - the Session object containing the credentials for the Subject
1151
   * @param pid - The identifier of the object to register the system metadata against
1152
   * @param scope - An optional string to be used to qualify the scope of 
1153
   *                the identifier namespace, which is applied differently 
1154
   *                depending on the format requested. If scope is not 
1155
   *                supplied, a default scope will be used.
1156
   * @param format - The optional name of the identifier format to be used, 
1157
   *                  drawn from a DataONE-specific vocabulary of identifier 
1158
   *                 format names, including several common syntaxes such 
1159
   *                 as DOI, LSID, UUID, and LSRN, among others. If the 
1160
   *                 format is not supplied by the caller, the CN service 
1161
   *                 will use a default identifier format, which may change 
1162
   *                 over time.
1163
   * 
1164
   * @return true if the registration succeeds
1165
   * 
1166
   * @throws InvalidToken
1167
   * @throws ServiceFailure
1168
   * @throws NotAuthorized
1169
   * @throws IdentifierNotUnique
1170
   * @throws NotImplemented
1171
   */
1172
  @Override
1173
  public Identifier reserveIdentifier(Session session, Identifier pid)
1174
  throws InvalidToken, ServiceFailure,
1175
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
1176

    
1177
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1178
  }
1179
  
1180
  @Override
1181
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1182
  throws InvalidToken, ServiceFailure,
1183
        NotAuthorized, NotImplemented, InvalidRequest {
1184
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
1185
  }
1186
  
1187
  /**
1188
    * Checks whether the pid is reserved by the subject in the session param
1189
    * If the reservation is held on the pid by the subject, we return true.
1190
    * 
1191
   * @param session - the Session object containing the Subject
1192
   * @param pid - The identifier to check
1193
   * 
1194
   * @return true if the reservation exists for the subject/pid
1195
   * 
1196
   * @throws InvalidToken
1197
   * @throws ServiceFailure
1198
   * @throws NotFound - when the pid is not found (in use or in reservation)
1199
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
1200
   * @throws IdentifierNotUnique - when the pid is in use
1201
   * @throws NotImplemented
1202
   */
1203

    
1204
  @Override
1205
  public boolean hasReservation(Session session, Subject subject, Identifier pid) 
1206
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique, 
1207
      NotImplemented, InvalidRequest {
1208
  
1209
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1210
  }
1211

    
1212
  /**
1213
   * Changes ownership (RightsHolder) of the specified object to the 
1214
   * subject specified by userId
1215
    * 
1216
   * @param session - the Session object containing the credentials for the Subject
1217
   * @param pid - Identifier of the object to be modified
1218
   * @param userId - The subject that will be taking ownership of the specified object.
1219
   *
1220
   * @return pid - the identifier of the modified object
1221
   * 
1222
   * @throws ServiceFailure
1223
   * @throws InvalidToken
1224
   * @throws NotFound
1225
   * @throws NotAuthorized
1226
   * @throws NotImplemented
1227
   * @throws InvalidRequest
1228
   */  
1229
  @Override
1230
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1231
      long serialVersion)
1232
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1233
      NotImplemented, InvalidRequest, VersionMismatch {
1234
      
1235
      // The lock to be used for this identifier
1236
      Lock lock = null;
1237

    
1238
      // get the subject
1239
      Subject subject = session.getSubject();
1240
      
1241
      // are we allowed to do this?
1242
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1243
          throw new NotAuthorized("4440", "not allowed by "
1244
                  + subject.getValue() + " on " + pid.getValue());
1245
          
1246
      }
1247
      
1248
      SystemMetadata systemMetadata = null;
1249
      try {
1250
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1251
          lock.lock();
1252
          logMetacat.debug("Locked identifier " + pid.getValue());
1253

    
1254
          try {
1255
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1256
              
1257
              // does the request have the most current system metadata?
1258
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1259
                 String msg = "The requested system metadata version number " + 
1260
                     serialVersion + " differs from the current version at " +
1261
                     systemMetadata.getSerialVersion().longValue() +
1262
                     ". Please get the latest copy in order to modify it.";
1263
                 throw new VersionMismatch("4443", msg);
1264
              }
1265
              
1266
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1267
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1268
              
1269
          }
1270
              
1271
          // set the new rights holder
1272
          systemMetadata.setRightsHolder(userId);
1273
          
1274
          // update the metadata
1275
          try {
1276
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1277
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1278
              HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
1279
              notifyReplicaNodes(systemMetadata);
1280
              
1281
          } catch (RuntimeException e) {
1282
              throw new ServiceFailure("4490", e.getMessage());
1283
          
1284
          }
1285
          
1286
      } catch (RuntimeException e) {
1287
          throw new ServiceFailure("4490", e.getMessage());
1288
          
1289
      } finally {
1290
          lock.unlock();
1291
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1292
      
1293
      }
1294
      
1295
      return pid;
1296
  }
1297

    
1298
  /**
1299
   * Verify that a replication task is authorized by comparing the target node's
1300
   * Subject (from the X.509 certificate-derived Session) with the list of 
1301
   * subjects in the known, pending replication tasks map.
1302
   * 
1303
   * @param originatingNodeSession - Session information that contains the 
1304
   *                                 identity of the calling user
1305
   * @param targetNodeSubject - Subject identifying the target node
1306
   * @param pid - the identifier of the object to be replicated
1307
   * @param replicatePermission - the execute permission to be granted
1308
   * 
1309
   * @throws ServiceFailure
1310
   * @throws NotImplemented
1311
   * @throws InvalidToken
1312
   * @throws NotAuthorized
1313
   * @throws InvalidRequest
1314
   * @throws NotFound
1315
   */
1316
  @Override
1317
  public boolean isNodeAuthorized(Session originatingNodeSession, 
1318
    Subject targetNodeSubject, Identifier pid) 
1319
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure, 
1320
    NotFound, InvalidRequest {
1321
    
1322
    boolean isAllowed = false;
1323
    SystemMetadata sysmeta = null;
1324
    NodeReference targetNode = null;
1325
    
1326
    try {
1327
      // get the target node reference from the nodes list
1328
      CNode cn = D1Client.getCN();
1329
      List<Node> nodes = cn.listNodes().getNodeList();
1330
      
1331
      if ( nodes != null ) {
1332
        for (Node node : nodes) {
1333
            
1334
        	if (node.getSubjectList() != null) {
1335
        		
1336
	            for (Subject nodeSubject : node.getSubjectList()) {
1337
	            	
1338
	                if ( nodeSubject.equals(targetNodeSubject) ) {
1339
	                    targetNode = node.getIdentifier();
1340
	                    logMetacat.debug("targetNode is : " + targetNode.getValue());
1341
	                    break;
1342
	                }
1343
	            }
1344
        	}
1345
            
1346
            if ( targetNode != null) { break; }
1347
        }
1348
        
1349
      } else {
1350
          String msg = "Couldn't get the node list from the CN";
1351
          logMetacat.debug(msg);
1352
          throw new ServiceFailure("4872", msg);
1353
          
1354
      }
1355
      
1356
      // can't find a node listed with the given subject
1357
      if ( targetNode == null ) {
1358
          String msg = "There is no Member Node registered with a node subject " +
1359
              "matching " + targetNodeSubject.getValue();
1360
          logMetacat.info(msg);
1361
          throw new NotAuthorized("4871", msg);
1362
          
1363
      }
1364
      
1365
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1366
      
1367
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1368

    
1369
      if ( sysmeta != null ) {
1370
          
1371
          List<Replica> replicaList = sysmeta.getReplicaList();
1372
          
1373
          if ( replicaList != null ) {
1374
              
1375
              // find the replica with the status set to 'requested'
1376
              for (Replica replica : replicaList) {
1377
                  ReplicationStatus status = replica.getReplicationStatus();
1378
                  NodeReference listedNode = replica.getReplicaMemberNode();
1379
                  if ( listedNode != null && targetNode != null ) {
1380
                      logMetacat.debug("Comparing " + listedNode.getValue()
1381
                              + " to " + targetNode.getValue());
1382
                      
1383
                      if (listedNode.getValue().equals(targetNode.getValue())
1384
                              && status.equals(ReplicationStatus.REQUESTED)) {
1385
                          isAllowed = true;
1386
                          break;
1387

    
1388
                      }
1389
                  }
1390
              }
1391
          }
1392
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1393
              "to replicate: " + isAllowed + " for " + pid.getValue());
1394

    
1395
          
1396
      } else {
1397
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1398
          " is null.");          
1399
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue());
1400
          
1401
      }
1402

    
1403
    } catch (RuntimeException e) {
1404
    	  ServiceFailure sf = new ServiceFailure("4872", 
1405
                "Runtime Exception: Couldn't determine if node is allowed: " + 
1406
                e.getMessage());
1407
    	  sf.initCause(e);
1408
        throw sf;
1409
        
1410
    }
1411
      
1412
    return isAllowed;
1413
    
1414
  }
1415

    
1416
  /**
1417
   * Adds a new object to the Node, where the object is a science metadata object.
1418
   * 
1419
   * @param session - the Session object containing the credentials for the Subject
1420
   * @param pid - The object identifier to be created
1421
   * @param object - the object bytes
1422
   * @param sysmeta - the system metadata that describes the object  
1423
   * 
1424
   * @return pid - the object identifier created
1425
   * 
1426
   * @throws InvalidToken
1427
   * @throws ServiceFailure
1428
   * @throws NotAuthorized
1429
   * @throws IdentifierNotUnique
1430
   * @throws UnsupportedType
1431
   * @throws InsufficientResources
1432
   * @throws InvalidSystemMetadata
1433
   * @throws NotImplemented
1434
   * @throws InvalidRequest
1435
   */
1436
  public Identifier create(Session session, Identifier pid, InputStream object,
1437
    SystemMetadata sysmeta) 
1438
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
1439
    UnsupportedType, InsufficientResources, InvalidSystemMetadata, 
1440
    NotImplemented, InvalidRequest {
1441
                  
1442
      // The lock to be used for this identifier
1443
      Lock lock = null;
1444

    
1445
      try {
1446
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1447
          // are we allowed?
1448
          boolean isAllowed = false;
1449
          isAllowed = isAdminAuthorized(session);
1450
          
1451
          // additional check if it is the authoritative node if it is not the admin
1452
          if(!isAllowed) {
1453
              isAllowed = isAuthoritativeMNodeAdmin(session, pid);
1454
          }
1455

    
1456
          // proceed if we're called by a CN
1457
          if ( isAllowed ) {
1458
              // create the coordinating node version of the document      
1459
              lock.lock();
1460
              logMetacat.debug("Locked identifier " + pid.getValue());
1461
              sysmeta.setSerialVersion(BigInteger.ONE);
1462
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1463
              sysmeta.setArchived(false); // this is a create op, not update
1464
              
1465
              // the CN should have set the origin and authoritative member node fields
1466
              try {
1467
                  sysmeta.getOriginMemberNode().getValue();
1468
                  sysmeta.getAuthoritativeMemberNode().getValue();
1469
                  
1470
              } catch (NullPointerException npe) {
1471
                  throw new InvalidSystemMetadata("4896", 
1472
                      "Both the origin and authoritative member node identifiers need to be set.");
1473
                  
1474
              }
1475
              pid = super.create(session, pid, object, sysmeta);
1476

    
1477
          } else {
1478
              String msg = "The subject listed as " + session.getSubject().getValue() + 
1479
                  " isn't allowed to call create() on a Coordinating Node.";
1480
              logMetacat.info(msg);
1481
              throw new NotAuthorized("1100", msg);
1482
          }
1483
          
1484
      } catch (RuntimeException e) {
1485
          // Convert Hazelcast runtime exceptions to service failures
1486
          String msg = "There was a problem creating the object identified by " +
1487
              pid.getValue() + ". There error message was: " + e.getMessage();
1488
          throw new ServiceFailure("4893", msg);
1489
          
1490
      } finally {
1491
    	  if (lock != null) {
1492
	          lock.unlock();
1493
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1494
    	  }
1495
      }
1496
      
1497
      return pid;
1498

    
1499
  }
1500

    
1501
  /**
1502
   * Set access for a given object using the object identifier and a Subject
1503
   * under a given Session.
1504
   * 
1505
   * @param session - the Session object containing the credentials for the Subject
1506
   * @param pid - the object identifier for the given object to apply the policy
1507
   * @param policy - the access policy to be applied
1508
   * 
1509
   * @return true if the application of the policy succeeds
1510
   * @throws InvalidToken
1511
   * @throws ServiceFailure
1512
   * @throws NotFound
1513
   * @throws NotAuthorized
1514
   * @throws NotImplemented
1515
   * @throws InvalidRequest
1516
   */
1517
  public boolean setAccessPolicy(Session session, Identifier pid, 
1518
      AccessPolicy accessPolicy, long serialVersion) 
1519
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, 
1520
      NotImplemented, InvalidRequest, VersionMismatch {
1521
      
1522
      // The lock to be used for this identifier
1523
      Lock lock = null;
1524
      SystemMetadata systemMetadata = null;
1525
      
1526
      boolean success = false;
1527
      
1528
      // get the subject
1529
      Subject subject = session.getSubject();
1530
      
1531
      // are we allowed to do this?
1532
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1533
          throw new NotAuthorized("4420", "not allowed by "
1534
                  + subject.getValue() + " on " + pid.getValue());
1535
      }
1536
      
1537
      try {
1538
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1539
          lock.lock();
1540
          logMetacat.debug("Locked identifier " + pid.getValue());
1541

    
1542
          try {
1543
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1544

    
1545
              if ( systemMetadata == null ) {
1546
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1547
                  
1548
              }
1549
              // does the request have the most current system metadata?
1550
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1551
                 String msg = "The requested system metadata version number " + 
1552
                     serialVersion + " differs from the current version at " +
1553
                     systemMetadata.getSerialVersion().longValue() +
1554
                     ". Please get the latest copy in order to modify it.";
1555
                 throw new VersionMismatch("4402", msg);
1556
                 
1557
              }
1558
              
1559
          } catch (RuntimeException e) {
1560
              // convert Hazelcast RuntimeException to NotFound
1561
              throw new NotFound("4400", "No record found for: " + pid);
1562
            
1563
          }
1564
              
1565
          // set the access policy
1566
          systemMetadata.setAccessPolicy(accessPolicy);
1567
          
1568
          // update the system metadata
1569
          try {
1570
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1571
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1572
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1573
              notifyReplicaNodes(systemMetadata);
1574
              
1575
          } catch (RuntimeException e) {
1576
              // convert Hazelcast RuntimeException to ServiceFailure
1577
              throw new ServiceFailure("4430", e.getMessage());
1578
            
1579
          }
1580
          
1581
      } catch (RuntimeException e) {
1582
          throw new ServiceFailure("4430", e.getMessage());
1583
          
1584
      } finally {
1585
          lock.unlock();
1586
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1587
        
1588
      }
1589

    
1590
    
1591
    // TODO: how do we know if the map was persisted?
1592
    success = true;
1593
    
1594
    return success;
1595
  }
1596

    
1597
  /**
1598
   * Full replacement of replication metadata in the system metadata for the 
1599
   * specified object, changes date system metadata modified
1600
   * 
1601
   * @param session - the Session object containing the credentials for the Subject
1602
   * @param pid - the object identifier for the given object to apply the policy
1603
   * @param replica - the replica to be updated
1604
   * @return
1605
   * @throws NotImplemented
1606
   * @throws NotAuthorized
1607
   * @throws ServiceFailure
1608
   * @throws InvalidRequest
1609
   * @throws NotFound
1610
   * @throws VersionMismatch
1611
   */
1612
  @Override
1613
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1614
      Replica replica, long serialVersion) 
1615
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1616
      NotFound, VersionMismatch {
1617
      
1618
      // The lock to be used for this identifier
1619
      Lock lock = null;
1620
      
1621
      // get the subject
1622
      Subject subject = session.getSubject();
1623
      
1624
      // are we allowed to do this?
1625
      try {
1626

    
1627
          // what is the controlling permission?
1628
          if (!isAuthorized(session, pid, Permission.WRITE)) {
1629
              throw new NotAuthorized("4851", "not allowed by "
1630
                      + subject.getValue() + " on " + pid.getValue());
1631
          }
1632

    
1633
        
1634
      } catch (InvalidToken e) {
1635
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() + 
1636
                  " on " + pid.getValue());  
1637
          
1638
      }
1639

    
1640
      SystemMetadata systemMetadata = null;
1641
      try {
1642
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1643
          lock.lock();
1644
          logMetacat.debug("Locked identifier " + pid.getValue());
1645

    
1646
          try {      
1647
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1648

    
1649
              // does the request have the most current system metadata?
1650
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1651
                 String msg = "The requested system metadata version number " + 
1652
                     serialVersion + " differs from the current version at " +
1653
                     systemMetadata.getSerialVersion().longValue() +
1654
                     ". Please get the latest copy in order to modify it.";
1655
                 throw new VersionMismatch("4855", msg);
1656
              }
1657
              
1658
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1659
              throw new NotFound("4854", "No record found for: " + pid.getValue() +
1660
                  " : " + e.getMessage());
1661
            
1662
          }
1663
              
1664
          // set the status for the replica
1665
          List<Replica> replicas = systemMetadata.getReplicaList();
1666
          NodeReference replicaNode = replica.getReplicaMemberNode();
1667
          ReplicationStatus replicaStatus = replica.getReplicationStatus();
1668
          int index = 0;
1669
          for (Replica listedReplica: replicas) {
1670
              
1671
              // remove the replica that we are replacing
1672
              if ( replicaNode.getValue().equals(listedReplica.getReplicaMemberNode().getValue())) {
1673
                      // don't allow status to change from COMPLETED to anything other
1674
                      // than INVALIDATED: prevents overwrites from race conditions
1675
                	  if ( !listedReplica.getReplicationStatus().equals(replicaStatus) && 
1676
                	       listedReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
1677
            		       !replicaStatus.equals(ReplicationStatus.INVALIDATED) ) {
1678
                	  throw new InvalidRequest("4853", "Status state change from " +
1679
                			  listedReplica.getReplicationStatus() + " to " +
1680
                			  replicaStatus.toString() + "is prohibited for identifier " +
1681
                			  pid.getValue() + " and target node " + 
1682
                			  listedReplica.getReplicaMemberNode().getValue());
1683

    
1684
            	  }
1685
                  replicas.remove(index);
1686
                  break;
1687
                  
1688
              }
1689
              index++;
1690
          }
1691
          
1692
          // add the new replica item
1693
          replicas.add(replica);
1694
          systemMetadata.setReplicaList(replicas);
1695
          
1696
          // update the metadata
1697
          try {
1698
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1699
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1700
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1701
              
1702
              // inform replica nodes of the change if the status is complete
1703
              if ( replicaStatus.equals(ReplicationStatus.COMPLETED) ) {
1704
            	  notifyReplicaNodes(systemMetadata);
1705
            	  
1706
              }
1707
          } catch (RuntimeException e) {
1708
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1709
              throw new ServiceFailure("4852", e.getMessage());
1710
          
1711
          }
1712
          
1713
      } catch (RuntimeException e) {
1714
          logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1715
          throw new ServiceFailure("4852", e.getMessage());
1716
      
1717
      } finally {
1718
          lock.unlock();
1719
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1720
          
1721
      }
1722
    
1723
      return true;
1724
      
1725
  }
1726
  
1727
  /**
1728
   * 
1729
   */
1730
  @Override
1731
  public ObjectList listObjects(Session session, Date startTime, 
1732
      Date endTime, ObjectFormatIdentifier formatid, Boolean replicaStatus,
1733
      Integer start, Integer count)
1734
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1735
      ServiceFailure {
1736
      
1737
      ObjectList objectList = null;
1738
        try {
1739
        	if (count == null || count > MAXIMUM_DB_RECORD_COUNT) {
1740
            	count = MAXIMUM_DB_RECORD_COUNT;
1741
            }
1742
            objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, formatid, replicaStatus, start, count);
1743
        } catch (Exception e) {
1744
            throw new ServiceFailure("1580", "Error querying system metadata: " + e.getMessage());
1745
        }
1746

    
1747
        return objectList;
1748
  }
1749

    
1750
  
1751
 	/**
1752
 	 * Returns a list of checksum algorithms that are supported by DataONE.
1753
 	 * @return cal  the list of checksum algorithms
1754
 	 * 
1755
 	 * @throws ServiceFailure
1756
 	 * @throws NotImplemented
1757
 	 */
1758
  @Override
1759
  public ChecksumAlgorithmList listChecksumAlgorithms()
1760
			throws ServiceFailure, NotImplemented {
1761
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
1762
		cal.addAlgorithm("MD5");
1763
		cal.addAlgorithm("SHA-1");
1764
		return cal;
1765
		
1766
	}
1767

    
1768
  /**
1769
   * Notify replica Member Nodes of system metadata changes for a given pid
1770
   * 
1771
   * @param currentSystemMetadata - the up to date system metadata
1772
   */
1773
  public void notifyReplicaNodes(SystemMetadata currentSystemMetadata) {
1774
      
1775
      Session session = null;
1776
      List<Replica> replicaList = currentSystemMetadata.getReplicaList();
1777
      MNode mn = null;
1778
      NodeReference replicaNodeRef = null;
1779
      CNode cn = null;
1780
      NodeType nodeType = null;
1781
      List<Node> nodeList = null;
1782
      
1783
      try {
1784
          cn = D1Client.getCN();
1785
          nodeList = cn.listNodes().getNodeList();
1786
          
1787
      } catch (Exception e) { // handle BaseException and other I/O issues
1788
          
1789
          // swallow errors since the call is not critical
1790
          logMetacat.error("Can't inform MNs of system metadata changes due " +
1791
              "to communication issues with the CN: " + e.getMessage());
1792
          
1793
      }
1794
      
1795
      if ( replicaList != null ) {
1796
          
1797
          // iterate through the replicas and inform  MN replica nodes
1798
          for (Replica replica : replicaList) {
1799
              
1800
              replicaNodeRef = replica.getReplicaMemberNode();
1801
              try {
1802
                  if (nodeList != null) {
1803
                      // find the node type
1804
                      for (Node node : nodeList) {
1805
                          if ( node.getIdentifier().getValue().equals(replicaNodeRef.getValue()) ) {
1806
                              nodeType = node.getType();
1807
                              break;
1808
              
1809
                          }
1810
                      }
1811
                  }
1812
              
1813
                  // notify only MNs
1814
                  if (nodeType != null && nodeType == NodeType.MN) {
1815
                      mn = D1Client.getMN(replicaNodeRef);
1816
                      mn.systemMetadataChanged(session, 
1817
                          currentSystemMetadata.getIdentifier(), 
1818
                          currentSystemMetadata.getSerialVersion().longValue(),
1819
                          currentSystemMetadata.getDateSysMetadataModified());
1820
                  }
1821
              
1822
              } catch (Exception e) { // handle BaseException and other I/O issues
1823
              
1824
                  // swallow errors since the call is not critical
1825
                  logMetacat.error("Can't inform "
1826
                          + replicaNodeRef.getValue()
1827
                          + " of system metadata changes due "
1828
                          + "to communication issues with the CN: "
1829
                          + e.getMessage());
1830
              
1831
              }
1832
          }
1833
      }
1834
  }
1835

    
1836
	@Override
1837
	public boolean isAuthorized(Identifier pid, Permission permission)
1838
			throws ServiceFailure, InvalidToken, NotFound, NotAuthorized,
1839
			NotImplemented, InvalidRequest {
1840
		
1841
		return isAuthorized(null, pid, permission);
1842
	}
1843
	
1844
	@Override
1845
	public boolean setAccessPolicy(Identifier pid, AccessPolicy accessPolicy, long serialVersion)
1846
			throws InvalidToken, NotFound, NotImplemented, NotAuthorized,
1847
			ServiceFailure, InvalidRequest, VersionMismatch {
1848
		
1849
		return setAccessPolicy(null, pid, accessPolicy, serialVersion);
1850
	}
1851
	
1852
	@Override
1853
	public Identifier setRightsHolder(Identifier pid, Subject userId, long serialVersion)
1854
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1855
			NotImplemented, InvalidRequest, VersionMismatch {
1856
		
1857
		return setRightsHolder(null, pid, userId, serialVersion);
1858
	}
1859
	
1860
	@Override
1861
	public Identifier create(Identifier pid, InputStream object, SystemMetadata sysmeta)
1862
			throws InvalidToken, ServiceFailure, NotAuthorized,
1863
			IdentifierNotUnique, UnsupportedType, InsufficientResources,
1864
			InvalidSystemMetadata, NotImplemented, InvalidRequest {
1865

    
1866
		return create(null, pid, object, sysmeta);
1867
	}
1868
	
1869
	@Override
1870
	public Identifier delete(Identifier pid) throws InvalidToken, ServiceFailure,
1871
			NotAuthorized, NotFound, NotImplemented {
1872

    
1873
		return delete(null, pid);
1874
	}
1875
	
1876
	@Override
1877
	public Identifier generateIdentifier(String scheme, String fragment)
1878
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
1879
			InvalidRequest {
1880

    
1881
		return generateIdentifier(null, scheme, fragment);
1882
	}
1883
	
1884
	@Override
1885
	public Log getLogRecords(Date fromDate, Date toDate, Event event, String pidFilter,
1886
			Integer start, Integer count) throws InvalidToken, InvalidRequest,
1887
			ServiceFailure, NotAuthorized, NotImplemented, InsufficientResources {
1888

    
1889
		return getLogRecords(null, fromDate, toDate, event, pidFilter, start, count);
1890
	}
1891
	
1892
	@Override
1893
	public boolean hasReservation(Subject subject, Identifier pid)
1894
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1895
			NotImplemented, InvalidRequest, IdentifierNotUnique {
1896

    
1897
		return hasReservation(null, subject, pid);
1898
	}
1899
	
1900
	@Override
1901
	public Identifier registerSystemMetadata(Identifier pid, SystemMetadata sysmeta)
1902
			throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1903
			InvalidSystemMetadata, InvalidToken {
1904

    
1905
		return registerSystemMetadata(null, pid, sysmeta);
1906
	}
1907
	
1908
	@Override
1909
	public Identifier reserveIdentifier(Identifier pid) throws InvalidToken,
1910
			ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented,
1911
			InvalidRequest {
1912

    
1913
		return reserveIdentifier(null, pid);
1914
	}
1915
	
1916
	@Override
1917
	public boolean setObsoletedBy(Identifier pid, Identifier obsoletedByPid, long serialVersion)
1918
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1919
			InvalidRequest, InvalidToken, VersionMismatch {
1920

    
1921
		return setObsoletedBy(null, pid, obsoletedByPid, serialVersion);
1922
	}
1923
	
1924
	@Override
1925
	public DescribeResponse describe(Identifier pid) throws InvalidToken,
1926
			NotAuthorized, NotImplemented, ServiceFailure, NotFound {
1927

    
1928
		return describe(null, pid);
1929
	}
1930
	
1931
	@Override
1932
	public InputStream get(Identifier pid) throws InvalidToken, ServiceFailure,
1933
			NotAuthorized, NotFound, NotImplemented {
1934

    
1935
		return get(null, pid);
1936
	}
1937
	
1938
	@Override
1939
	public Checksum getChecksum(Identifier pid) throws InvalidToken,
1940
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1941

    
1942
		return getChecksum(null, pid);
1943
	}
1944
	
1945
	@Override
1946
	public SystemMetadata getSystemMetadata(Identifier pid) throws InvalidToken,
1947
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1948

    
1949
		return getSystemMetadata(null, pid);
1950
	}
1951
	
1952
	@Override
1953
	public ObjectList listObjects(Date startTime, Date endTime,
1954
			ObjectFormatIdentifier formatid, Boolean replicaStatus, Integer start, Integer count)
1955
			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1956
			ServiceFailure {
1957

    
1958
		return listObjects(null, startTime, endTime, formatid, replicaStatus, start, count);
1959
	}
1960
	
1961
	@Override
1962
	public ObjectLocationList resolve(Identifier pid) throws InvalidToken,
1963
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1964

    
1965
		return resolve(null, pid);
1966
	}
1967
	
1968
	@Override
1969
	public ObjectList search(String queryType, String query) throws InvalidToken,
1970
			ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented {
1971

    
1972
		return search(null, queryType, query);
1973
	}
1974
	
1975
	@Override
1976
	public boolean deleteReplicationMetadata(Identifier pid, NodeReference nodeId,
1977
			long serialVersion) throws InvalidToken, InvalidRequest, ServiceFailure,
1978
			NotAuthorized, NotFound, NotImplemented, VersionMismatch {
1979

    
1980
		return deleteReplicationMetadata(null, pid, nodeId, serialVersion);
1981
	}
1982
	
1983
	@Override
1984
	public boolean isNodeAuthorized(Subject targetNodeSubject, Identifier pid)
1985
			throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
1986
			NotFound, InvalidRequest {
1987

    
1988
		return isNodeAuthorized(null, targetNodeSubject, pid);
1989
	}
1990
	
1991
	@Override
1992
	public boolean setReplicationPolicy(Identifier pid, ReplicationPolicy policy,
1993
			long serialVersion) throws NotImplemented, NotFound, NotAuthorized,
1994
			ServiceFailure, InvalidRequest, InvalidToken, VersionMismatch {
1995

    
1996
		return setReplicationPolicy(null, pid, policy, serialVersion);
1997
	}
1998
	
1999
	@Override
2000
	public boolean setReplicationStatus(Identifier pid, NodeReference targetNode,
2001
			ReplicationStatus status, BaseException failure) throws ServiceFailure,
2002
			NotImplemented, InvalidToken, NotAuthorized, InvalidRequest, NotFound {
2003

    
2004
		return setReplicationStatus(null, pid, targetNode, status, failure);
2005
	}
2006
	
2007
	@Override
2008
	public boolean updateReplicationMetadata(Identifier pid, Replica replica,
2009
			long serialVersion) throws NotImplemented, NotAuthorized, ServiceFailure,
2010
			NotFound, InvalidRequest, InvalidToken, VersionMismatch {
2011

    
2012
		return updateReplicationMetadata(null, pid, replica, serialVersion);
2013
	}
2014

    
2015
  @Override
2016
  public QueryEngineDescription getQueryEngineDescription(String arg0)
2017
          throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
2018
          NotFound {
2019
      throw new NotImplemented("4410", "getQueryEngineDescription not implemented");
2020
      
2021
  }
2022

    
2023
  @Override
2024
  public QueryEngineList listQueryEngines() throws InvalidToken, ServiceFailure,
2025
          NotAuthorized, NotImplemented {
2026
      throw new NotImplemented("4420", "listQueryEngines not implemented");
2027
      
2028
  }
2029

    
2030
  @Override
2031
  public InputStream query(String arg0, String arg1) throws InvalidToken,
2032
          ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, NotFound {
2033
      throw new NotImplemented("4324", "query not implemented");
2034
      
2035
  }
2036
}
(1-1/7)