Project

General

Profile

1 6177 cjones
/**
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 6569 cjones
import java.io.InputStream;
27 6567 cjones
import java.math.BigInteger;
28 6883 leinfelder
import java.util.ArrayList;
29 6567 cjones
import java.util.Calendar;
30 6177 cjones
import java.util.Date;
31 6220 leinfelder
import java.util.List;
32 6859 cjones
import java.util.concurrent.locks.Lock;
33 6177 cjones
34 6542 leinfelder
import javax.servlet.http.HttpServletRequest;
35
36 6178 cjones
import org.apache.log4j.Logger;
37 6484 cjones
import org.dataone.client.CNode;
38
import org.dataone.client.D1Client;
39 7073 cjones
import org.dataone.client.MNode;
40 6366 leinfelder
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 6792 cjones
import org.dataone.service.exceptions.BaseException;
45 6177 cjones
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 6569 cjones
import org.dataone.service.exceptions.UnsupportedType;
55 6869 cjones
import org.dataone.service.exceptions.VersionMismatch;
56 6571 cjones
import org.dataone.service.types.v1.AccessPolicy;
57 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
58 6803 leinfelder
import org.dataone.service.types.v1.ChecksumAlgorithmList;
59 7144 leinfelder
import org.dataone.service.types.v1.DescribeResponse;
60
import org.dataone.service.types.v1.Event;
61 6366 leinfelder
import org.dataone.service.types.v1.Identifier;
62 7144 leinfelder
import org.dataone.service.types.v1.Log;
63 6463 cjones
import org.dataone.service.types.v1.Node;
64 6366 leinfelder
import org.dataone.service.types.v1.NodeList;
65 6409 cjones
import org.dataone.service.types.v1.NodeReference;
66 6570 cjones
import org.dataone.service.types.v1.NodeType;
67 6366 leinfelder
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 6881 leinfelder
import org.dataone.service.types.v1.util.ServiceMethodRestrictionUtil;
80 7401 cjones
import org.dataone.service.types.v1_1.QueryEngineDescription;
81
import org.dataone.service.types.v1_1.QueryEngineList;
82 6177 cjones
83 6188 leinfelder
import edu.ucsb.nceas.metacat.EventLog;
84
import edu.ucsb.nceas.metacat.IdentifierManager;
85 8444 cjones
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
86 6446 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
87 6188 leinfelder
88 6177 cjones
/**
89
 * Represents Metacat's implementation of the DataONE Coordinating Node
90 6179 cjones
 * service API. Methods implement the various CN* interfaces, and methods common
91 6177 cjones
 * 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 6446 leinfelder
    CNCore, CNRead, CNReplication {
97 6177 cjones
98 6178 cjones
  /* the logger instance */
99
  private Logger logMetacat = null;
100 6177 cjones
101 6178 cjones
  /**
102
   * singleton accessor
103
   */
104 6542 leinfelder
  public static CNodeService getInstance(HttpServletRequest request) {
105
    return new CNodeService(request);
106 6178 cjones
  }
107
108
  /**
109
   * Constructor, private for singleton access
110
   */
111 6542 leinfelder
  private CNodeService(HttpServletRequest request) {
112
    super(request);
113 6178 cjones
    logMetacat = Logger.getLogger(CNodeService.class);
114
115
  }
116
117 6410 cjones
  /**
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 6869 cjones
   * @throws VersionMismatch
131 6410 cjones
   *
132
   */
133 6471 jones
  @Override
134 6410 cjones
  public boolean setReplicationPolicy(Session session, Identifier pid,
135 6593 cjones
      ReplicationPolicy policy, long serialVersion)
136 6567 cjones
      throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
137 6869 cjones
      InvalidRequest, InvalidToken, VersionMismatch {
138 6567 cjones
139 6717 cjones
      // The lock to be used for this identifier
140 6859 cjones
      Lock lock = null;
141 6702 cjones
142 6567 cjones
      // get the subject
143
      Subject subject = session.getSubject();
144
145
      // are we allowed to do this?
146 7068 cjones
      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 6869 cjones
      }
152
153
      SystemMetadata systemMetadata = null;
