Project

General

Profile

1
/**
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
import java.util.List;
28
import java.util.Set;
29

    
30
import org.apache.log4j.Logger;
31
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
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
import org.dataone.service.types.v1.Checksum;
45
import org.dataone.service.types.v1.Identifier;
46
import org.dataone.service.types.v1.Node;
47
import org.dataone.service.types.v1.NodeList;
48
import org.dataone.service.types.v1.NodeReference;
49
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

    
62
import com.hazelcast.query.SqlPredicate;
63

    
64
import edu.ucsb.nceas.metacat.EventLog;
65
import edu.ucsb.nceas.metacat.IdentifierManager;
66
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
67
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
68

    
69
/**
70
 * Represents Metacat's implementation of the DataONE Coordinating Node 
71
 * service API. Methods implement the various CN* interfaces, and methods common
72
 * 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
    CNCore, CNRead, CNReplication {
78

    
79
  /* the instance of the CNodeService object */
80
  private static CNodeService instance = null;
81

    
82
  /* the logger instance */
83
  private Logger logMetacat = null;
84

    
85
  /**
86
   * singleton accessor
87
   */
88
  public static CNodeService getInstance() { 
89
    if (instance == null) {
90
    
91
      instance = new CNodeService();
92
      
93
    }
94
  
95
    return instance;
96
  }
97
  
98
  /**
99
   * Constructor, private for singleton access
100
   */
101
  private CNodeService() {
102
    super();
103
    logMetacat = Logger.getLogger(CNodeService.class);
104
        
105
  }
106
    
107
  /**
108
   * Set the replication policy for an object given the object identifier
109
   * 
110
   * @param session - the Session object containing the credentials for the Subject
111
   * @param pid - the object identifier for the given object
112
   * @param policy - the replication policy to be applied
113
   * 
114
   * @return true or false
115
   * 
116
   * @throws NotImplemented
117
   * @throws NotAuthorized
118
   * @throws ServiceFailure
119
   * @throws InvalidRequest
120
   * 
121
   */
122
  @Override
123
  public boolean setReplicationPolicy(Session session, Identifier pid,
124
    ReplicationPolicy policy) 
125
    throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, InvalidRequest, InvalidToken {
126

    
127
    // get the subject
128
    Subject subject = session.getSubject();
129
    // get the system metadata
130
    String guid = pid.getValue();
131
    
132
    // are we allowed to do this?
133
    if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
134
      throw new NotAuthorized("4881", Permission.CHANGE_PERMISSION + " not allowed by " + subject.getValue() + " on " + guid);  
135
    }
136
    
137
    SystemMetadata systemMetadata = null;
138
    try {
139
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
140
    } catch (McdbDocNotFoundException e) {
141
      throw new NotFound("4884", "No record found for: " + guid);
142
    }
143
        
144
    // set the new policy
145
    systemMetadata.setReplicationPolicy(policy);
146
    
147
    // update the metadata
148
    HazelcastService.getInstance().getSystemMetadataMap().lock(systemMetadata.getIdentifier());
149
    HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
150
    HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
151

    
152
    return true;
153
  }
154

    
155
  /**
156
   * Set the replication status for an object given the object identifier
157
   * 
158
   * @param session - the Session object containing the credentials for the Subject
159
   * @param pid - the object identifier for the given object
160
   * @param status - the replication status to be applied
161
   * 
162
   * @return true or false
163
   * 
164
   * @throws NotImplemented
165
   * @throws NotAuthorized
166
   * @throws ServiceFailure
167
   * @throws InvalidRequest
168
   * @throws InvalidToken
169
   * @throws NotFound
170
   * 
171
   */
172
  @Override
173
  public boolean setReplicationStatus(Session session, Identifier pid,
174
    NodeReference targetNode, ReplicationStatus status) 
175
    throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
