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