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