176
    InvalidRequest, NotFound {
177

    
178
    // get the subject
179
    Subject subject = session.getSubject();
180
    // get the system metadata
181
    String guid = pid.getValue();
182
    
183
    // are we allowed to do this?
184
    if (!isAuthorized(session, pid, Permission.WRITE)) {
185
      throw new NotAuthorized("4720", Permission.WRITE + " not allowed by " + subject.getValue() + " on " + guid);  
186
    }
187
    
188
    SystemMetadata systemMetadata = null;
189
    try {
190
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
191
    } catch (McdbDocNotFoundException e) {
192
      throw new NotFound("4740", "No record found for: " + guid);
193
    }
194
        
195
    // set the status for each replica
196
    // TODO: should this method select a certain replica?
197
    List<Replica> replicas = systemMetadata.getReplicaList();
198
    for (Replica replica: replicas) {
199
      replica.setReplicationStatus(status);
200
    }
201
    
202
    // [re]set the list -- redundant?
203
    systemMetadata.setReplicaList(replicas);
204
    
205
    // update the metadata
206
    HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
207

    
208
    return true;
209
  }
210

    
211
  /**
212
   * Test that the specified relationship between pidOfSubject and pidOfObject exists
213
   * 
214
   * @param session - the Session object containing the credentials for the Subject
215
   * @param node - the node information for the given node be modified
216
   * 
217
   * @return true if the relationship exists
218
   * 
219
   * @throws InvalidToken
220
   * @throws ServiceFailure
221
   * @throws NotAuthorized
222
   * @throws NotFound
223
   * @throws InvalidRequest
224
   * @throws NotImplemented
225
   */
226
  @Override
227
  public boolean assertRelation(Session session, Identifier pidOfSubject, 
228
    String relationship, Identifier pidOfObject) 
229
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
230
    InvalidRequest, NotImplemented {
231
    
232
    
233
    // get the system metadata
234
    String guid1 = pidOfSubject.getValue();
235
    // are we allowed to do this?
236
    if (!isAuthorized(session, pidOfSubject, Permission.READ)) {
237
      throw new NotAuthorized("4881", Permission.READ + " not allowed on " + guid1);  
238
    }
239
    
240
    SystemMetadata systemMetadata = null;
241
    try {
242
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid1);
243
    } catch (McdbDocNotFoundException e) {
244
      throw new NotFound("4884", "No record found for: " + guid1);
245
    }
246
        
247
    // check relationships
248
    // TODO: use ORE map
249
    if (relationship.equalsIgnoreCase("describes")) {
250
      
251
    }
252
    if (relationship.equalsIgnoreCase("describedBy")) {
253
      
254
    }
255
    if (relationship.equalsIgnoreCase("derivedFrom")) {
256
      
257
    }
258
    if (relationship.equalsIgnoreCase("obsoletes")) {
259
      Identifier pid = systemMetadata.getObsoletes();
260
      if (pid.getValue().equals(pidOfObject.getValue())) {
261
        return true;
262
      }
263
      //return systemMetadata.getObsoleteList().contains(pidOfObject);
264
    }
265
    if (relationship.equalsIgnoreCase("obsoletedBy")) {
266
      Identifier pid = systemMetadata.getObsoletedBy();
267
      if (pid.getValue().equals(pidOfObject.getValue())) {
268
        return true;
269
      }
270
      //return systemMetadata.getObsoletedByList().contains(pidOfObject);
271
    }
272

    
273
    return false;
274
  }
275
  
276
  /**
277
   * Return the checksum of the object given the identifier 
278
   * 
279
   * @param session - the Session object containing the credentials for the Subject
280
   * @param pid - the object identifier for the given object
281
   * 
282
   * @return checksum - the checksum of the object
283
   * 
284
   * @throws InvalidToken
285
   * @throws ServiceFailure
286
   * @throws NotAuthorized
287
   * @throws NotFound
288
   * @throws InvalidRequest
289
   * @throws NotImplemented
290
   */
291
  @Override
292
  public Checksum getChecksum(Session session, Identifier pid)
293
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
294
    InvalidRequest, NotImplemented {
295
    
296
    if (!isAuthorized(session, pid, Permission.READ)) {
297
      throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());  
298
    }
299
    SystemMetadata systemMetadata = null;
300
    try {
301
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
302
    } catch (McdbDocNotFoundException e) {
303
      throw new NotFound("1420", "No record found for: " + pid.getValue());
304
    }
305
    Checksum checksum = systemMetadata.getChecksum();
306
    
307
    return checksum;
308
  }
