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
import java.util.Date;
27 6220 leinfelder
import java.util.List;
28 6419 leinfelder
import java.util.Set;
29 6177 cjones
30 6178 cjones
import org.apache.log4j.Logger;
31 6366 leinfelder
import org.dataone.service.cn.v1.CNAuthorization;
32
import org.dataone.service.cn.v1.CNCore;
33
import org.dataone.service.cn.v1.CNRead;
34
import org.dataone.service.cn.v1.CNReplication;
35 6177 cjones
import org.dataone.service.exceptions.IdentifierNotUnique;
36
import org.dataone.service.exceptions.InsufficientResources;
37
import org.dataone.service.exceptions.InvalidRequest;
38
import org.dataone.service.exceptions.InvalidSystemMetadata;
39
import org.dataone.service.exceptions.InvalidToken;
40
import org.dataone.service.exceptions.NotAuthorized;
41
import org.dataone.service.exceptions.NotFound;
42
import org.dataone.service.exceptions.NotImplemented;
43
import org.dataone.service.exceptions.ServiceFailure;
44 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
45
import org.dataone.service.types.v1.Identifier;
46
import org.dataone.service.types.v1.NodeList;
47 6409 cjones
import org.dataone.service.types.v1.NodeReference;
48 6366 leinfelder
import org.dataone.service.types.v1.ObjectFormat;
49
import org.dataone.service.types.v1.ObjectFormatIdentifier;
50
import org.dataone.service.types.v1.ObjectFormatList;
51
import org.dataone.service.types.v1.ObjectList;
52
import org.dataone.service.types.v1.ObjectLocationList;
53
import org.dataone.service.types.v1.Permission;
54
import org.dataone.service.types.v1.Replica;
55
import org.dataone.service.types.v1.ReplicationPolicy;
56
import org.dataone.service.types.v1.ReplicationStatus;
57
import org.dataone.service.types.v1.Session;
58
import org.dataone.service.types.v1.Subject;
59
import org.dataone.service.types.v1.SystemMetadata;
60 6177 cjones
61 6419 leinfelder
import com.hazelcast.query.SqlPredicate;
62 6409 cjones
63 6188 leinfelder
import edu.ucsb.nceas.metacat.EventLog;
64
import edu.ucsb.nceas.metacat.IdentifierManager;
65 6194 leinfelder
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
66 6455 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.CNReplicationTask;
67 6446 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
68 6188 leinfelder
69 6177 cjones
/**
70
 * Represents Metacat's implementation of the DataONE Coordinating Node
71 6179 cjones
 * service API. Methods implement the various CN* interfaces, and methods common
72 6177 cjones
 * to both Member Node and Coordinating Node interfaces are found in the
73
 * D1NodeService super class.
74
 *
75
 */
