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