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

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

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

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

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

    
414
		  }
415

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

    
421
      }
422

    
423
      
424
	  // notify the replicas
425
	  SystemMetadata systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
426
	  if (systemMetadata.getReplicaList() != null) {
427
		  for (Replica replica: systemMetadata.getReplicaList()) {
428
			  NodeReference replicaNode = replica.getReplicaMemberNode();
429
			  try {
430
				  Identifier mnRetId = D1Client.getMN(replicaNode).delete(null, pid);
431
			  } catch (Exception e) {
432
				  // all we can really do is log errors and carry on with life
433
				  logMetacat.error("Error deleting pid: " +  pid.getValue() + " from replica MN: " + replicaNode.getValue(), e);
434
			}
435
			  
436
		  }
437
	  }
438
	  
439
	  return pid;
440
      
441
  }
442
  
443
  /**
444
   * Archives an object from the Coordinating Node
445
   * 
446
   * @param session - the Session object containing the credentials for the Subject
447
   * @param pid - The object identifier to be deleted
448
   * 
449
   * @return pid - the identifier of the object used for the deletion
450
   * 
451
   * @throws InvalidToken
452
   * @throws ServiceFailure
453
   * @throws NotAuthorized
454
   * @throws NotFound
455
   * @throws NotImplemented
456
   * @throws InvalidRequest
457
   */
458
  @Override
459
  public Identifier archive(Session session, Identifier pid) 
460
      throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
461

    
462
      String localId = null; // The corresponding docid for this pid
463
	  Lock lock = null;      // The lock to be used for this identifier
464

    
465
      // check for a valid session
466
      if (session == null) {
467
        	throw new InvalidToken("4973", "No session has been provided");
468
        	
469
      }
470

    
471
      // do we have a valid pid?
472
      if (pid == null || pid.getValue().trim().equals("")) {
473
          throw new ServiceFailure("4972", "The provided identifier was invalid.");
474
          
475
      }
476

    
477
	  // check that it is CN/admin
478
	  boolean allowed = isAdminAuthorized(session);
479
	  
480
	  //check if it is the authoritative member node
481
	  if(!allowed) {
482
	      allowed = isAuthoritativeMNodeAdmin(session, pid);
483
	  }
484
	  
485
	  if (!allowed) {
486
		  String msg = "The subject " + session.getSubject().getValue() + 
487
				  " is not allowed to call archive() on a Coordinating Node.";
488
		  logMetacat.info(msg);
489
		  throw new NotAuthorized("4970", msg);
490
	  }
491
	  
492
      // Check for the existing identifier
493
      try {
494
          localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
495
          super.archive(session, pid);
496
          
497
      } catch (McdbDocNotFoundException e) {
498
          // This object is not registered in the identifier table. Assume it is of formatType DATA,
499
    	  // and set the archive flag. (i.e. the *object* doesn't exist on the CN)
500
    	  
501
          try {
502
  			  lock = HazelcastService.getInstance().getLock(pid.getValue());
503
  			  lock.lock();
504
  			  logMetacat.debug("Locked identifier " + pid.getValue());
505

    
506
			  SystemMetadata sysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
507
			  if ( sysMeta != null ) {
508
				sysMeta.setArchived(true);
509
				sysMeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
510
				HazelcastService.getInstance().getSystemMetadataMap().put(pid, sysMeta);
511
				
512
			  } else {
513
				  throw new ServiceFailure("4972", "Couldn't archive the object " + pid.getValue() +
514
					  ". Couldn't obtain the system metadata record.");
515
				  
516
			  }
517
			  
518
		  } catch (RuntimeException re) {
519
			  throw new ServiceFailure("4972", "Couldn't archive " + pid.getValue() + 
520
				  ". The error message was: " + re.getMessage());
521
			  
522
		  } finally {
523
			  lock.unlock();
524
			  logMetacat.debug("Unlocked identifier " + pid.getValue());
525

    
526
		  }
527

    
528
          // Log the archive
529
          EventLog.getInstance().log(request.getRemoteAddr(), 
530
                  request.getHeader("User-Agent"), session.getSubject().getValue(), 
531
                  pid.getValue(), Event.DELETE.xmlValue());
532

    
533
      }
534
      
535
	  // notify the replicas
536
	  SystemMetadata systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
537
	  if (systemMetadata.getReplicaList() != null) {
538
		  for (Replica replica: systemMetadata.getReplicaList()) {
539
			  NodeReference replicaNode = replica.getReplicaMemberNode();
540
			  try {
541
				  // TODO: implement in the clients
542
				  //Identifier mnRetId = D1Client.getMN(replicaNode).archive(null, pid);
543
			  } catch (Exception e) {
544
				  // all we can really do is log errors and carry on with life
545
				  logMetacat.error("Error archiving pid: " +  pid.getValue() + " from replica MN: " + replicaNode.getValue(), e);
546
			}
547
			  
548
		  }
549
	  }
550
	  
551
	  return pid;
552
      
553
  }
554
  
555
  /**
556
   * Set the obsoletedBy attribute in System Metadata
557
   * @param session
558
   * @param pid
559
   * @param obsoletedByPid
560
   * @param serialVersion
561
   * @return
562
   * @throws NotImplemented
563
   * @throws NotFound
564
   * @throws NotAuthorized
565
   * @throws ServiceFailure
566
   * @throws InvalidRequest
567
   * @throws InvalidToken
568
   * @throws VersionMismatch
569
   */
570
  @Override
571
  public boolean setObsoletedBy(Session session, Identifier pid,
572
			Identifier obsoletedByPid, long serialVersion)
573
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
574
			InvalidRequest, InvalidToken, VersionMismatch {
575

    
576
		// The lock to be used for this identifier
577
		Lock lock = null;
578

    
579
		// get the subject
580
		Subject subject = session.getSubject();
581

    
582
		// are we allowed to do this?
583
		if (!isAuthorized(session, pid, Permission.WRITE)) {
584
			throw new NotAuthorized("4881", Permission.WRITE
585
					+ " not allowed by " + subject.getValue() + " on "
586
					+ pid.getValue());
587

    
588
		}
589

    
590

    
591
		SystemMetadata systemMetadata = null;
592
		try {
593
			lock = HazelcastService.getInstance().getLock(pid.getValue());
594
			lock.lock();
595
			logMetacat.debug("Locked identifier " + pid.getValue());
596

    
597
			try {
598
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
599
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
600
				}
601

    
602
				// did we get it correctly?
603
				if (systemMetadata == null) {
604
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
605
				}
606

    
607
				// does the request have the most current system metadata?
608
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
609
					String msg = "The requested system metadata version number "
610
							+ serialVersion
611
							+ " differs from the current version at "
612
							+ systemMetadata.getSerialVersion().longValue()
613
							+ ". Please get the latest copy in order to modify it.";
614
					throw new VersionMismatch("4886", msg);
615

    
616
				}
617

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

    
621
			}