76
public class CNodeService extends D1NodeService implements CNAuthorization,
77 6446 leinfelder
    CNCore, CNRead, CNReplication {
78 6177 cjones
79 6410 cjones
  /* the instance of the CNodeService object */
80 6178 cjones
  private static CNodeService instance = null;
81 6409 cjones
82 6178 cjones
  /* the logger instance */
83
  private Logger logMetacat = null;
84 6177 cjones
85 6178 cjones
  /**
86
   * singleton accessor
87
   */
88 6241 cjones
  public static CNodeService getInstance() {
89 6178 cjones
    if (instance == null) {
90 6241 cjones
91 6254 cjones
      instance = new CNodeService();
92 6241 cjones
93 6178 cjones
    }
94 6241 cjones
95 6178 cjones
    return instance;
96
  }
97
98
  /**
99
   * Constructor, private for singleton access
100
   */
101 6254 cjones
  private CNodeService() {
102 6410 cjones
    super();
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
  @Override
123
  public boolean setReplicationPolicy(Session session, Identifier pid,
124
    ReplicationPolicy policy)
125
    throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, InvalidRequest, InvalidToken {
126 6177 cjones
127 6410 cjones
    // get the subject
128
    Subject subject = session.getSubject();
129
    // get the system metadata
130
    String guid = pid.getValue();
131
132
    // are we allowed to do this?
133
    if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
134
      throw new NotAuthorized("4881", Permission.CHANGE_PERMISSION + " not allowed by " + subject.getValue() + " on " + guid);
135
    }
136
137
    SystemMetadata systemMetadata = null;
138
    try {
139
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
140
    } catch (McdbDocNotFoundException e) {
141
      throw new NotFound("4884", "No record found for: " + guid);
142
    }
143
144
    // set the new policy
145
    systemMetadata.setReplicationPolicy(policy);
146
147
    // update the metadata
148 6449 leinfelder
    HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
149 6219 leinfelder
150 6410 cjones
    return true;
151
  }
152 6177 cjones
153 6410 cjones
  /**
154
   * Set the replication status for an object given the object identifier
155
   *
156
   * @param session - the Session object containing the credentials for the Subject
157
   * @param pid - the object identifier for the given object
158
   * @param status - the replication status to be applied
159
   *
160
   * @return true or false
161
   *
162
   * @throws NotImplemented
163
   * @throws NotAuthorized
164
   * @throws ServiceFailure
165
   * @throws InvalidRequest
166
   * @throws InvalidToken
167
   * @throws NotFound
168
   *
169
   */
170
  @Override
171
  public boolean setReplicationStatus(Session session, Identifier pid,
172
    NodeReference targetNode, ReplicationStatus status)
173
    throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized,
174
    InvalidRequest, NotFound {
175 6177 cjones
176 6410 cjones
    // get the subject
177
    Subject subject = session.getSubject();
178
    // get the system metadata
179
    String guid = pid.getValue();
180
181
    // are we allowed to do this?
182
    if (!isAuthorized(session, pid, Permission.WRITE)) {
183
      throw new NotAuthorized("4720", Permission.WRITE + " not allowed by " + subject.getValue() + " on " + guid);
184
    }
185
186
    SystemMetadata systemMetadata = null;
187
    try {
188
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
189
    } catch (McdbDocNotFoundException e) {
190
      throw new NotFound("4740", "No record found for: " + guid);
191
    }
192
193
    // set the status for each replica
194
    // TODO: should this method select a certain replica?
195
    List<Replica> replicas = systemMetadata.getReplicaList();
196
    for (Replica replica: replicas) {
197
      replica.setReplicationStatus(status);
198
    }
199
200
    // [re]set the list -- redundant?
201
    systemMetadata.setReplicaList(replicas);
202
203
    // update the metadata
204 6449 leinfelder
    HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
205 6220 leinfelder
206 6410 cjones
    return true;
207
  }
208 6177 cjones
209 6410 cjones
  /**
210
   * Test that the specified relationship between pidOfSubject and pidOfObject exists
211
   *
212
   * @param session - the Session object containing the credentials for the Subject
213
   * @param node - the node information for the given node be modified
214
   *
215
   * @return true if the relationship exists
216
   *
217
   * @throws InvalidToken
218
   * @throws ServiceFailure
219
   * @throws NotAuthorized
220
   * @throws NotFound
221
   * @throws InvalidRequest
222
   * @throws NotImplemented
223
   */
224
  @Override
225
  public boolean assertRelation(Session session, Identifier pidOfSubject,
226
    String relationship, Identifier pidOfObject)
227
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
228
    InvalidRequest, NotImplemented {
229
230
231
    // get the system metadata
232
    String guid1 = pidOfSubject.getValue();
233
    // are we allowed to do this?
234
    if (!isAuthorized(session, pidOfSubject, Permission.READ)) {
235
      throw new NotAuthorized("4881", Permission.READ + " not allowed on " + guid1);
236
    }
237
238
    SystemMetadata systemMetadata = null;
239
    try {
240
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid1);
241
    } catch (McdbDocNotFoundException e) {
242
      throw new NotFound("4884", "No record found for: " + guid1);
243
    }
244
245
    // check relationships
246
    // TODO: use ORE map
247
    if (relationship.equalsIgnoreCase("describes")) {
248
249
    }
250
    if (relationship.equalsIgnoreCase("describedBy")) {
251
252
    }
253
    if (relationship.equalsIgnoreCase("derivedFrom")) {
254
255
    }
256
    if (relationship.equalsIgnoreCase("obsoletes")) {
257
      Identifier pid = systemMetadata.getObsoletes();
258
      if (pid.getValue().equals(pidOfObject.getValue())) {
259
        return true;
260
      }
261
      //return systemMetadata.getObsoleteList().contains(pidOfObject);
262
    }
263
    if (relationship.equalsIgnoreCase("obsoletedBy")) {
264
      Identifier pid = systemMetadata.getObsoletedBy();
265
      if (pid.getValue().equals(pidOfObject.getValue())) {
266
        return true;
267
      }
268
      //return systemMetadata.getObsoletedByList().contains(pidOfObject);
269
    }
270 6221 leinfelder
271 6410 cjones
    return false;
272
  }