309

    
310
  /**
311
   * Resolve the location of a given object
312
   * 
313
   * @param session - the Session object containing the credentials for the Subject
314
   * @param pid - the object identifier for the given object
315
   * 
316
   * @return objectLocationList - the list of nodes known to contain the object
317
   * 
318
   * @throws InvalidRequest
319
   * @throws InvalidToken
320
   * @throws ServiceFailure
321
   * @throws NotAuthorized
322
   * @throws NotFound
323
   * @throws NotImplemented
324
   */
325
  @Override
326
  public ObjectLocationList resolve(Session session, Identifier pid)
327
    throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized,
328
    NotFound, NotImplemented {
329

    
330
    throw new NotImplemented("4131", "resolve not implemented");
331

    
332
  }
333

    
334
  /**
335
   * Search the metadata catalog for identifiers that match the criteria
336
   * 
337
   * @param session - the Session object containing the credentials for the Subject
338
   * @param queryType - An identifier for the type of query expression 
339
   *                    provided in the query
340
   * @param query -  The criteria for matching the characteristics of the 
341
   *                 metadata objects of interest
342
   * 
343
   * @return objectList - the list of objects matching the criteria
344
   * 
345
   * @throws InvalidToken
346
   * @throws ServiceFailure
347
   * @throws NotAuthorized
348
   * @throws InvalidRequest
349
   * @throws NotImplemented
350
   */
351
  @Override
352
  public ObjectList search(Session session, String queryType, String query)
353
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
354
    NotImplemented {
355

    
356
    ObjectList objectList = null;
357
    try {
358
        objectList = 
359
          IdentifierManager.getInstance().querySystemMetadata(
360
              null, //startTime, 
361
              null, //endTime,
362
              null, //objectFormat, 
363
              false, //replicaStatus, 
364
              0, //start, 
365
              -1 //count
366
              );
367
        
368
    } catch (Exception e) {
369
      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
370
    }
371

    
372
      return objectList;
373
      
374
    //throw new NotImplemented("4281", "search not implemented");
375
    
376
    // the code block below is from an older implementation
377
    
378
    /*  This block commented out because of the EcoGrid circular dependency.
379
         *  For now, query will not be supported until the circularity can be
380
         *  resolved, probably by moving the ecogrid query syntax transformers
381
         *  directly into the Metacat codebase.  MBJ 2010-02-03
382
         
383
        try {
384
            EcogridQueryParser parser = new EcogridQueryParser(request
385
                    .getReader());
386
            parser.parseXML();
387
            QueryType queryType = parser.getEcogridQuery();
388
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
389
                new EcogridJavaToMetacatJavaQueryTransformer();
390
            QuerySpecification metacatQuery = queryTransformer
391
                    .transform(queryType);
392

    
393
            DBQuery metacat = new DBQuery();
394

    
395
            boolean useXMLIndex = (new Boolean(PropertyService
396
                    .getProperty("database.usexmlindex"))).booleanValue();
397
            String xmlquery = "query"; // we don't care the query in resultset,
398
            // the query can be anything
399
            PrintWriter out = null; // we don't want metacat result, so set out null
400

    
401
            // parameter: queryspecification, user, group, usingIndexOrNot
402
            StringBuffer result = metacat.createResultDocument(xmlquery,
403
                    metacatQuery, out, username, groupNames, useXMLIndex);
404

    
405
            // create result set transfer       
406
            String saxparser = PropertyService.getProperty("xml.saxparser");
407
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
408
                    new StringReader(result.toString()), saxparser, queryType
409
                            .getNamespace().get_value());
410
            ResultsetType records = metacatResultsetParser.getEcogridResult();
411

    
412
            System.out
413
                    .println(EcogridResultsetTransformer.toXMLString(records));
414
            response.setContentType("text/xml");
415
            out = response.getWriter();
416
            out.print(EcogridResultsetTransformer.toXMLString(records));
417

    
418
        } catch (Exception e) {
419
            e.printStackTrace();
420
        }*/
421
    
422

    
423
  }
424
  
425
  /**
426
   * Returns the object format registered in the DataONE Object Format 
427
   * Vocabulary for the given format identifier
428
   * 
429
   * @param fmtid - the identifier of the format requested
430
   * 
431
   * @return objectFormat - the object format requested
432
   * 
433
   * @throws InvalidRequest
434
   * @throws ServiceFailure
435
   * @throws NotFound
436
   * @throws InsufficientResources
437
   * @throws NotImplemented
438
   */
