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 6366 leinfelder
import org.dataone.service.cn.v1.CNAuthorization;
40
import org.dataone.service.cn.v1.CNCore;
41
import org.dataone.service.cn.v1.CNRead;
42
import org.dataone.service.cn.v1.CNReplication;
43 6792 cjones
import org.dataone.service.exceptions.BaseException;
44 6177 cjones
import org.dataone.service.exceptions.IdentifierNotUnique;
45
import org.dataone.service.exceptions.InsufficientResources;
46
import org.dataone.service.exceptions.InvalidRequest;
47
import org.dataone.service.exceptions.InvalidSystemMetadata;
48
import org.dataone.service.exceptions.InvalidToken;
49
import org.dataone.service.exceptions.NotAuthorized;
50
import org.dataone.service.exceptions.NotFound;
51
import org.dataone.service.exceptions.NotImplemented;
52
import org.dataone.service.exceptions.ServiceFailure;
53 6569 cjones
import org.dataone.service.exceptions.UnsupportedType;
54 6869 cjones
import org.dataone.service.exceptions.VersionMismatch;
55 6571 cjones
import org.dataone.service.types.v1.AccessPolicy;
56 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
57 6803 leinfelder
import org.dataone.service.types.v1.ChecksumAlgorithmList;
58 6366 leinfelder
import org.dataone.service.types.v1.Identifier;
59 6463 cjones
import org.dataone.service.types.v1.Node;
60 6366 leinfelder
import org.dataone.service.types.v1.NodeList;
61 6409 cjones
import org.dataone.service.types.v1.NodeReference;
62 6570 cjones
import org.dataone.service.types.v1.NodeType;
63 6366 leinfelder
import org.dataone.service.types.v1.ObjectFormat;
64
import org.dataone.service.types.v1.ObjectFormatIdentifier;
65
import org.dataone.service.types.v1.ObjectFormatList;
66
import org.dataone.service.types.v1.ObjectList;
67
import org.dataone.service.types.v1.ObjectLocationList;
68
import org.dataone.service.types.v1.Permission;
69
import org.dataone.service.types.v1.Replica;
70
import org.dataone.service.types.v1.ReplicationPolicy;
71
import org.dataone.service.types.v1.ReplicationStatus;
72
import org.dataone.service.types.v1.Session;
73
import org.dataone.service.types.v1.Subject;
74
import org.dataone.service.types.v1.SystemMetadata;
75 6881 leinfelder
import org.dataone.service.types.v1.util.ServiceMethodRestrictionUtil;
76 6177 cjones
77 6188 leinfelder
import edu.ucsb.nceas.metacat.EventLog;
78
import edu.ucsb.nceas.metacat.IdentifierManager;
79 6446 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
80 6188 leinfelder
81 6177 cjones
/**
82
 * Represents Metacat's implementation of the DataONE Coordinating Node
83 6179 cjones
 * service API. Methods implement the various CN* interfaces, and methods common
84 6177 cjones
 * to both Member Node and Coordinating Node interfaces are found in the
85
 * D1NodeService super class.
86
 *
87
 */
88
public class CNodeService extends D1NodeService implements CNAuthorization,
89 6446 leinfelder
    CNCore, CNRead, CNReplication {
90 6177 cjones
91 6178 cjones
  /* the logger instance */
92
  private Logger logMetacat = null;
93 6177 cjones
94 6178 cjones
  /**
95
   * singleton accessor
96
   */
97 6542 leinfelder
  public static CNodeService getInstance(HttpServletRequest request) {
98
    return new CNodeService(request);
99 6178 cjones
  }
100
101
  /**
102
   * Constructor, private for singleton access
103
   */
104 6542 leinfelder
  private CNodeService(HttpServletRequest request) {
105
    super(request);
106 6178 cjones
    logMetacat = Logger.getLogger(CNodeService.class);
107
108
  }
109
110 6410 cjones
  /**
111
   * Set the replication policy for an object given the object identifier
112
   *
113
   * @param session - the Session object containing the credentials for the Subject
114
   * @param pid - the object identifier for the given object
115
   * @param policy - the replication policy to be applied
116
   *
117
   * @return true or false
118
   *
119
   * @throws NotImplemented
120
   * @throws NotAuthorized
121
   * @throws ServiceFailure
122
   * @throws InvalidRequest
123 6869 cjones
   * @throws VersionMismatch
124 6410 cjones
   *
125
   */
126 6471 jones
  @Override
127 6410 cjones
  public boolean setReplicationPolicy(Session session, Identifier pid,
128 6593 cjones
      ReplicationPolicy policy, long serialVersion)
129 6567 cjones
      throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
130 6869 cjones
      InvalidRequest, InvalidToken, VersionMismatch {
131 6567 cjones
132 6717 cjones
      // The lock to be used for this identifier
133 6859 cjones
      Lock lock = null;
134 6702 cjones
135 6567 cjones
      // get the subject
136
      Subject subject = session.getSubject();
137
138
      // are we allowed to do this?
139 6866 cjones
      if (!isAdminAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
140 6869 cjones
          if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
141
              throw new NotAuthorized("4881", Permission.CHANGE_PERMISSION
142
                      + " not allowed by " + subject.getValue() + " on "
143
                      + pid.getValue());
144
145
          }
146
      }
147
148
      SystemMetadata systemMetadata = null;
149 6567 cjones
      try {
150 6858 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
151
          lock.lock();
152 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
153 6858 cjones
154
          try {
155
              if ( HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid) ) {
156
                  systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
157
158
              }
159 6869 cjones
160
              // did we get it correctly?
161
              if ( systemMetadata == null ) {
162
                  throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
163
164
              }
165 6858 cjones
166
              // does the request have the most current system metadata?
167
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
168
                 String msg = "The requested system metadata version number " +
169
                     serialVersion + " differs from the current version at " +
170
                     systemMetadata.getSerialVersion().longValue() +
171
                     ". Please get the latest copy in order to modify it.";
172 6869 cjones
                 throw new VersionMismatch("4886", msg);
173
174 6858 cjones
              }
175 6717 cjones
176 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
177 6858 cjones
              throw new NotFound("4884", "No record found for: " + pid.getValue());
178
179 6717 cjones
          }
180 6858 cjones
181
          // set the new policy
182
          systemMetadata.setReplicationPolicy(policy);
183
184
          // update the metadata
185
          try {
186
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
187
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
188
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
189
190 6869 cjones
          } catch (RuntimeException e) {
191 6858 cjones
              throw new ServiceFailure("4882", e.getMessage());
192
193 6593 cjones
          }
194
195 6869 cjones
      } catch (RuntimeException e) {
196
          throw new ServiceFailure("4882", e.getMessage());
197
198
      } finally {
199
          lock.unlock();
200
          logMetacat.debug("Unlocked identifier " + pid.getValue());
201
202
      }