273
274
  /**
275
   * Return the checksum of the object given the identifier
276
   *
277
   * @param session - the Session object containing the credentials for the Subject
278
   * @param pid - the object identifier for the given object
279
   *
280
   * @return checksum - the checksum of the object
281
   *
282
   * @throws InvalidToken
283
   * @throws ServiceFailure
284
   * @throws NotAuthorized
285
   * @throws NotFound
286
   * @throws InvalidRequest
287
   * @throws NotImplemented
288
   */
289
  @Override
290
  public Checksum getChecksum(Session session, Identifier pid)
291
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
292
    InvalidRequest, NotImplemented {
293
294
    if (!isAuthorized(session, pid, Permission.READ)) {
295
      throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());
296
    }
297
    SystemMetadata systemMetadata = null;
298
    try {
299
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
300
    } catch (McdbDocNotFoundException e) {
301
      throw new NotFound("1420", "No record found for: " + pid.getValue());
302
    }
303
    Checksum checksum = systemMetadata.getChecksum();
304
305
    return checksum;
306
  }
307 6177 cjones
308 6410 cjones
  /**
309
   * Resolve the location of a given object
310
   *
311
   * @param session - the Session object containing the credentials for the Subject
312
   * @param pid - the object identifier for the given object
313
   *
314
   * @return objectLocationList - the list of nodes known to contain the object
315
   *
316
   * @throws InvalidRequest
317
   * @throws InvalidToken
318
   * @throws ServiceFailure
319
   * @throws NotAuthorized
320
   * @throws NotFound
321
   * @throws NotImplemented
322
   */
323
  @Override
324
  public ObjectLocationList resolve(Session session, Identifier pid)
325
    throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized,
326
    NotFound, NotImplemented {
327 6177 cjones
328 6410 cjones
    throw new NotImplemented("4131", "resolve not implemented");
329 6303 leinfelder
330 6410 cjones
  }
331 6177 cjones
332 6410 cjones
  /**
333
   * Search the metadata catalog for identifiers that match the criteria
334
   *
335
   * @param session - the Session object containing the credentials for the Subject
336
   * @param queryType - An identifier for the type of query expression
337
   *                    provided in the query
338
   * @param query -  The criteria for matching the characteristics of the
339
   *                 metadata objects of interest
340
   *
341
   * @return objectList - the list of objects matching the criteria
342
   *
343
   * @throws InvalidToken
344
   * @throws ServiceFailure
345
   * @throws NotAuthorized
346
   * @throws InvalidRequest
347
   * @throws NotImplemented
348
   */
349
  @Override
350
  public ObjectList search(Session session, String queryType, String query)