439
  @Override
440
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
441
    throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources,
442
    NotImplemented {
443
     
444
      return ObjectFormatService.getInstance().getFormat(fmtid);
445
      
446
  }
447

    
448
  /**
449
   * Returns a list of all object formats registered in the DataONE Object 
450
   * Format Vocabulary
451
    * 
452
   * @return objectFormatList - The list of object formats registered in 
453
   *                            the DataONE Object Format Vocabulary
454
   * 
455
   * @throws InvalidRequest
456
   * @throws ServiceFailure
457
   * @throws NotImplemented
458
   * @throws NotFound
459
   * @throws InsufficientResources
460
   */
461
  @Override
462
  public ObjectFormatList listFormats() 
463
    throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources, 
464
    NotImplemented {
465

    
466
    return ObjectFormatService.getInstance().listFormats();
467
  }
468

    
469
  /**
470
   * Returns a list of nodes that have been registered with the DataONE infrastructure
471
    * 
472
   * @return nodeList - List of nodes from the registry
473
   * 
474
   * @throws ServiceFailure
475
   * @throws NotImplemented
476
   */
477
  @Override
478
  public NodeList listNodes() 
479
    throws NotImplemented, ServiceFailure {
480

    
481
    throw new NotImplemented("4800", "listNodes not implemented");
482
  }
483

    
484
  /**
485
   * Provides a mechanism for adding system metadata independently of its 
486
   * associated object, such as when adding system metadata for data objects.
487
    * 
488
   * @param session - the Session object containing the credentials for the Subject
489
   * @param pid - The identifier of the object to register the system metadata against
490
   * @param sysmeta - The system metadata to be registered
491
   * 
492
   * @return true if the registration succeeds
493
   * 
494
   * @throws NotImplemented
495
   * @throws NotAuthorized
496
   * @throws ServiceFailure
497
   * @throws InvalidRequest
498
   * @throws InvalidSystemMetadata
499
   */
500
  @Override
501
  public Identifier registerSystemMetadata(Session session, Identifier guid,
502
    SystemMetadata sysmeta) 
503
    throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
504
    InvalidSystemMetadata {
505

    
506
    // TODO: control who can call this?
507
        if (session == null) {
508
            //TODO: many of the thrown exceptions do not use the correct error codes
509
            //check these against the docs and correct them
510
            throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
511
                    "  If you are not logged in, please do so and retry the request.");
512
        }
513
        
514
        // verify that guid == SystemMetadata.getIdentifier()
515
        logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
516
        if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
517
            throw new InvalidRequest("4863", 
518
                "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
519
                sysmeta.getIdentifier().getValue() + ").");
520
        }
521

    
522
        logMetacat.debug("Checking if identifier exists...");
523
        // Check that the identifier does not already exist
524
        if (IdentifierManager.getInstance().identifierExists(guid.getValue())) {
525
            throw new InvalidRequest("4863", 
526
                "GUID is already in use by an existing object.");
527
      
528
        }
529

    
530
        // insert the system metadata into the object store
531
        logMetacat.debug("Starting to insert SystemMetadata...");
532
        sysmeta.setDateSysMetadataModified(new Date());
533
        try {
534
          HazelcastService.getInstance().getSystemMetadataMap().lock(sysmeta.getIdentifier());
535
        	HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
536
          HazelcastService.getInstance().getSystemMetadataMap().unlock(sysmeta.getIdentifier());
537
          
538
        } catch (Exception e) {
539
            throw new ServiceFailure("4862", "Error inserting system metadata: " + e.getClass() + ": " + e.getMessage());
540
        } finally {
541
          HazelcastService.getInstance().getSystemMetadataMap().unlock(sysmeta.getIdentifier());
542

    
543
        }
544
        
545
        logMetacat.debug("Returning from registerSystemMetadata");
546
        EventLog.getInstance().log(null, session.getSubject().getValue(), guid.getValue(), "registerSystemMetadata");
547
        return guid;
548
  }