154 6567 cjones
      try {
155 6858 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
156
          lock.lock();
157 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
158 6858 cjones
159
          try {
160
              if ( HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid) ) {
161
                  systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
162
163
              }
164 6869 cjones
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 6858 cjones
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 6869 cjones
                 throw new VersionMismatch("4886", msg);
178
179 6858 cjones
              }
180 6717 cjones
181 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
182 6858 cjones
              throw new NotFound("4884", "No record found for: " + pid.getValue());
183
184 6717 cjones
          }
185 6858 cjones
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 7076 cjones
              notifyReplicaNodes(systemMetadata);
195
196 6869 cjones
          } catch (RuntimeException e) {
197 6858 cjones
              throw new ServiceFailure("4882", e.getMessage());
198
199 6593 cjones
          }
200
201 6869 cjones
      } 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 6410 cjones
210 6567 cjones
      return true;
211 6410 cjones
  }
212 6177 cjones
213 6410 cjones
  /**
214 6881 leinfelder
   * 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 6883 leinfelder
   * @throws VersionMismatch
227 6881 leinfelder
   */
228 6884 leinfelder
  @Override
229 6881 leinfelder
  public boolean deleteReplicationMetadata(Session session, Identifier pid, NodeReference nodeId, long serialVersion)
230 6883 leinfelder
  	throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, VersionMismatch {
231 6881 leinfelder
232 6883 leinfelder
	  	// 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 7068 cjones
		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 6883 leinfelder
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 7218 cjones
			if (!isAllowed) {
289 6883 leinfelder
				throw new NotAuthorized("4881", "Caller is not authorized to deleteReplicationMetadata");
290
			}
291
292
			// delete the replica from the given node
293 7252 cjones
			// CSJ: use CN.delete() to truly delete a replica, semantically
294
			// deleteReplicaMetadata() only modifies the sytem metadata entry.
295 7251 cjones
			//D1Client.getMN(nodeId).delete(session, pid);
296 6883 leinfelder
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 6881 leinfelder
325
  }