351
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
352
    NotImplemented {
353 6177 cjones
354 6410 cjones
    ObjectList objectList = null;
355
    try {
356
        objectList =
357
          IdentifierManager.getInstance().querySystemMetadata(
358
              null, //startTime,
359
              null, //endTime,
360
              null, //objectFormat,
361
              false, //replicaStatus,
362
              0, //start,
363
              -1 //count
364
              );
365
366
    } catch (Exception e) {
367
      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
368
    }
369 6300 leinfelder
370 6410 cjones
      return objectList;
371
372
    //throw new NotImplemented("4281", "search not implemented");
373
374
    // the code block below is from an older implementation
375
376
    /*  This block commented out because of the EcoGrid circular dependency.
377 6281 leinfelder
         *  For now, query will not be supported until the circularity can be
378
         *  resolved, probably by moving the ecogrid query syntax transformers
379
         *  directly into the Metacat codebase.  MBJ 2010-02-03
380
381
        try {
382
            EcogridQueryParser parser = new EcogridQueryParser(request
383
                    .getReader());
384
            parser.parseXML();
385
            QueryType queryType = parser.getEcogridQuery();
386
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer =
387
                new EcogridJavaToMetacatJavaQueryTransformer();
388
            QuerySpecification metacatQuery = queryTransformer
389
                    .transform(queryType);
390 6223 leinfelder
391 6281 leinfelder
            DBQuery metacat = new DBQuery();
392
393
            boolean useXMLIndex = (new Boolean(PropertyService
394
                    .getProperty("database.usexmlindex"))).booleanValue();
395
            String xmlquery = "query"; // we don't care the query in resultset,
396
            // the query can be anything
397
            PrintWriter out = null; // we don't want metacat result, so set out null
398
399
            // parameter: queryspecification, user, group, usingIndexOrNot
400
            StringBuffer result = metacat.createResultDocument(xmlquery,
401
                    metacatQuery, out, username, groupNames, useXMLIndex);
402
403
            // create result set transfer
404
            String saxparser = PropertyService.getProperty("xml.saxparser");
405
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
406
                    new StringReader(result.toString()), saxparser, queryType
407
                            .getNamespace().get_value());
408
            ResultsetType records = metacatResultsetParser.getEcogridResult();
409
410
            System.out
411
                    .println(EcogridResultsetTransformer.toXMLString(records));
412
            response.setContentType("text/xml");
413
            out = response.getWriter();
414
            out.print(EcogridResultsetTransformer.toXMLString(records));
415
416
        } catch (Exception e) {
417
            e.printStackTrace();
418
        }*/
419 6410 cjones
420 6281 leinfelder
421 6410 cjones
  }
422
423
  /**
424
   * Returns the object format registered in the DataONE Object Format
425
   * Vocabulary for the given format identifier
426
   *
427
   * @param fmtid - the identifier of the format requested
428
   *
429
   * @return objectFormat - the object format requested
430
   *
431
   * @throws InvalidRequest
432
   * @throws ServiceFailure
433
   * @throws NotFound
434
   * @throws InsufficientResources
435
   * @throws NotImplemented
436
   */
437
  @Override
438
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
439
    throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources,
440
    NotImplemented {
441
442
      return ObjectFormatService.getInstance().getFormat(fmtid);
443
444
  }
445 6177 cjones
446 6410 cjones
  /**
447 6177 cjones
   * Returns a list of all object formats registered in the DataONE Object
448
   * Format Vocabulary
449 6410 cjones
    *
450
   * @return objectFormatList - The list of object formats registered in
451
   *                            the DataONE Object Format Vocabulary
452
   *
453
   * @throws InvalidRequest
454
   * @throws ServiceFailure
455
   * @throws NotImplemented
456
   * @throws NotFound
457
   * @throws InsufficientResources
458
   */
459
  @Override
460
  public ObjectFormatList listFormats()
461
    throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources,
462
    NotImplemented {
463 6177 cjones
464 6410 cjones
    return ObjectFormatService.getInstance().listFormats();
465
  }