549

    
550
  /**
551
   * Provides a mechanism for updating system metadata independently of its 
552
   * associated object
553
    * 
554
   * @param session - the Session object containing the credentials for the Subject
555
   * @param pid - The identifier of the system metadata
556
   * @param sysmeta - The system metadata to be registered
557
   * 
558
   * @return true if the update succeeds
559
   * 
560
   * @throws NotImplemented
561
   * @throws NotAuthorized
562
   * @throws ServiceFailure
563
   * @throws InvalidRequest
564
   * @throws InvalidSystemMetadata
565
   * @throws NotFound
566
   */
567
  @Override
568
  public boolean updateSystemMetadata(Session session, Identifier guid,
569
    SystemMetadata sysmeta) 
570
    throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
571
    InvalidSystemMetadata, NotFound {
572

    
573
    // TODO: control who can call this?
574
        if (session == null) {
575
            //TODO: many of the thrown exceptions do not use the correct error codes
576
            //check these against the docs and correct them
577
            throw new NotAuthorized("4861", "No Session - could not authorize for update." +
578
                    "  If you are not logged in, please do so and retry the request.");
579
        }
580
        
581
        // verify that guid == SystemMetadata.getIdentifier()
582
        logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
583
        if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
584
            throw new InvalidRequest("4863", 
585
                "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
586
                sysmeta.getIdentifier().getValue() + ").");
587
        }
588

    
589
        logMetacat.debug("Checking if identifier exists...");
590
        // Check that the identifier exists
591
        if (!IdentifierManager.getInstance().identifierExists(guid.getValue())) {
592
            throw new NotFound("000", 
593
                "GUID does not exist");
594
        }
595

    
596
        // update the system metadata into the object store
597
        logMetacat.debug("Starting to update SystemMetadata...");
598
        sysmeta.setDateSysMetadataModified(new Date());
599
        HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
600
        
601
        logMetacat.debug("Returning from updateSystemMetadata");
602
        EventLog.getInstance().log(null, session.getSubject().getValue(), guid.getValue(), "updateSystemMetadata");
603
        return true;
604
  }
605
  
606
  /**
607
   * Given an optional scope and format, reserves and returns an identifier 
608
   * within that scope and format that is unique and will not be 
609
   * used by any other sessions. 
610
    * 
611
   * @param session - the Session object containing the credentials for the Subject
612
   * @param pid - The identifier of the object to register the system metadata against
613
   * @param scope - An optional string to be used to qualify the scope of 
614
   *                the identifier namespace, which is applied differently 
615
   *                depending on the format requested. If scope is not 
616
   *                supplied, a default scope will be used.
617
   * @param format - The optional name of the identifier format to be used, 
618
   *                  drawn from a DataONE-specific vocabulary of identifier 
619
   *                 format names, including several common syntaxes such 
620
   *                 as DOI, LSID, UUID, and LSRN, among others. If the 
621
   *                 format is not supplied by the caller, the CN service 
622
   *                 will use a default identifier format, which may change 
623
   *                 over time.
624
   * 
625
   * @return true if the registration succeeds
626
   * 
627
   * @throws InvalidToken
628
   * @throws ServiceFailure
629
   * @throws NotAuthorized
630
   * @throws IdentifierNotUnique
631
   * @throws NotImplemented
632
   */
633
  @Override
634
  public boolean reserveIdentifier(Session session, Identifier pid)
635
  throws InvalidToken, ServiceFailure,
636
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
637

    
638
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
639
  }
640
  
641
  @Override
642
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
643
  throws InvalidToken, ServiceFailure,
644
        NotAuthorized, NotImplemented, InvalidRequest {
645
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
646
  }
647
  
648
  /**
649
    * Checks whether the pid is reserved by the subject in the session param
650
    * If the reservation is held on the pid by the subject, we return true.
651
    * 
652
   * @param session - the Session object containing the Subject
653
   * @param pid - The identifier to check
654
   * 
655
   * @return true if the reservation exists for the subject/pid
656
   * 
657
   * @throws InvalidToken
658
   * @throws ServiceFailure
659
   * @throws NotFound - when the pid is not found (in use or in reservation)
660
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
661
   * @throws IdentifierNotUnique - when the pid is in use
662
   * @throws NotImplemented
663
   */
664

    
665
  @Override
666
  public boolean hasReservation(Session session, Identifier pid) 