326
327 6883 leinfelder
  /**
328 8444 cjones
   * Deletes an object from the Coordinating Node
329 7077 leinfelder
   *
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 8444 cjones
346
      String localId = null; // The corresponding docid for this pid
347
	  Lock lock = null;      // The lock to be used for this identifier
348 7077 leinfelder
349 8444 cjones
      // 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 7078 leinfelder
	  // check that it is CN/admin
362 7142 leinfelder
	  boolean allowed = isAdminAuthorized(session);
363 7077 leinfelder
364 8360 tao
	  // additional check if it is the authoritative node if it is not the admin
365
      if(!allowed) {
366
          allowed = isAuthoritativeMNodeAdmin(session, pid);
367 8444 cjones
368 8360 tao
      }
369
370 7078 leinfelder
	  if (!allowed) {
371 8444 cjones
		  String msg = "The subject " + session.getSubject().getValue() +
372
			  " is not allowed to call delete() on a Coordinating Node.";
373 7078 leinfelder
		  logMetacat.info(msg);
374 8444 cjones
		  throw new NotAuthorized("4960", msg);
375
376 7078 leinfelder
	  }
377
378 8444 cjones
	  // 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 7147 leinfelder
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 8444 cjones
	  return pid;
440 7147 leinfelder
441 7077 leinfelder
  }
442
443
  /**
444 8444 cjones
   * Archives an object from the Coordinating Node
445 7148 leinfelder
   *
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 8444 cjones
      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 7148 leinfelder
	  // check that it is CN/admin
478
	  boolean allowed = isAdminAuthorized(session);
479
480 8360 tao
	  //check if it is the authoritative member node
481
	  if(!allowed) {
482
	      allowed = isAuthoritativeMNodeAdmin(session, pid);
483
	  }
484
485 7148 leinfelder
	  if (!allowed) {
486 8444 cjones
		  String msg = "The subject " + session.getSubject().getValue() +
487
				  " is not allowed to call archive() on a Coordinating Node.";
488 7148 leinfelder
		  logMetacat.info(msg);
489 8444 cjones
		  throw new NotAuthorized("4970", msg);
490 7148 leinfelder
	  }
491
492 8444 cjones
      // 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 7148 leinfelder
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 8444 cjones
	  return pid;
552 7148 leinfelder
553
  }
554
555
  /**
556 6883 leinfelder
   * 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 6884 leinfelder
  @Override
571 6883 leinfelder
  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 7068 cjones
		if (!isAuthorized(session, pid, Permission.WRITE)) {
584
			throw new NotAuthorized("4881", Permission.WRITE
585
					+ " not allowed by " + subject.getValue() + " on "
586
					+ pid.getValue());
587 6883 leinfelder
588
		}
589
590 7068 cjones
591 6883 leinfelder
		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 6881 leinfelder
645 6883 leinfelder
646 6881 leinfelder
  /**
647 6410 cjones
   * 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 6471 jones
  @Override
664 6410 cjones
  public boolean setReplicationStatus(Session session, Identifier pid,
665 6792 cjones
      NodeReference targetNode, ReplicationStatus status, BaseException failure)
666 6644 cjones
      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized,
667
      InvalidRequest, NotFound {
668 7066 leinfelder
669
	  // cannot be called by public
670
	  if (session == null) {
671
		  throw new NotAuthorized("4720", "Session cannot be null");
672
	  }
673 6644 cjones
674 6702 cjones
      // The lock to be used for this identifier
675 6859 cjones
      Lock lock = null;
676 6702 cjones
677 6644 cjones
      boolean allowed = false;
678
      int replicaEntryIndex = -1;
679
      List<Replica> replicas = null;
680
      // get the subject
681
      Subject subject = session.getSubject();
682 6676 cjones
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
683
          " is " + status.toString());
684 6644 cjones
685
      SystemMetadata systemMetadata = null;
686 6858 cjones
687
      try {
688 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
689 6702 cjones
          lock.lock();
690 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
691
692 6858 cjones
          try {
693
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
694 6657 cjones
695 6869 cjones
              // did we get it correctly?
696 6858 cjones
              if ( systemMetadata == null ) {
697
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
698 6869 cjones
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
699 6858 cjones
700
              }
701
              replicas = systemMetadata.getReplicaList();
702
              int count = 0;
703 6657 cjones
704 6876 cjones
              // was there a failure? log it
705 7600 cjones
              if ( failure != null && status.equals(ReplicationStatus.FAILED) ) {
706 6876 cjones
                 String msg = "The replication request of the object identified by " +
707
                     pid.getValue() + " failed.  The error message was " +
708
                     failure.getMessage() + ".";
709 6858 cjones
              }
710 6869 cjones
711 6876 cjones
              if (replicas.size() > 0 && replicas != null) {
712
                  // find the target replica index in the replica list
713
                  for (Replica replica : replicas) {
714 7600 cjones
                      String replicaNodeStr = replica.getReplicaMemberNode().getValue();
715 6876 cjones
                      String targetNodeStr = targetNode.getValue();
716 7600 cjones
                      logMetacat.debug("Comparing " + replicaNodeStr + " to " + targetNodeStr);
717 6869 cjones
718 6876 cjones
                      if (replicaNodeStr.equals(targetNodeStr)) {
719
                          replicaEntryIndex = count;
720
                          logMetacat.debug("replica entry index is: "
721
                                  + replicaEntryIndex);
722
                          break;
723
                      }
724
                      count++;
725 6858 cjones
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 6657 cjones
732 6858 cjones
              // find the node in the node list
733
              for ( Node node : nodes ) {
734
735
                  NodeReference nodeReference = node.getIdentifier();
736 7600 cjones
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " +
737
                      nodeReference.getValue());
738 6858 cjones
739 7074 cjones
                  // allow target MN certs
740 7600 cjones
                  if ( targetNode.getValue().equals(nodeReference.getValue() ) &&
741
                      node.getType().equals(NodeType.MN)) {
742 6858 cjones
                      List<Subject> nodeSubjects = node.getSubjectList();
743
744
                      // check if the session subject is in the node subject list
745
                      for (Subject nodeSubject : nodeSubjects) {
746 7071 cjones
                          logMetacat.debug("In setReplicationStatus(), comparing subjects: " +
747
                                  nodeSubject.getValue() + " and " + subject.getValue());
748 7074 cjones
                          if ( nodeSubject.equals(subject) ) { // subject of session == target node subject
749 6858 cjones
750 7179 cjones
                              // lastly limit to COMPLETED, INVALIDATED,
751
                              // and FAILED status updates from MNs only
752 7600 cjones
                              if ( status.equals(ReplicationStatus.COMPLETED) ||
753
                                   status.equals(ReplicationStatus.INVALIDATED) ||
754
                                   status.equals(ReplicationStatus.FAILED)) {
755 7074 cjones
                                  allowed = true;
756
                                  break;
757
758
                              }
759 6858 cjones
                          }
760
                      }
761
                  }
762
              }
763 6657 cjones
764 7071 cjones
              if ( !allowed ) {
765
                  //check for CN admin access
766
                  allowed = isAuthorized(session, pid, Permission.WRITE);
767 6858 cjones
768 7071 cjones
              }
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 6858 cjones
              }
780 6876 cjones
781 6858 cjones
          } 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 6644 cjones
          }
786
787 6876 cjones
          Replica targetReplica = new Replica();
788 6858 cjones
          // set the status for the replica
789
          if ( replicaEntryIndex != -1 ) {
790 6876 cjones
              targetReplica = replicas.get(replicaEntryIndex);
791 7231 cjones
792
              // don't allow status to change from COMPLETED to anything other
793
              // than INVALIDATED: prevents overwrites from race conditions
794 7600 cjones
              if ( targetReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
795
            	   !status.equals(ReplicationStatus.INVALIDATED)) {
796 7231 cjones
            	  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 6858 cjones
              targetReplica.setReplicationStatus(status);
804 7514 cjones
805 6858 cjones
              logMetacat.debug("Set the replication status for " +
806
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
807 7231 cjones
                  targetReplica.getReplicationStatus() + " for identifier " +
808
                  pid.getValue());
809 6644 cjones
810 6858 cjones
          } else {
811 6876 cjones
              // 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 6644 cjones
          }
818
819 6858 cjones
          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 7179 cjones
827 7600 cjones
              if ( !status.equals(ReplicationStatus.QUEUED) &&
828
            	   !status.equals(ReplicationStatus.REQUESTED)) {
829 7179 cjones
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 7600 cjones
              if ( status.equals(ReplicationStatus.FAILED) && failure != null ) {
841 6858 cjones
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
842
                      " on target node " + targetNode + ". The exception was: " +
843
                      failure.getMessage());
844
              }
845 7514 cjones
846
			  // update the replica nodes about the completed replica when complete
847 7600 cjones
              if (status.equals(ReplicationStatus.COMPLETED)) {
848 8439 cjones
				notifyReplicaNodes(systemMetadata);
849 7514 cjones
			}
850
851 6869 cjones
          } catch (RuntimeException e) {
852 6858 cjones
              throw new ServiceFailure("4700", e.getMessage());
853
854 6644 cjones
          }
855
856 6867 cjones
    } 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 6858 cjones
        lock.unlock();
863
        logMetacat.debug("Unlocked identifier " + pid.getValue());
864 6593 cjones
865 6858 cjones
    }
866 6676 cjones
867 6644 cjones
      return true;
868 6410 cjones
  }
869
870 7514 cjones
/**
871 6410 cjones
   * 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 6471 jones
  @Override
885 6410 cjones
  public Checksum getChecksum(Session session, Identifier pid)
886
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
887 6622 leinfelder
    NotImplemented {
888 7029 leinfelder
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 6568 cjones
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());
897 6410 cjones
    }
898 6568 cjones
899 6410 cjones
    SystemMetadata systemMetadata = null;
900 6568 cjones
    Checksum checksum = null;
901
902 6410 cjones
    try {
903 6869 cjones
        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 6568 cjones
        checksum = systemMetadata.getChecksum();
909 6869 cjones
910
    } catch (RuntimeException e) {
911 6568 cjones
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " +
912
            pid.getValue() + ". The error message was: " + e.getMessage());
913
914 6410 cjones
    }
915
916
    return checksum;
917
  }
918 6177 cjones
919 6410 cjones
  /**
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 6471 jones
  @Override
934 6410 cjones
  public ObjectLocationList resolve(Session session, Identifier pid)
935 6622 leinfelder
    throws InvalidToken, ServiceFailure, NotAuthorized,
936 6410 cjones
    NotFound, NotImplemented {
937 6177 cjones
938 6410 cjones
    throw new NotImplemented("4131", "resolve not implemented");
939 6303 leinfelder
940 6410 cjones
  }
941 6177 cjones
942 6410 cjones
  /**
943 7464 leinfelder
   * Metacat does not implement this method at the CN level
944 6410 cjones
   */
