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.io.InputStream;
27
import java.util.Date;
28
import java.util.List;
29

    
30
import org.apache.log4j.Logger;
31
import org.dataone.service.cn.CNAuthorization;
32
import org.dataone.service.cn.CNCore;
33
import org.dataone.service.cn.CNRead;
34
import org.dataone.service.cn.CNRegister;
35
import org.dataone.service.cn.CNReplication;
36
import org.dataone.service.exceptions.IdentifierNotUnique;
37
import org.dataone.service.exceptions.InsufficientResources;
38
import org.dataone.service.exceptions.InvalidRequest;
39
import org.dataone.service.exceptions.InvalidSystemMetadata;
40
import org.dataone.service.exceptions.InvalidToken;
41
import org.dataone.service.exceptions.NotAuthorized;
42
import org.dataone.service.exceptions.NotFound;
43
import org.dataone.service.exceptions.NotImplemented;
44
import org.dataone.service.exceptions.ServiceFailure;
45
import org.dataone.service.exceptions.UnsupportedType;
46
import org.dataone.service.types.AccessPolicy;
47
import org.dataone.service.types.AccessRule;
48
import org.dataone.service.types.Checksum;
49
import org.dataone.service.types.Event;
50
import org.dataone.service.types.Identifier;
51
import org.dataone.service.types.Log;
52
import org.dataone.service.types.Node;
53
import org.dataone.service.types.NodeList;
54
import org.dataone.service.types.NodeReference;
55
import org.dataone.service.types.ObjectFormat;
56
import org.dataone.service.types.ObjectFormatIdentifier;
57
import org.dataone.service.types.ObjectFormatList;
58
import org.dataone.service.types.ObjectList;
59
import org.dataone.service.types.ObjectLocationList;
60
import org.dataone.service.types.Permission;
61
import org.dataone.service.types.QueryType;
62
import org.dataone.service.types.ReplicationPolicy;
63
import org.dataone.service.types.ReplicationStatus;
64
import org.dataone.service.types.Session;
65
import org.dataone.service.types.Subject;
66
import org.dataone.service.types.SystemMetadata;
67

    
68
import edu.ucsb.nceas.metacat.EventLog;
69
import edu.ucsb.nceas.metacat.IdentifierManager;
70
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
71
import edu.ucsb.nceas.metacat.replication.ForceReplicationSystemMetadataHandler;
72

    
73
/**
74
 * Represents Metacat's implementation of the DataONE Coordinating Node 
75
 * service API. Methods implement the various CN* interfaces, and methods common
76
 * 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
    CNCore, CNRead, CNRegister, CNReplication {
82

    
83
	/* the instance of the CNodeService object */
84
  private static CNodeService instance = null;
85
  
86
  /* the logger instance */
87
  private Logger logMetacat = null;
88

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

    
130
		return false;
131
	}
132

    
133
	/**
134
	 * Set the replication status for an object given the object identifier
135
	 * 
136
	 * @param session - the Session object containing the credentials for the Subject
137
	 * @param pid - the object identifier for the given object
138
	 * @param status - the replication status to be applied
139
	 * 
140
	 * @return true or false
141
	 * 
142
	 * @throws NotImplemented
143
	 * @throws NotAuthorized
144
	 * @throws ServiceFailure
145
	 * @throws InvalidRequest
146
	 * @throws InvalidToken
147
	 * @throws NotFound
148
	 * 
149
	 */
150
	@Override
151
	public boolean setReplicationStatus(Session session, Identifier pid,
152
	  ReplicationStatus status) 
153
	  throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
154
	  InvalidRequest, NotFound {
155

    
156
		return false;
157
	}
158

    
159
	/**
160
	 * Add capabilities to the node description
161
	 * 
162
	 * @param session - the Session object containing the credentials for the Subject
163
	 * @param nodeid - the node identifier for the given node be modified
164
	 * @param node - the node information to be added
165
	 * 
166
	 * @return true or false
167
	 * 
168
	 * @throws NotImplemented
169
	 * @throws NotAuthorized
170
	 * @throws ServiceFailure
171
	 * @throws InvalidRequest
172
	 * @throws NotFound
173
	 */
174
	@Override
175
	/*public boolean updateNodeCapabilities(Session session, NodeReference nodeid, Node node) */
176
	public boolean addNodeCapabilities(Session session, NodeReference nodeid, Node node)
177
	  throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
178
	  NotFound {
179

    
180
		return false;
181
	}
182

    
183
	/**
184
	 * Register a Coordinating Node
185
	 * 
186
	 * @param session - the Session object containing the credentials for the Subject
187
	 * @param node - the node information for the given node be modified
188
	 * 
189
	 * @return nodeid - the identifier of the node to be registered
190
	 * 
191
	 * @throws NotImplemented
192
	 * @throws NotAuthorized
193
	 * @throws ServiceFailure
194
	 * @throws InvalidRequest
195
	 * @throws IdentifierNotUnique
196
	 */