203 6410 cjones
204 6567 cjones
      return true;
205 6410 cjones
  }
206 6177 cjones
207 6410 cjones
  /**
208 6881 leinfelder
   * Deletes the replica from the given Member Node
209
   * NOTE: MN.delete() may be an "archive" operation. TBD.
210
   * @param session
211
   * @param pid
212
   * @param nodeId
213
   * @param serialVersion
214
   * @return
215
   * @throws InvalidToken
216
   * @throws ServiceFailure
217
   * @throws NotAuthorized
218
   * @throws NotFound
219
   * @throws NotImplemented
220 6883 leinfelder
   * @throws VersionMismatch
221 6881 leinfelder
   */
222 6884 leinfelder
  @Override
223 6881 leinfelder
  public boolean deleteReplicationMetadata(Session session, Identifier pid, NodeReference nodeId, long serialVersion)
224 6883 leinfelder
  	throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, VersionMismatch {
225 6881 leinfelder
226 6883 leinfelder
	  	// The lock to be used for this identifier
227
		Lock lock = null;
228
229
		// get the subject
230
		Subject subject = session.getSubject();
231
232
		// are we allowed to do this?
233
		if (!isAdminAuthorized(session, pid, Permission.WRITE)) {
234
			if (!isAuthorized(session, pid, Permission.WRITE)) {
235
				throw new NotAuthorized("4881", Permission.WRITE
236
						+ " not allowed by " + subject.getValue() + " on "
237
						+ pid.getValue());
238
239
			}
240
		}
241
242
		SystemMetadata systemMetadata = null;
243
		try {
244
			lock = HazelcastService.getInstance().getLock(pid.getValue());
245
			lock.lock();
246
			logMetacat.debug("Locked identifier " + pid.getValue());
247
248
			try {
249
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
250
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
251
				}
252
253
				// did we get it correctly?
254
				if (systemMetadata == null) {
255
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
256
				}
257
258
				// does the request have the most current system metadata?
259
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
260
					String msg = "The requested system metadata version number "
261
							+ serialVersion
262
							+ " differs from the current version at "
263
							+ systemMetadata.getSerialVersion().longValue()
264
							+ ". Please get the latest copy in order to modify it.";
265
					throw new VersionMismatch("4886", msg);
266
267
				}
268
269
			} catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
270
				throw new NotFound("4884", "No record found for: " + pid.getValue());
271
272
			}
273
274
			// check permissions
275
			// TODO: is this necessary?
276
			List<Node> nodeList = D1Client.getCN().listNodes().getNodeList();
277
			boolean isAllowed = ServiceMethodRestrictionUtil.isMethodAllowed(session.getSubject(), nodeList, "CNReplication", "deleteReplicationMetadata");
278
			if (isAllowed) {
279
				throw new NotAuthorized("4881", "Caller is not authorized to deleteReplicationMetadata");
280
			}
281
282
			// delete the replica from the given node
283
			D1Client.getMN(nodeId).delete(session, pid);
284
285
			// reflect that change in the system metadata
286
			List<Replica> updatedReplicas = new ArrayList<Replica>(systemMetadata.getReplicaList());
287
			for (Replica r: systemMetadata.getReplicaList()) {
288
				  if (r.getReplicaMemberNode().equals(nodeId)) {
289
					  updatedReplicas.remove(r);
290
					  break;
291
				  }
292
			}
293
			systemMetadata.setReplicaList(updatedReplicas);
294
295
			// update the metadata
296
			try {
297
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
298
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
299
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
300
			} catch (RuntimeException e) {
301
				throw new ServiceFailure("4882", e.getMessage());
302
			}
303
304
		} catch (RuntimeException e) {
305
			throw new ServiceFailure("4882", e.getMessage());
306
		} finally {
307
			lock.unlock();
308
			logMetacat.debug("Unlocked identifier " + pid.getValue());
309
		}
310
311
		return true;
312 6881 leinfelder
313
  }
314
315 6883 leinfelder
  /**
316
   * Set the obsoletedBy attribute in System Metadata
317
   * @param session
318
   * @param pid
319
   * @param obsoletedByPid
320
   * @param serialVersion
321
   * @return
322
   * @throws NotImplemented
323
   * @throws NotFound
324
   * @throws NotAuthorized
325
   * @throws ServiceFailure
326
   * @throws InvalidRequest
327
   * @throws InvalidToken
328
   * @throws VersionMismatch
329
   */
330 6884 leinfelder
  @Override
331 6883 leinfelder
  public boolean setObsoletedBy(Session session, Identifier pid,
332
			Identifier obsoletedByPid, long serialVersion)
333
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
334
			InvalidRequest, InvalidToken, VersionMismatch {
335
336
		// The lock to be used for this identifier
337
		Lock lock = null;
338
339
		// get the subject
340
		Subject subject = session.getSubject();
341
342
		// are we allowed to do this?
343
		if (!isAdminAuthorized(session, pid, Permission.WRITE)) {
344
			if (!isAuthorized(session, pid, Permission.WRITE)) {
345
				throw new NotAuthorized("4881", Permission.WRITE
346
						+ " not allowed by " + subject.getValue() + " on "
347
						+ pid.getValue());
348
349
			}
350
		}
351
352
		SystemMetadata systemMetadata = null;
353
		try {
354
			lock = HazelcastService.getInstance().getLock(pid.getValue());
355
			lock.lock();
356
			logMetacat.debug("Locked identifier " + pid.getValue());
357
358
			try {
359
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
360
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
361
				}
362
363
				// did we get it correctly?
364
				if (systemMetadata == null) {
365
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
366
				}
367
368
				// does the request have the most current system metadata?
369
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
370
					String msg = "The requested system metadata version number "
371
							+ serialVersion
372
							+ " differs from the current version at "
373
							+ systemMetadata.getSerialVersion().longValue()
374
							+ ". Please get the latest copy in order to modify it.";
375
					throw new VersionMismatch("4886", msg);
376
377
				}
378
379
			} catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
380
				throw new NotFound("4884", "No record found for: " + pid.getValue());
381
382
			}
383
384
			// set the new policy
385
			systemMetadata.setObsoletedBy(obsoletedByPid);
386
387
			// update the metadata
388
			try {
389
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
390
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
391
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
392
			} catch (RuntimeException e) {
393
				throw new ServiceFailure("4882", e.getMessage());
394
			}
395
396
		} catch (RuntimeException e) {
397
			throw new ServiceFailure("4882", e.getMessage());
398
		} finally {
399
			lock.unlock();
400
			logMetacat.debug("Unlocked identifier " + pid.getValue());
401
		}