945 6471 jones
  @Override
946 6410 cjones
  public ObjectList search(Session session, String queryType, String query)
947
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
948
    NotImplemented {
949 6177 cjones
950 7464 leinfelder
		  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 6410 cjones
  }
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 6471 jones
  @Override
986 6410 cjones
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
987 6803 leinfelder
    throws ServiceFailure, NotFound, NotImplemented {
988 6410 cjones
989
      return ObjectFormatService.getInstance().getFormat(fmtid);
990
991
  }
992 6177 cjones
993 6410 cjones
  /**
994 6177 cjones
   * Returns a list of all object formats registered in the DataONE Object
995
   * Format Vocabulary
996 6410 cjones
    *
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 6471 jones
  @Override
1005 6410 cjones
  public ObjectFormatList listFormats()
1006 6803 leinfelder
    throws ServiceFailure, NotImplemented {
1007 6177 cjones
1008 6410 cjones
    return ObjectFormatService.getInstance().listFormats();
1009
  }
1010 6177 cjones
1011 6410 cjones
  /**
1012 6177 cjones
   * Returns a list of nodes that have been registered with the DataONE infrastructure
1013 6410 cjones
    *
1014
   * @return nodeList - List of nodes from the registry
1015
   *
1016
   * @throws ServiceFailure
1017
   * @throws NotImplemented
1018
   */
