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 9189 tao
import java.io.IOException;
27 6569 cjones
import java.io.InputStream;
28 9189 tao
import java.io.PipedInputStream;
29
import java.io.PipedOutputStream;
30
import java.lang.reflect.InvocationTargetException;
31 6567 cjones
import java.math.BigInteger;
32 9024 tao
import java.sql.SQLException;
33 6883 leinfelder
import java.util.ArrayList;
34 6567 cjones
import java.util.Calendar;
35 6177 cjones
import java.util.Date;
36 6220 leinfelder
import java.util.List;
37 6859 cjones
import java.util.concurrent.locks.Lock;
38 6177 cjones
39 6542 leinfelder
import javax.servlet.http.HttpServletRequest;
40
41 9189 tao
import org.apache.commons.beanutils.BeanUtils;
42 6178 cjones
import org.apache.log4j.Logger;
43 8810 leinfelder
import org.dataone.client.v2.CNode;
44 9189 tao
import org.dataone.client.v2.MNode;
45 8810 leinfelder
import org.dataone.client.v2.itk.D1Client;
46
import org.dataone.service.cn.v2.CNAuthorization;
47
import org.dataone.service.cn.v2.CNCore;
48
import org.dataone.service.cn.v2.CNRead;
49
import org.dataone.service.cn.v2.CNReplication;
50 9146 tao
import org.dataone.service.cn.v2.CNView;
51 6792 cjones
import org.dataone.service.exceptions.BaseException;
52 6177 cjones
import org.dataone.service.exceptions.IdentifierNotUnique;
53
import org.dataone.service.exceptions.InsufficientResources;
54
import org.dataone.service.exceptions.InvalidRequest;
55
import org.dataone.service.exceptions.InvalidSystemMetadata;
56
import org.dataone.service.exceptions.InvalidToken;
57
import org.dataone.service.exceptions.NotAuthorized;
58
import org.dataone.service.exceptions.NotFound;
59
import org.dataone.service.exceptions.NotImplemented;
60
import org.dataone.service.exceptions.ServiceFailure;
61 6569 cjones
import org.dataone.service.exceptions.UnsupportedType;
62 6869 cjones
import org.dataone.service.exceptions.VersionMismatch;
63 6571 cjones
import org.dataone.service.types.v1.AccessPolicy;
64 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
65 6803 leinfelder
import org.dataone.service.types.v1.ChecksumAlgorithmList;
66 7144 leinfelder
import org.dataone.service.types.v1.Event;
67 6366 leinfelder
import org.dataone.service.types.v1.Identifier;
68 6409 cjones
import org.dataone.service.types.v1.NodeReference;
69 6570 cjones
import org.dataone.service.types.v1.NodeType;
70 6366 leinfelder
import org.dataone.service.types.v1.ObjectFormatIdentifier;
71
import org.dataone.service.types.v1.ObjectList;
72
import org.dataone.service.types.v1.ObjectLocationList;
73
import org.dataone.service.types.v1.Permission;
74
import org.dataone.service.types.v1.Replica;
75
import org.dataone.service.types.v1.ReplicationPolicy;
76
import org.dataone.service.types.v1.ReplicationStatus;
77
import org.dataone.service.types.v1.Session;
78
import org.dataone.service.types.v1.Subject;
79 9189 tao
import org.dataone.service.types.v1_1.QueryEngineDescription;
80
import org.dataone.service.types.v1_1.QueryEngineList;
81
import org.dataone.service.types.v2.Node;
82
import org.dataone.service.types.v2.NodeList;
83
import org.dataone.service.types.v2.ObjectFormat;
84
import org.dataone.service.types.v2.ObjectFormatList;
85 8810 leinfelder
import org.dataone.service.types.v2.SystemMetadata;
86
import org.dataone.service.types.v2.util.ServiceMethodRestrictionUtil;
87 9189 tao
import org.dataone.service.util.TypeMarshaller;
88
import org.jibx.runtime.JiBXException;
89 6177 cjones
90 9189 tao
import edu.ucsb.nceas.metacat.DBUtil;
91 6188 leinfelder
import edu.ucsb.nceas.metacat.EventLog;
92
import edu.ucsb.nceas.metacat.IdentifierManager;
93 8444 cjones
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
94 6446 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
95 9189 tao
import edu.ucsb.nceas.metacat.properties.PropertyService;
96
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
97 6188 leinfelder
98 6177 cjones
/**
99
 * Represents Metacat's implementation of the DataONE Coordinating Node
100 6179 cjones
 * service API. Methods implement the various CN* interfaces, and methods common
101 6177 cjones
 * to both Member Node and Coordinating Node interfaces are found in the
102
 * D1NodeService super class.
103
 *
104
 */
105
public class CNodeService extends D1NodeService implements CNAuthorization,
106 9146 tao
    CNCore, CNRead, CNReplication, CNView {
107 6177 cjones
108 6178 cjones
  /* the logger instance */
109
  private Logger logMetacat = null;
110 6177 cjones
111 6178 cjones
  /**
112
   * singleton accessor
113
   */
114 6542 leinfelder
  public static CNodeService getInstance(HttpServletRequest request) {
115
    return new CNodeService(request);
116 6178 cjones
  }
117
118
  /**
119
   * Constructor, private for singleton access
120
   */
121 6542 leinfelder
  private CNodeService(HttpServletRequest request) {
122
    super(request);
123 6178 cjones
    logMetacat = Logger.getLogger(CNodeService.class);
124
125
  }
126
127 6410 cjones
  /**
128
   * Set the replication policy for an object given the object identifier
129
   *
130
   * @param session - the Session object containing the credentials for the Subject
131
   * @param pid - the object identifier for the given object
132
   * @param policy - the replication policy to be applied
133
   *
134
   * @return true or false
135
   *
136
   * @throws NotImplemented
137
   * @throws NotAuthorized
138
   * @throws ServiceFailure
139
   * @throws InvalidRequest
140 6869 cjones
   * @throws VersionMismatch
141 6410 cjones
   *
142
   */
143 6471 jones
  @Override
144 6410 cjones
  public boolean setReplicationPolicy(Session session, Identifier pid,
145 6593 cjones
      ReplicationPolicy policy, long serialVersion)
146 6567 cjones
      throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
147 6869 cjones
      InvalidRequest, InvalidToken, VersionMismatch {
148 6567 cjones
149 9066 tao
      // do we have a valid pid?
150
      if (pid == null || pid.getValue().trim().equals("")) {
151
          throw new InvalidRequest("4883", "The provided identifier was invalid.");
152
153
      }
154
155 9087 tao
      /*String serviceFailureCode = "4882";
156 9066 tao
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
157
      if(sid != null) {
158
          pid = sid;
159 9087 tao
      }*/
160 6717 cjones
      // The lock to be used for this identifier
161 6859 cjones
      Lock lock = null;
162 6702 cjones
163 6567 cjones
      // get the subject
164
      Subject subject = session.getSubject();
165
166
      // are we allowed to do this?
167 7068 cjones
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
168
          throw new NotAuthorized("4881", Permission.CHANGE_PERMISSION
169
                  + " not allowed by " + subject.getValue() + " on "
170
                  + pid.getValue());
171
172 6869 cjones
      }
173
174
      SystemMetadata systemMetadata = null;
175 6567 cjones
      try {
176 6858 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
177
          lock.lock();
178 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
179 6858 cjones
180
          try {
181
              if ( HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid) ) {
182
                  systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
183
184
              }
185 6869 cjones
186
              // did we get it correctly?
187
              if ( systemMetadata == null ) {
188
                  throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
189
190
              }
191 6858 cjones
192
              // does the request have the most current system metadata?
193
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
194
                 String msg = "The requested system metadata version number " +
195
                     serialVersion + " differs from the current version at " +
196
                     systemMetadata.getSerialVersion().longValue() +
197
                     ". Please get the latest copy in order to modify it.";
198 6869 cjones
                 throw new VersionMismatch("4886", msg);
199
200 6858 cjones
              }
201 6717 cjones
202 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
203 6858 cjones
              throw new NotFound("4884", "No record found for: " + pid.getValue());
204
205 6717 cjones
          }
206 6858 cjones
207
          // set the new policy
208
          systemMetadata.setReplicationPolicy(policy);
209
210
          // update the metadata
211
          try {
212
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
213
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
214
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
215 7076 cjones
              notifyReplicaNodes(systemMetadata);
216
217 6869 cjones
          } catch (RuntimeException e) {
218 6858 cjones
              throw new ServiceFailure("4882", e.getMessage());
219
220 6593 cjones
          }
221
222 6869 cjones
      } catch (RuntimeException e) {
223
          throw new ServiceFailure("4882", e.getMessage());
224
225
      } finally {
226
          lock.unlock();
227
          logMetacat.debug("Unlocked identifier " + pid.getValue());
228
229
      }
230 6410 cjones
231 6567 cjones
      return true;
232 6410 cjones
  }
233 6177 cjones
234 6410 cjones
  /**
235 6881 leinfelder
   * Deletes the replica from the given Member Node
236
   * NOTE: MN.delete() may be an "archive" operation. TBD.
237
   * @param session
238
   * @param pid
239
   * @param nodeId
240
   * @param serialVersion
241
   * @return
242
   * @throws InvalidToken
243
   * @throws ServiceFailure
244
   * @throws NotAuthorized
245
   * @throws NotFound
246
   * @throws NotImplemented
247 6883 leinfelder
   * @throws VersionMismatch
248 6881 leinfelder
   */
249 6884 leinfelder
  @Override
250 6881 leinfelder
  public boolean deleteReplicationMetadata(Session session, Identifier pid, NodeReference nodeId, long serialVersion)
251 6883 leinfelder
  	throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, VersionMismatch {
252 6881 leinfelder
253 6883 leinfelder
	  	// The lock to be used for this identifier
254
		Lock lock = null;
255
256
		// get the subject
257
		Subject subject = session.getSubject();
258
259
		// are we allowed to do this?
260 9265 tao
		/*boolean isAuthorized = false;
261 7068 cjones
		try {
262
			isAuthorized = isAuthorized(session, pid, Permission.WRITE);
263
		} catch (InvalidRequest e) {
264
			throw new ServiceFailure("4882", e.getDescription());
265
		}
266
		if (!isAuthorized) {
267
			throw new NotAuthorized("4881", Permission.WRITE
268
					+ " not allowed by " + subject.getValue() + " on "
269
					+ pid.getValue());
270 6883 leinfelder
271 9265 tao
		}*/
272
		if(session == null) {
273
		    throw new NotAuthorized("4882", "Session cannot be null. It is not authorized for deleting the replication metadata of the object "+pid.getValue());
274
		} else {
275
		    if(!isCNAdmin(session)) {
276
		        throw new NotAuthorized("4882", "The client -"+ session.getSubject().getValue()+ "is not a CN and is not authorized for deleting the replication metadata of the object "+pid.getValue());
277
		    }
278 6883 leinfelder
		}
279
280
		SystemMetadata systemMetadata = null;
281
		try {
282
			lock = HazelcastService.getInstance().getLock(pid.getValue());
283
			lock.lock();
284
			logMetacat.debug("Locked identifier " + pid.getValue());
285
286
			try {
287
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
288
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
289
				}
290
291
				// did we get it correctly?
292
				if (systemMetadata == null) {
293
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
294
				}
295
296
				// does the request have the most current system metadata?
297
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
298
					String msg = "The requested system metadata version number "
299
							+ serialVersion
300
							+ " differs from the current version at "
301
							+ systemMetadata.getSerialVersion().longValue()
302
							+ ". Please get the latest copy in order to modify it.";
303
					throw new VersionMismatch("4886", msg);
304
305
				}
306
307
			} catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