466 6177 cjones
467 6410 cjones
  /**
468 6177 cjones
   * Returns a list of nodes that have been registered with the DataONE infrastructure
469 6410 cjones
    *
470
   * @return nodeList - List of nodes from the registry
471
   *
472
   * @throws ServiceFailure
473
   * @throws NotImplemented
474
   */
475
  @Override
476
  public NodeList listNodes()
477
    throws NotImplemented, ServiceFailure {
478 6177 cjones
479 6410 cjones
    throw new NotImplemented("4800", "listNodes not implemented");
480
  }
481 6177 cjones
482 6410 cjones
  /**
483 6177 cjones
   * Provides a mechanism for adding system metadata independently of its
484
   * associated object, such as when adding system metadata for data objects.
485 6410 cjones
    *
486
   * @param session - the Session object containing the credentials for the Subject
487
   * @param pid - The identifier of the object to register the system metadata against
488
   * @param sysmeta - The system metadata to be registered
489
   *
490
   * @return true if the registration succeeds
491
   *
492
   * @throws NotImplemented
493
   * @throws NotAuthorized
494
   * @throws ServiceFailure
495
   * @throws InvalidRequest
496
   * @throws InvalidSystemMetadata
497
   */
498
  @Override
499
  public Identifier registerSystemMetadata(Session session, Identifier guid,
500
    SystemMetadata sysmeta)
501
    throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
502
    InvalidSystemMetadata {
503 6177 cjones
504 6410 cjones
    // TODO: control who can call this?
505
        if (session == null) {
506
            //TODO: many of the thrown exceptions do not use the correct error codes
507
            //check these against the docs and correct them
508
            throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
509
                    "  If you are not logged in, please do so and retry the request.");
510
        }
511
512
        // verify that guid == SystemMetadata.getIdentifier()
513
        logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
514
        if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
515
            throw new InvalidRequest("4863",
516
                "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
517
                sysmeta.getIdentifier().getValue() + ").");
518
        }
519 6188 leinfelder
520 6410 cjones
        logMetacat.debug("Checking if identifier exists...");
521
        // Check that the identifier does not already exist
522
        if (IdentifierManager.getInstance().identifierExists(guid.getValue())) {
523
            throw new InvalidRequest("4863",
524
                "GUID is already in use by an existing object.");
525
526
        }
527 6188 leinfelder
528 6410 cjones
        // insert the system metadata into the object store
529
        logMetacat.debug("Starting to insert SystemMetadata...");
530
        sysmeta.setDateSysMetadataModified(new Date());
531
        try {
532 6447 leinfelder
        	HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
533 6410 cjones
        } catch (Exception e) {
534
            throw new ServiceFailure("4862", "Error inserting system metadata: " + e.getClass() + ": " + e.getMessage());
535
        }
536
537
        logMetacat.debug("Returning from registerSystemMetadata");
538
        EventLog.getInstance().log(null, session.getSubject().getValue(), guid.getValue(), "registerSystemMetadata");
539
        return guid;
540
  }
541 6177 cjones
542 6410 cjones
  /**
543
   * Provides a mechanism for updating system metadata independently of its
544
   * associated object
545
    *
546
   * @param session - the Session object containing the credentials for the Subject
547
   * @param pid - The identifier of the system metadata
548
   * @param sysmeta - The system metadata to be registered
549
   *
550
   * @return true if the update succeeds
551
   *
552
   * @throws NotImplemented
553
   * @throws NotAuthorized
554
   * @throws ServiceFailure
555
   * @throws InvalidRequest
556
   * @throws InvalidSystemMetadata
557
   * @throws NotFound
558
   */
559
  @Override
560
  public boolean updateSystemMetadata(Session session, Identifier guid,
561
    SystemMetadata sysmeta)
562
    throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