1019 6471 jones
  @Override
1020 6410 cjones
  public NodeList listNodes()
1021
    throws NotImplemented, ServiceFailure {
1022 6177 cjones
1023 6410 cjones
    throw new NotImplemented("4800", "listNodes not implemented");
1024
  }
1025 6177 cjones
1026 6410 cjones
  /**
1027 6177 cjones
   * Provides a mechanism for adding system metadata independently of its
1028
   * associated object, such as when adding system metadata for data objects.
1029 6410 cjones
    *
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 6471 jones
  @Override
1043 6575 cjones
  public Identifier registerSystemMetadata(Session session, Identifier pid,
1044
      SystemMetadata sysmeta)
1045
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1046
      InvalidSystemMetadata {
1047 6177 cjones
1048 6702 cjones
      // The lock to be used for this identifier
1049 6859 cjones
      Lock lock = null;
1050 6702 cjones
1051 6575 cjones
      // 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 6188 leinfelder
1069 6575 cjones
      try {
1070 6703 cjones
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
1071 6863 cjones
          lock.lock();
1072 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1073 6863 cjones
          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 6575 cjones
1079 6863 cjones
          }
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 6869 cjones
          } catch (RuntimeException e) {
1089 6863 cjones
            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 6869 cjones
      } catch (RuntimeException e) {
1096 6575 cjones
          throw new ServiceFailure("4862", "Error inserting system metadata: " +
1097 6863 cjones
                  e.getClass() + ": " + e.getMessage());
1098 6575 cjones
1099 6863 cjones
      }  finally {
1100
          lock.unlock();
1101
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1102
1103
      }
1104 6466 cjones
1105 6575 cjones
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 6410 cjones
  }
1112
1113
  /**
1114 6177 cjones
   * 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 6410 cjones
    *
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 6471 jones
  @Override
1141 6622 leinfelder
  public Identifier reserveIdentifier(Session session, Identifier pid)
1142 6410 cjones
  throws InvalidToken, ServiceFailure,
1143 6378 leinfelder
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
1144 6177 cjones
1145 6410 cjones
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1146
  }
1147
1148 6471 jones
  @Override
1149 6410 cjones
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1150
  throws InvalidToken, ServiceFailure,
1151 6378 leinfelder
        NotAuthorized, NotImplemented, InvalidRequest {
1152 6410 cjones
    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 6177 cjones
1172 6471 jones
  @Override
1173 6934 leinfelder
  public boolean hasReservation(Session session, Subject subject, Identifier pid)
1174 6410 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique,
1175
      NotImplemented, InvalidRequest {
1176
1177
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1178
  }
1179 6339 leinfelder
1180 6410 cjones
  /**
1181 6177 cjones
   * Changes ownership (RightsHolder) of the specified object to the
1182
   * subject specified by userId
1183 6410 cjones
    *
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 6471 jones
  @Override
1198 6803 leinfelder
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1199 6593 cjones
      long serialVersion)
1200
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1201 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
1202 6593 cjones
1203 6702 cjones
      // The lock to be used for this identifier
1204 6859 cjones
      Lock lock = null;
1205 6702 cjones
1206 6593 cjones
      // get the subject
1207
      Subject subject = session.getSubject();
1208
1209
      // are we allowed to do this?
1210 7068 cjones
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1211
          throw new NotAuthorized("4440", "not allowed by "
1212
                  + subject.getValue() + " on " + pid.getValue());
1213
1214 6869 cjones
      }
1215
1216
      SystemMetadata systemMetadata = null;
1217 6593 cjones
      try {
1218 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1219 7467 leinfelder
          lock.lock();
1220 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1221
1222 6858 cjones
          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 6869 cjones
                 throw new VersionMismatch("4443", msg);
1232 6858 cjones
              }
1233
1234 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1235 6858 cjones
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1236
1237 6593 cjones
          }
1238 6858 cjones
1239
          // set the new rights holder
1240
          systemMetadata.setRightsHolder(userId);
1241 6593 cjones
1242 6858 cjones
          // 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 7076 cjones
              notifyReplicaNodes(systemMetadata);
1248 6858 cjones
1249 6869 cjones
          } catch (RuntimeException e) {
1250
              throw new ServiceFailure("4490", e.getMessage());
1251 6593 cjones
1252 6858 cjones
          }
1253 6593 cjones
1254 6869 cjones
      } catch (RuntimeException e) {
1255 6858 cjones
          throw new ServiceFailure("4490", e.getMessage());
1256 6644 cjones
1257
      } finally {
1258 6702 cjones
          lock.unlock();
1259 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1260 6858 cjones
1261 6644 cjones
      }
1262
1263 6869 cjones
      return pid;
1264 6410 cjones
  }
1265 6177 cjones
1266 6410 cjones
  /**
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 6471 jones
  @Override
1285 6409 cjones
  public boolean isNodeAuthorized(Session originatingNodeSession,
1286 6777 leinfelder
    Subject targetNodeSubject, Identifier pid)
1287 6410 cjones
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
1288
    NotFound, InvalidRequest {
1289 6702 cjones
1290 6644 cjones
    boolean isAllowed = false;
1291
    SystemMetadata sysmeta = null;
1292 6463 cjones
    NodeReference targetNode = null;
1293
1294 6644 cjones
    try {
1295
      // get the target node reference from the nodes list
1296
      CNode cn = D1Client.getCN();
1297
      List<Node> nodes = cn.listNodes().getNodeList();
1298 6665 cjones
1299 6657 cjones
      if ( nodes != null ) {
1300
        for (Node node : nodes) {
1301 6665 cjones
1302 7141 leinfelder
        	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 6657 cjones
1314 6665 cjones
            if ( targetNode != null) { break; }
1315 6657 cjones
        }
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 6644 cjones
      }
1323 6757 cjones
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 7062 leinfelder
          throw new NotAuthorized("4871", msg);
1330 6757 cjones
1331
      }
1332
1333 6657 cjones
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1334
1335 6644 cjones
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1336 6463 cjones
1337 6657 cjones
      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 6757 cjones
                  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 6657 cjones
1356 6757 cjones
                      }
1357 6657 cjones
                  }
1358
              }
1359 6568 cjones
          }
1360 6665 cjones
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1361
              "to replicate: " + isAllowed + " for " + pid.getValue());
1362
1363 6657 cjones
1364
      } else {
1365
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1366
          " is null.");
1367 6869 cjones
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue());
1368 6657 cjones
1369 6568 cjones
      }
1370 6484 cjones
1371 6662 cjones
    } catch (RuntimeException e) {
1372 6665 cjones
    	  ServiceFailure sf = new ServiceFailure("4872",
1373
                "Runtime Exception: Couldn't determine if node is allowed: " +
1374 7140 leinfelder
                e.getMessage());
1375 6665 cjones
    	  sf.initCause(e);
1376 6659 leinfelder
        throw sf;
1377 6636 cjones
1378 6644 cjones
    }
1379
1380
    return isAllowed;
1381 6410 cjones
1382 6384 cjones
  }
1383
1384 6569 cjones
  /**
1385 6570 cjones
   * Adds a new object to the Node, where the object is a science metadata object.
1386 6569 cjones
   *
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 6917 cjones
1410 6702 cjones
      // The lock to be used for this identifier
1411 6859 cjones
      Lock lock = null;
1412 6917 cjones
1413 6570 cjones
      try {
1414 6869 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1415
          // are we allowed?
1416 6570 cjones
          boolean isAllowed = false;
1417 7142 leinfelder
          isAllowed = isAdminAuthorized(session);
1418 8360 tao
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 6570 cjones
1424
          // proceed if we're called by a CN
1425
          if ( isAllowed ) {
1426
              // create the coordinating node version of the document
1427 6702 cjones
              lock.lock();
1428 6867 cjones
              logMetacat.debug("Locked identifier " + pid.getValue());
1429 6570 cjones
              sysmeta.setSerialVersion(BigInteger.ONE);
1430
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1431 6917 cjones
              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 6570 cjones
              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 6676 cjones
      } catch (RuntimeException e) {
1453 6570 cjones
          // 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 6676 cjones
          throw new ServiceFailure("4893", msg);
1457 6570 cjones
1458
      } finally {
1459 6805 leinfelder
    	  if (lock != null) {
1460
	          lock.unlock();
1461
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1462
    	  }
1463 6570 cjones
      }
1464
1465 6569 cjones
      return pid;
1466
1467
  }
1468
1469 6571 cjones
  /**
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 6593 cjones
      AccessPolicy accessPolicy, long serialVersion)
1487 6571 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1488 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
1489 6571 cjones
1490 6702 cjones
      // The lock to be used for this identifier
1491 6859 cjones
      Lock lock = null;
1492 6869 cjones
      SystemMetadata systemMetadata = null;
1493 6702 cjones
1494 6571 cjones
      boolean success = false;
1495
1496
      // get the subject
1497
      Subject subject = session.getSubject();
1498
1499 7068 cjones
      // 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 6571 cjones
      }
1504
1505
      try {
1506 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1507 6702 cjones
          lock.lock();
1508 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1509
1510 6858 cjones
          try {
1511
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1512 6571 cjones
1513 6869 cjones
              if ( systemMetadata == null ) {
1514
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1515
1516
              }
1517 6858 cjones
              // 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 6869 cjones
                 throw new VersionMismatch("4402", msg);
1524
1525 6858 cjones
              }
1526
1527 6869 cjones
          } catch (RuntimeException e) {
1528 6858 cjones
              // convert Hazelcast RuntimeException to NotFound
1529
              throw new NotFound("4400", "No record found for: " + pid);
1530
1531 6593 cjones
          }
1532 6858 cjones
1533
          // set the access policy
1534
          systemMetadata.setAccessPolicy(accessPolicy);
1535 6593 cjones
1536 6858 cjones
          // 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 7076 cjones
              notifyReplicaNodes(systemMetadata);
1542
1543 6869 cjones
          } catch (RuntimeException e) {
1544 6858 cjones
              // convert Hazelcast RuntimeException to ServiceFailure
1545
              throw new ServiceFailure("4430", e.getMessage());
1546
1547
          }
1548 6571 cjones
1549 6869 cjones
      } catch (RuntimeException e) {
1550 6571 cjones
          throw new ServiceFailure("4430", e.getMessage());
1551 6858 cjones
1552 6571 cjones
      } finally {
1553 6702 cjones
          lock.unlock();
1554 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1555 6571 cjones
1556
      }
1557 6858 cjones
1558 6571 cjones
1559
    // TODO: how do we know if the map was persisted?
1560
    success = true;
1561
1562
    return success;
1563
  }
1564
1565 6578 cjones
  /**
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 6869 cjones
   * @throws VersionMismatch
1579 6578 cjones
   */