622

    
623
			// set the new policy
624
			systemMetadata.setObsoletedBy(obsoletedByPid);
625

    
626
			// update the metadata
627
			try {
628
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
629
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
630
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
631
			} catch (RuntimeException e) {
632
				throw new ServiceFailure("4882", e.getMessage());
633
			}
634

    
635
		} catch (RuntimeException e) {
636
			throw new ServiceFailure("4882", e.getMessage());
637
		} finally {
638
			lock.unlock();
639
			logMetacat.debug("Unlocked identifier " + pid.getValue());
640
		}
641

    
642
		return true;
643
	}
644
  
645
  
646
  /**
647
   * Set the replication status for an object given the object identifier
648
   * 
649
   * @param session - the Session object containing the credentials for the Subject
650
   * @param pid - the object identifier for the given object
651
   * @param status - the replication status to be applied
652
   * 
653
   * @return true or false
654
   * 
655
   * @throws NotImplemented
656
   * @throws NotAuthorized
657
   * @throws ServiceFailure
658
   * @throws InvalidRequest
659
   * @throws InvalidToken
660
   * @throws NotFound
661
   * 
662
   */
663
  @Override
664
  public boolean setReplicationStatus(Session session, Identifier pid,
665
      NodeReference targetNode, ReplicationStatus status, BaseException failure) 
666
      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
667
      InvalidRequest, NotFound {
668
	  
669
	  // cannot be called by public
670
	  if (session == null) {
671
		  throw new NotAuthorized("4720", "Session cannot be null");
672
	  }
673
      
674
      // The lock to be used for this identifier
675
      Lock lock = null;
676
      
677
      boolean allowed = false;
678
      int replicaEntryIndex = -1;
679
      List<Replica> replicas = null;
680
      // get the subject
681
      Subject subject = session.getSubject();
682
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
683
          " is " + status.toString());
684
      
685
      SystemMetadata systemMetadata = null;
686

    
687
      try {
688
          lock = HazelcastService.getInstance().getLock(pid.getValue());
689
          lock.lock();
690
          logMetacat.debug("Locked identifier " + pid.getValue());
691

    
692
          try {      
693
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
694

    
695
              // did we get it correctly?
696
              if ( systemMetadata == null ) {
697
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
698
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
699
                  
700
              }
701
              replicas = systemMetadata.getReplicaList();
702
              int count = 0;
703
              
704
              // was there a failure? log it
705
              if ( failure != null && status.equals(ReplicationStatus.FAILED) ) {
706
                 String msg = "The replication request of the object identified by " + 
707
                     pid.getValue() + " failed.  The error message was " +
708
                     failure.getMessage() + ".";
709
              }
710
              
711
              if (replicas.size() > 0 && replicas != null) {
712
                  // find the target replica index in the replica list
713
                  for (Replica replica : replicas) {
714
                      String replicaNodeStr = replica.getReplicaMemberNode().getValue();
715
                      String targetNodeStr = targetNode.getValue();
716
                      logMetacat.debug("Comparing " + replicaNodeStr + " to " + targetNodeStr);
717
                  
718
                      if (replicaNodeStr.equals(targetNodeStr)) {
719
                          replicaEntryIndex = count;
720
                          logMetacat.debug("replica entry index is: "
721
                                  + replicaEntryIndex);
722
                          break;
723
                      }
724
                      count++;
725
                  
726
                  }
727
              }
728
              // are we allowed to do this? only CNs and target MNs are allowed
729
              CNode cn = D1Client.getCN();
730
              List<Node> nodes = cn.listNodes().getNodeList();
731
              
732
              // find the node in the node list
733
              for ( Node node : nodes ) {
734
                  
735
                  NodeReference nodeReference = node.getIdentifier();
736
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " + 
737
                      nodeReference.getValue());
738
                  
739
                  // allow target MN certs
740
                  if ( targetNode.getValue().equals(nodeReference.getValue() ) &&
741
                      node.getType().equals(NodeType.MN)) {
742
                      List<Subject> nodeSubjects = node.getSubjectList();
743
                      
744
                      // check if the session subject is in the node subject list
745
                      for (Subject nodeSubject : nodeSubjects) {
746
                          logMetacat.debug("In setReplicationStatus(), comparing subjects: " +
747
                                  nodeSubject.getValue() + " and " + subject.getValue());
748
                          if ( nodeSubject.equals(subject) ) { // subject of session == target node subject
749
                              
750
                              // lastly limit to COMPLETED, INVALIDATED,
751
                              // and FAILED status updates from MNs only
752
                              if ( status.equals(ReplicationStatus.COMPLETED) ||
753
                                   status.equals(ReplicationStatus.INVALIDATED) ||
754
                                   status.equals(ReplicationStatus.FAILED)) {
755
                                  allowed = true;
756
                                  break;
757
                                  
758
                              }                              
759
                          }
760
                      }                 
761
                  }
762
              }
763

    
764
              if ( !allowed ) {
765
                  //check for CN admin access
766
                  allowed = isAuthorized(session, pid, Permission.WRITE);
767
                  
768
              }              
769
              
770
              if ( !allowed ) {
771
                  String msg = "The subject identified by "
772
                          + subject.getValue()
773
                          + " does not have permission to set the replication status for "
774
                          + "the replica identified by "
775
                          + targetNode.getValue() + ".";
776
                  logMetacat.info(msg);
777
                  throw new NotAuthorized("4720", msg);
778
                  
779
              }
780

    
781
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
782
            throw new NotFound("4740", "No record found for: " + pid.getValue() +
783
                " : " + e.getMessage());
784
            
785
          }
786
          
787
          Replica targetReplica = new Replica();
788
          // set the status for the replica
789
          if ( replicaEntryIndex != -1 ) {
790
              targetReplica = replicas.get(replicaEntryIndex);
791
              
792
              // don't allow status to change from COMPLETED to anything other
793
              // than INVALIDATED: prevents overwrites from race conditions
794
              if ( targetReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
795
            	   !status.equals(ReplicationStatus.INVALIDATED)) {
796
            	  throw new InvalidRequest("4730", "Status state change from " +
797
            			  targetReplica.getReplicationStatus() + " to " +
798
            			  status.toString() + "is prohibited for identifier " +
799
            			  pid.getValue() + " and target node " + 
800
            			  targetReplica.getReplicaMemberNode().getValue());
801
              }
802
              
803
              targetReplica.setReplicationStatus(status);
804
              
805
              logMetacat.debug("Set the replication status for " + 
806
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
807
                  targetReplica.getReplicationStatus() + " for identifier " +
808
                  pid.getValue());
809
              
810
          } else {
811
              // this is a new entry, create it
812
              targetReplica.setReplicaMemberNode(targetNode);
813
              targetReplica.setReplicationStatus(status);
814
              targetReplica.setReplicaVerified(Calendar.getInstance().getTime());
815
              replicas.add(targetReplica);
816
              
817
          }
818
          