402
403
		return true;
404
	}
405 6881 leinfelder
406 6883 leinfelder
407 6881 leinfelder
  /**
408 6410 cjones
   * Set the replication status for an object given the object identifier
409
   *
410
   * @param session - the Session object containing the credentials for the Subject
411
   * @param pid - the object identifier for the given object
412
   * @param status - the replication status to be applied
413
   *
414
   * @return true or false
415
   *
416
   * @throws NotImplemented
417
   * @throws NotAuthorized
418
   * @throws ServiceFailure
419
   * @throws InvalidRequest
420
   * @throws InvalidToken
421
   * @throws NotFound
422
   *
423
   */
424 6471 jones
  @Override
425 6410 cjones
  public boolean setReplicationStatus(Session session, Identifier pid,
426 6792 cjones
      NodeReference targetNode, ReplicationStatus status, BaseException failure)
427 6644 cjones
      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized,
428
      InvalidRequest, NotFound {
429
430 6702 cjones
      // The lock to be used for this identifier
431 6859 cjones
      Lock lock = null;
432 6702 cjones
433 6644 cjones
      boolean allowed = false;
434
      int replicaEntryIndex = -1;
435
      List<Replica> replicas = null;
436
      // get the subject
437
      Subject subject = session.getSubject();
438 6676 cjones
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
439
          " is " + status.toString());
440 6644 cjones
441
      SystemMetadata systemMetadata = null;
442 6858 cjones
443
      try {
444 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
445 6702 cjones
          lock.lock();
446 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
447
448 6858 cjones
          try {
449
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
450 6657 cjones
451 6869 cjones
              // did we get it correctly?
452 6858 cjones
              if ( systemMetadata == null ) {
453
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
454 6869 cjones
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
455 6858 cjones
456
              }
457
              replicas = systemMetadata.getReplicaList();
458
              int count = 0;
459 6657 cjones
460 6876 cjones
              // was there a failure? log it
461
              if ( failure != null && status == ReplicationStatus.FAILED ) {
462
                 String msg = "The replication request of the object identified by " +
463
                     pid.getValue() + " failed.  The error message was " +
464
                     failure.getMessage() + ".";
465 6858 cjones
              }
466 6869 cjones
467 6876 cjones
              if (replicas.size() > 0 && replicas != null) {
468
                  // find the target replica index in the replica list
469
                  for (Replica replica : replicas) {
470
                      String replicaNodeStr = replica.getReplicaMemberNode()
471
                              .getValue();
472
                      String targetNodeStr = targetNode.getValue();
473
                      logMetacat.debug("Comparing " + replicaNodeStr + " to "
474
                              + targetNodeStr);
475 6869 cjones
476 6876 cjones
                      if (replicaNodeStr.equals(targetNodeStr)) {
477
                          replicaEntryIndex = count;
478
                          logMetacat.debug("replica entry index is: "
479
                                  + replicaEntryIndex);
480
                          break;
481
                      }
482
                      count++;
483 6858 cjones
484
                  }
485
              }
486
              // are we allowed to do this? only CNs and target MNs are allowed
487
              CNode cn = D1Client.getCN();
488
              List<Node> nodes = cn.listNodes().getNodeList();
489 6657 cjones
490 6858 cjones
              // find the node in the node list
491
              for ( Node node : nodes ) {
492
493
                  NodeReference nodeReference = node.getIdentifier();
494
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " + nodeReference.getValue());
495
496
                  // allow target MN certs and CN certs
497
                  if (targetNode.getValue().equals(nodeReference.getValue()) ||
498
                      node.getType() == NodeType.CN) {
499
                      List<Subject> nodeSubjects = node.getSubjectList();
500
501
                      // check if the session subject is in the node subject list
502
                      for (Subject nodeSubject : nodeSubjects) {
503
                          if ( nodeSubject.equals(subject) ) {
504
                              allowed = true; // subject of session == target node subject
505
                              break;
506
507
                          }
508
                      }
509
                  }
510
              }
511 6657 cjones
512 6876 cjones
              if ( !isAdminAuthorized(session, pid, Permission.WRITE) ) {
513
                  if (!allowed) {
514
                    String msg = "The subject identified by "
515
                            + subject.getValue()
516
                            + " does not have permission to set the replication status for "
517
                            + "the replica identified by "
518
                            + targetNode.getValue() + ".";
519
                    logMetacat.info(msg);
520
                    throw new NotAuthorized("4720", msg);
521
                }
522 6858 cjones
523
              }
524 6657 cjones
525 6876 cjones
526 6858 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
527
            throw new NotFound("4740", "No record found for: " + pid.getValue() +
528
                " : " + e.getMessage());
529
530 6644 cjones
          }
531
532 6876 cjones
          Replica targetReplica = new Replica();
533 6858 cjones
          // set the status for the replica
534
          if ( replicaEntryIndex != -1 ) {
535 6876 cjones
              targetReplica = replicas.get(replicaEntryIndex);
536 6858 cjones
              targetReplica.setReplicationStatus(status);
537
              logMetacat.debug("Set the replication status for " +
538
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
539
                  targetReplica.getReplicationStatus());
540 6644 cjones
541 6858 cjones
          } else {
542 6876 cjones
              // this is a new entry, create it
543
              targetReplica.setReplicaMemberNode(targetNode);
544
              targetReplica.setReplicationStatus(status);
545
              targetReplica.setReplicaVerified(Calendar.getInstance().getTime());
546
              replicas.add(targetReplica);
547
548 6644 cjones
          }
549
550 6858 cjones
          systemMetadata.setReplicaList(replicas);
551
552
          // update the metadata
553
          try {
554
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
555
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
556
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
557
558
              if ( status == ReplicationStatus.FAILED && failure != null ) {
559
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
560
                      " on target node " + targetNode + ". The exception was: " +
561
                      failure.getMessage());
562
              }
563 6869 cjones
          } catch (RuntimeException e) {
564 6858 cjones
              throw new ServiceFailure("4700", e.getMessage());
565
566 6644 cjones
          }
567
568 6867 cjones
    } catch (RuntimeException e) {
569
        String msg = "There was a RuntimeException getting the lock for " +
570
            pid.getValue();
571
        logMetacat.info(msg);
572
573
    } finally {
574 6858 cjones
        lock.unlock();
575
        logMetacat.debug("Unlocked identifier " + pid.getValue());
576 6593 cjones
577 6858 cjones
    }
578 6676 cjones
579 6644 cjones
      return true;
580 6410 cjones
  }