1580 6869 cjones
  @Override
1581 6578 cjones
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1582 6593 cjones
      Replica replica, long serialVersion)
1583 6578 cjones
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1584 6869 cjones
      NotFound, VersionMismatch {
1585 6578 cjones
1586 6702 cjones
      // The lock to be used for this identifier
1587 6859 cjones
      Lock lock = null;
1588 6702 cjones
1589 6578 cjones
      // get the subject
1590
      Subject subject = session.getSubject();
1591
1592
      // are we allowed to do this?
1593
      try {
1594 7068 cjones
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 6578 cjones
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 6858 cjones
      try {
1610 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1611 6702 cjones
          lock.lock();
1612 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1613 6578 cjones
1614 6858 cjones
          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 6869 cjones
                 throw new VersionMismatch("4855", msg);
1624 6858 cjones
              }
1625
1626 6869 cjones
          } 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 6858 cjones
1630 6593 cjones
          }
1631 6858 cjones
1632
          // set the status for the replica
1633
          List<Replica> replicas = systemMetadata.getReplicaList();
1634
          NodeReference replicaNode = replica.getReplicaMemberNode();
1635 7231 cjones
          ReplicationStatus replicaStatus = replica.getReplicationStatus();
1636 6858 cjones
          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 7231 cjones
                      // don't allow status to change from COMPLETED to anything other