819
          systemMetadata.setReplicaList(replicas);
820
                
821
          // update the metadata
822
          try {
823
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
824
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
825
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
826

    
827
              if ( !status.equals(ReplicationStatus.QUEUED) && 
828
            	   !status.equals(ReplicationStatus.REQUESTED)) {
829
                  
830
                logMetacat.trace("METRICS:\tREPLICATION:\tEND REQUEST:\tPID:\t" + pid.getValue() + 
831
                          "\tNODE:\t" + targetNode.getValue() + 
832
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
833
                
834
                logMetacat.trace("METRICS:\tREPLICATION:\t" + status.toString().toUpperCase() +
835
                          "\tPID:\t"  + pid.getValue() + 
836
                          "\tNODE:\t" + targetNode.getValue() + 
837
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
838
              }
839

    
840
              if ( status.equals(ReplicationStatus.FAILED) && failure != null ) {
841
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
842
                      " on target node " + targetNode + ". The exception was: " +
843
                      failure.getMessage());
844
              }
845
              
846
			  // update the replica nodes about the completed replica when complete
847
              if (status.equals(ReplicationStatus.COMPLETED)) {
848
				notifyReplicaNodes(systemMetadata);
849
			}
850
          
851
          } catch (RuntimeException e) {
852
              throw new ServiceFailure("4700", e.getMessage());
853
          
854
          }
855
          
856
    } catch (RuntimeException e) {
857
        String msg = "There was a RuntimeException getting the lock for " +
858
            pid.getValue();
859
        logMetacat.info(msg);
860
        
861
    } finally {
862
        lock.unlock();
863
        logMetacat.debug("Unlocked identifier " + pid.getValue());
864
        
865
    }
866
      
867
      return true;
868
  }
869
  
870
/**
871
   * Return the checksum of the object given the identifier 
872
   * 
873
   * @param session - the Session object containing the credentials for the Subject
874
   * @param pid - the object identifier for the given object
875
   * 
876
   * @return checksum - the checksum of the object
877
   * 
878
   * @throws InvalidToken
879
   * @throws ServiceFailure
880
   * @throws NotAuthorized
881
   * @throws NotFound
882
   * @throws NotImplemented
883
   */
884
  @Override
885
  public Checksum getChecksum(Session session, Identifier pid)
886
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
887
    NotImplemented {
888
    
889
	boolean isAuthorized = false;
890
	try {
891
		isAuthorized = isAuthorized(session, pid, Permission.READ);
892
	} catch (InvalidRequest e) {
893
		throw new ServiceFailure("1410", e.getDescription());
894
	}  
895
    if (!isAuthorized) {
896
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());  
897
    }
898
    
899
    SystemMetadata systemMetadata = null;
900
    Checksum checksum = null;
901
    
902
    try {
903
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);        
904

    
905
        if (systemMetadata == null ) {
906
            throw new NotFound("1420", "Couldn't find an object identified by " + pid.getValue());
907
        }
908
        checksum = systemMetadata.getChecksum();
909
        
910
    } catch (RuntimeException e) {
911
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " + 
912
            pid.getValue() + ". The error message was: " + e.getMessage());
913
      
914
    }
915
    
916
    return checksum;
917
  }
918

    
919
  /**
920
   * Resolve the location of a given object
921
   * 
922
   * @param session - the Session object containing the credentials for the Subject
923
   * @param pid - the object identifier for the given object
924
   * 
925
   * @return objectLocationList - the list of nodes known to contain the object
926
   * 
927
   * @throws InvalidToken
928
   * @throws ServiceFailure
929
   * @throws NotAuthorized
930
   * @throws NotFound
931
   * @throws NotImplemented
932
   */
933
  @Override
934
  public ObjectLocationList resolve(Session session, Identifier pid)
935
    throws InvalidToken, ServiceFailure, NotAuthorized,
936
    NotFound, NotImplemented {
937

    
938
    throw new NotImplemented("4131", "resolve not implemented");
939

    
940
  }
941

    
942
  /**
943
   * Metacat does not implement this method at the CN level
944
   */
945
  @Override
946
  public ObjectList search(Session session, String queryType, String query)
947
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
948
    NotImplemented {
949

    
950
		  throw new NotImplemented("4281", "Metacat does not implement CN.search");
951
	  
952
//    ObjectList objectList = null;
953
//    try {
954
//        objectList = 
955
//          IdentifierManager.getInstance().querySystemMetadata(
956
//              null, //startTime, 
957
//              null, //endTime,
958
//              null, //objectFormat, 
959
//              false, //replicaStatus, 
960
//              0, //start, 
961
//              1000 //count
962
//              );
963
//        
964
//    } catch (Exception e) {
965
//      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
966
//    }
967
//
968
//      return objectList;
969
		  
970
  }
971
  
972
  /**
973
   * Returns the object format registered in the DataONE Object Format 
974
   * Vocabulary for the given format identifier
975
   * 
976
   * @param fmtid - the identifier of the format requested
977
   * 
978
   * @return objectFormat - the object format requested
979
   * 
980
   * @throws ServiceFailure
981
   * @throws NotFound
982
   * @throws InsufficientResources
983
   * @throws NotImplemented
984
   */
985
  @Override
986
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
987
    throws ServiceFailure, NotFound, NotImplemented {
988
     
989
      return ObjectFormatService.getInstance().getFormat(fmtid);
990
      
991
  }
992

    
993
  /**
994
   * Returns a list of all object formats registered in the DataONE Object 
995
   * Format Vocabulary
996
    * 
997
   * @return objectFormatList - The list of object formats registered in 
998
   *                            the DataONE Object Format Vocabulary
999
   * 
1000
   * @throws ServiceFailure
1001
   * @throws NotImplemented
1002
   * @throws InsufficientResources
1003
   */
1004
  @Override
1005
  public ObjectFormatList listFormats() 
1006
    throws ServiceFailure, NotImplemented {
1007

    
1008
    return ObjectFormatService.getInstance().listFormats();
1009
  }
1010

    
1011
  /**
1012
   * Returns a list of nodes that have been registered with the DataONE infrastructure
1013
    * 
1014
   * @return nodeList - List of nodes from the registry
1015
   * 
1016
   * @throws ServiceFailure
1017
   * @throws NotImplemented
1018
   */
1019
  @Override
1020
  public NodeList listNodes() 
1021
    throws NotImplemented, ServiceFailure {
1022

    
1023
    throw new NotImplemented("4800", "listNodes not implemented");
1024
  }
1025

    
1026
  /**
1027
   * Provides a mechanism for adding system metadata independently of its 
1028
   * associated object, such as when adding system metadata for data objects.
1029
    * 
1030
   * @param session - the Session object containing the credentials for the Subject
1031
   * @param pid - The identifier of the object to register the system metadata against
1032
   * @param sysmeta - The system metadata to be registered
1033
   * 
1034
   * @return true if the registration succeeds
1035
   * 
1036
   * @throws NotImplemented
1037
   * @throws NotAuthorized
1038
   * @throws ServiceFailure
1039
   * @throws InvalidRequest
1040
   * @throws InvalidSystemMetadata
1041
   */