581
582
  /**
583
   * Return the checksum of the object given the identifier
584
   *
585
   * @param session - the Session object containing the credentials for the Subject
586
   * @param pid - the object identifier for the given object
587
   *
588
   * @return checksum - the checksum of the object
589
   *
590
   * @throws InvalidToken
591
   * @throws ServiceFailure
592
   * @throws NotAuthorized
593
   * @throws NotFound
594
   * @throws NotImplemented
595
   */
596 6471 jones
  @Override
597 6410 cjones
  public Checksum getChecksum(Session session, Identifier pid)
598
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
599 6622 leinfelder
    NotImplemented {
600 6869 cjones
601 6410 cjones
    if (!isAuthorized(session, pid, Permission.READ)) {
602 6568 cjones
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());
603 6410 cjones
    }
604 6568 cjones
605 6410 cjones
    SystemMetadata systemMetadata = null;
606 6568 cjones
    Checksum checksum = null;
607
608 6410 cjones
    try {
609 6869 cjones
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
610
611
        if (systemMetadata == null ) {
612
            throw new NotFound("1420", "Couldn't find an object identified by " + pid.getValue());
613
        }
614 6568 cjones
        checksum = systemMetadata.getChecksum();
615 6869 cjones
616
    } catch (RuntimeException e) {
617 6568 cjones
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " +
618
            pid.getValue() + ". The error message was: " + e.getMessage());
619
620 6410 cjones
    }
621
622
    return checksum;
623
  }
624 6177 cjones
625 6410 cjones
  /**
626
   * Resolve the location of a given object
627
   *
628
   * @param session - the Session object containing the credentials for the Subject
629
   * @param pid - the object identifier for the given object
630
   *
631
   * @return objectLocationList - the list of nodes known to contain the object
632
   *
633
   * @throws InvalidToken
634
   * @throws ServiceFailure
635
   * @throws NotAuthorized
636
   * @throws NotFound
637
   * @throws NotImplemented
638
   */
639 6471 jones
  @Override
640 6410 cjones
  public ObjectLocationList resolve(Session session, Identifier pid)
641 6622 leinfelder
    throws InvalidToken, ServiceFailure, NotAuthorized,
642 6410 cjones
    NotFound, NotImplemented {
643 6177 cjones
644 6410 cjones
    throw new NotImplemented("4131", "resolve not implemented");
645 6303 leinfelder
646 6410 cjones
  }
647 6177 cjones
648 6410 cjones
  /**
649
   * Search the metadata catalog for identifiers that match the criteria
650
   *
651
   * @param session - the Session object containing the credentials for the Subject
652
   * @param queryType - An identifier for the type of query expression
653
   *                    provided in the query
654
   * @param query -  The criteria for matching the characteristics of the
655
   *                 metadata objects of interest
656
   *
657
   * @return objectList - the list of objects matching the criteria
658
   *
659
   * @throws InvalidToken
660
   * @throws ServiceFailure
661
   * @throws NotAuthorized
662
   * @throws InvalidRequest
663
   * @throws NotImplemented
664
   */
665 6471 jones
  @Override
666 6410 cjones
  public ObjectList search(Session session, String queryType, String query)
667
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
668
    NotImplemented {
669 6177 cjones
670 6410 cjones
    ObjectList objectList = null;
671
    try {
672
        objectList =
673
          IdentifierManager.getInstance().querySystemMetadata(
674
              null, //startTime,
675
              null, //endTime,
676
              null, //objectFormat,
677
              false, //replicaStatus,
678
              0, //start,
679
              -1 //count
680
              );
681
682
    } catch (Exception e) {
683
      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
684
    }
685 6300 leinfelder
686 6410 cjones
      return objectList;
687
688
    //throw new NotImplemented("4281", "search not implemented");
689
690
    // the code block below is from an older implementation
691
692
    /*  This block commented out because of the EcoGrid circular dependency.
693 6281 leinfelder
         *  For now, query will not be supported until the circularity can be
694
         *  resolved, probably by moving the ecogrid query syntax transformers
695
         *  directly into the Metacat codebase.  MBJ 2010-02-03
696
697
        try {
698
            EcogridQueryParser parser = new EcogridQueryParser(request
699
                    .getReader());
700
            parser.parseXML();
701
            QueryType queryType = parser.getEcogridQuery();
702
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer =
703
                new EcogridJavaToMetacatJavaQueryTransformer();
704
            QuerySpecification metacatQuery = queryTransformer
705
                    .transform(queryType);
706 6223 leinfelder
707 6281 leinfelder
            DBQuery metacat = new DBQuery();
708
709
            boolean useXMLIndex = (new Boolean(PropertyService
710
                    .getProperty("database.usexmlindex"))).booleanValue();
711
            String xmlquery = "query"; // we don't care the query in resultset,
712
            // the query can be anything
713
            PrintWriter out = null; // we don't want metacat result, so set out null
714
715
            // parameter: queryspecification, user, group, usingIndexOrNot
716
            StringBuffer result = metacat.createResultDocument(xmlquery,
717
                    metacatQuery, out, username, groupNames, useXMLIndex);
718
719
            // create result set transfer
720
            String saxparser = PropertyService.getProperty("xml.saxparser");
721
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
722
                    new StringReader(result.toString()), saxparser, queryType
723
                            .getNamespace().get_value());
724
            ResultsetType records = metacatResultsetParser.getEcogridResult();
725
726
            System.out
727
                    .println(EcogridResultsetTransformer.toXMLString(records));
728
            response.setContentType("text/xml");
729
            out = response.getWriter();
730
            out.print(EcogridResultsetTransformer.toXMLString(records));
731
732
        } catch (Exception e) {
733
            e.printStackTrace();
734
        }*/
735 6410 cjones
736 6281 leinfelder
737 6410 cjones
  }
738
739
  /**
740
   * Returns the object format registered in the DataONE Object Format
741
   * Vocabulary for the given format identifier
742
   *
743
   * @param fmtid - the identifier of the format requested
744
   *
745
   * @return objectFormat - the object format requested
746
   *
747
   * @throws ServiceFailure
748
   * @throws NotFound
749
   * @throws InsufficientResources
750
   * @throws NotImplemented
751
   */
752 6471 jones
  @Override
753 6410 cjones
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
754 6803 leinfelder
    throws ServiceFailure, NotFound, NotImplemented {
755 6410 cjones
756
      return ObjectFormatService.getInstance().getFormat(fmtid);
757
758
  }
759 6177 cjones
760 6410 cjones
  /**
761 6177 cjones
   * Returns a list of all object formats registered in the DataONE Object
762
   * Format Vocabulary
763 6410 cjones
    *
764
   * @return objectFormatList - The list of object formats registered in
765
   *                            the DataONE Object Format Vocabulary
766
   *
767
   * @throws ServiceFailure
768
   * @throws NotImplemented
769
   * @throws InsufficientResources
770
   */