1642
                      // than INVALIDATED: prevents overwrites from race conditions
1643 7600 cjones
                	  if ( !listedReplica.getReplicationStatus().equals(replicaStatus) &&
1644
                	       listedReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
1645
            		       !replicaStatus.equals(ReplicationStatus.INVALIDATED) ) {
1646 7231 cjones
                	  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 6858 cjones
                  replicas.remove(index);
1654
                  break;
1655
1656
              }
1657
              index++;
1658
          }
1659 6593 cjones
1660 6858 cjones
          // add the new replica item
1661
          replicas.add(replica);
1662
          systemMetadata.setReplicaList(replicas);
1663 6578 cjones
1664 6858 cjones
          // 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 7514 cjones
1670
              // inform replica nodes of the change if the status is complete
1671 7600 cjones
              if ( replicaStatus.equals(ReplicationStatus.COMPLETED) ) {
1672 8439 cjones
            	  notifyReplicaNodes(systemMetadata);
1673 7514 cjones
1674
              }
1675 6869 cjones
          } catch (RuntimeException e) {
1676
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1677 6858 cjones
              throw new ServiceFailure("4852", e.getMessage());
1678 6578 cjones
1679
          }
1680 6858 cjones
1681 6869 cjones
      } 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 6578 cjones
1691
      return true;