1042
  @Override
1043
  public Identifier registerSystemMetadata(Session session, Identifier pid,
1044
      SystemMetadata sysmeta) 
1045
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
1046
      InvalidSystemMetadata {
1047

    
1048
      // The lock to be used for this identifier
1049
      Lock lock = null;
1050

    
1051
      // TODO: control who can call this?
1052
      if (session == null) {
1053
          //TODO: many of the thrown exceptions do not use the correct error codes
1054
          //check these against the docs and correct them
1055
          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
1056
                  "  If you are not logged in, please do so and retry the request.");
1057
      }
1058
      
1059
      // verify that guid == SystemMetadata.getIdentifier()
1060
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() + 
1061
          "|" + sysmeta.getIdentifier().getValue());
1062
      if (!pid.getValue().equals(sysmeta.getIdentifier().getValue())) {
1063
          throw new InvalidRequest("4863", 
1064
              "The identifier in method call (" + pid.getValue() + 
1065
              ") does not match identifier in system metadata (" +
1066
              sysmeta.getIdentifier().getValue() + ").");
1067
      }
1068

    
1069
      try {
1070
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
1071
          lock.lock();
1072
          logMetacat.debug("Locked identifier " + pid.getValue());
1073
          logMetacat.debug("Checking if identifier exists...");
1074
          // Check that the identifier does not already exist
1075
          if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
1076
              throw new InvalidRequest("4863", 
1077
                  "The identifier is already in use by an existing object.");
1078
          
1079
          }
1080
          
1081
          // insert the system metadata into the object store
1082
          logMetacat.debug("Starting to insert SystemMetadata...");
1083
          try {
1084
              sysmeta.setSerialVersion(BigInteger.ONE);
1085
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1086
              HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
1087
              
1088
          } catch (RuntimeException e) {
1089
            logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
1090
              throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1091
                  e.getClass() + ": " + e.getMessage());
1092
              
1093
          }
1094
          
1095
      } catch (RuntimeException e) {
1096
          throw new ServiceFailure("4862", "Error inserting system metadata: " + 
1097
                  e.getClass() + ": " + e.getMessage());
1098
          
1099
      }  finally {
1100
          lock.unlock();
1101
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1102
          
1103
      }
1104

    
1105
      
1106
      logMetacat.debug("Returning from registerSystemMetadata");
1107
      EventLog.getInstance().log(request.getRemoteAddr(), 
1108
          request.getHeader("User-Agent"), session.getSubject().getValue(), 
1109
          pid.getValue(), "registerSystemMetadata");
1110
      return pid;
1111
  }
1112
  
1113
  /**
1114
   * Given an optional scope and format, reserves and returns an identifier 
1115
   * within that scope and format that is unique and will not be 
1116
   * used by any other sessions. 
1117
    * 
1118
   * @param session - the Session object containing the credentials for the Subject
1119
   * @param pid - The identifier of the object to register the system metadata against
1120
   * @param scope - An optional string to be used to qualify the scope of 
1121
   *                the identifier namespace, which is applied differently 
1122
   *                depending on the format requested. If scope is not 
1123
   *                supplied, a default scope will be used.
1124
   * @param format - The optional name of the identifier format to be used, 
1125
   *                  drawn from a DataONE-specific vocabulary of identifier 
1126
   *                 format names, including several common syntaxes such 
1127
   *                 as DOI, LSID, UUID, and LSRN, among others. If the 
1128
   *                 format is not supplied by the caller, the CN service 
1129
   *                 will use a default identifier format, which may change 
1130
   *                 over time.
1131
   * 
1132
   * @return true if the registration succeeds
1133
   * 
1134
   * @throws InvalidToken
1135
   * @throws ServiceFailure
1136
   * @throws NotAuthorized
1137
   * @throws IdentifierNotUnique
1138
   * @throws NotImplemented
1139
   */
1140
  @Override
1141
  public Identifier reserveIdentifier(Session session, Identifier pid)
1142
  throws InvalidToken, ServiceFailure,
1143
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
1144

    
1145
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1146
  }
1147
  
1148
  @Override
1149
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1150
  throws InvalidToken, ServiceFailure,
1151
        NotAuthorized, NotImplemented, InvalidRequest {
1152
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
1153
  }
1154
  
1155
  /**
1156
    * Checks whether the pid is reserved by the subject in the session param
1157
    * If the reservation is held on the pid by the subject, we return true.
1158
    * 
1159
   * @param session - the Session object containing the Subject
1160
   * @param pid - The identifier to check
1161
   * 
1162
   * @return true if the reservation exists for the subject/pid
1163
   * 
1164
   * @throws InvalidToken
1165
   * @throws ServiceFailure
1166
   * @throws NotFound - when the pid is not found (in use or in reservation)
1167
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
1168
   * @throws IdentifierNotUnique - when the pid is in use
1169
   * @throws NotImplemented
1170
   */
1171

    
1172
  @Override
1173
  public boolean hasReservation(Session session, Subject subject, Identifier pid) 
1174
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique, 
1175
      NotImplemented, InvalidRequest {
1176
  
1177
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1178
  }
1179

    
1180
  /**
1181
   * Changes ownership (RightsHolder) of the specified object to the 
1182
   * subject specified by userId
1183
    * 
1184
   * @param session - the Session object containing the credentials for the Subject
1185
   * @param pid - Identifier of the object to be modified
1186
   * @param userId - The subject that will be taking ownership of the specified object.
1187
   *
1188
   * @return pid - the identifier of the modified object
1189
   * 
1190
   * @throws ServiceFailure
1191
   * @throws InvalidToken
1192
   * @throws NotFound
1193
   * @throws NotAuthorized
1194
   * @throws NotImplemented
1195
   * @throws InvalidRequest
1196
   */  
1197
  @Override
1198
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1199
      long serialVersion)
1200
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1201
      NotImplemented, InvalidRequest, VersionMismatch {
1202
      
1203
      // The lock to be used for this identifier
1204
      Lock lock = null;
1205

    
1206
      // get the subject
1207
      Subject subject = session.getSubject();
1208
      
1209
      // are we allowed to do this?
1210
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1211
          throw new NotAuthorized("4440", "not allowed by "
1212
                  + subject.getValue() + " on " + pid.getValue());
1213
          
1214
      }
1215
      
1216
      SystemMetadata systemMetadata = null;
1217
      try {
1218
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1219
          lock.lock();
1220
          logMetacat.debug("Locked identifier " + pid.getValue());
1221

    
1222
          try {
1223
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1224
              
1225
              // does the request have the most current system metadata?
1226
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1227
                 String msg = "The requested system metadata version number " + 
1228
                     serialVersion + " differs from the current version at " +
1229
                     systemMetadata.getSerialVersion().longValue() +
1230
                     ". Please get the latest copy in order to modify it.";
1231
                 throw new VersionMismatch("4443", msg);
1232
              }
1233
              
1234
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1235
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1236
              
1237
          }