771 6471 jones
  @Override
772 6410 cjones
  public ObjectFormatList listFormats()
773 6803 leinfelder
    throws ServiceFailure, NotImplemented {
774 6177 cjones
775 6410 cjones
    return ObjectFormatService.getInstance().listFormats();
776
  }
777 6177 cjones
778 6410 cjones
  /**
779 6177 cjones
   * Returns a list of nodes that have been registered with the DataONE infrastructure
780 6410 cjones
    *
781
   * @return nodeList - List of nodes from the registry
782
   *
783
   * @throws ServiceFailure
784
   * @throws NotImplemented
785
   */
786 6471 jones
  @Override
787 6410 cjones
  public NodeList listNodes()
788
    throws NotImplemented, ServiceFailure {
789 6177 cjones
790 6410 cjones
    throw new NotImplemented("4800", "listNodes not implemented");
791
  }
792 6177 cjones
793 6410 cjones
  /**
794 6177 cjones
   * Provides a mechanism for adding system metadata independently of its
795
   * associated object, such as when adding system metadata for data objects.
796 6410 cjones
    *
797
   * @param session - the Session object containing the credentials for the Subject
798
   * @param pid - The identifier of the object to register the system metadata against
799
   * @param sysmeta - The system metadata to be registered
800
   *
801
   * @return true if the registration succeeds
802
   *
803
   * @throws NotImplemented
804
   * @throws NotAuthorized
805
   * @throws ServiceFailure
806
   * @throws InvalidRequest
807
   * @throws InvalidSystemMetadata
808
   */
809 6471 jones
  @Override
810 6575 cjones
  public Identifier registerSystemMetadata(Session session, Identifier pid,
811
      SystemMetadata sysmeta)
812
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
813
      InvalidSystemMetadata {
814 6177 cjones
815 6702 cjones
      // The lock to be used for this identifier
816 6859 cjones
      Lock lock = null;
817 6702 cjones
818 6575 cjones
      // TODO: control who can call this?
819
      if (session == null) {
820
          //TODO: many of the thrown exceptions do not use the correct error codes
821
          //check these against the docs and correct them
822
          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
823
                  "  If you are not logged in, please do so and retry the request.");
824
      }
825
826
      // verify that guid == SystemMetadata.getIdentifier()
827
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() +
828
          "|" + sysmeta.getIdentifier().getValue());
829
      if (!pid.getValue().equals(sysmeta.getIdentifier().getValue())) {
830
          throw new InvalidRequest("4863",
831
              "The identifier in method call (" + pid.getValue() +
832
              ") does not match identifier in system metadata (" +
833
              sysmeta.getIdentifier().getValue() + ").");
834
      }
835 6188 leinfelder
836 6575 cjones
      try {
837 6703 cjones
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
838 6863 cjones
          lock.lock();
839 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
840 6863 cjones
          logMetacat.debug("Checking if identifier exists...");
841
          // Check that the identifier does not already exist
842
          if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
843
              throw new InvalidRequest("4863",
844
                  "The identifier is already in use by an existing object.");
845 6575 cjones
846 6863 cjones
          }
847
848
          // insert the system metadata into the object store
849
          logMetacat.debug("Starting to insert SystemMetadata...");
850
          try {
851
              sysmeta.setSerialVersion(BigInteger.ONE);
852
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
853
              HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
854
855 6869 cjones
          } catch (RuntimeException e) {
856 6863 cjones
            logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
857
              throw new ServiceFailure("4862", "Error inserting system metadata: " +
858
                  e.getClass() + ": " + e.getMessage());
859
860
          }
861
862 6869 cjones
      } catch (RuntimeException e) {
863 6575 cjones
          throw new ServiceFailure("4862", "Error inserting system metadata: " +
864 6863 cjones
                  e.getClass() + ": " + e.getMessage());
865 6575 cjones
866 6863 cjones
      }  finally {
867
          lock.unlock();
868
          logMetacat.debug("Unlocked identifier " + pid.getValue());
869
870
      }
871 6466 cjones
872 6575 cjones
873
      logMetacat.debug("Returning from registerSystemMetadata");
874
      EventLog.getInstance().log(request.getRemoteAddr(),
875
          request.getHeader("User-Agent"), session.getSubject().getValue(),
876
          pid.getValue(), "registerSystemMetadata");
877
      return pid;
878 6410 cjones
  }
879
880
  /**
881 6177 cjones
   * Given an optional scope and format, reserves and returns an identifier
882
   * within that scope and format that is unique and will not be
883
   * used by any other sessions.
884 6410 cjones
    *
885
   * @param session - the Session object containing the credentials for the Subject
886
   * @param pid - The identifier of the object to register the system metadata against
887
   * @param scope - An optional string to be used to qualify the scope of
888
   *                the identifier namespace, which is applied differently
889
   *                depending on the format requested. If scope is not
890
   *                supplied, a default scope will be used.
891
   * @param format - The optional name of the identifier format to be used,
892
   *                  drawn from a DataONE-specific vocabulary of identifier
893
   *                 format names, including several common syntaxes such
894
   *                 as DOI, LSID, UUID, and LSRN, among others. If the
895
   *                 format is not supplied by the caller, the CN service
896
   *                 will use a default identifier format, which may change
897
   *                 over time.
898
   *
899
   * @return true if the registration succeeds
900
   *
901
   * @throws InvalidToken
902
   * @throws ServiceFailure
903
   * @throws NotAuthorized
904
   * @throws IdentifierNotUnique
905
   * @throws NotImplemented
906
   */
907 6471 jones
  @Override
908 6622 leinfelder
  public Identifier reserveIdentifier(Session session, Identifier pid)
909 6410 cjones
  throws InvalidToken, ServiceFailure,
910 6378 leinfelder
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
911 6177 cjones
912 6410 cjones
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
913
  }
914
915 6471 jones
  @Override
916 6410 cjones
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
917
  throws InvalidToken, ServiceFailure,
918 6378 leinfelder
        NotAuthorized, NotImplemented, InvalidRequest {
919 6410 cjones
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
920
  }
921
922
  /**
923
    * Checks whether the pid is reserved by the subject in the session param
924
    * If the reservation is held on the pid by the subject, we return true.
925
    *
926
   * @param session - the Session object containing the Subject
927
   * @param pid - The identifier to check
928
   *
929
   * @return true if the reservation exists for the subject/pid
930
   *
931
   * @throws InvalidToken
932
   * @throws ServiceFailure
933
   * @throws NotFound - when the pid is not found (in use or in reservation)
934
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
935
   * @throws IdentifierNotUnique - when the pid is in use
936
   * @throws NotImplemented
937
   */
938 6177 cjones
939 6471 jones
  @Override