308
				throw new NotFound("4884", "No record found for: " + pid.getValue());
309
310
			}
311
312
			// check permissions
313
			// TODO: is this necessary?
314
			List<Node> nodeList = D1Client.getCN().listNodes().getNodeList();
315
			boolean isAllowed = ServiceMethodRestrictionUtil.isMethodAllowed(session.getSubject(), nodeList, "CNReplication", "deleteReplicationMetadata");
316 7218 cjones
			if (!isAllowed) {
317 6883 leinfelder
				throw new NotAuthorized("4881", "Caller is not authorized to deleteReplicationMetadata");
318
			}
319
320
			// delete the replica from the given node
321 7252 cjones
			// CSJ: use CN.delete() to truly delete a replica, semantically
322
			// deleteReplicaMetadata() only modifies the sytem metadata entry.
323 7251 cjones
			//D1Client.getMN(nodeId).delete(session, pid);
324 6883 leinfelder
325
			// reflect that change in the system metadata
326
			List<Replica> updatedReplicas = new ArrayList<Replica>(systemMetadata.getReplicaList());
327
			for (Replica r: systemMetadata.getReplicaList()) {
328
				  if (r.getReplicaMemberNode().equals(nodeId)) {
329
					  updatedReplicas.remove(r);
330
					  break;
331
				  }
332
			}
333
			systemMetadata.setReplicaList(updatedReplicas);
334
335
			// update the metadata
336
			try {
337
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
338
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
339
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
340
			} catch (RuntimeException e) {
341
				throw new ServiceFailure("4882", e.getMessage());
342
			}
343
344
		} catch (RuntimeException e) {
345
			throw new ServiceFailure("4882", e.getMessage());
346
		} finally {
347
			lock.unlock();
348
			logMetacat.debug("Unlocked identifier " + pid.getValue());
349
		}
350
351
		return true;
352 6881 leinfelder
353
  }
354
355 6883 leinfelder
  /**
356 8444 cjones
   * Deletes an object from the Coordinating Node
357 7077 leinfelder
   *
358
   * @param session - the Session object containing the credentials for the Subject
359
   * @param pid - The object identifier to be deleted
360
   *
361
   * @return pid - the identifier of the object used for the deletion
362
   *
363
   * @throws InvalidToken
364
   * @throws ServiceFailure
365
   * @throws NotAuthorized
366
   * @throws NotFound
367
   * @throws NotImplemented
368
   * @throws InvalidRequest
369
   */
370
  @Override
371
  public Identifier delete(Session session, Identifier pid)
372
      throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
373 8444 cjones
374 8450 cjones
      String localId = null;      // The corresponding docid for this pid
375
	  Lock lock = null;           // The lock to be used for this identifier
376
      CNode cn = null;            // a reference to the CN to get the node list
377
      NodeType nodeType = null;   // the nodeType of the replica node being contacted
378
      List<Node> nodeList = null; // the list of nodes in this CN environment
379 7077 leinfelder
380 8444 cjones
      // check for a valid session
381
      if (session == null) {
382
        	throw new InvalidToken("4963", "No session has been provided");
383
384
      }
385
386
      // do we have a valid pid?
387
      if (pid == null || pid.getValue().trim().equals("")) {
388
          throw new ServiceFailure("4960", "The provided identifier was invalid.");
389
390
      }
391 9050 tao
392
      String serviceFailureCode = "4962";
393
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
394
      if(sid != null) {
395
          pid = sid;
396
      }
397 8444 cjones
398 7078 leinfelder
	  // check that it is CN/admin
399 7142 leinfelder
	  boolean allowed = isAdminAuthorized(session);
400 7077 leinfelder
401 8360 tao
	  // additional check if it is the authoritative node if it is not the admin
402
      if(!allowed) {
403
          allowed = isAuthoritativeMNodeAdmin(session, pid);
404 8444 cjones
405 8360 tao
      }
406
407 7078 leinfelder
	  if (!allowed) {
408 8444 cjones
		  String msg = "The subject " + session.getSubject().getValue() +
409
			  " is not allowed to call delete() on a Coordinating Node.";
410 7078 leinfelder
		  logMetacat.info(msg);
411 8444 cjones
		  throw new NotAuthorized("4960", msg);
412
413 7078 leinfelder
	  }
414
415 8444 cjones
	  // Don't defer to superclass implementation without a locally registered identifier
416 8869 tao
	  SystemMetadata systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
417 8444 cjones
      // Check for the existing identifier
418
      try {
419
          localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
420
          super.delete(session, pid);
421
422
      } catch (McdbDocNotFoundException e) {
423
          // This object is not registered in the identifier table. Assume it is of formatType DATA,
424
    	  // and set the archive flag. (i.e. the *object* doesn't exist on the CN)
425
426
          try {
427
  			  lock = HazelcastService.getInstance().getLock(pid.getValue());
428
  			  lock.lock();
429
  			  logMetacat.debug("Locked identifier " + pid.getValue());
430
431
			  SystemMetadata sysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
432
			  if ( sysMeta != null ) {
433 8887 tao
				/*sysMeta.setSerialVersion(sysMeta.getSerialVersion().add(BigInteger.ONE));
434 8444 cjones
				sysMeta.setArchived(true);
435
				sysMeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
436 8887 tao
				HazelcastService.getInstance().getSystemMetadataMap().put(pid, sysMeta);*/
437
			    //move the systemmetadata object from the map and delete the records in the systemmetadata database table
438
	            //since this is cn, we don't need worry about the mn solr index.
439
	            HazelcastService.getInstance().getSystemMetadataMap().remove(pid);
440
	            HazelcastService.getInstance().getIdentifiers().remove(pid);
441 8971 tao
	            String username = session.getSubject().getValue();//just for logging purpose
442
                //since data objects were not registered in the identifier table, we use pid as the docid
443
                EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), username, pid.getValue(), Event.DELETE.xmlValue());
444 8444 cjones
445
			  } else {
446
				  throw new ServiceFailure("4962", "Couldn't delete the object " + pid.getValue() +
447
					  ". Couldn't obtain the system metadata record.");
448
449
			  }
450
451
		  } catch (RuntimeException re) {
452
			  throw new ServiceFailure("4962", "Couldn't delete " + pid.getValue() +
453
				  ". The error message was: " + re.getMessage());
454
455
		  } finally {
456
			  lock.unlock();
457
			  logMetacat.debug("Unlocked identifier " + pid.getValue());
458
459
		  }
460
461 8553 leinfelder
          // NOTE: cannot log the delete without localId
462
//          EventLog.getInstance().log(request.getRemoteAddr(),
463
//                  request.getHeader("User-Agent"), session.getSubject().getValue(),
464
//                  pid.getValue(), Event.DELETE.xmlValue());
465 8444 cjones
466 9024 tao
      } catch (SQLException e) {
467
          throw new ServiceFailure("4962", "Couldn't delete " + pid.getValue() +
468
                  ". The local id of the object with the identifier can't be identified since " + e.getMessage());
469 8444 cjones
      }
470
471 8450 cjones
      // get the node list
472
      try {
473
          cn = D1Client.getCN();
474
          nodeList = cn.listNodes().getNodeList();
475
476
      } catch (Exception e) { // handle BaseException and other I/O issues
477
478
          // swallow errors since the call is not critical
479
          logMetacat.error("Can't inform MNs of the deletion of " + pid.getValue() +
480
              " due to communication issues with the CN: " + e.getMessage());
481
482
      }
483
484 7147 leinfelder
	  // notify the replicas
485
	  if (systemMetadata.getReplicaList() != null) {
486
		  for (Replica replica: systemMetadata.getReplicaList()) {
487
			  NodeReference replicaNode = replica.getReplicaMemberNode();
488
			  try {
489 8450 cjones
                  if (nodeList != null) {
490
                      // find the node type
491
                      for (Node node : nodeList) {
492
                          if ( node.getIdentifier().getValue().equals(replicaNode.getValue()) ) {
493
                              nodeType = node.getType();
494
                              break;
495
496
                          }
497
                      }
498
                  }
499
500
                  // only send call MN.delete() to avoid an infinite loop with the CN
501
                  if (nodeType != null && nodeType == NodeType.MN) {
502
				      Identifier mnRetId = D1Client.getMN(replicaNode).delete(null, pid);
503
                  }
504
505 7147 leinfelder
			  } catch (Exception e) {
506
				  // all we can really do is log errors and carry on with life
507 8450 cjones
				  logMetacat.error("Error deleting pid: " +  pid.getValue() +
508
					  " from replica MN: " + replicaNode.getValue(), e);
509 7147 leinfelder
			}
510
511
		  }
512
	  }
513
514 8444 cjones
	  return pid;
515 7147 leinfelder
516 7077 leinfelder
  }
517
518
  /**
519 8444 cjones
   * Archives an object from the Coordinating Node
520 7148 leinfelder
   *
521
   * @param session - the Session object containing the credentials for the Subject
522
   * @param pid - The object identifier to be deleted
523
   *
524
   * @return pid - the identifier of the object used for the deletion
525
   *
526
   * @throws InvalidToken
527
   * @throws ServiceFailure
528
   * @throws NotAuthorized
529
   * @throws NotFound
530
   * @throws NotImplemented
531
   * @throws InvalidRequest
532
   */
533
  @Override
534
  public Identifier archive(Session session, Identifier pid)
535
      throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
536
537 8444 cjones
      String localId = null; // The corresponding docid for this pid
538
	  Lock lock = null;      // The lock to be used for this identifier
539 8450 cjones
      CNode cn = null;            // a reference to the CN to get the node list
540
      NodeType nodeType = null;   // the nodeType of the replica node being contacted
541
      List<Node> nodeList = null; // the list of nodes in this CN environment
542
543 8444 cjones
544
      // check for a valid session
545
      if (session == null) {
546
        	throw new InvalidToken("4973", "No session has been provided");
547
548
      }
549
550
      // do we have a valid pid?
551
      if (pid == null || pid.getValue().trim().equals("")) {
552
          throw new ServiceFailure("4972", "The provided identifier was invalid.");
553
554
      }
555
556 7148 leinfelder
	  // check that it is CN/admin
557
	  boolean allowed = isAdminAuthorized(session);
558
559 9050 tao
	  String serviceFailureCode = "4972";
560
	  Identifier sid = getPIDForSID(pid, serviceFailureCode);
561
	  if(sid != null) {
562
	        pid = sid;
563
	  }
564
565 8360 tao
	  //check if it is the authoritative member node