197
	@Override
198
	public Identifier register(Session session, Node node) 
199
	  throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
200
	  IdentifierNotUnique {
201

    
202
		return null;
203
	}
204

    
205
	/**
206
	 * Test that the specified relationship between pidOfSubject and pidOfObject exists
207
	 * 
208
	 * @param session - the Session object containing the credentials for the Subject
209
	 * @param node - the node information for the given node be modified
210
	 * 
211
	 * @return true if the relationship exists
212
	 * 
213
	 * @throws InvalidToken
214
	 * @throws ServiceFailure
215
	 * @throws NotAuthorized
216
	 * @throws NotFound
217
	 * @throws InvalidRequest
218
	 * @throws NotImplemented
219
	 */
220
	@Override
221
	public boolean assertRelation(Session session, Identifier pidofsubject, 
222
		String relationship, Identifier pidOfObject) 
223
	  throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
224
	  InvalidRequest, NotImplemented {
225
		
226
		return false;
227
	}
228

    
229
	/**
230
	 * Return the object identified by the given object identifier
231
	 * 
232
	 * @param session - the Session object containing the credentials for the Subject
233
	 * @param pid - the object identifier for the given object
234
	 * 
235
	 * @return inputStream - the input stream of the given object
236
	 * 
237
	 * @throws InvalidToken
238
	 * @throws ServiceFailure
239
	 * @throws NotAuthorized
240
	 * @throws InvalidRequest
241
	 * @throws NotImplemented
242
	 */
243
	@Override
244
	public InputStream get(Session session, Identifier pid) 
245
	  throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized, 
246
	  NotFound, NotImplemented {
247
		
248
		return super.get(session, pid);
249
	}
250
	
251
	/**
252
	 * Return a checksum of the object given the object identifier and the name
253
	 * of the checksum algorithm (the default being SHA-1)
254
	 * 
255
	 * @param session - the Session object containing the credentials for the Subject
256
	 * @param pid - the object identifier for the given object
257
	 * 
258
	 * @return checksum - the checksum of the object
259
	 * 
260
	 * @throws InvalidToken
261
	 * @throws ServiceFailure
262
	 * @throws NotAuthorized
263
	 * @throws NotFound
264
	 * @throws InvalidRequest
265
	 * @throws NotImplemented
266
	 */
267
	@Override
268
	public Checksum getChecksum(Session session, Identifier pid)
269
	  throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
270
	  InvalidRequest, NotImplemented {
271
		
272
		return null;
273
	}
274

    
275
	/**
276
	 * Return the system metadata for a given object
277
	 * 
278
	 * @param session - the Session object containing the credentials for the Subject
279
	 * @param pid - the object identifier for the given object
280
	 * 
281
	 * @return inputStream - the input stream of the given system metadata object
282
	 * 
283
	 * @throws InvalidToken
284
	 * @throws ServiceFailure
285
	 * @throws NotAuthorized
286
	 * @throws NotFound
287
	 * @throws InvalidRequest
288
	 * @throws NotImplemented
289
	 */
290
	@Override
291
	public SystemMetadata getSystemMetadata(Session session, Identifier pid)
292
	  throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized,
293
	  NotFound, NotImplemented {
294

    
295
		return super.getSystemMetadata(session, pid);
296
	}
297

    
298
	/**
299
	 * Resolve the location of a given object
300
	 * 
301
	 * @param session - the Session object containing the credentials for the Subject
302
	 * @param pid - the object identifier for the given object
303
	 * 
304
	 * @return objectLocationList - the list of nodes known to contain the object
305
	 * 
306
	 * @throws InvalidRequest
307
	 * @throws InvalidToken
308
	 * @throws ServiceFailure
309
	 * @throws NotAuthorized
310
	 * @throws NotFound
311
	 * @throws NotImplemented
312
	 */
313
	@Override
314
	public ObjectLocationList resolve(Session session, Identifier pid)
315
	  throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized,
316
	  NotFound, NotImplemented {
317

    
318
		return null;
319
	}
320

    
321
	/**
322
	 * Search the metadata catalog for identifiers that match the criteria
323
	 * 
324
	 * @param session - the Session object containing the credentials for the Subject
325
	 * @param queryType - An identifier for the type of query expression 
326
	 *                    provided in the query
327
	 * @param query -  The criteria for matching the characteristics of the 
328
	 *                 metadata objects of interest
329
	 * 
330
	 * @return objectList - the list of objects matching the criteria
331
	 * 
332
	 * @throws InvalidToken
333
	 * @throws ServiceFailure
334
	 * @throws NotAuthorized
335
	 * @throws InvalidRequest
336
	 * @throws NotImplemented
337
	 */