940 6934 leinfelder
  public boolean hasReservation(Session session, Subject subject, Identifier pid)
941 6410 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique,
942
      NotImplemented, InvalidRequest {
943
944
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
945
  }
946 6339 leinfelder
947 6410 cjones
  /**
948 6177 cjones
   * Changes ownership (RightsHolder) of the specified object to the
949
   * subject specified by userId
950 6410 cjones
    *
951
   * @param session - the Session object containing the credentials for the Subject
952
   * @param pid - Identifier of the object to be modified
953
   * @param userId - The subject that will be taking ownership of the specified object.
954
   *
955
   * @return pid - the identifier of the modified object
956
   *
957
   * @throws ServiceFailure
958
   * @throws InvalidToken
959
   * @throws NotFound
960
   * @throws NotAuthorized
961
   * @throws NotImplemented
962
   * @throws InvalidRequest
963
   */
964 6471 jones
  @Override
965 6803 leinfelder
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
966 6593 cjones
      long serialVersion)
967
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
968 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
969 6593 cjones
970 6702 cjones
      // The lock to be used for this identifier
971 6859 cjones
      Lock lock = null;
972 6702 cjones
973 6593 cjones
      // get the subject
974
      Subject subject = session.getSubject();
975
976
      // are we allowed to do this?
977 6866 cjones
      if (!isAdminAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
978 6869 cjones
          if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
979
              throw new NotAuthorized("4440", "not allowed by "
980
                      + subject.getValue() + " on " + pid.getValue());
981
982
          }
983
      }
984
985
      SystemMetadata systemMetadata = null;
986 6593 cjones
      try {
987 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
988 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
989
990 6858 cjones
          try {
991
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
992
993
              // does the request have the most current system metadata?
994
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
995
                 String msg = "The requested system metadata version number " +
996
                     serialVersion + " differs from the current version at " +
997
                     systemMetadata.getSerialVersion().longValue() +
998
                     ". Please get the latest copy in order to modify it.";
999 6869 cjones
                 throw new VersionMismatch("4443", msg);
1000 6858 cjones
              }
1001
1002 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1003 6858 cjones
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1004
1005 6593 cjones
          }
1006 6858 cjones
1007
          // set the new rights holder
1008
          systemMetadata.setRightsHolder(userId);
1009 6593 cjones
1010 6858 cjones
          // update the metadata
1011
          try {
1012
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1013
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1014
              HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
1015
1016 6869 cjones
          } catch (RuntimeException e) {
1017
              throw new ServiceFailure("4490", e.getMessage());
1018 6593 cjones
1019 6858 cjones
          }
1020 6593 cjones
1021 6869 cjones
      } catch (RuntimeException e) {
1022 6858 cjones
          throw new ServiceFailure("4490", e.getMessage());
1023 6644 cjones
1024
      } finally {
1025 6702 cjones
          lock.unlock();
1026 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1027 6858 cjones
1028 6644 cjones
      }
1029
1030 6869 cjones
      return pid;
1031 6410 cjones
  }
1032 6177 cjones
1033 6410 cjones
  /**
1034
   * Verify that a replication task is authorized by comparing the target node's
1035
   * Subject (from the X.509 certificate-derived Session) with the list of
1036
   * subjects in the known, pending replication tasks map.
1037
   *
1038
   * @param originatingNodeSession - Session information that contains the
1039
   *                                 identity of the calling user
1040
   * @param targetNodeSubject - Subject identifying the target node
1041
   * @param pid - the identifier of the object to be replicated
1042
   * @param replicatePermission - the execute permission to be granted
1043
   *
1044
   * @throws ServiceFailure
1045
   * @throws NotImplemented
1046
   * @throws InvalidToken
1047
   * @throws NotAuthorized
1048
   * @throws InvalidRequest
1049
   * @throws NotFound
1050
   */
1051 6471 jones
  @Override
1052 6409 cjones
  public boolean isNodeAuthorized(Session originatingNodeSession,
1053 6777 leinfelder
    Subject targetNodeSubject, Identifier pid)
1054 6410 cjones
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
1055
    NotFound, InvalidRequest {
1056 6702 cjones
1057 6644 cjones
    boolean isAllowed = false;
1058
    SystemMetadata sysmeta = null;
1059 6463 cjones
    NodeReference targetNode = null;
1060
1061 6644 cjones
    try {
1062
      // get the target node reference from the nodes list
1063
      CNode cn = D1Client.getCN();
1064
      List<Node> nodes = cn.listNodes().getNodeList();
1065 6665 cjones
1066 6657 cjones
      if ( nodes != null ) {
1067
        for (Node node : nodes) {
1068 6665 cjones
1069 6657 cjones
            for (Subject nodeSubject : node.getSubjectList()) {
1070 6665 cjones
1071 6676 cjones
                if ( nodeSubject.equals(targetNodeSubject) ) {
1072 6657 cjones
                    targetNode = node.getIdentifier();
1073
                    logMetacat.debug("targetNode is : " + targetNode.getValue());
1074
                    break;
1075
                }
1076
            }
1077
1078 6665 cjones
            if ( targetNode != null) { break; }
1079 6657 cjones
        }
1080
1081
      } else {
1082
          String msg = "Couldn't get the node list from the CN";
1083
          logMetacat.debug(msg);
1084
          throw new ServiceFailure("4872", msg);
1085
1086 6644 cjones
      }
1087 6757 cjones
1088
      // can't find a node listed with the given subject
1089
      if ( targetNode == null ) {
1090
          String msg = "There is no Member Node registered with a node subject " +
1091
              "matching " + targetNodeSubject.getValue();
1092
          logMetacat.info(msg);
1093
          throw new ServiceFailure("4872", msg);
1094
1095
      }
1096
1097 6657 cjones
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1098
1099 6644 cjones
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1100 6463 cjones
1101 6657 cjones
      if ( sysmeta != null ) {
1102
1103
          List<Replica> replicaList = sysmeta.getReplicaList();
1104
1105
          if ( replicaList != null ) {
1106
1107
              // find the replica with the status set to 'requested'
1108
              for (Replica replica : replicaList) {
1109
                  ReplicationStatus status = replica.getReplicationStatus();
1110
                  NodeReference listedNode = replica.getReplicaMemberNode();
1111 6757 cjones
                  if ( listedNode != null && targetNode != null ) {
1112
                      logMetacat.debug("Comparing " + listedNode.getValue()
1113
                              + " to " + targetNode.getValue());
1114
1115
                      if (listedNode.getValue().equals(targetNode.getValue())
1116
                              && status.equals(ReplicationStatus.REQUESTED)) {
1117
                          isAllowed = true;
1118
                          break;
1119 6657 cjones
1120 6757 cjones
                      }
1121 6657 cjones
                  }
1122
              }
1123 6568 cjones
          }
1124 6665 cjones
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1125
              "to replicate: " + isAllowed + " for " + pid.getValue());
1126
1127 6657 cjones
1128
      } else {
1129
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1130
          " is null.");
1131 6869 cjones
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue());
1132 6657 cjones
1133 6568 cjones
      }