566
	  if(!allowed) {
567
	      allowed = isAuthoritativeMNodeAdmin(session, pid);
568
	  }
569
570 7148 leinfelder
	  if (!allowed) {
571 8444 cjones
		  String msg = "The subject " + session.getSubject().getValue() +
572
				  " is not allowed to call archive() on a Coordinating Node.";
573 7148 leinfelder
		  logMetacat.info(msg);
574 8444 cjones
		  throw new NotAuthorized("4970", msg);
575 7148 leinfelder
	  }
576
577 8444 cjones
      // Check for the existing identifier
578
      try {
579
          localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
580
          super.archive(session, pid);
581
582
      } catch (McdbDocNotFoundException e) {
583
          // This object is not registered in the identifier table. Assume it is of formatType DATA,
584
    	  // and set the archive flag. (i.e. the *object* doesn't exist on the CN)
585
586
          try {
587
  			  lock = HazelcastService.getInstance().getLock(pid.getValue());
588
  			  lock.lock();
589
  			  logMetacat.debug("Locked identifier " + pid.getValue());
590
591
			  SystemMetadata sysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
592
			  if ( sysMeta != null ) {
593 8454 cjones
				sysMeta.setSerialVersion(sysMeta.getSerialVersion().add(BigInteger.ONE));
594 8444 cjones
				sysMeta.setArchived(true);
595
				sysMeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
596
				HazelcastService.getInstance().getSystemMetadataMap().put(pid, sysMeta);
597 8589 cjones
			    // notify the replicas
598
				notifyReplicaNodes(sysMeta);
599
600 8444 cjones
			  } else {
601
				  throw new ServiceFailure("4972", "Couldn't archive the object " + pid.getValue() +
602
					  ". Couldn't obtain the system metadata record.");
603
604
			  }
605
606
		  } catch (RuntimeException re) {
607
			  throw new ServiceFailure("4972", "Couldn't archive " + pid.getValue() +
608
				  ". The error message was: " + re.getMessage());
609
610
		  } finally {
611
			  lock.unlock();
612
			  logMetacat.debug("Unlocked identifier " + pid.getValue());
613
614
		  }
615
616 8553 leinfelder
          // NOTE: cannot log the archive without localId
617
//          EventLog.getInstance().log(request.getRemoteAddr(),
618
//                  request.getHeader("User-Agent"), session.getSubject().getValue(),
619
//                  pid.getValue(), Event.DELETE.xmlValue());
620 8444 cjones
621 9024 tao
      } catch (SQLException e) {
622
          throw new ServiceFailure("4972", "Couldn't archive the object " + pid.getValue() +
623
                  ". The local id of the object with the identifier can't be identified since "+e.getMessage());
624 8444 cjones
      }
625 8450 cjones
626 8444 cjones
	  return pid;
627 7148 leinfelder
628
  }
629
630
  /**
631 6883 leinfelder
   * Set the obsoletedBy attribute in System Metadata
632
   * @param session
633
   * @param pid
634
   * @param obsoletedByPid
635
   * @param serialVersion
636
   * @return
637
   * @throws NotImplemented
638
   * @throws NotFound
639
   * @throws NotAuthorized
640
   * @throws ServiceFailure
641
   * @throws InvalidRequest
642
   * @throws InvalidToken
643
   * @throws VersionMismatch
644
   */
645 6884 leinfelder
  @Override
646 6883 leinfelder
  public boolean setObsoletedBy(Session session, Identifier pid,
647
			Identifier obsoletedByPid, long serialVersion)
648
			throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
649
			InvalidRequest, InvalidToken, VersionMismatch {
650 9066 tao
651
      // do we have a valid pid?
652
      if (pid == null || pid.getValue().trim().equals("")) {
653
          throw new InvalidRequest("4942", "The provided identifier was invalid.");
654
655
      }
656
657 9125 tao
      /*String serviceFailureCode = "4941";
658 9066 tao
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
659
      if(sid != null) {
660
          pid = sid;
661 9125 tao
      }*/
662 9066 tao
663
      // do we have a valid pid?
664
      if (obsoletedByPid == null || obsoletedByPid.getValue().trim().equals("")) {
665
          throw new InvalidRequest("4942", "The provided obsoletedByPid was invalid.");
666
667
      }
668
669
      try {
670
          if(IdentifierManager.getInstance().systemMetadataSIDExists(obsoletedByPid)) {
671
              throw new InvalidRequest("4942", "The provided obsoletedByPid "+obsoletedByPid.getValue()+" is an existing SID. However, it must NOT be an SID.");
672
          }
673
      } catch (SQLException ee) {
674
          throw new ServiceFailure("4941", "Couldn't determine if the obsoletedByPid "+obsoletedByPid.getValue()+" is an SID or not. The id shouldn't be an SID.");
675
      }
676
677 6883 leinfelder
678
		// The lock to be used for this identifier
679
		Lock lock = null;
680
681
		// get the subject
682
		Subject subject = session.getSubject();
683
684
		// are we allowed to do this?
685 7068 cjones
		if (!isAuthorized(session, pid, Permission.WRITE)) {
686
			throw new NotAuthorized("4881", Permission.WRITE
687
					+ " not allowed by " + subject.getValue() + " on "
688
					+ pid.getValue());
689 6883 leinfelder
690
		}
691
692 7068 cjones
693 6883 leinfelder
		SystemMetadata systemMetadata = null;
694
		try {
695
			lock = HazelcastService.getInstance().getLock(pid.getValue());
696
			lock.lock();
697
			logMetacat.debug("Locked identifier " + pid.getValue());
698
699
			try {
700
				if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
701
					systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
702
				}
703
704
				// did we get it correctly?
705
				if (systemMetadata == null) {
706
					throw new NotFound("4884", "Couldn't find an object identified by " + pid.getValue());
707
				}
708
709
				// does the request have the most current system metadata?
710
				if (systemMetadata.getSerialVersion().longValue() != serialVersion) {
711
					String msg = "The requested system metadata version number "
712
							+ serialVersion
713
							+ " differs from the current version at "
714
							+ systemMetadata.getSerialVersion().longValue()
715
							+ ". Please get the latest copy in order to modify it.";
716
					throw new VersionMismatch("4886", msg);
717
718
				}
719
720
			} catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
721
				throw new NotFound("4884", "No record found for: " + pid.getValue());
722
723
			}
724
725
			// set the new policy
726
			systemMetadata.setObsoletedBy(obsoletedByPid);
727
728
			// update the metadata
729
			try {
730
				systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
731
				systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
732
				HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
733
			} catch (RuntimeException e) {
734
				throw new ServiceFailure("4882", e.getMessage());
735
			}
736
737
		} catch (RuntimeException e) {
738
			throw new ServiceFailure("4882", e.getMessage());
739
		} finally {
740
			lock.unlock();
741
			logMetacat.debug("Unlocked identifier " + pid.getValue());
742
		}
743
744
		return true;
745
	}
746 6881 leinfelder
747 6883 leinfelder
748 6881 leinfelder
  /**
749 6410 cjones
   * Set the replication status for an object given the object identifier
750
   *
751
   * @param session - the Session object containing the credentials for the Subject
752
   * @param pid - the object identifier for the given object
753
   * @param status - the replication status to be applied
754
   *
755
   * @return true or false
756
   *
757
   * @throws NotImplemented
758
   * @throws NotAuthorized
759
   * @throws ServiceFailure
760
   * @throws InvalidRequest
761
   * @throws InvalidToken
762
   * @throws NotFound
763
   *
764
   */
765 6471 jones
  @Override
766 6410 cjones
  public boolean setReplicationStatus(Session session, Identifier pid,
767 6792 cjones
      NodeReference targetNode, ReplicationStatus status, BaseException failure)
768 6644 cjones
      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized,
769
      InvalidRequest, NotFound {
770 7066 leinfelder
771
	  // cannot be called by public
772
	  if (session == null) {
773
		  throw new NotAuthorized("4720", "Session cannot be null");
774 9265 tao
	  } else {
775
	      if(!isCNAdmin(session)) {
776
              throw new NotAuthorized("4720", "The client -"+ session.getSubject().getValue()+ "is not a CN and is not authorized for setting the replication status of the object "+pid.getValue());
777
        }
778 7066 leinfelder
	  }
779 9066 tao
780
	// do we have a valid pid?
781
      if (pid == null || pid.getValue().trim().equals("")) {
782
          throw new InvalidRequest("4730", "The provided identifier was invalid.");
783
784
      }
785 6644 cjones
786 9093 tao
      /*String serviceFailureCode = "4700";
787 9066 tao
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
788
      if(sid != null) {
789
          pid = sid;
790 9093 tao
      }*/
791 9066 tao
792 6702 cjones
      // The lock to be used for this identifier
793 6859 cjones
      Lock lock = null;
794 6702 cjones
795 6644 cjones
      boolean allowed = false;
796
      int replicaEntryIndex = -1;
797
      List<Replica> replicas = null;
798
      // get the subject
799
      Subject subject = session.getSubject();
800 6676 cjones
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
801
          " is " + status.toString());
802 6644 cjones
803
      SystemMetadata systemMetadata = null;