1238
              
1239
          // set the new rights holder
1240
          systemMetadata.setRightsHolder(userId);
1241
          
1242
          // update the metadata
1243
          try {
1244
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1245
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1246
              HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
1247
              notifyReplicaNodes(systemMetadata);
1248
              
1249
          } catch (RuntimeException e) {
1250
              throw new ServiceFailure("4490", e.getMessage());
1251
          
1252
          }
1253
          
1254
      } catch (RuntimeException e) {
1255
          throw new ServiceFailure("4490", e.getMessage());
1256
          
1257
      } finally {
1258
          lock.unlock();
1259
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1260
      
1261
      }
1262
      
1263
      return pid;
1264
  }
1265

    
1266
  /**
1267
   * Verify that a replication task is authorized by comparing the target node's
1268
   * Subject (from the X.509 certificate-derived Session) with the list of 
1269
   * subjects in the known, pending replication tasks map.
1270
   * 
1271
   * @param originatingNodeSession - Session information that contains the 
1272
   *                                 identity of the calling user
1273
   * @param targetNodeSubject - Subject identifying the target node
1274
   * @param pid - the identifier of the object to be replicated
1275
   * @param replicatePermission - the execute permission to be granted
1276
   * 
1277
   * @throws ServiceFailure
1278
   * @throws NotImplemented
1279
   * @throws InvalidToken
1280
   * @throws NotAuthorized
1281
   * @throws InvalidRequest
1282
   * @throws NotFound
1283
   */
1284
  @Override
1285
  public boolean isNodeAuthorized(Session originatingNodeSession, 
1286
    Subject targetNodeSubject, Identifier pid) 
1287
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure, 
1288
    NotFound, InvalidRequest {
1289
    
1290
    boolean isAllowed = false;
1291
    SystemMetadata sysmeta = null;
1292
    NodeReference targetNode = null;
1293
    
1294
    try {
1295
      // get the target node reference from the nodes list
1296
      CNode cn = D1Client.getCN();
1297
      List<Node> nodes = cn.listNodes().getNodeList();
1298
      
1299
      if ( nodes != null ) {
1300
        for (Node node : nodes) {
1301
            
1302
        	if (node.getSubjectList() != null) {
1303
        		
1304
	            for (Subject nodeSubject : node.getSubjectList()) {
1305
	            	
1306
	                if ( nodeSubject.equals(targetNodeSubject) ) {
1307
	                    targetNode = node.getIdentifier();
1308
	                    logMetacat.debug("targetNode is : " + targetNode.getValue());
1309
	                    break;
1310
	                }
1311
	            }
1312
        	}
1313
            
1314
            if ( targetNode != null) { break; }
1315
        }
1316
        
1317
      } else {
1318
          String msg = "Couldn't get the node list from the CN";
1319
          logMetacat.debug(msg);
1320
          throw new ServiceFailure("4872", msg);
1321
          
1322
      }
1323
      
1324
      // can't find a node listed with the given subject
1325
      if ( targetNode == null ) {
1326
          String msg = "There is no Member Node registered with a node subject " +
1327
              "matching " + targetNodeSubject.getValue();
1328
          logMetacat.info(msg);
1329
          throw new NotAuthorized("4871", msg);
1330
          
1331
      }
1332
      
1333
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1334
      
1335
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1336

    
1337
      if ( sysmeta != null ) {
1338
          
1339
          List<Replica> replicaList = sysmeta.getReplicaList();
1340
          
1341
          if ( replicaList != null ) {
1342
              
1343
              // find the replica with the status set to 'requested'
1344
              for (Replica replica : replicaList) {
1345
                  ReplicationStatus status = replica.getReplicationStatus();
1346
                  NodeReference listedNode = replica.getReplicaMemberNode();
1347
                  if ( listedNode != null && targetNode != null ) {
1348
                      logMetacat.debug("Comparing " + listedNode.getValue()
1349
                              + " to " + targetNode.getValue());
1350
                      
1351
                      if (listedNode.getValue().equals(targetNode.getValue())
1352
                              && status.equals(ReplicationStatus.REQUESTED)) {
1353
                          isAllowed = true;
1354
                          break;
1355

    
1356
                      }
1357
                  }
1358
              }
1359
          }
1360
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1361
              "to replicate: " + isAllowed + " for " + pid.getValue());
1362

    
1363
          
1364
      } else {
1365
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1366
          " is null.");          
1367
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue());
1368
          
1369
      }
1370

    
1371
    } catch (RuntimeException e) {
1372
    	  ServiceFailure sf = new ServiceFailure("4872", 
1373
                "Runtime Exception: Couldn't determine if node is allowed: " + 
1374
                e.getMessage());
1375
    	  sf.initCause(e);
1376
        throw sf;
1377
        
1378
    }
1379
      
1380
    return isAllowed;
1381
    
1382
  }
1383

    
1384
  /**
1385
   * Adds a new object to the Node, where the object is a science metadata object.
1386
   * 
1387
   * @param session - the Session object containing the credentials for the Subject
1388
   * @param pid - The object identifier to be created
1389
   * @param object - the object bytes
1390
   * @param sysmeta - the system metadata that describes the object  
1391
   * 
1392
   * @return pid - the object identifier created
1393
   * 
1394
   * @throws InvalidToken
1395
   * @throws ServiceFailure
1396
   * @throws NotAuthorized
1397
   * @throws IdentifierNotUnique
1398
   * @throws UnsupportedType
1399
   * @throws InsufficientResources
1400
   * @throws InvalidSystemMetadata
1401
   * @throws NotImplemented
1402
   * @throws InvalidRequest
1403
   */
1404
  public Identifier create(Session session, Identifier pid, InputStream object,
1405
    SystemMetadata sysmeta) 
1406
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
1407
    UnsupportedType, InsufficientResources, InvalidSystemMetadata, 