1134 6484 cjones
1135 6662 cjones
    } catch (RuntimeException e) {
1136 6665 cjones
    	  ServiceFailure sf = new ServiceFailure("4872",
1137
                "Runtime Exception: Couldn't determine if node is allowed: " +
1138 6757 cjones
                e.getCause().getMessage());
1139 6665 cjones
    	  sf.initCause(e);
1140 6659 leinfelder
        throw sf;
1141 6636 cjones
1142 6644 cjones
    }
1143
1144
    return isAllowed;
1145 6410 cjones
1146 6384 cjones
  }
1147
1148 6569 cjones
  /**
1149 6570 cjones
   * Adds a new object to the Node, where the object is a science metadata object.
1150 6569 cjones
   *
1151
   * @param session - the Session object containing the credentials for the Subject
1152
   * @param pid - The object identifier to be created
1153
   * @param object - the object bytes
1154
   * @param sysmeta - the system metadata that describes the object
1155
   *
1156
   * @return pid - the object identifier created
1157
   *
1158
   * @throws InvalidToken
1159
   * @throws ServiceFailure
1160
   * @throws NotAuthorized
1161
   * @throws IdentifierNotUnique
1162
   * @throws UnsupportedType
1163
   * @throws InsufficientResources
1164
   * @throws InvalidSystemMetadata
1165
   * @throws NotImplemented
1166
   * @throws InvalidRequest
1167
   */
1168
  public Identifier create(Session session, Identifier pid, InputStream object,
1169
    SystemMetadata sysmeta)
1170
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
1171
    UnsupportedType, InsufficientResources, InvalidSystemMetadata,
1172
    NotImplemented, InvalidRequest {
1173 6917 cjones
1174 6702 cjones
      // The lock to be used for this identifier
1175 6859 cjones
      Lock lock = null;
1176 6917 cjones
1177 6570 cjones
      try {
1178 6869 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1179
          // are we allowed?
1180 6570 cjones
          boolean isAllowed = false;
1181
          CNode cn = D1Client.getCN();
1182 6687 leinfelder
          NodeList nodeList = cn.listNodes();
1183 6570 cjones
1184 6687 leinfelder
          for (Node node : nodeList.getNodeList()) {
1185 6570 cjones
              if ( node.getType().equals(NodeType.CN) ) {
1186
1187
                  List<Subject> subjects = node.getSubjectList();
1188
                  for (Subject subject : subjects) {
1189 6688 leinfelder
                     if (subject.equals(session.getSubject())) {
1190 6570 cjones
                         isAllowed = true;
1191
                         break;
1192
                     }
1193
                  }
1194 6917 cjones
              } else {
1195
1196 6570 cjones
              }
1197
          }
1198
1199
          // proceed if we're called by a CN
1200
          if ( isAllowed ) {
1201
              // create the coordinating node version of the document
1202 6702 cjones
              lock.lock();
1203 6867 cjones
              logMetacat.debug("Locked identifier " + pid.getValue());
1204 6570 cjones
              sysmeta.setSerialVersion(BigInteger.ONE);
1205
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1206 6917 cjones
              sysmeta.setArchived(false); // this is a create op, not update
1207
1208
              // the CN should have set the origin and authoritative member node fields
1209
              try {
1210
                  sysmeta.getOriginMemberNode().getValue();
1211
                  sysmeta.getAuthoritativeMemberNode().getValue();
1212
1213
              } catch (NullPointerException npe) {
1214
                  throw new InvalidSystemMetadata("4896",
1215
                      "Both the origin and authoritative member node identifiers need to be set.");
1216
1217
              }
1218 6570 cjones
              pid = super.create(session, pid, object, sysmeta);
1219
1220
          } else {
1221
              String msg = "The subject listed as " + session.getSubject().getValue() +
1222
                  " isn't allowed to call create() on a Coordinating Node.";
1223
              logMetacat.info(msg);
1224
              throw new NotAuthorized("1100", msg);
1225
          }
1226
1227 6676 cjones
      } catch (RuntimeException e) {
1228 6570 cjones
          // Convert Hazelcast runtime exceptions to service failures
1229
          String msg = "There was a problem creating the object identified by " +
1230
              pid.getValue() + ". There error message was: " + e.getMessage();
1231 6676 cjones
          throw new ServiceFailure("4893", msg);
1232 6570 cjones
1233
      } finally {
1234 6805 leinfelder
    	  if (lock != null) {
1235
	          lock.unlock();
1236
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1237
    	  }
1238 6570 cjones
      }
1239
1240 6569 cjones
      return pid;
1241
1242
  }
1243
1244 6571 cjones
  /**
1245
   * Set access for a given object using the object identifier and a Subject
1246
   * under a given Session.
1247
   *
1248
   * @param session - the Session object containing the credentials for the Subject
1249
   * @param pid - the object identifier for the given object to apply the policy
1250
   * @param policy - the access policy to be applied
1251
   *
1252
   * @return true if the application of the policy succeeds
1253
   * @throws InvalidToken
1254
   * @throws ServiceFailure
1255
   * @throws NotFound
1256
   * @throws NotAuthorized
1257
   * @throws NotImplemented
1258
   * @throws InvalidRequest
1259
   */
1260
  public boolean setAccessPolicy(Session session, Identifier pid,
1261 6593 cjones
      AccessPolicy accessPolicy, long serialVersion)
1262 6571 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1263 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
1264 6571 cjones
1265 6702 cjones
      // The lock to be used for this identifier
1266 6859 cjones
      Lock lock = null;
1267 6869 cjones
      SystemMetadata systemMetadata = null;
1268 6702 cjones
1269 6571 cjones
      boolean success = false;
1270
1271
      // get the subject
1272
      Subject subject = session.getSubject();
1273
1274 6869 cjones
      if (!isAdminAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1275
          // are we allowed to do this?
1276
          if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1277
              throw new NotAuthorized("4420", "not allowed by "
1278
                      + subject.getValue() + " on " + pid.getValue());
1279
          }
1280 6571 cjones
      }