338
	@Override
339
	public ObjectList search(Session session, QueryType queryType, String query)
340
	  throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
341
	  NotImplemented {
342

    
343
		return null;
344
	}
345

    
346
	/**
347
	 * Used internally within a Coordinating Node to add a new object 
348
	 * to the object store
349
	 * 
350
	 * @param session - the Session object containing the credentials for the Subject
351
	 * @param pid - The object identifier to be created
352
	 * @param object - the object bytes
353
	 * @param sysmeta - the system metadata that describes the object  
354
	 * 
355
	 * @return pid - the object identifier created
356
	 * 
357
	 * @throws InvalidToken
358
	 * @throws ServiceFailure
359
	 * @throws NotAuthorized
360
	 * @throws IdentifierNotUnique
361
	 * @throws UnsupportedType
362
	 * @throws InsufficientResources
363
	 * @throws InvalidSystemMetadata
364
	 * @throws NotImplemented
365
	 * @throws InvalidRequest
366
	 */
367
	@Override
368
	public Identifier create(Session session, Identifier pid, InputStream object,
369
	  SystemMetadata sysmeta) 
370
	  throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
371
	  UnsupportedType, InsufficientResources, InvalidSystemMetadata, 
372
	  NotImplemented, InvalidRequest {
373

    
374
		return null;
375
	}
376
	
377
	/**
378
	 * Returns the object format registered in the DataONE Object Format 
379
	 * Vocabulary for the given format identifier
380
	 * 
381
	 * @param fmtid - the identifier of the format requested
382
	 * 
383
	 * @return objectFormat - the object format requested
384
	 * 
385
	 * @throws InvalidRequest
386
	 * @throws ServiceFailure
387
	 * @throws NotFound
388
	 * @throws InsufficientResources
389
	 * @throws NotImplemented
390
	 */
391
	@Override
392
	public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
393
	  throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources,
394
	  NotImplemented {
395
		 
396
	  	return ObjectFormatService.getInstance().getFormat(fmtid);
397
			
398
	}
399

    
400
	/**
401
   * Returns a list of all object formats registered in the DataONE Object 
402
   * Format Vocabulary
403
 	 * 
404
	 * @return objectFormatList - The list of object formats registered in 
405
	 *                            the DataONE Object Format Vocabulary
406
	 * 
407
	 * @throws InvalidRequest
408
	 * @throws ServiceFailure
409
	 * @throws NotImplemented
410
	 * @throws NotFound
411
	 * @throws InsufficientResources
412
	 */
413
	@Override
414
	public ObjectFormatList listFormats() 
415
	  throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources, 
416
	  NotImplemented {
417

    
418
		return ObjectFormatService.getInstance().listFormats();
419
	}
420

    
421
	/**
422
   * Returns a list of nodes that have been registered with the DataONE infrastructure
423
 	 * 
424
	 * @return nodeList - List of nodes from the registry
425
	 * 
426
	 * @throws ServiceFailure
427
	 * @throws NotImplemented
428
	 */
429
	@Override
430
	public NodeList listNodes() 
431
	  throws NotImplemented, ServiceFailure {
432

    
433
		return null;
434
	}
435

    
436
	/**
437
   * Provides a mechanism for adding system metadata independently of its 
438
   * associated object, such as when adding system metadata for data objects.
439
 	 * 
440
	 * @param session - the Session object containing the credentials for the Subject
441
	 * @param pid - The identifier of the object to register the system metadata against
442
	 * @param sysmeta - The system metadata to be registered
443
	 * 
444
	 * @return true if the registration succeeds
445
	 * 
446
	 * @throws NotImplemented
447
	 * @throws NotAuthorized
448
	 * @throws ServiceFailure
449
	 * @throws InvalidRequest
450
	 * @throws InvalidSystemMetadata
451
	 */
452
	@Override
453
	public boolean registerSystemMetadata(Session session, Identifier guid,
454
	  SystemMetadata sysmeta) 
455
	  throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest, 
456
	  InvalidSystemMetadata {
457

    
458
		// TODO: control who can call this?
459
	      if (session == null) {
460
	          //TODO: many of the thrown exceptions do not use the correct error codes
461
	          //check these against the docs and correct them
462
	          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
463
	                  "  If you are not logged in, please do so and retry the request.");
464
	      }
465
	      
466
	      // verify that guid == SystemMetadata.getIdentifier()
467
	      logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
468
	      if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
469
	          throw new InvalidRequest("4863", 
470
	              "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
471
	              sysmeta.getIdentifier().getValue() + ").");
472
	      }