1408
    NotImplemented, InvalidRequest {
1409
                  
1410
      // The lock to be used for this identifier
1411
      Lock lock = null;
1412

    
1413
      try {
1414
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1415
          // are we allowed?
1416
          boolean isAllowed = false;
1417
          isAllowed = isAdminAuthorized(session);
1418
          
1419
          // additional check if it is the authoritative node if it is not the admin
1420
          if(!isAllowed) {
1421
              isAllowed = isAuthoritativeMNodeAdmin(session, pid);
1422
          }
1423

    
1424
          // proceed if we're called by a CN
1425
          if ( isAllowed ) {
1426
              // create the coordinating node version of the document      
1427
              lock.lock();
1428
              logMetacat.debug("Locked identifier " + pid.getValue());
1429
              sysmeta.setSerialVersion(BigInteger.ONE);
1430
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1431
              sysmeta.setArchived(false); // this is a create op, not update
1432
              
1433
              // the CN should have set the origin and authoritative member node fields
1434
              try {
1435
                  sysmeta.getOriginMemberNode().getValue();
1436
                  sysmeta.getAuthoritativeMemberNode().getValue();
1437
                  
1438
              } catch (NullPointerException npe) {
1439
                  throw new InvalidSystemMetadata("4896", 
1440
                      "Both the origin and authoritative member node identifiers need to be set.");
1441
                  
1442
              }
1443
              pid = super.create(session, pid, object, sysmeta);
1444

    
1445
          } else {
1446
              String msg = "The subject listed as " + session.getSubject().getValue() + 
1447
                  " isn't allowed to call create() on a Coordinating Node.";
1448
              logMetacat.info(msg);
1449
              throw new NotAuthorized("1100", msg);
1450
          }
1451
          
1452
      } catch (RuntimeException e) {
1453
          // Convert Hazelcast runtime exceptions to service failures
1454
          String msg = "There was a problem creating the object identified by " +
1455
              pid.getValue() + ". There error message was: " + e.getMessage();
1456
          throw new ServiceFailure("4893", msg);
1457
          
1458
      } finally {
1459
    	  if (lock != null) {
1460
	          lock.unlock();
1461
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1462
    	  }
1463
      }
1464
      
1465
      return pid;
1466

    
1467
  }
1468

    
1469
  /**
1470
   * Set access for a given object using the object identifier and a Subject
1471
   * under a given Session.
1472
   * 
1473
   * @param session - the Session object containing the credentials for the Subject
1474
   * @param pid - the object identifier for the given object to apply the policy
1475
   * @param policy - the access policy to be applied
1476
   * 
1477
   * @return true if the application of the policy succeeds
1478
   * @throws InvalidToken
1479
   * @throws ServiceFailure
1480
   * @throws NotFound
1481
   * @throws NotAuthorized
1482
   * @throws NotImplemented
1483
   * @throws InvalidRequest
1484
   */
1485
  public boolean setAccessPolicy(Session session, Identifier pid, 
1486
      AccessPolicy accessPolicy, long serialVersion) 
1487
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, 
1488
      NotImplemented, InvalidRequest, VersionMismatch {
1489
      
1490
      // The lock to be used for this identifier
1491
      Lock lock = null;
1492
      SystemMetadata systemMetadata = null;
1493
      
1494
      boolean success = false;
1495
      
1496
      // get the subject
1497
      Subject subject = session.getSubject();
1498
      
1499
      // are we allowed to do this?
1500
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1501
          throw new NotAuthorized("4420", "not allowed by "
1502
                  + subject.getValue() + " on " + pid.getValue());
1503
      }
1504
      
1505
      try {
1506
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1507
          lock.lock();
1508
          logMetacat.debug("Locked identifier " + pid.getValue());
1509

    
1510
          try {
1511
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1512

    
1513
              if ( systemMetadata == null ) {
1514
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1515
                  
1516
              }
1517
              // does the request have the most current system metadata?
1518
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1519
                 String msg = "The requested system metadata version number " + 
1520
                     serialVersion + " differs from the current version at " +
1521
                     systemMetadata.getSerialVersion().longValue() +
1522
                     ". Please get the latest copy in order to modify it.";
1523
                 throw new VersionMismatch("4402", msg);
1524
                 
1525
              }
1526
              
1527
          } catch (RuntimeException e) {
1528
              // convert Hazelcast RuntimeException to NotFound
1529
              throw new NotFound("4400", "No record found for: " + pid);
1530
            
1531
          }
1532
              
1533
          // set the access policy
1534
          systemMetadata.setAccessPolicy(accessPolicy);
1535
          
1536
          // update the system metadata
1537
          try {
1538
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1539
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1540
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1541
              notifyReplicaNodes(systemMetadata);
1542
              
1543
          } catch (RuntimeException e) {
1544
              // convert Hazelcast RuntimeException to ServiceFailure
1545
              throw new ServiceFailure("4430", e.getMessage());
1546
            
1547
          }
1548
          
1549
      } catch (RuntimeException e) {
1550
          throw new ServiceFailure("4430", e.getMessage());
1551
          
1552
      } finally {
1553
          lock.unlock();
1554
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1555
        
1556
      }
1557

    
1558
    
1559
    // TODO: how do we know if the map was persisted?
1560
    success = true;
1561
    
1562
    return success;
1563
  }
1564

    
1565
  /**
1566
   * Full replacement of replication metadata in the system metadata for the 
1567
   * specified object, changes date system metadata modified
1568
   * 
1569
   * @param session - the Session object containing the credentials for the Subject
1570
   * @param pid - the object identifier for the given object to apply the policy
1571
   * @param replica - the replica to be updated
1572
   * @return
1573
   * @throws NotImplemented
1574
   * @throws NotAuthorized
1575
   * @throws ServiceFailure
1576
   * @throws InvalidRequest
1577
   * @throws NotFound
1578
   * @throws VersionMismatch
1579
   */
1580
  @Override
1581
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1582
      Replica replica, long serialVersion) 
1583
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1584
      NotFound, VersionMismatch {
1585
      
1586
      // The lock to be used for this identifier
1587
      Lock lock = null;
1588
      
1589
      // get the subject
1590
      Subject subject = session.getSubject();
1591
      
1592
      // are we allowed to do this?
1593
      try {
1594

    
1595
          // what is the controlling permission?
1596
          if (!isAuthorized(session, pid, Permission.WRITE)) {
1597
              throw new NotAuthorized("4851", "not allowed by "
1598
                      + subject.getValue() + " on " + pid.getValue());
1599
          }
1600

    
1601
        
1602
      } catch (InvalidToken e) {
1603
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() + 
1604
                  " on " + pid.getValue());  
1605
          
1606
      }
1607

    
1608
      SystemMetadata systemMetadata = null;
1609
      try {
1610
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1611
          lock.lock();
1612
          logMetacat.debug("Locked identifier " + pid.getValue());
1613

    
1614
          try {      
1615
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1616

    
1617
              // does the request have the most current system metadata?
1618
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1619
                 String msg = "The requested system metadata version number " + 
1620
                     serialVersion + " differs from the current version at " +
1621
                     systemMetadata.getSerialVersion().longValue() +
1622
                     ". Please get the latest copy in order to modify it.";
1623
                 throw new VersionMismatch("4855", msg);
1624
              }
1625
              
1626
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1627
              throw new NotFound("4854", "No record found for: " + pid.getValue() +
1628
                  " : " + e.getMessage());
1629
            
1630
          }
1631
              
1632
          // set the status for the replica
1633
          List<Replica> replicas = systemMetadata.getReplicaList();
1634
          NodeReference replicaNode = replica.getReplicaMemberNode();
1635
          ReplicationStatus replicaStatus = replica.getReplicationStatus();
1636
          int index = 0;