563
    InvalidSystemMetadata, NotFound {
564 6378 leinfelder
565 6410 cjones
    // TODO: control who can call this?
566
        if (session == null) {
567
            //TODO: many of the thrown exceptions do not use the correct error codes
568
            //check these against the docs and correct them
569
            throw new NotAuthorized("4861", "No Session - could not authorize for update." +
570
                    "  If you are not logged in, please do so and retry the request.");
571
        }
572
573
        // verify that guid == SystemMetadata.getIdentifier()
574
        logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
575
        if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
576
            throw new InvalidRequest("4863",
577
                "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
578
                sysmeta.getIdentifier().getValue() + ").");
579
        }
580 6378 leinfelder
581 6410 cjones
        logMetacat.debug("Checking if identifier exists...");
582
        // Check that the identifier exists
583
        if (!IdentifierManager.getInstance().identifierExists(guid.getValue())) {
584
            throw new NotFound("000",
585
                "GUID does not exist");
586
        }
587 6378 leinfelder
588 6410 cjones
        // update the system metadata into the object store
589
        logMetacat.debug("Starting to update SystemMetadata...");
590
        sysmeta.setDateSysMetadataModified(new Date());
591 6449 leinfelder
        HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
592 6410 cjones
593
        logMetacat.debug("Returning from updateSystemMetadata");
594
        EventLog.getInstance().log(null, session.getSubject().getValue(), guid.getValue(), "updateSystemMetadata");
595
        return true;
596
  }
597
598
  /**
599 6177 cjones
   * Given an optional scope and format, reserves and returns an identifier
600
   * within that scope and format that is unique and will not be
601
   * used by any other sessions.
602 6410 cjones
    *
603
   * @param session - the Session object containing the credentials for the Subject
604
   * @param pid - The identifier of the object to register the system metadata against
605
   * @param scope - An optional string to be used to qualify the scope of
606
   *                the identifier namespace, which is applied differently
607
   *                depending on the format requested. If scope is not
608
   *                supplied, a default scope will be used.
609
   * @param format - The optional name of the identifier format to be used,
610
   *                  drawn from a DataONE-specific vocabulary of identifier
611
   *                 format names, including several common syntaxes such
612
   *                 as DOI, LSID, UUID, and LSRN, among others. If the
613
   *                 format is not supplied by the caller, the CN service
614
   *                 will use a default identifier format, which may change
615
   *                 over time.
616
   *
617
   * @return true if the registration succeeds
618
   *
619
   * @throws InvalidToken
620
   * @throws ServiceFailure
621
   * @throws NotAuthorized
622
   * @throws IdentifierNotUnique
623
   * @throws NotImplemented
624
   */
625
  @Override
626
  public boolean reserveIdentifier(Session session, Identifier pid)
627
  throws InvalidToken, ServiceFailure,
628 6378 leinfelder
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
629 6177 cjones
630 6410 cjones
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
631
  }
632
633
  @Override
634
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
635
  throws InvalidToken, ServiceFailure,
636 6378 leinfelder
        NotAuthorized, NotImplemented, InvalidRequest {
637 6410 cjones
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
638
  }
639
640
  /**
641
    * Checks whether the pid is reserved by the subject in the session param
642
    * If the reservation is held on the pid by the subject, we return true.
643
    *
644
   * @param session - the Session object containing the Subject
645
   * @param pid - The identifier to check
646
   *
647
   * @return true if the reservation exists for the subject/pid
648
   *
649
   * @throws InvalidToken
650
   * @throws ServiceFailure
651
   * @throws NotFound - when the pid is not found (in use or in reservation)
652
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
653
   * @throws IdentifierNotUnique - when the pid is in use
654
   * @throws NotImplemented
655
   */
656 6177 cjones
657 6410 cjones
  @Override
658
  public boolean hasReservation(Session session, Identifier pid)
659
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique,
660
      NotImplemented, InvalidRequest {
661
662
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
663
  }