804 6858 cjones
805
      try {
806 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
807 6702 cjones
          lock.lock();
808 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
809
810 6858 cjones
          try {
811
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
812 6657 cjones
813 6869 cjones
              // did we get it correctly?
814 6858 cjones
              if ( systemMetadata == null ) {
815
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
816 6869 cjones
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
817 6858 cjones
818
              }
819
              replicas = systemMetadata.getReplicaList();
820
              int count = 0;
821 6657 cjones
822 6876 cjones
              // was there a failure? log it
823 7600 cjones
              if ( failure != null && status.equals(ReplicationStatus.FAILED) ) {
824 6876 cjones
                 String msg = "The replication request of the object identified by " +
825
                     pid.getValue() + " failed.  The error message was " +
826
                     failure.getMessage() + ".";
827 6858 cjones
              }
828 6869 cjones
829 6876 cjones
              if (replicas.size() > 0 && replicas != null) {
830
                  // find the target replica index in the replica list
831
                  for (Replica replica : replicas) {
832 7600 cjones
                      String replicaNodeStr = replica.getReplicaMemberNode().getValue();
833 6876 cjones
                      String targetNodeStr = targetNode.getValue();
834 7600 cjones
                      logMetacat.debug("Comparing " + replicaNodeStr + " to " + targetNodeStr);
835 6869 cjones
836 6876 cjones
                      if (replicaNodeStr.equals(targetNodeStr)) {
837
                          replicaEntryIndex = count;
838
                          logMetacat.debug("replica entry index is: "
839
                                  + replicaEntryIndex);
840
                          break;
841
                      }
842
                      count++;
843 6858 cjones
844
                  }
845
              }
846
              // are we allowed to do this? only CNs and target MNs are allowed
847
              CNode cn = D1Client.getCN();
848
              List<Node> nodes = cn.listNodes().getNodeList();
849 6657 cjones
850 6858 cjones
              // find the node in the node list
851
              for ( Node node : nodes ) {
852
853
                  NodeReference nodeReference = node.getIdentifier();
854 7600 cjones
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " +
855
                      nodeReference.getValue());
856 6858 cjones
857 7074 cjones
                  // allow target MN certs
858 7600 cjones
                  if ( targetNode.getValue().equals(nodeReference.getValue() ) &&
859
                      node.getType().equals(NodeType.MN)) {
860 6858 cjones
                      List<Subject> nodeSubjects = node.getSubjectList();
861
862
                      // check if the session subject is in the node subject list
863
                      for (Subject nodeSubject : nodeSubjects) {
864 7071 cjones
                          logMetacat.debug("In setReplicationStatus(), comparing subjects: " +
865
                                  nodeSubject.getValue() + " and " + subject.getValue());
866 7074 cjones
                          if ( nodeSubject.equals(subject) ) { // subject of session == target node subject
867 6858 cjones
868 7179 cjones
                              // lastly limit to COMPLETED, INVALIDATED,
869
                              // and FAILED status updates from MNs only
870 7600 cjones
                              if ( status.equals(ReplicationStatus.COMPLETED) ||
871
                                   status.equals(ReplicationStatus.INVALIDATED) ||
872
                                   status.equals(ReplicationStatus.FAILED)) {
873 7074 cjones
                                  allowed = true;
874
                                  break;
875
876
                              }
877 6858 cjones
                          }
878
                      }
879
                  }
880
              }
881 6657 cjones
882 7071 cjones
              if ( !allowed ) {
883
                  //check for CN admin access
884
                  allowed = isAuthorized(session, pid, Permission.WRITE);
885 6858 cjones
886 7071 cjones
              }
887
888
              if ( !allowed ) {
889
                  String msg = "The subject identified by "
890
                          + subject.getValue()
891
                          + " does not have permission to set the replication status for "
892
                          + "the replica identified by "
893
                          + targetNode.getValue() + ".";
894
                  logMetacat.info(msg);
895
                  throw new NotAuthorized("4720", msg);
896
897 6858 cjones
              }
898 6876 cjones
899 6858 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
900
            throw new NotFound("4740", "No record found for: " + pid.getValue() +
901
                " : " + e.getMessage());
902
903 6644 cjones
          }
904
905 6876 cjones
          Replica targetReplica = new Replica();
906 6858 cjones
          // set the status for the replica
907
          if ( replicaEntryIndex != -1 ) {
908 6876 cjones
              targetReplica = replicas.get(replicaEntryIndex);
909 7231 cjones
910
              // don't allow status to change from COMPLETED to anything other
911
              // than INVALIDATED: prevents overwrites from race conditions
912 7600 cjones
              if ( targetReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
913
            	   !status.equals(ReplicationStatus.INVALIDATED)) {
914 7231 cjones
            	  throw new InvalidRequest("4730", "Status state change from " +
915
            			  targetReplica.getReplicationStatus() + " to " +
916
            			  status.toString() + "is prohibited for identifier " +
917
            			  pid.getValue() + " and target node " +
918
            			  targetReplica.getReplicaMemberNode().getValue());
919
              }
920
921 6858 cjones
              targetReplica.setReplicationStatus(status);
922 7514 cjones
923 6858 cjones
              logMetacat.debug("Set the replication status for " +
924
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
925 7231 cjones
                  targetReplica.getReplicationStatus() + " for identifier " +
926
                  pid.getValue());
927 6644 cjones
928 6858 cjones
          } else {
929 6876 cjones
              // this is a new entry, create it
930
              targetReplica.setReplicaMemberNode(targetNode);
931
              targetReplica.setReplicationStatus(status);
932
              targetReplica.setReplicaVerified(Calendar.getInstance().getTime());
933
              replicas.add(targetReplica);
934
935 6644 cjones
          }
936
937 6858 cjones
          systemMetadata.setReplicaList(replicas);
938
939
          // update the metadata
940
          try {
941
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
942
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
943
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
944 7179 cjones
945 7600 cjones
              if ( !status.equals(ReplicationStatus.QUEUED) &&
946
            	   !status.equals(ReplicationStatus.REQUESTED)) {
947 7179 cjones
948
                logMetacat.trace("METRICS:\tREPLICATION:\tEND REQUEST:\tPID:\t" + pid.getValue() +
949
                          "\tNODE:\t" + targetNode.getValue() +
950
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
951
952
                logMetacat.trace("METRICS:\tREPLICATION:\t" + status.toString().toUpperCase() +
953
                          "\tPID:\t"  + pid.getValue() +
954
                          "\tNODE:\t" + targetNode.getValue() +
955
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
956
              }
957
958 7600 cjones
              if ( status.equals(ReplicationStatus.FAILED) && failure != null ) {
959 6858 cjones
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
960
                      " on target node " + targetNode + ". The exception was: " +
961
                      failure.getMessage());
962
              }
963 7514 cjones
964
			  // update the replica nodes about the completed replica when complete
965 7600 cjones
              if (status.equals(ReplicationStatus.COMPLETED)) {
966 8439 cjones
				notifyReplicaNodes(systemMetadata);
967 7514 cjones
			}
968
969 6869 cjones
          } catch (RuntimeException e) {
970 6858 cjones
              throw new ServiceFailure("4700", e.getMessage());
971
972 6644 cjones
          }
973
974 6867 cjones
    } catch (RuntimeException e) {
975
        String msg = "There was a RuntimeException getting the lock for " +
976
            pid.getValue();
977
        logMetacat.info(msg);
978
979
    } finally {
980 6858 cjones
        lock.unlock();
981
        logMetacat.debug("Unlocked identifier " + pid.getValue());
982 6593 cjones
983 6858 cjones
    }
984 6676 cjones
985 6644 cjones
      return true;
986 6410 cjones
  }
987
988 7514 cjones
/**
989 6410 cjones
   * Return the checksum of the object given the identifier
990
   *
991
   * @param session - the Session object containing the credentials for the Subject
992
   * @param pid - the object identifier for the given object
993
   *
994
   * @return checksum - the checksum of the object
995
   *
996
   * @throws InvalidToken
997
   * @throws ServiceFailure
998
   * @throws NotAuthorized
999
   * @throws NotFound
1000
   * @throws NotImplemented
1001
   */
1002 6471 jones
  @Override
1003 6410 cjones
  public Checksum getChecksum(Session session, Identifier pid)
1004
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
1005 6622 leinfelder
    NotImplemented {
1006 7029 leinfelder
1007
	boolean isAuthorized = false;
1008
	try {
1009
		isAuthorized = isAuthorized(session, pid, Permission.READ);
1010
	} catch (InvalidRequest e) {
1011
		throw new ServiceFailure("1410", e.getDescription());
1012
	}
1013
    if (!isAuthorized) {
1014 6568 cjones
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());
1015 6410 cjones
    }
1016 6568 cjones
1017 6410 cjones
    SystemMetadata systemMetadata = null;
1018 6568 cjones
    Checksum checksum = null;
1019
1020 6410 cjones
    try {
1021 6869 cjones
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1022
1023
        if (systemMetadata == null ) {
1024 8903 tao
            String error ="";
1025
            String localId = null;
1026
            try {
1027
                localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1028
1029
             } catch (Exception e) {
1030
                logMetacat.warn("Couldn't find the local id for the pid "+pid.getValue());
1031
            }
1032
1033
            if(localId != null && EventLog.getInstance().isDeleted(localId)) {
1034
                error = DELETEDMESSAGE;
1035 8971 tao
            } else if (localId == null && EventLog.getInstance().isDeleted(pid.getValue())) {
1036
                error = DELETEDMESSAGE;
1037 8903 tao
            }
1038
            throw new NotFound("1420", "Couldn't find an object identified by " + pid.getValue()+". "+error);
1039 6869 cjones
        }
1040 6568 cjones
        checksum = systemMetadata.getChecksum();
1041 6869 cjones
1042
    } catch (RuntimeException e) {
1043 6568 cjones
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " +
1044
            pid.getValue() + ". The error message was: " + e.getMessage());
1045
1046 6410 cjones
    }
1047
1048
    return checksum;
1049
  }
1050 6177 cjones
1051 6410 cjones
  /**
1052
   * Resolve the location of a given object
1053
   *
1054
   * @param session - the Session object containing the credentials for the Subject
1055
   * @param pid - the object identifier for the given object
1056
   *
1057
   * @return objectLocationList - the list of nodes known to contain the object
1058
   *
1059
   * @throws InvalidToken
1060
   * @throws ServiceFailure
1061
   * @throws NotAuthorized
1062
   * @throws NotFound
1063
   * @throws NotImplemented
1064
   */
1065 6471 jones
  @Override
1066 6410 cjones
  public ObjectLocationList resolve(Session session, Identifier pid)
1067 6622 leinfelder
    throws InvalidToken, ServiceFailure, NotAuthorized,
1068 6410 cjones
    NotFound, NotImplemented {
1069 6177 cjones
1070 6410 cjones
    throw new NotImplemented("4131", "resolve not implemented");
1071 6303 leinfelder
1072 6410 cjones
  }
1073 6177 cjones
1074 6410 cjones
  /**
1075 7464 leinfelder
   * Metacat does not implement this method at the CN level
1076 6410 cjones
   */
1077 6471 jones
  @Override
1078 6410 cjones
  public ObjectList search(Session session, String queryType, String query)
1079
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
1080
    NotImplemented {
1081 6177 cjones
1082 7464 leinfelder
		  throw new NotImplemented("4281", "Metacat does not implement CN.search");
1083
1084
//    ObjectList objectList = null;
1085
//    try {
1086
//        objectList =
1087
//          IdentifierManager.getInstance().querySystemMetadata(
1088
//              null, //startTime,
1089
//              null, //endTime,
1090
//              null, //objectFormat,
1091
//              false, //replicaStatus,
1092
//              0, //start,
1093
//              1000 //count
1094
//              );
1095
//
1096
//    } catch (Exception e) {
1097
//      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
1098
//    }
1099
//
1100
//      return objectList;
1101
1102 6410 cjones
  }
1103
1104
  /**
1105
   * Returns the object format registered in the DataONE Object Format
1106
   * Vocabulary for the given format identifier
1107
   *
1108
   * @param fmtid - the identifier of the format requested
1109
   *
1110
   * @return objectFormat - the object format requested
1111
   *
1112
   * @throws ServiceFailure
1113
   * @throws NotFound
1114
   * @throws InsufficientResources
1115
   * @throws NotImplemented
1116
   */
1117 6471 jones
  @Override
1118 6410 cjones
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
1119 6803 leinfelder
    throws ServiceFailure, NotFound, NotImplemented {
1120 6410 cjones
1121
      return ObjectFormatService.getInstance().getFormat(fmtid);
1122
1123
  }
1124 6177 cjones
1125 9189 tao
    @Override
1126
    public ObjectFormatIdentifier addFormat(Session session, ObjectFormatIdentifier formatId, ObjectFormat format)