473

    
474
	      logMetacat.debug("Checking if identifier exists...");
475
	      // Check that the identifier does not already exist
476
	      IdentifierManager im = IdentifierManager.getInstance();
477
	      if (im.identifierExists(guid.getValue())) {
478
	          throw new InvalidRequest("4863", 
479
	              "GUID is already in use by an existing object.");
480
	      }
481

    
482
	      // insert the system metadata into the object store
483
	      logMetacat.debug("Starting to insert SystemMetadata...");
484
	      sysmeta.setDateSysMetadataModified(new Date());
485
	      try {
486
			    IdentifierManager.getInstance().createSystemMetadata(sysmeta);
487
			    IdentifierManager.getInstance().updateSystemMetadata(sysmeta);
488
			    // force replication of this record
489
			    ForceReplicationSystemMetadataHandler forceReplication = 
490
			    	new ForceReplicationSystemMetadataHandler(guid.getValue(), null);
491
		    } catch (Exception e) {
492
	          throw new ServiceFailure("4862", "Error inserting system metadata: " + e.getClass() + ": " + e.getMessage());
493
		    }
494
	      
495
	      logMetacat.debug("Returning from registerSystemMetadata");
496
	      EventLog.getInstance().log(null, session.getSubject().getValue(), guid.getValue(), "registerSystemMetadata");
497
	      return true;
498
	}
499

    
500
	/**
501
   * Given an optional scope and format, reserves and returns an identifier 
502
   * within that scope and format that is unique and will not be 
503
   * used by any other sessions. 
504
 	 * 
505
	 * @param session - the Session object containing the credentials for the Subject
506
	 * @param pid - The identifier of the object to register the system metadata against
507
	 * @param scope - An optional string to be used to qualify the scope of 
508
	 *                the identifier namespace, which is applied differently 
509
	 *                depending on the format requested. If scope is not 
510
	 *                supplied, a default scope will be used.
511
	 * @param format - The optional name of the identifier format to be used, 
512
	 * 								 drawn from a DataONE-specific vocabulary of identifier 
513
	 *                 format names, including several common syntaxes such 
514
	 *                 as DOI, LSID, UUID, and LSRN, among others. If the 
515
	 *                 format is not supplied by the caller, the CN service 
516
	 *                 will use a default identifier format, which may change 
517
	 *                 over time.
518
	 * 
519
	 * @return true if the registration succeeds
520
	 * 
521
	 * @throws InvalidToken
522
	 * @throws ServiceFailure
523
	 * @throws NotAuthorized
524
	 * @throws IdentifierNotUnique
525
	 * @throws NotImplemented
526
	 */
527
	@Override
528
	public Identifier reserveIdentifier(Session session, Identifier pid,
529
	  String scope, String format) 
530
	  throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
531
	  NotImplemented, InvalidRequest {
532

    
533
		return null;
534
	}
535

    
536
	/**
537
   * Changes ownership (RightsHolder) of the specified object to the 
538
   * subject specified by userId
539
 	 * 
540
	 * @param session - the Session object containing the credentials for the Subject
541
	 * @param pid - Identifier of the object to be modified
542
	 * @param userId - The subject that will be taking ownership of the specified object.
543
	 *
544
	 * @return pid - the identifier of the modified object
545
	 * 
546
	 * @throws ServiceFailure
547
	 * @throws InvalidToken
548
	 * @throws NotFound
549
	 * @throws NotAuthorized
550
	 * @throws NotImplemented
551
	 * @throws InvalidRequest
552
	 */	
553
	@Override
554
	public Identifier setOwner(Session session, Identifier pid, Subject userId)
555
	  throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
556
	  NotImplemented, InvalidRequest {
557
		
558
		// get the subject
559
		Subject subject = session.getSubject();
560
		// get the system metadata
561
		String guid = pid.getValue();
562
		
563
		// are we allowed to do this?
564
		if (!hasPermission(session, pid, Permission.CHANGE_PERMISSION)) {
565
			throw new NotAuthorized("4440", "not allowed by " + subject.getValue() + " on " + guid);	
566
		}
567
		
568
		SystemMetadata systemMetadata = null;
569
		try {
570
			systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
571
		} catch (McdbDocNotFoundException e) {
572
			throw new NotFound("4460", "No record found for: " + guid);
573
		}
574
				
575
		// set the new rights holder
576
		systemMetadata.setRightsHolder(userId);
577
		
578
		// update the metadata
579
		try {
580
			IdentifierManager.getInstance().updateSystemMetadata(systemMetadata);
581
		} catch (McdbDocNotFoundException e) {
582
			throw new ServiceFailure("4490", e.getMessage());
583
		}
584

    
585
		return pid;
586
	}
587

    
588
}
(1-1/8)