1637
          for (Replica listedReplica: replicas) {
1638
              
1639
              // remove the replica that we are replacing
1640
              if ( replicaNode.getValue().equals(listedReplica.getReplicaMemberNode().getValue())) {
1641
                      // don't allow status to change from COMPLETED to anything other
1642
                      // than INVALIDATED: prevents overwrites from race conditions
1643
                	  if ( !listedReplica.getReplicationStatus().equals(replicaStatus) && 
1644
                	       listedReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
1645
            		       !replicaStatus.equals(ReplicationStatus.INVALIDATED) ) {
1646
                	  throw new InvalidRequest("4853", "Status state change from " +
1647
                			  listedReplica.getReplicationStatus() + " to " +
1648
                			  replicaStatus.toString() + "is prohibited for identifier " +
1649
                			  pid.getValue() + " and target node " + 
1650
                			  listedReplica.getReplicaMemberNode().getValue());
1651

    
1652
            	  }
1653
                  replicas.remove(index);
1654
                  break;
1655
                  
1656
              }
1657
              index++;
1658
          }
1659
          
1660
          // add the new replica item
1661
          replicas.add(replica);
1662
          systemMetadata.setReplicaList(replicas);
1663
          
1664
          // update the metadata
1665
          try {
1666
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1667
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1668
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1669
              
1670
              // inform replica nodes of the change if the status is complete
1671
              if ( replicaStatus.equals(ReplicationStatus.COMPLETED) ) {
1672
            	  notifyReplicaNodes(systemMetadata);
1673
            	  
1674
              }
1675
          } catch (RuntimeException e) {
1676
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1677
              throw new ServiceFailure("4852", e.getMessage());
1678
          
1679
          }
1680
          
1681
      } catch (RuntimeException e) {
1682
          logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1683
          throw new ServiceFailure("4852", e.getMessage());
1684
      
1685
      } finally {
1686
          lock.unlock();
1687
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1688
          
1689
      }
1690
    
1691
      return true;
1692
      
1693
  }
1694
  
1695
  /**
1696
   * 
1697
   */
1698
  @Override
1699
  public ObjectList listObjects(Session session, Date startTime, 
1700
      Date endTime, ObjectFormatIdentifier formatid, Boolean replicaStatus,
1701
      Integer start, Integer count)
1702
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1703
      ServiceFailure {
1704
      
1705
      ObjectList objectList = null;
1706
        try {
1707
        	if (count == null || count > MAXIMUM_DB_RECORD_COUNT) {
1708
            	count = MAXIMUM_DB_RECORD_COUNT;
1709
            }
1710
            objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, formatid, replicaStatus, start, count);
1711
        } catch (Exception e) {
1712
            throw new ServiceFailure("1580", "Error querying system metadata: " + e.getMessage());
1713
        }
1714

    
1715
        return objectList;
1716
  }
1717

    
1718
  
1719
 	/**
1720
 	 * Returns a list of checksum algorithms that are supported by DataONE.
1721
 	 * @return cal  the list of checksum algorithms
1722
 	 * 
1723
 	 * @throws ServiceFailure
1724
 	 * @throws NotImplemented
1725
 	 */
1726
  @Override
1727
  public ChecksumAlgorithmList listChecksumAlgorithms()
1728
			throws ServiceFailure, NotImplemented {
1729
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
1730
		cal.addAlgorithm("MD5");
1731
		cal.addAlgorithm("SHA-1");
1732
		return cal;
1733
		
1734
	}
1735

    
1736
  /**
1737
   * Notify replica Member Nodes of system metadata changes for a given pid
1738
   * 
1739
   * @param currentSystemMetadata - the up to date system metadata
1740
   */
1741
  public void notifyReplicaNodes(SystemMetadata currentSystemMetadata) {
1742
      
1743
      Session session = null;
1744
      List<Replica> replicaList = currentSystemMetadata.getReplicaList();
1745
      MNode mn = null;
1746
      NodeReference replicaNodeRef = null;
1747
      CNode cn = null;
1748
      NodeType nodeType = null;
1749
      List<Node> nodeList = null;
1750
      
1751
      try {
1752
          cn = D1Client.getCN();
1753
          nodeList = cn.listNodes().getNodeList();
1754
          
1755
      } catch (Exception e) { // handle BaseException and other I/O issues
1756
          
1757
          // swallow errors since the call is not critical
1758
          logMetacat.error("Can't inform MNs of system metadata changes due " +
1759
              "to communication issues with the CN: " + e.getMessage());
1760
          
1761
      }
1762
      
1763
      if ( replicaList != null ) {
1764
          
1765
          // iterate through the replicas and inform  MN replica nodes
1766
          for (Replica replica : replicaList) {
1767
              
1768
              replicaNodeRef = replica.getReplicaMemberNode();
1769
              try {
1770
                  if (nodeList != null) {
1771
                      // find the node type
1772
                      for (Node node : nodeList) {
1773
                          if (node.getIdentifier().getValue() == 
1774
                              replicaNodeRef.getValue()) {
1775
                              nodeType = node.getType();
1776
                              break;
1777
              
1778
                          }
1779
                      }
1780
                  }
1781
              
1782
                  // notify only MNs
1783
                  if (nodeType != null && nodeType == NodeType.MN) {
1784
                      mn = D1Client.getMN(replicaNodeRef);
1785
                      mn.systemMetadataChanged(session, 
1786
                          currentSystemMetadata.getIdentifier(), 
1787
                          currentSystemMetadata.getSerialVersion().longValue(),
1788
                          currentSystemMetadata.getDateSysMetadataModified());
1789
                  }
1790
              
1791
              } catch (Exception e) { // handle BaseException and other I/O issues
1792
              
1793
                  // swallow errors since the call is not critical
1794
                  logMetacat.error("Can't inform "
1795
                          + replicaNodeRef.getValue()
1796
                          + " of system metadata changes due "
1797
                          + "to communication issues with the CN: "
1798
                          + e.getMessage());
1799
              
1800
              }
1801
          }
1802
      }
1803
  }
1804

    
1805
	@Override
1806
	public boolean isAuthorized(Identifier pid, Permission permission)
1807
			throws ServiceFailure, InvalidToken, NotFound, NotAuthorized,
1808
			NotImplemented, InvalidRequest {
1809
		
1810
		return isAuthorized(null, pid, permission);
1811
	}
1812
	
1813
	@Override
1814
	public boolean setAccessPolicy(Identifier pid, AccessPolicy accessPolicy, long serialVersion)
1815
			throws InvalidToken, NotFound, NotImplemented, NotAuthorized,
1816
			ServiceFailure, InvalidRequest, VersionMismatch {
1817
		
1818
		return setAccessPolicy(null, pid, accessPolicy, serialVersion);
1819
	}
1820
	
1821
	@Override
1822
	public Identifier setRightsHolder(Identifier pid, Subject userId, long serialVersion)
1823
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1824
			NotImplemented, InvalidRequest, VersionMismatch {
1825
		
1826
		return setRightsHolder(null, pid, userId, serialVersion);
1827
	}