1127
            throws ServiceFailure, NotFound, NotImplemented, NotAuthorized, InvalidToken {
1128
1129
        logMetacat.debug("CNodeService.addFormat() called.\n" +
1130
                "format ID: " + format.getFormatId() + "\n" +
1131
                "format name: " + format.getFormatName() + "\n" +
1132
                "format type: " + format.getFormatType() );
1133
1134
        // FIXME remove:
1135
        if (true)
1136
            throw new NotImplemented("0000", "Implementation underway... Will need testing too...");
1137
1138
        if (!isAdminAuthorized(session))
1139
            throw new NotAuthorized("0000", "Not authorized to call addFormat()");
1140
1141
        String separator = ".";
1142
        try {
1143
            separator = PropertyService.getProperty("document.accNumSeparator");
1144
        } catch (PropertyNotFoundException e) {
1145
            logMetacat.warn("Unable to find property \"document.accNumSeparator\"\n" + e.getMessage());
1146
        }
1147
1148
        // find pids of last and next ObjectFormatList
1149
        String OBJECT_FORMAT_DOCID = ObjectFormatService.OBJECT_FORMAT_DOCID;
1150
        int lastRev = -1;
1151
        try {
1152
            lastRev = DBUtil.getLatestRevisionInDocumentTable(OBJECT_FORMAT_DOCID);
1153
        } catch (SQLException e) {
1154
            throw new ServiceFailure("0000", "Unable to locate last revision of the object format list.\n" + e.getMessage());
1155
        }
1156
        int nextRev = lastRev + 1;
1157
        String lastDocID = OBJECT_FORMAT_DOCID + separator + lastRev;
1158
        String nextDocID = OBJECT_FORMAT_DOCID + separator + nextRev;
1159
1160
        Identifier lastPid = new Identifier();
1161
        lastPid.setValue(lastDocID);
1162
        Identifier nextPid = new Identifier();
1163
        nextPid.setValue(nextDocID);
1164
1165
        logMetacat.debug("Last ObjectFormatList document ID: " + lastDocID + "\n"
1166
                + "Next ObjectFormatList document ID: " + nextDocID);
1167
1168
        // add new format to the current ObjectFormatList
1169
        ObjectFormatList objectFormatList = ObjectFormatService.getInstance().listFormats();
1170
        List<ObjectFormat> innerList = objectFormatList.getObjectFormatList();
1171
        innerList.add(format);
1172
1173
        // get existing (last) sysmeta and make a copy
1174
        SystemMetadata lastSysmeta = getSystemMetadata(session, lastPid);
1175
        SystemMetadata nextSysmeta = new SystemMetadata();
1176
        try {
1177
            BeanUtils.copyProperties(nextSysmeta, lastSysmeta);
1178
        } catch (IllegalAccessException | InvocationTargetException e) {
1179
            throw new ServiceFailure("0000", "Unable to create system metadata for updated object format list.\n" + e.getMessage());
1180
        }
1181
1182
        // create the new object format list, and update the old sysmeta with obsoletedBy
1183
        createNewObjectFormatList(session, lastPid, nextPid, objectFormatList, nextSysmeta);
1184
        updateOldObjectFormatList(session, lastPid, nextPid, lastSysmeta);
1185
1186
        // TODO add to ObjectFormatService local cache?
1187
1188
        return formatId;
1189
    }
1190
1191
    /**
1192
     * Creates the object for the next / updated version of the ObjectFormatList.
1193
     *
1194
     * @param session
1195
     * @param lastPid
1196
     * @param nextPid
1197
     * @param objectFormatList
1198
     * @param lastSysmeta
1199
     */
1200
    private void createNewObjectFormatList(Session session, Identifier lastPid, Identifier nextPid,
1201
            ObjectFormatList objectFormatList, SystemMetadata lastSysmeta)
1202
                    throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented {
1203
1204
        PipedInputStream is = new PipedInputStream();
1205
        PipedOutputStream os = null;
1206
1207
        try {
1208
            os = new PipedOutputStream(is);
1209
            TypeMarshaller.marshalTypeToOutputStream(objectFormatList, os);
1210
        } catch (JiBXException | IOException e) {
1211
            throw new ServiceFailure("0000", "Unable to marshal object format list.\n" + e.getMessage());
1212
        } finally {
1213
            try {
1214
                os.flush();
1215
                os.close();
1216
            } catch (IOException ioe) {
1217
                throw new ServiceFailure("0000", "Unable to marshal object format list.\n" + ioe.getMessage());
1218
            }
1219
        }
1220
1221
        BigInteger docSize = lastSysmeta.getSize();
1222
        try {
1223
            docSize = BigInteger.valueOf(is.available());
1224
        } catch (IOException e) {
1225
            logMetacat.warn("Unable to set an accurate size for the new object format list.", e);
1226
        }
1227
1228
        lastSysmeta.setIdentifier(nextPid);
1229
        lastSysmeta.setObsoletes(lastPid);
1230
        lastSysmeta.setSize(docSize);
1231
        lastSysmeta.setSubmitter(session.getSubject());
1232
        lastSysmeta.setDateUploaded(new Date());
1233
1234
        // create new object format list
1235
        try {
1236
            create(session, nextPid, is, lastSysmeta);
1237
        } catch (IdentifierNotUnique | UnsupportedType | InsufficientResources
1238
                | InvalidSystemMetadata | InvalidRequest e) {
1239
            throw new ServiceFailure("0000", "Unable to create() new object format list" + e.getMessage());
1240
        }
1241
    }
1242
1243
    /**
1244
     * Updates the SystemMetadata for the old version of the ObjectFormatList
1245
     * by setting the obsoletedBy value to the pid of the new version of the
1246
     * ObjectFormatList.
1247
     *
1248
     * @param session
1249
     * @param lastPid
1250
     * @param obsoletedByPid
1251
     * @param lastSysmeta
1252
     * @throws ServiceFailure
1253
     */
1254
    private void updateOldObjectFormatList(Session session, Identifier lastPid, Identifier obsoletedByPid, SystemMetadata lastSysmeta)
1255
            throws ServiceFailure {
1256
1257
        lastSysmeta.setObsoletedBy(obsoletedByPid);
1258
1259
        try {
1260
            this.updateSystemMetadata(session, lastPid, lastSysmeta);
1261
        } catch (NotImplemented | NotAuthorized | ServiceFailure | InvalidRequest
1262
                | InvalidSystemMetadata | InvalidToken e) {
1263
            throw new ServiceFailure("0000", "Unable to update metadata of old object format list.\n" + e.getMessage());
1264
        }
1265
    }
1266 6410 cjones
  /**
1267 6177 cjones
   * Returns a list of all object formats registered in the DataONE Object
1268
   * Format Vocabulary
1269 6410 cjones
    *
1270
   * @return objectFormatList - The list of object formats registered in
1271
   *                            the DataONE Object Format Vocabulary
1272
   *
1273
   * @throws ServiceFailure
1274
   * @throws NotImplemented
1275
   * @throws InsufficientResources
1276
   */
1277 6471 jones
  @Override
1278 6410 cjones
  public ObjectFormatList listFormats()
1279 6803 leinfelder
    throws ServiceFailure, NotImplemented {
1280 6177 cjones
1281 6410 cjones
    return ObjectFormatService.getInstance().listFormats();
1282
  }
1283 6177 cjones
1284 6410 cjones
  /**
1285 6177 cjones
   * Returns a list of nodes that have been registered with the DataONE infrastructure
1286 6410 cjones
    *
1287
   * @return nodeList - List of nodes from the registry
1288
   *
1289
   * @throws ServiceFailure
1290
   * @throws NotImplemented
1291
   */
1292 6471 jones
  @Override
1293 6410 cjones
  public NodeList listNodes()
1294
    throws NotImplemented, ServiceFailure {
1295 6177 cjones
1296 6410 cjones
    throw new NotImplemented("4800", "listNodes not implemented");
1297
  }
1298 6177 cjones
1299 6410 cjones
  /**
1300 6177 cjones
   * Provides a mechanism for adding system metadata independently of its
1301
   * associated object, such as when adding system metadata for data objects.
1302 6410 cjones
    *
1303
   * @param session - the Session object containing the credentials for the Subject
1304
   * @param pid - The identifier of the object to register the system metadata against
1305
   * @param sysmeta - The system metadata to be registered
1306
   *
1307
   * @return true if the registration succeeds
1308
   *
1309
   * @throws NotImplemented
1310
   * @throws NotAuthorized
1311
   * @throws ServiceFailure
1312
   * @throws InvalidRequest
1313
   * @throws InvalidSystemMetadata
1314
   */
1315 6471 jones
  @Override
1316 6575 cjones
  public Identifier registerSystemMetadata(Session session, Identifier pid,
1317
      SystemMetadata sysmeta)
1318
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1319
      InvalidSystemMetadata {
1320 6177 cjones
1321 6702 cjones
      // The lock to be used for this identifier
1322 6859 cjones
      Lock lock = null;
1323 6702 cjones
1324 6575 cjones
      // TODO: control who can call this?
1325
      if (session == null) {
1326
          //TODO: many of the thrown exceptions do not use the correct error codes
1327
          //check these against the docs and correct them
1328
          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
1329
                  "  If you are not logged in, please do so and retry the request.");
1330 9265 tao
      } else {
1331
          //only CN is allwoed
1332
          if(!isCNAdmin(session)) {
1333
                throw new NotAuthorized("4861", "The client -"+ session.getSubject().getValue()+ "is not a CN and is not authorized for registering the system metadata of the object "+pid.getValue());
1334
          }
1335 6575 cjones
      }
1336 9070 tao
      // the identifier can't be an SID
1337
      try {
1338
          if(IdentifierManager.getInstance().systemMetadataSIDExists(pid)) {
1339
              throw new InvalidRequest("4863", "The provided identifier "+pid.getValue()+" is a series id which is not allowed.");
1340
          }
1341
      } catch (SQLException sqle) {
1342
          throw new ServiceFailure("4862", "Couldn't determine if the pid "+pid.getValue()+" is a series id since "+sqle.getMessage());
1343
      }
1344 6575 cjones
1345
      // verify that guid == SystemMetadata.getIdentifier()
1346
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() +
1347
          "|" + sysmeta.getIdentifier().getValue());
1348
      if (!pid.getValue().equals(sysmeta.getIdentifier().getValue())) {
1349
          throw new InvalidRequest("4863",
1350
              "The identifier in method call (" + pid.getValue() +
1351
              ") does not match identifier in system metadata (" +
1352
              sysmeta.getIdentifier().getValue() + ").");
1353
      }
1354 9067 tao
1355
      //check if the sid is legitimate in the system metadata
1356 9170 tao
      //checkSidInModifyingSystemMetadata(sysmeta, "4864", "4862");
1357
      Identifier sid = sysmeta.getSeriesId();
1358
      if(sid != null) {
1359
          if (!isValidIdentifier(sid)) {
1360
              throw new InvalidRequest("4863", "The series id in the system metadata is invalid in the request.");
1361
          }
1362
      }
1363 6188 leinfelder
1364 6575 cjones
      try {
1365 6703 cjones
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
1366 6863 cjones
          lock.lock();
1367 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1368 6863 cjones
          logMetacat.debug("Checking if identifier exists...");
1369
          // Check that the identifier does not already exist
1370
          if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
1371
              throw new InvalidRequest("4863",
1372
                  "The identifier is already in use by an existing object.");
1373 6575 cjones
1374 6863 cjones
          }