1692
1693
  }
1694 6622 leinfelder
1695 6869 cjones
  /**
1696
   *
1697
   */
1698
  @Override
1699 6858 cjones
  public ObjectList listObjects(Session session, Date startTime,
1700
      Date endTime, ObjectFormatIdentifier formatid, Boolean replicaStatus,
1701
      Integer start, Integer count)
1702 6644 cjones
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1703
      ServiceFailure {
1704
1705
      ObjectList objectList = null;
1706 6622 leinfelder
        try {
1707 7439 leinfelder
        	if (count == null || count > MAXIMUM_DB_RECORD_COUNT) {
1708
            	count = MAXIMUM_DB_RECORD_COUNT;
1709
            }
1710 6622 leinfelder
            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 6644 cjones
  }
1717 6803 leinfelder
1718 7012 cjones
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 6869 cjones
  @Override
1727 7012 cjones
  public ChecksumAlgorithmList listChecksumAlgorithms()
1728 6803 leinfelder
			throws ServiceFailure, NotImplemented {
1729
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
1730
		cal.addAlgorithm("MD5");
1731
		cal.addAlgorithm("SHA-1");
1732 7012 cjones
		return cal;
1733
1734 6803 leinfelder
	}
1735 7073 cjones
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 7144 leinfelder
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 7171 leinfelder
			NotAuthorized, NotFound, NotImplemented {
1841 7144 leinfelder
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 7401 cjones
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 6177 cjones
}