1828
	
1829
	@Override
1830
	public Identifier create(Identifier pid, InputStream object, SystemMetadata sysmeta)
1831
			throws InvalidToken, ServiceFailure, NotAuthorized,
1832
			IdentifierNotUnique, UnsupportedType, InsufficientResources,
1833
			InvalidSystemMetadata, NotImplemented, InvalidRequest {
1834

    
1835
		return create(null, pid, object, sysmeta);
1836
	}
1837
	
1838
	@Override
1839
	public Identifier delete(Identifier pid) throws InvalidToken, ServiceFailure,
1840
			NotAuthorized, NotFound, NotImplemented {
1841

    
1842
		return delete(null, pid);
1843
	}
1844
	
1845
	@Override
1846
	public Identifier generateIdentifier(String scheme, String fragment)
1847
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
1848
			InvalidRequest {
1849

    
1850
		return generateIdentifier(null, scheme, fragment);
1851
	}
1852
	
1853
	@Override
1854
	public Log getLogRecords(Date fromDate, Date toDate, Event event, String pidFilter,
1855
			Integer start, Integer count) throws InvalidToken, InvalidRequest,
1856
			ServiceFailure, NotAuthorized, NotImplemented, InsufficientResources {
1857

    
1858
		return getLogRecords(null, fromDate, toDate, event, pidFilter, start, count);
1859
	}
1860
	
1861
	@Override
1862
	public boolean hasReservation(Subject subject, Identifier pid)
1863
			throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1864
			NotImplemented, InvalidRequest, IdentifierNotUnique {
1865

    
1866
		return hasReservation(null, subject, pid);
1867
	}
1868
	
1869
	@Override
1870
	public Identifier registerSystemMetadata(Identifier pid, SystemMetadata sysmeta)
1871
			throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1872
			InvalidSystemMetadata, InvalidToken {
1873

    
1874
		return registerSystemMetadata(null, pid, sysmeta);
1875
	}
1876
	
1877
	@Override
1878
	public Identifier reserveIdentifier(Identifier pid) throws InvalidToken,
1879
			ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented,
1880
			InvalidRequest {
1881

    
1882
		return reserveIdentifier(null, pid);
1883
	}
1884
	
1885
	@Override
1886
	public boolean setObsoletedBy(Identifier pid, Identifier obsoletedByPid, long serialVersion)
1887
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1888
			InvalidRequest, InvalidToken, VersionMismatch {
1889

    
1890
		return setObsoletedBy(null, pid, obsoletedByPid, serialVersion);
1891
	}
1892
	
1893
	@Override
1894
	public DescribeResponse describe(Identifier pid) throws InvalidToken,
1895
			NotAuthorized, NotImplemented, ServiceFailure, NotFound {
1896

    
1897
		return describe(null, pid);
1898
	}
1899
	
1900
	@Override
1901
	public InputStream get(Identifier pid) throws InvalidToken, ServiceFailure,
1902
			NotAuthorized, NotFound, NotImplemented {
1903

    
1904
		return get(null, pid);
1905
	}
1906
	
1907
	@Override
1908
	public Checksum getChecksum(Identifier pid) throws InvalidToken,
1909
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1910

    
1911
		return getChecksum(null, pid);
1912
	}
1913
	
1914
	@Override
1915
	public SystemMetadata getSystemMetadata(Identifier pid) throws InvalidToken,
1916
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1917

    
1918
		return getSystemMetadata(null, pid);
1919
	}
1920
	
1921
	@Override
1922
	public ObjectList listObjects(Date startTime, Date endTime,
1923
			ObjectFormatIdentifier formatid, Boolean replicaStatus, Integer start, Integer count)
1924
			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1925
			ServiceFailure {
1926

    
1927
		return listObjects(null, startTime, endTime, formatid, replicaStatus, start, count);
1928
	}
1929
	
1930
	@Override
1931
	public ObjectLocationList resolve(Identifier pid) throws InvalidToken,
1932
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
1933

    
1934
		return resolve(null, pid);
1935
	}
1936
	
1937
	@Override
1938
	public ObjectList search(String queryType, String query) throws InvalidToken,
1939
			ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented {
1940

    
1941
		return search(null, queryType, query);
1942
	}
1943
	
1944
	@Override
1945
	public boolean deleteReplicationMetadata(Identifier pid, NodeReference nodeId,
1946
			long serialVersion) throws InvalidToken, InvalidRequest, ServiceFailure,
1947
			NotAuthorized, NotFound, NotImplemented, VersionMismatch {
1948

    
1949
		return deleteReplicationMetadata(null, pid, nodeId, serialVersion);
1950
	}
1951
	
1952
	@Override
1953
	public boolean isNodeAuthorized(Subject targetNodeSubject, Identifier pid)
1954
			throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
1955
			NotFound, InvalidRequest {
1956

    
1957
		return isNodeAuthorized(null, targetNodeSubject, pid);
1958
	}
1959
	
1960
	@Override
1961
	public boolean setReplicationPolicy(Identifier pid, ReplicationPolicy policy,
1962
			long serialVersion) throws NotImplemented, NotFound, NotAuthorized,
1963
			ServiceFailure, InvalidRequest, InvalidToken, VersionMismatch {
1964

    
1965
		return setReplicationPolicy(null, pid, policy, serialVersion);
1966
	}
1967
	
1968
	@Override
1969
	public boolean setReplicationStatus(Identifier pid, NodeReference targetNode,
1970
			ReplicationStatus status, BaseException failure) throws ServiceFailure,
1971
			NotImplemented, InvalidToken, NotAuthorized, InvalidRequest, NotFound {
1972

    
1973
		return setReplicationStatus(null, pid, targetNode, status, failure);
1974
	}
1975
	
1976
	@Override
1977
	public boolean updateReplicationMetadata(Identifier pid, Replica replica,
1978
			long serialVersion) throws NotImplemented, NotAuthorized, ServiceFailure,
1979
			NotFound, InvalidRequest, InvalidToken, VersionMismatch {
1980

    
1981
		return updateReplicationMetadata(null, pid, replica, serialVersion);
1982
	}
1983

    
1984
  @Override
1985
  public QueryEngineDescription getQueryEngineDescription(String arg0)
1986
          throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
1987
          NotFound {
1988
      throw new NotImplemented("4410", "getQueryEngineDescription not implemented");
1989
      
1990
  }
1991

    
1992
  @Override
1993
  public QueryEngineList listQueryEngines() throws InvalidToken, ServiceFailure,
1994
          NotAuthorized, NotImplemented {
1995
      throw new NotImplemented("4420", "listQueryEngines not implemented");
1996
      
1997
  }
1998

    
1999
  @Override
2000
  public InputStream query(String arg0, String arg1) throws InvalidToken,
2001
          ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, NotFound {
2002
      throw new NotImplemented("4324", "query not implemented");
2003
      
2004
  }
2005
}
(1-1/6)