1375
1376
          // insert the system metadata into the object store
1377
          logMetacat.debug("Starting to insert SystemMetadata...");
1378
          try {
1379
              sysmeta.setSerialVersion(BigInteger.ONE);
1380
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1381
              HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
1382
1383 6869 cjones
          } catch (RuntimeException e) {
1384 6863 cjones
            logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
1385
              throw new ServiceFailure("4862", "Error inserting system metadata: " +
1386
                  e.getClass() + ": " + e.getMessage());
1387
1388
          }
1389
1390 6869 cjones
      } catch (RuntimeException e) {
1391 6575 cjones
          throw new ServiceFailure("4862", "Error inserting system metadata: " +
1392 6863 cjones
                  e.getClass() + ": " + e.getMessage());
1393 6575 cjones
1394 6863 cjones
      }  finally {
1395
          lock.unlock();
1396
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1397
1398
      }
1399 6466 cjones
1400 6575 cjones
1401
      logMetacat.debug("Returning from registerSystemMetadata");
1402 8553 leinfelder
1403
      try {
1404
    	  String localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1405
    	  EventLog.getInstance().log(request.getRemoteAddr(),
1406
    	          request.getHeader("User-Agent"), session.getSubject().getValue(),
1407
    	          localId, "registerSystemMetadata");
1408
      } catch (McdbDocNotFoundException e) {
1409
    	  // do nothing, no localId to log with
1410
    	  logMetacat.warn("Could not log 'registerSystemMetadata' event because no localId was found for pid: " + pid.getValue());
1411 9024 tao
      } catch (SQLException ee) {
1412
          // do nothing, no localId to log with
1413
          logMetacat.warn("Could not log 'registerSystemMetadata' event because the localId couldn't be identified for pid: " + pid.getValue());
1414 8553 leinfelder
      }
1415
1416
1417 6575 cjones
      return pid;
1418 6410 cjones
  }
1419
1420
  /**
1421 6177 cjones
   * Given an optional scope and format, reserves and returns an identifier
1422
   * within that scope and format that is unique and will not be
1423
   * used by any other sessions.
1424 6410 cjones
    *
1425
   * @param session - the Session object containing the credentials for the Subject
1426
   * @param pid - The identifier of the object to register the system metadata against
1427
   * @param scope - An optional string to be used to qualify the scope of
1428
   *                the identifier namespace, which is applied differently
1429
   *                depending on the format requested. If scope is not
1430
   *                supplied, a default scope will be used.
1431
   * @param format - The optional name of the identifier format to be used,
1432
   *                  drawn from a DataONE-specific vocabulary of identifier
1433
   *                 format names, including several common syntaxes such
1434
   *                 as DOI, LSID, UUID, and LSRN, among others. If the
1435
   *                 format is not supplied by the caller, the CN service
1436
   *                 will use a default identifier format, which may change
1437
   *                 over time.
1438
   *
1439
   * @return true if the registration succeeds
1440
   *
1441
   * @throws InvalidToken
1442
   * @throws ServiceFailure
1443
   * @throws NotAuthorized
1444
   * @throws IdentifierNotUnique
1445
   * @throws NotImplemented
1446
   */
1447 6471 jones
  @Override
1448 6622 leinfelder
  public Identifier reserveIdentifier(Session session, Identifier pid)
1449 6410 cjones
  throws InvalidToken, ServiceFailure,
1450 6378 leinfelder
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
1451 6177 cjones
1452 6410 cjones
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1453
  }
1454
1455 6471 jones
  @Override
1456 6410 cjones
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1457
  throws InvalidToken, ServiceFailure,
1458 6378 leinfelder
        NotAuthorized, NotImplemented, InvalidRequest {
1459 6410 cjones
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
1460
  }
1461
1462
  /**
1463
    * Checks whether the pid is reserved by the subject in the session param
1464
    * If the reservation is held on the pid by the subject, we return true.
1465
    *
1466
   * @param session - the Session object containing the Subject
1467
   * @param pid - The identifier to check
1468
   *
1469
   * @return true if the reservation exists for the subject/pid
1470
   *
1471
   * @throws InvalidToken
1472
   * @throws ServiceFailure
1473
   * @throws NotFound - when the pid is not found (in use or in reservation)
1474
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
1475
   * @throws IdentifierNotUnique - when the pid is in use
1476
   * @throws NotImplemented
1477
   */
1478 6177 cjones
1479 6471 jones
  @Override
1480 6934 leinfelder
  public boolean hasReservation(Session session, Subject subject, Identifier pid)
1481 6410 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique,
1482
      NotImplemented, InvalidRequest {
1483
1484
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1485
  }
1486 6339 leinfelder
1487 6410 cjones
  /**
1488 6177 cjones
   * Changes ownership (RightsHolder) of the specified object to the
1489
   * subject specified by userId
1490 6410 cjones
    *
1491
   * @param session - the Session object containing the credentials for the Subject
1492
   * @param pid - Identifier of the object to be modified
1493
   * @param userId - The subject that will be taking ownership of the specified object.
1494
   *
1495
   * @return pid - the identifier of the modified object
1496
   *
1497
   * @throws ServiceFailure
1498
   * @throws InvalidToken
1499
   * @throws NotFound
1500
   * @throws NotAuthorized
1501
   * @throws NotImplemented
1502
   * @throws InvalidRequest
1503
   */
1504 6471 jones
  @Override
1505 6803 leinfelder
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1506 6593 cjones
      long serialVersion)
1507
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1508 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
1509 6593 cjones
1510 6702 cjones
      // The lock to be used for this identifier
1511 6859 cjones
      Lock lock = null;
1512 6702 cjones
1513 6593 cjones
      // get the subject
1514
      Subject subject = session.getSubject();
1515
1516 9093 tao
      String serviceFailureCode = "4490";
1517
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
1518
      if(sid != null) {
1519
          pid = sid;
1520
      }
1521
1522 6593 cjones
      // are we allowed to do this?
1523 7068 cjones
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1524
          throw new NotAuthorized("4440", "not allowed by "
1525
                  + subject.getValue() + " on " + pid.getValue());
1526
1527 6869 cjones
      }
1528
1529
      SystemMetadata systemMetadata = null;
1530 6593 cjones
      try {
1531 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1532 7467 leinfelder
          lock.lock();
1533 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1534
1535 6858 cjones
          try {
1536
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1537
1538
              // does the request have the most current system metadata?
1539
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1540
                 String msg = "The requested system metadata version number " +
1541
                     serialVersion + " differs from the current version at " +
1542
                     systemMetadata.getSerialVersion().longValue() +
1543
                     ". Please get the latest copy in order to modify it.";
1544 6869 cjones
                 throw new VersionMismatch("4443", msg);
1545 6858 cjones
              }
1546
1547 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1548 6858 cjones
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1549
1550 6593 cjones
          }
1551 6858 cjones
1552
          // set the new rights holder
1553
          systemMetadata.setRightsHolder(userId);
1554 6593 cjones
1555 6858 cjones
          // update the metadata
1556
          try {
1557
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1558
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1559
              HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
1560 7076 cjones
              notifyReplicaNodes(systemMetadata);
1561 6858 cjones
1562 6869 cjones
          } catch (RuntimeException e) {
1563
              throw new ServiceFailure("4490", e.getMessage());
1564 6593 cjones
1565 6858 cjones
          }
1566 6593 cjones
1567 6869 cjones
      } catch (RuntimeException e) {
1568 6858 cjones
          throw new ServiceFailure("4490", e.getMessage());
1569 6644 cjones
1570
      } finally {
1571 6702 cjones
          lock.unlock();
1572 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1573 6858 cjones
1574 6644 cjones
      }
1575
1576 6869 cjones
      return pid;
1577 6410 cjones
  }
1578 6177 cjones
1579 6410 cjones
  /**
1580
   * Verify that a replication task is authorized by comparing the target node's
1581
   * Subject (from the X.509 certificate-derived Session) with the list of
1582
   * subjects in the known, pending replication tasks map.
1583
   *
1584
   * @param originatingNodeSession - Session information that contains the
1585
   *                                 identity of the calling user
1586
   * @param targetNodeSubject - Subject identifying the target node
1587
   * @param pid - the identifier of the object to be replicated
1588
   * @param replicatePermission - the execute permission to be granted
1589
   *
1590
   * @throws ServiceFailure
1591
   * @throws NotImplemented
1592
   * @throws InvalidToken
1593
   * @throws NotAuthorized
1594
   * @throws InvalidRequest
1595
   * @throws NotFound
1596
   */
1597 6471 jones
  @Override
1598 6409 cjones
  public boolean isNodeAuthorized(Session originatingNodeSession,
1599 6777 leinfelder
    Subject targetNodeSubject, Identifier pid)
1600 6410 cjones
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
1601
    NotFound, InvalidRequest {
1602 6702 cjones
1603 6644 cjones
    boolean isAllowed = false;
1604
    SystemMetadata sysmeta = null;
1605 6463 cjones
    NodeReference targetNode = null;
1606
1607 6644 cjones
    try {
1608
      // get the target node reference from the nodes list
1609
      CNode cn = D1Client.getCN();
1610
      List<Node> nodes = cn.listNodes().getNodeList();
1611 6665 cjones
1612 6657 cjones
      if ( nodes != null ) {
1613
        for (Node node : nodes) {
1614 6665 cjones
1615 7141 leinfelder
        	if (node.getSubjectList() != null) {
1616
1617
	            for (Subject nodeSubject : node.getSubjectList()) {
1618
1619
	                if ( nodeSubject.equals(targetNodeSubject) ) {
1620
	                    targetNode = node.getIdentifier();
1621
	                    logMetacat.debug("targetNode is : " + targetNode.getValue());
1622
	                    break;
1623
	                }
1624
	            }
1625
        	}
1626 6657 cjones
1627 6665 cjones
            if ( targetNode != null) { break; }
1628 6657 cjones
        }
1629
1630
      } else {
1631
          String msg = "Couldn't get the node list from the CN";
1632
          logMetacat.debug(msg);
1633
          throw new ServiceFailure("4872", msg);
1634
1635 6644 cjones
      }
1636 6757 cjones
1637
      // can't find a node listed with the given subject
1638
      if ( targetNode == null ) {
1639
          String msg = "There is no Member Node registered with a node subject " +
1640
              "matching " + targetNodeSubject.getValue();
1641
          logMetacat.info(msg);
1642 7062 leinfelder
          throw new NotAuthorized("4871", msg);
1643 6757 cjones
1644
      }
1645
1646 6657 cjones
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1647
1648 6644 cjones
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1649 6463 cjones
1650 6657 cjones
      if ( sysmeta != null ) {
1651
1652
          List<Replica> replicaList = sysmeta.getReplicaList();
1653
1654
          if ( replicaList != null ) {
1655
1656
              // find the replica with the status set to 'requested'
1657
              for (Replica replica : replicaList) {
1658
                  ReplicationStatus status = replica.getReplicationStatus();
1659
                  NodeReference listedNode = replica.getReplicaMemberNode();
1660 6757 cjones
                  if ( listedNode != null && targetNode != null ) {
1661
                      logMetacat.debug("Comparing " + listedNode.getValue()
1662
                              + " to " + targetNode.getValue());
1663
1664
                      if (listedNode.getValue().equals(targetNode.getValue())
1665
                              && status.equals(ReplicationStatus.REQUESTED)) {
1666
                          isAllowed = true;
1667
                          break;
1668 6657 cjones
1669 6757 cjones
                      }
1670 6657 cjones
                  }
1671
              }
1672 6568 cjones
          }
1673 6665 cjones
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1674
              "to replicate: " + isAllowed + " for " + pid.getValue());
1675
1676 6657 cjones
1677
      } else {
1678
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1679 8903 tao
          " is null.");
1680
          String error ="";
1681
          String localId = null;
1682
          try {
1683
              localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1684
1685
           } catch (Exception e) {
1686
              logMetacat.warn("Couldn't find the local id for the pid "+pid.getValue());
1687
          }
1688 6657 cjones
1689 8903 tao
          if(localId != null && EventLog.getInstance().isDeleted(localId)) {
1690
              error = DELETEDMESSAGE;
1691 8971 tao
          } else if (localId == null && EventLog.getInstance().isDeleted(pid.getValue())) {
1692
              error = DELETEDMESSAGE;
1693 8903 tao
          }
1694
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue()+". "+error);
1695
1696 6568 cjones
      }