664 6339 leinfelder
665 6410 cjones
  /**
666 6177 cjones
   * Changes ownership (RightsHolder) of the specified object to the
667
   * subject specified by userId
668 6410 cjones
    *
669
   * @param session - the Session object containing the credentials for the Subject
670
   * @param pid - Identifier of the object to be modified
671
   * @param userId - The subject that will be taking ownership of the specified object.
672
   *
673
   * @return pid - the identifier of the modified object
674
   *
675
   * @throws ServiceFailure
676
   * @throws InvalidToken
677
   * @throws NotFound
678
   * @throws NotAuthorized
679
   * @throws NotImplemented
680
   * @throws InvalidRequest
681
   */
682
  @Override
683
  public Identifier setOwner(Session session, Identifier pid, Subject userId)
684
    throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
685
    NotImplemented, InvalidRequest {
686
687
    // get the subject
688
    Subject subject = session.getSubject();
689
    // get the system metadata
690
    String guid = pid.getValue();
691
692
    // are we allowed to do this?
693
    if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
694
      throw new NotAuthorized("4440", "not allowed by " + subject.getValue() + " on " + guid);
695
    }
696
697
    SystemMetadata systemMetadata = null;
698
    try {
699
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
700
    } catch (McdbDocNotFoundException e) {
701
      throw new NotFound("4460", "No record found for: " + guid);
702
    }
703
704
    // set the new rights holder
705
    systemMetadata.setRightsHolder(userId);
706
707
    // update the metadata
708 6449 leinfelder
    HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
709 6177 cjones
710 6410 cjones
    return pid;
711
  }
712 6177 cjones
713 6410 cjones
  /**
714
   * Verify that a replication task is authorized by comparing the target node's
715
   * Subject (from the X.509 certificate-derived Session) with the list of
716
   * subjects in the known, pending replication tasks map.
717
   *
718
   * @param originatingNodeSession - Session information that contains the
719
   *                                 identity of the calling user
720
   * @param targetNodeSubject - Subject identifying the target node
721
   * @param pid - the identifier of the object to be replicated
722
   * @param replicatePermission - the execute permission to be granted
723
   *
724
   * @throws ServiceFailure
725
   * @throws NotImplemented
726
   * @throws InvalidToken
727
   * @throws NotAuthorized
728
   * @throws InvalidRequest
729
   * @throws NotFound
730
   */
731
  @Override
732 6409 cjones
  public boolean isNodeAuthorized(Session originatingNodeSession,
733 6384 cjones
    Subject targetNodeSubject, Identifier pid, Permission replicatePermission)
734 6410 cjones
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
735
    NotFound, InvalidRequest {
736 6384 cjones
737 6419 leinfelder
	// build a predicate like:
738
	    // "pid                    = '{pid}                   ' AND
739
	    //  pemission              = '{permission}            ' AND
740
	    //  originatingNodeSubject = '{originatingNodeSubject}' AND
741
	    //  targetNodeSubject      = '{targetNodeSubject}     '"
742
	    boolean isAllowed = false;
743
	    String query = "";
744
	    query += "pid = '";
745
	    query += pid;
746
	    query += "' AND permission = '";
747
	    query += replicatePermission.name();
748
	    query += "' AND originatingNodeSubject = '";
749
	    query += originatingNodeSession.getSubject().getValue();
750
	    query += "' AND targetNodeSubject = '";
751
	    query += targetNodeSubject.getValue();
752
	    query += "'";
753
754
	    logMetacat.debug("Pending replication task query is: " + query);
755
	    // search the hzPendingReplicationTasks map for the  originating node subject,
756
	    // target node subject, pid, and replicate permission
757
758
	    Set<CNReplicationTask> tasks =
759 6446 leinfelder
	      (Set<CNReplicationTask>) HazelcastService.getInstance().getPendingReplicationTasks().values(new SqlPredicate(query));
760 6419 leinfelder
761
	    // do we have a matching task?
762
	    if ( tasks.size() >= 1 ) {
763
	      isAllowed = true;
764
765
	    }
766
767
	    return isAllowed;
768 6410 cjones
769 6384 cjones
  }
770
771 6177 cjones
}