667
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique, 
668
      NotImplemented, InvalidRequest {
669
  
670
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
671
  }
672

    
673
  /**
674
   * Changes ownership (RightsHolder) of the specified object to the 
675
   * subject specified by userId
676
    * 
677
   * @param session - the Session object containing the credentials for the Subject
678
   * @param pid - Identifier of the object to be modified
679
   * @param userId - The subject that will be taking ownership of the specified object.
680
   *
681
   * @return pid - the identifier of the modified object
682
   * 
683
   * @throws ServiceFailure
684
   * @throws InvalidToken
685
   * @throws NotFound
686
   * @throws NotAuthorized
687
   * @throws NotImplemented
688
   * @throws InvalidRequest
689
   */  
690
  @Override
691
  public Identifier setOwner(Session session, Identifier pid, Subject userId)
692
    throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
693
    NotImplemented, InvalidRequest {
694
    
695
    // get the subject
696
    Subject subject = session.getSubject();
697
    // get the system metadata
698
    String guid = pid.getValue();
699
    
700
    // are we allowed to do this?
701
    if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
702
      throw new NotAuthorized("4440", "not allowed by " + subject.getValue() + " on " + guid);  
703
    }
704
    
705
    SystemMetadata systemMetadata = null;
706
    try {
707
      systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
708
    } catch (McdbDocNotFoundException e) {
709
      throw new NotFound("4460", "No record found for: " + guid);
710
    }
711
        
712
    // set the new rights holder
713
    systemMetadata.setRightsHolder(userId);
714
    
715
    // update the metadata
716
    HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
717

    
718
    return pid;
719
  }
720

    
721
  /**
722
   * Verify that a replication task is authorized by comparing the target node's
723
   * Subject (from the X.509 certificate-derived Session) with the list of 
724
   * subjects in the known, pending replication tasks map.
725
   * 
726
   * @param originatingNodeSession - Session information that contains the 
727
   *                                 identity of the calling user
728
   * @param targetNodeSubject - Subject identifying the target node
729
   * @param pid - the identifier of the object to be replicated
730
   * @param replicatePermission - the execute permission to be granted
731
   * 
732
   * @throws ServiceFailure
733
   * @throws NotImplemented
734
   * @throws InvalidToken
735
   * @throws NotAuthorized
736
   * @throws InvalidRequest
737
   * @throws NotFound
738
   */
739
  @Override
740
  public boolean isNodeAuthorized(Session originatingNodeSession, 
741
    Subject targetNodeSubject, Identifier pid, Permission replicatePermission) 
742
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure, 
743
    NotFound, InvalidRequest {
744

    
745
	  boolean isAllowed = false;
746
	  SystemMetadata sysmeta = null;
747
    String query = "subject = '" + targetNodeSubject + "'";
748
    NodeReference targetNode = null;
749
    
750
	  try {
751
	    // get the target node reference from the hzNodes map
752
	    Set<Node> nodeList = (Set<Node>) 
753
	      HazelcastService.getInstance().getNodesMap().values(new SqlPredicate(query));
754
	    
755
	    // we should only have one subject DN per node
756
	    for (Node node : nodeList) {      
757
	      targetNode = node.getIdentifier();
758
	      break;
759
	        
760
      }
761
	     //lock, get, and unlock the pid
762
	    HazelcastService.getInstance().getSystemMetadataMap().lock(pid);
763
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
764
      HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
765
	    List<Replica> replicaList = sysmeta.getReplicaList();
766
	    
767
	    // find the replica with the status set to 'requested'
768
	    for(Replica replica : replicaList) {
769
	      ReplicationStatus status = replica.getReplicationStatus();
770
	      NodeReference listedNode = replica.getReplicaMemberNode();
771
	      if ( listedNode.equals(targetNode) && 
772
	           status.equals(ReplicationStatus.REQUESTED)) {
773
	        isAllowed = true;
774
	        break;
775
	        
776
	      }
777
	    }
778

    
779
	  } catch(Exception e) {
780
	    // Catch Hazelcast RuntimeExceptions
781
	    
782
	  } finally {
783
	    // always unlock the pid
784
      HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
785

    
786
	  }
787
	    
788
	  return isAllowed;
789
    
790
  }
791

    
792
}
(1-1/6)