1697 6484 cjones
1698 6662 cjones
    } catch (RuntimeException e) {
1699 6665 cjones
    	  ServiceFailure sf = new ServiceFailure("4872",
1700
                "Runtime Exception: Couldn't determine if node is allowed: " +
1701 7140 leinfelder
                e.getMessage());
1702 6665 cjones
    	  sf.initCause(e);
1703 6659 leinfelder
        throw sf;
1704 6636 cjones
1705 6644 cjones
    }
1706
1707
    return isAllowed;
1708 6410 cjones
1709 6384 cjones
  }
1710
1711 6569 cjones
  /**
1712 6570 cjones
   * Adds a new object to the Node, where the object is a science metadata object.
1713 6569 cjones
   *
1714
   * @param session - the Session object containing the credentials for the Subject
1715
   * @param pid - The object identifier to be created
1716
   * @param object - the object bytes
1717
   * @param sysmeta - the system metadata that describes the object
1718
   *
1719
   * @return pid - the object identifier created
1720
   *
1721
   * @throws InvalidToken
1722
   * @throws ServiceFailure
1723
   * @throws NotAuthorized
1724
   * @throws IdentifierNotUnique
1725
   * @throws UnsupportedType
1726
   * @throws InsufficientResources
1727
   * @throws InvalidSystemMetadata
1728
   * @throws NotImplemented
1729
   * @throws InvalidRequest
1730
   */
1731
  public Identifier create(Session session, Identifier pid, InputStream object,
1732
    SystemMetadata sysmeta)
1733
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
1734
    UnsupportedType, InsufficientResources, InvalidSystemMetadata,
1735
    NotImplemented, InvalidRequest {
1736 9068 tao
1737
   // verify the pid is valid format
1738
      if (!isValidIdentifier(pid)) {
1739
          throw new InvalidRequest("4891", "The provided identifier is invalid.");
1740
      }
1741 6702 cjones
      // The lock to be used for this identifier
1742 6859 cjones
      Lock lock = null;
1743 6917 cjones
1744 6570 cjones
      try {
1745 6869 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1746 9111 tao
          lock.lock();
1747 6869 cjones
          // are we allowed?
1748 6570 cjones
          boolean isAllowed = false;
1749 7142 leinfelder
          isAllowed = isAdminAuthorized(session);
1750 8360 tao
1751
          // additional check if it is the authoritative node if it is not the admin
1752
          if(!isAllowed) {
1753
              isAllowed = isAuthoritativeMNodeAdmin(session, pid);
1754
          }
1755 6570 cjones
1756
          // proceed if we're called by a CN
1757
          if ( isAllowed ) {
1758 9067 tao
              //check if the series id is legitimate. It uses the same rules of the method registerSystemMetadata
1759 9170 tao
              //checkSidInModifyingSystemMetadata(sysmeta, "4896", "4893");
1760
              Identifier sid = sysmeta.getSeriesId();
1761
              if(sid != null) {
1762
                  if (!isValidIdentifier(sid)) {
1763
                      throw new InvalidRequest("4891", "The series id in the system metadata is invalid in the request.");
1764
                  }
1765
              }
1766 6570 cjones
              // create the coordinating node version of the document
1767 6867 cjones
              logMetacat.debug("Locked identifier " + pid.getValue());
1768 6570 cjones
              sysmeta.setSerialVersion(BigInteger.ONE);
1769
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1770 8770 leinfelder
              //sysmeta.setArchived(false); // this is a create op, not update
1771 6917 cjones
1772
              // the CN should have set the origin and authoritative member node fields
1773
              try {
1774
                  sysmeta.getOriginMemberNode().getValue();
1775
                  sysmeta.getAuthoritativeMemberNode().getValue();
1776
1777
              } catch (NullPointerException npe) {
1778
                  throw new InvalidSystemMetadata("4896",
1779
                      "Both the origin and authoritative member node identifiers need to be set.");
1780
1781
              }
1782 6570 cjones
              pid = super.create(session, pid, object, sysmeta);
1783
1784
          } else {
1785
              String msg = "The subject listed as " + session.getSubject().getValue() +
1786
                  " isn't allowed to call create() on a Coordinating Node.";
1787
              logMetacat.info(msg);
1788
              throw new NotAuthorized("1100", msg);
1789
          }
1790
1791 6676 cjones
      } catch (RuntimeException e) {
1792 6570 cjones
          // Convert Hazelcast runtime exceptions to service failures
1793
          String msg = "There was a problem creating the object identified by " +
1794
              pid.getValue() + ". There error message was: " + e.getMessage();
1795 6676 cjones
          throw new ServiceFailure("4893", msg);
1796 6570 cjones
1797
      } finally {
1798 6805 leinfelder
    	  if (lock != null) {
1799
	          lock.unlock();
1800
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1801
    	  }
1802 6570 cjones
      }
1803
1804 6569 cjones
      return pid;
1805
1806
  }
1807
1808 6571 cjones
  /**
1809
   * Set access for a given object using the object identifier and a Subject
1810
   * under a given Session.
1811
   *
1812
   * @param session - the Session object containing the credentials for the Subject
1813
   * @param pid - the object identifier for the given object to apply the policy
1814
   * @param policy - the access policy to be applied
1815
   *
1816
   * @return true if the application of the policy succeeds
1817
   * @throws InvalidToken
1818
   * @throws ServiceFailure
1819
   * @throws NotFound
1820
   * @throws NotAuthorized
1821
   * @throws NotImplemented
1822
   * @throws InvalidRequest
1823
   */
1824
  public boolean setAccessPolicy(Session session, Identifier pid,
1825 6593 cjones
      AccessPolicy accessPolicy, long serialVersion)
1826 6571 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1827 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
1828 6571 cjones
1829 9066 tao
   // do we have a valid pid?
1830
      if (pid == null || pid.getValue().trim().equals("")) {
1831
          throw new InvalidRequest("4402", "The provided identifier was invalid.");
1832
1833
      }
1834
1835
      String serviceFailureCode = "4430";
1836
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
1837
      if(sid != null) {
1838
          pid = sid;
1839
      }
1840 6702 cjones
      // The lock to be used for this identifier
1841 6859 cjones
      Lock lock = null;
1842 6869 cjones
      SystemMetadata systemMetadata = null;
1843 6702 cjones
1844 6571 cjones
      boolean success = false;
1845
1846
      // get the subject
1847
      Subject subject = session.getSubject();
1848
1849 7068 cjones
      // are we allowed to do this?
1850
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1851
          throw new NotAuthorized("4420", "not allowed by "
1852
                  + subject.getValue() + " on " + pid.getValue());
1853 6571 cjones
      }
1854
1855
      try {
1856 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1857 6702 cjones
          lock.lock();
1858 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1859
1860 6858 cjones
          try {
1861
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1862 6571 cjones
1863 6869 cjones
              if ( systemMetadata == null ) {
1864
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1865
1866
              }
1867 6858 cjones
              // does the request have the most current system metadata?
1868
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1869
                 String msg = "The requested system metadata version number " +
1870
                     serialVersion + " differs from the current version at " +
1871
                     systemMetadata.getSerialVersion().longValue() +
1872
                     ". Please get the latest copy in order to modify it.";
1873 6869 cjones
                 throw new VersionMismatch("4402", msg);
1874
1875 6858 cjones
              }
1876
1877 6869 cjones
          } catch (RuntimeException e) {
1878 6858 cjones
              // convert Hazelcast RuntimeException to NotFound
1879
              throw new NotFound("4400", "No record found for: " + pid);
1880
1881 6593 cjones
          }
1882 6858 cjones
1883
          // set the access policy
1884
          systemMetadata.setAccessPolicy(accessPolicy);
1885 6593 cjones
1886 6858 cjones
          // update the system metadata
1887
          try {
1888
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1889
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1890
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1891 7076 cjones
              notifyReplicaNodes(systemMetadata);
1892
1893 6869 cjones
          } catch (RuntimeException e) {
1894 6858 cjones
              // convert Hazelcast RuntimeException to ServiceFailure
1895
              throw new ServiceFailure("4430", e.getMessage());
1896
1897
          }
1898 6571 cjones
1899 6869 cjones
      } catch (RuntimeException e) {
1900 6571 cjones
          throw new ServiceFailure("4430", e.getMessage());
1901 6858 cjones
1902 6571 cjones
      } finally {
1903 6702 cjones
          lock.unlock();
1904 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1905 6571 cjones
1906
      }
1907 6858 cjones
1908 6571 cjones
1909
    // TODO: how do we know if the map was persisted?
1910
    success = true;
1911
1912
    return success;
1913
  }
1914
1915 6578 cjones
  /**
1916
   * Full replacement of replication metadata in the system metadata for the
1917
   * specified object, changes date system metadata modified
1918
   *
1919
   * @param session - the Session object containing the credentials for the Subject
1920
   * @param pid - the object identifier for the given object to apply the policy
1921
   * @param replica - the replica to be updated
1922
   * @return
1923
   * @throws NotImplemented
1924
   * @throws NotAuthorized
1925
   * @throws ServiceFailure
1926
   * @throws InvalidRequest
1927
   * @throws NotFound
1928 6869 cjones
   * @throws VersionMismatch
1929 6578 cjones
   */
1930 6869 cjones
  @Override
1931 6578 cjones
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1932 6593 cjones
      Replica replica, long serialVersion)