1281
1282
      try {
1283 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1284 6702 cjones
          lock.lock();
1285 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1286
1287 6858 cjones
          try {
1288
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1289 6571 cjones
1290 6869 cjones
              if ( systemMetadata == null ) {
1291
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1292
1293
              }
1294 6858 cjones
              // does the request have the most current system metadata?
1295
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1296
                 String msg = "The requested system metadata version number " +
1297
                     serialVersion + " differs from the current version at " +
1298
                     systemMetadata.getSerialVersion().longValue() +
1299
                     ". Please get the latest copy in order to modify it.";
1300 6869 cjones
                 throw new VersionMismatch("4402", msg);
1301
1302 6858 cjones
              }
1303
1304 6869 cjones
          } catch (RuntimeException e) {
1305 6858 cjones
              // convert Hazelcast RuntimeException to NotFound
1306
              throw new NotFound("4400", "No record found for: " + pid);
1307
1308 6593 cjones
          }
1309 6858 cjones
1310
          // set the access policy
1311
          systemMetadata.setAccessPolicy(accessPolicy);
1312 6593 cjones
1313 6858 cjones
          // update the system metadata
1314
          try {
1315
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1316
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1317
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1318
1319 6869 cjones
          } catch (RuntimeException e) {
1320 6858 cjones
              // convert Hazelcast RuntimeException to ServiceFailure
1321
              throw new ServiceFailure("4430", e.getMessage());
1322
1323
          }
1324 6571 cjones
1325 6869 cjones
      } catch (RuntimeException e) {
1326 6571 cjones
          throw new ServiceFailure("4430", e.getMessage());
1327 6858 cjones
1328 6571 cjones
      } finally {
1329 6702 cjones
          lock.unlock();
1330 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1331 6571 cjones
1332
      }
1333 6858 cjones
1334 6571 cjones
1335
    // TODO: how do we know if the map was persisted?
1336
    success = true;
1337
1338
    return success;
1339
  }
1340
1341 6578 cjones
  /**
1342
   * Full replacement of replication metadata in the system metadata for the
1343
   * specified object, changes date system metadata modified
1344
   *
1345
   * @param session - the Session object containing the credentials for the Subject
1346
   * @param pid - the object identifier for the given object to apply the policy
1347
   * @param replica - the replica to be updated
1348
   * @return
1349
   * @throws NotImplemented
1350
   * @throws NotAuthorized
1351
   * @throws ServiceFailure
1352
   * @throws InvalidRequest
1353
   * @throws NotFound
1354 6869 cjones
   * @throws VersionMismatch
1355 6578 cjones
   */
1356 6869 cjones
  @Override
1357 6578 cjones
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1358 6593 cjones
      Replica replica, long serialVersion)
1359 6578 cjones
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1360 6869 cjones
      NotFound, VersionMismatch {
1361 6578 cjones
1362 6702 cjones
      // The lock to be used for this identifier
1363 6859 cjones
      Lock lock = null;
1364 6702 cjones
1365 6578 cjones
      // get the subject
1366
      Subject subject = session.getSubject();
1367
1368
      // are we allowed to do this?
1369
      try {
1370 6866 cjones
        if (!isAdminAuthorized(session, pid, Permission.WRITE)) {
1371
            // what is the controlling permission?
1372
            if (!isAuthorized(session, pid, Permission.WRITE)) {
1373
                throw new NotAuthorized("4851", "not allowed by "
1374
                        + subject.getValue() + " on " + pid.getValue());
1375
            }
1376 6578 cjones
        }
1377
1378
      } catch (InvalidToken e) {
1379
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() +
1380
                  " on " + pid.getValue());
1381
1382
      }
1383
1384
      SystemMetadata systemMetadata = null;
1385 6858 cjones
      try {
1386 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1387 6702 cjones
          lock.lock();
1388 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1389 6578 cjones
1390 6858 cjones
          try {
1391
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1392
1393
              // does the request have the most current system metadata?
1394
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1395
                 String msg = "The requested system metadata version number " +
1396
                     serialVersion + " differs from the current version at " +
1397
                     systemMetadata.getSerialVersion().longValue() +
1398
                     ". Please get the latest copy in order to modify it.";
1399 6869 cjones
                 throw new VersionMismatch("4855", msg);
1400 6858 cjones
              }
1401
1402 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1403
              throw new NotFound("4854", "No record found for: " + pid.getValue() +
1404
                  " : " + e.getMessage());
1405 6858 cjones
1406 6593 cjones
          }
1407 6858 cjones
1408
          // set the status for the replica
1409
          List<Replica> replicas = systemMetadata.getReplicaList();
1410
          NodeReference replicaNode = replica.getReplicaMemberNode();
1411
          int index = 0;
1412
          for (Replica listedReplica: replicas) {
1413
1414
              // remove the replica that we are replacing
1415
              if ( replicaNode.getValue().equals(listedReplica.getReplicaMemberNode().getValue())) {
1416
                  replicas.remove(index);
1417
                  break;
1418
1419
              }
1420
              index++;
1421
          }
1422 6593 cjones
1423 6858 cjones
          // add the new replica item
1424
          replicas.add(replica);
1425
          systemMetadata.setReplicaList(replicas);
1426 6578 cjones
1427 6858 cjones
          // update the metadata
1428
          try {
1429
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1430
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1431
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1432
1433 6869 cjones
          } catch (RuntimeException e) {
1434
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1435 6858 cjones
              throw new ServiceFailure("4852", e.getMessage());
1436 6578 cjones
1437
          }
1438 6858 cjones
1439 6869 cjones
      } catch (RuntimeException e) {
1440
          logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
1441
          throw new ServiceFailure("4852", e.getMessage());
1442
1443
      } finally {
1444
          lock.unlock();
1445
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1446
1447
      }
1448 6578 cjones
1449
      return true;
1450
1451
  }
1452 6622 leinfelder
1453 6869 cjones
  /**
1454
   *
1455
   */
1456
  @Override
1457 6858 cjones
  public ObjectList listObjects(Session session, Date startTime,
1458
      Date endTime, ObjectFormatIdentifier formatid, Boolean replicaStatus,
1459
      Integer start, Integer count)
1460 6644 cjones
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1461
      ServiceFailure {
1462
1463
      ObjectList objectList = null;
1464 6622 leinfelder
        try {
1465
            objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, formatid, replicaStatus, start, count);
1466
        } catch (Exception e) {
1467
            throw new ServiceFailure("1580", "Error querying system metadata: " + e.getMessage());
1468
        }
1469
1470
        return objectList;
1471 6644 cjones
  }
1472 6803 leinfelder
1473 6869 cjones
	/**
1474
	 *
1475
	 */
1476
  @Override
1477 6803 leinfelder
	public ChecksumAlgorithmList listChecksumAlgorithms()
1478
			throws ServiceFailure, NotImplemented {
1479
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
1480
		cal.addAlgorithm("MD5");
1481
		cal.addAlgorithm("SHA-1");
1482
		return null;
1483
	}
1484 6657 cjones
1485 6177 cjones
}