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