1933 6578 cjones
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1934 6869 cjones
      NotFound, VersionMismatch {
1935 6578 cjones
1936 6702 cjones
      // The lock to be used for this identifier
1937 6859 cjones
      Lock lock = null;
1938 6702 cjones
1939 6578 cjones
      // get the subject
1940
      Subject subject = session.getSubject();
1941
1942
      // are we allowed to do this?
1943 9265 tao
      if(session == null) {
1944
          throw new NotAuthorized("4851", "Session cannot be null. It is not authorized for updating the replication metadata of the object "+pid.getValue());
1945
      } else {
1946
          if(!isCNAdmin(session)) {
1947
              throw new NotAuthorized("4851", "The client -"+ session.getSubject().getValue()+ "is not a CN and is not authorized for updating the replication metadata of the object "+pid.getValue());
1948
        }
1949
      }
1950
      /*try {
1951 7068 cjones
1952
          // what is the controlling permission?
1953
          if (!isAuthorized(session, pid, Permission.WRITE)) {
1954
              throw new NotAuthorized("4851", "not allowed by "
1955
                      + subject.getValue() + " on " + pid.getValue());
1956
          }
1957
1958 6578 cjones
1959
      } catch (InvalidToken e) {
1960
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() +
1961
                  " on " + pid.getValue());
1962
1963 9265 tao
      }*/
1964 6578 cjones
1965
      SystemMetadata systemMetadata = null;
1966 6858 cjones
      try {
1967 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1968 6702 cjones
          lock.lock();
1969 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1970 6578 cjones
1971 6858 cjones
          try {
1972
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1973
1974
              // does the request have the most current system metadata?
1975
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1976
                 String msg = "The requested system metadata version number " +
1977
                     serialVersion + " differs from the current version at " +
1978
                     systemMetadata.getSerialVersion().longValue() +
1979
                     ". Please get the latest copy in order to modify it.";
1980 6869 cjones
                 throw new VersionMismatch("4855", msg);
1981 6858 cjones
              }
1982
1983 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1984
              throw new NotFound("4854", "No record found for: " + pid.getValue() +
1985
                  " : " + e.getMessage());
1986 6858 cjones
1987 6593 cjones
          }
1988 6858 cjones
1989
          // set the status for the replica
1990
          List<Replica> replicas = systemMetadata.getReplicaList();
1991
          NodeReference replicaNode = replica.getReplicaMemberNode();
1992 7231 cjones
          ReplicationStatus replicaStatus = replica.getReplicationStatus();
1993 6858 cjones
          int index = 0;
1994
          for (Replica listedReplica: replicas) {
1995
1996
              // remove the replica that we are replacing
1997
              if ( replicaNode.getValue().equals(listedReplica.getReplicaMemberNode().getValue())) {
1998 7231 cjones
                      // don't allow status to change from COMPLETED to anything other
1999
                      // than INVALIDATED: prevents overwrites from race conditions
2000 7600 cjones
                	  if ( !listedReplica.getReplicationStatus().equals(replicaStatus) &&
2001
                	       listedReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
2002
            		       !replicaStatus.equals(ReplicationStatus.INVALIDATED) ) {
2003 7231 cjones
                	  throw new InvalidRequest("4853", "Status state change from " +
2004
                			  listedReplica.getReplicationStatus() + " to " +
2005
                			  replicaStatus.toString() + "is prohibited for identifier " +
2006
                			  pid.getValue() + " and target node " +
2007
                			  listedReplica.getReplicaMemberNode().getValue());
2008
2009
            	  }
2010 6858 cjones
                  replicas.remove(index);
2011
                  break;
2012
2013
              }
2014
              index++;
2015
          }
2016 6593 cjones
2017 6858 cjones
          // add the new replica item
2018
          replicas.add(replica);
2019
          systemMetadata.setReplicaList(replicas);
2020 6578 cjones
2021 6858 cjones
          // update the metadata
2022
          try {
2023
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
2024
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
2025
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
2026 7514 cjones
2027
              // inform replica nodes of the change if the status is complete
2028 7600 cjones
              if ( replicaStatus.equals(ReplicationStatus.COMPLETED) ) {
2029 8439 cjones
            	  notifyReplicaNodes(systemMetadata);
2030 7514 cjones
2031
              }
2032 6869 cjones
          } catch (RuntimeException e) {
2033
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
2034 6858 cjones
              throw new ServiceFailure("4852", e.getMessage());
2035 6578 cjones
2036
          }
2037 6858 cjones
2038 6869 cjones
      } catch (RuntimeException e) {
2039
          logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
2040
          throw new ServiceFailure("4852", e.getMessage());
2041
2042
      } finally {
2043
          lock.unlock();
2044
          logMetacat.debug("Unlocked identifier " + pid.getValue());
2045
2046
      }
2047 6578 cjones
2048
      return true;
2049
2050
  }
2051 6622 leinfelder
2052 6869 cjones
  /**
2053
   *
2054
   */
2055
  @Override
2056 6858 cjones
  public ObjectList listObjects(Session session, Date startTime,
2057 9247 tao
      Date endTime, ObjectFormatIdentifier formatid, NodeReference nodeId,Identifier identifier,
2058 6858 cjones
      Integer start, Integer count)
2059 6644 cjones
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
2060
      ServiceFailure {
2061 9249 tao
2062
      return super.listObjects(session, startTime, endTime, formatid, identifier, nodeId, start, count);
2063 6644 cjones
  }
2064 6803 leinfelder
2065 7012 cjones
2066
 	/**
2067
 	 * Returns a list of checksum algorithms that are supported by DataONE.
2068
 	 * @return cal  the list of checksum algorithms
2069
 	 *
2070
 	 * @throws ServiceFailure
2071
 	 * @throws NotImplemented
2072
 	 */
2073 6869 cjones
  @Override
2074 7012 cjones
  public ChecksumAlgorithmList listChecksumAlgorithms()
2075 6803 leinfelder
			throws ServiceFailure, NotImplemented {
2076
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
2077
		cal.addAlgorithm("MD5");
2078
		cal.addAlgorithm("SHA-1");
2079 7012 cjones
		return cal;
2080
2081 6803 leinfelder
	}
2082 7073 cjones
2083
  /**
2084
   * Notify replica Member Nodes of system metadata changes for a given pid
2085
   *
2086
   * @param currentSystemMetadata - the up to date system metadata
2087
   */
2088
  public void notifyReplicaNodes(SystemMetadata currentSystemMetadata) {
2089
2090
      Session session = null;
2091
      List<Replica> replicaList = currentSystemMetadata.getReplicaList();
2092
      MNode mn = null;
2093
      NodeReference replicaNodeRef = null;
2094
      CNode cn = null;
2095
      NodeType nodeType = null;
2096
      List<Node> nodeList = null;
2097
2098
      try {
2099
          cn = D1Client.getCN();
2100
          nodeList = cn.listNodes().getNodeList();
2101
2102
      } catch (Exception e) { // handle BaseException and other I/O issues
2103
2104
          // swallow errors since the call is not critical
2105
          logMetacat.error("Can't inform MNs of system metadata changes due " +
2106
              "to communication issues with the CN: " + e.getMessage());
2107
2108
      }
2109
2110
      if ( replicaList != null ) {
2111
2112
          // iterate through the replicas and inform  MN replica nodes
2113
          for (Replica replica : replicaList) {
2114
2115
              replicaNodeRef = replica.getReplicaMemberNode();
2116
              try {
2117
                  if (nodeList != null) {
2118
                      // find the node type
2119
                      for (Node node : nodeList) {
2120 8450 cjones
                          if ( node.getIdentifier().getValue().equals(replicaNodeRef.getValue()) ) {
2121 7073 cjones
                              nodeType = node.getType();
2122
                              break;
2123
2124
                          }
2125
                      }
2126
                  }
2127
2128
                  // notify only MNs
2129
                  if (nodeType != null && nodeType == NodeType.MN) {
2130
                      mn = D1Client.getMN(replicaNodeRef);
2131
                      mn.systemMetadataChanged(session,
2132
                          currentSystemMetadata.getIdentifier(),
2133
                          currentSystemMetadata.getSerialVersion().longValue(),
2134
                          currentSystemMetadata.getDateSysMetadataModified());
2135
                  }
2136
2137
              } catch (Exception e) { // handle BaseException and other I/O issues
2138
2139
                  // swallow errors since the call is not critical
2140
                  logMetacat.error("Can't inform "
2141
                          + replicaNodeRef.getValue()
2142
                          + " of system metadata changes due "
2143
                          + "to communication issues with the CN: "
2144
                          + e.getMessage());
2145
2146
              }
2147
          }
2148
      }
2149
  }
2150 9177 tao
2151 9192 tao
  /**
2152
   * Update the system metadata of the specified pid.
2153
   */
2154
  @Override
2155
  public boolean updateSystemMetadata(Session session, Identifier pid,
2156
          SystemMetadata sysmeta) throws NotImplemented, NotAuthorized,
2157
          ServiceFailure, InvalidRequest, InvalidSystemMetadata, InvalidToken {
2158
   if(sysmeta == null) {
2159
       throw  new InvalidRequest("4863", "The system metadata object should NOT be null in the updateSystemMetadata request.");
2160
   }
2161
   if(pid == null || pid.getValue() == null) {
2162
       throw new InvalidRequest("4863", "Please specify the id in the updateSystemMetadata request ") ;
2163
   }
2164
2165
   if (session == null) {
2166
       //TODO: many of the thrown exceptions do not use the correct error codes
2167
       //check these against the docs and correct them
2168
       throw new NotAuthorized("4861", "No Session - could not authorize for updating system metadata." +
2169
               "  If you are not logged in, please do so and retry the request.");
2170
   } else {
2171
         //only CN is allwoed
2172
         if(!isCNAdmin(session)) {
2173
               throw new NotAuthorized("4861", "The client -"+ session.getSubject().getValue()+ "is not authorized for updating the system metadata of the object "+pid.getValue());
2174
         }
2175
   }
2176
    //update the system metadata locally
2177
    boolean success = super.updateSystemMetadata(session, pid, sysmeta);
2178
    return success;
2179
  }
2180
2181 9189 tao
    @Override
2182
    public boolean synchronize(Session session, Identifier pid) throws NotAuthorized, InvalidRequest, NotImplemented{
2183
        throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2184
2185 9177 tao
    }
2186 7144 leinfelder
2187
	@Override
2188 8810 leinfelder
	public QueryEngineDescription getQueryEngineDescription(Session session,
2189
			String queryEngine) throws InvalidToken, ServiceFailure, NotAuthorized,
2190
			NotImplemented, NotFound {
2191
		throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2192 7144 leinfelder
2193
	}
2194
2195
	@Override
2196 8810 leinfelder
	public QueryEngineList listQueryEngines(Session session) throws InvalidToken,
2197
			ServiceFailure, NotAuthorized, NotImplemented {
2198
		throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2199 7144 leinfelder
2200
	}
2201
2202
	@Override
2203 8810 leinfelder
	public InputStream query(Session session, String queryEngine, String query)
2204
			throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
2205
			NotImplemented, NotFound {
2206
		throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2207 7144 leinfelder
2208
	}
2209
2210
	@Override
2211 8810 leinfelder
	public Node getCapabilities() throws NotImplemented, ServiceFailure {
2212
		throw new NotImplemented("0000", "The CN capabilities are not stored in Metacat.");
2213 7144 leinfelder
	}
2214 9189 tao
2215 6177 cjones
}