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 9272 tao
			/*List<Node> nodeList = D1Client.getCN().listNodes().getNodeList();
315 6883 leinfelder
			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 9272 tao
			}*/
319 6883 leinfelder
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 9272 tao
	  }
775
776
	  /*else {
777 9265 tao
	      if(!isCNAdmin(session)) {
778
              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());
779
        }
780 9272 tao
	  }*/
781 9066 tao
782
	// do we have a valid pid?
783
      if (pid == null || pid.getValue().trim().equals("")) {
784
          throw new InvalidRequest("4730", "The provided identifier was invalid.");
785
786
      }
787 6644 cjones
788 9093 tao
      /*String serviceFailureCode = "4700";
789 9066 tao
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
790
      if(sid != null) {
791
          pid = sid;
792 9093 tao
      }*/
793 9066 tao
794 6702 cjones
      // The lock to be used for this identifier
795 6859 cjones
      Lock lock = null;
796 6702 cjones
797 6644 cjones
      boolean allowed = false;
798
      int replicaEntryIndex = -1;
799
      List<Replica> replicas = null;
800
      // get the subject
801
      Subject subject = session.getSubject();
802 6676 cjones
      logMetacat.debug("ReplicationStatus for identifier " + pid.getValue() +
803
          " is " + status.toString());
804 6644 cjones
805
      SystemMetadata systemMetadata = null;
806 6858 cjones
807
      try {
808 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
809 6702 cjones
          lock.lock();
810 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
811
812 6858 cjones
          try {
813
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
814 6657 cjones
815 6869 cjones
              // did we get it correctly?
816 6858 cjones
              if ( systemMetadata == null ) {
817
                  logMetacat.debug("systemMetadata is null for " + pid.getValue());
818 6869 cjones
                  throw new NotFound("4740", "Couldn't find an object identified by " + pid.getValue());
819 6858 cjones
820
              }
821
              replicas = systemMetadata.getReplicaList();
822
              int count = 0;
823 6657 cjones
824 6876 cjones
              // was there a failure? log it
825 7600 cjones
              if ( failure != null && status.equals(ReplicationStatus.FAILED) ) {
826 6876 cjones
                 String msg = "The replication request of the object identified by " +
827
                     pid.getValue() + " failed.  The error message was " +
828
                     failure.getMessage() + ".";
829 9315 tao
                 logMetacat.error(msg);
830 6858 cjones
              }
831 6869 cjones
832 6876 cjones
              if (replicas.size() > 0 && replicas != null) {
833
                  // find the target replica index in the replica list
834
                  for (Replica replica : replicas) {
835 7600 cjones
                      String replicaNodeStr = replica.getReplicaMemberNode().getValue();
836 6876 cjones
                      String targetNodeStr = targetNode.getValue();
837 7600 cjones
                      logMetacat.debug("Comparing " + replicaNodeStr + " to " + targetNodeStr);
838 6869 cjones
839 6876 cjones
                      if (replicaNodeStr.equals(targetNodeStr)) {
840
                          replicaEntryIndex = count;
841
                          logMetacat.debug("replica entry index is: "
842
                                  + replicaEntryIndex);
843
                          break;
844
                      }
845
                      count++;
846 6858 cjones
847
                  }
848
              }
849
              // are we allowed to do this? only CNs and target MNs are allowed
850
              CNode cn = D1Client.getCN();
851
              List<Node> nodes = cn.listNodes().getNodeList();
852 6657 cjones
853 6858 cjones
              // find the node in the node list
854
              for ( Node node : nodes ) {
855
856
                  NodeReference nodeReference = node.getIdentifier();
857 7600 cjones
                  logMetacat.debug("In setReplicationStatus(), Node reference is: " +
858
                      nodeReference.getValue());
859 6858 cjones
860 7074 cjones
                  // allow target MN certs
861 7600 cjones
                  if ( targetNode.getValue().equals(nodeReference.getValue() ) &&
862
                      node.getType().equals(NodeType.MN)) {
863 6858 cjones
                      List<Subject> nodeSubjects = node.getSubjectList();
864
865
                      // check if the session subject is in the node subject list
866
                      for (Subject nodeSubject : nodeSubjects) {
867 7071 cjones
                          logMetacat.debug("In setReplicationStatus(), comparing subjects: " +
868
                                  nodeSubject.getValue() + " and " + subject.getValue());
869 7074 cjones
                          if ( nodeSubject.equals(subject) ) { // subject of session == target node subject
870 6858 cjones
871 7179 cjones
                              // lastly limit to COMPLETED, INVALIDATED,
872
                              // and FAILED status updates from MNs only
873 7600 cjones
                              if ( status.equals(ReplicationStatus.COMPLETED) ||
874
                                   status.equals(ReplicationStatus.INVALIDATED) ||
875
                                   status.equals(ReplicationStatus.FAILED)) {
876 7074 cjones
                                  allowed = true;
877
                                  break;
878
879
                              }
880 6858 cjones
                          }
881
                      }
882
                  }
883
              }
884 6657 cjones
885 7071 cjones
              if ( !allowed ) {
886
                  //check for CN admin access
887 9272 tao
                  //allowed = isAuthorized(session, pid, Permission.WRITE);
888
                  allowed = isCNAdmin(session);
889 6858 cjones
890 7071 cjones
              }
891
892
              if ( !allowed ) {
893
                  String msg = "The subject identified by "
894
                          + subject.getValue()
895 9272 tao
                          + " is not a CN or MN, and does not have permission to set the replication status for "
896 7071 cjones
                          + "the replica identified by "
897
                          + targetNode.getValue() + ".";
898
                  logMetacat.info(msg);
899
                  throw new NotAuthorized("4720", msg);
900
901 6858 cjones
              }
902 6876 cjones
903 6858 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
904
            throw new NotFound("4740", "No record found for: " + pid.getValue() +
905
                " : " + e.getMessage());
906
907 6644 cjones
          }
908
909 6876 cjones
          Replica targetReplica = new Replica();
910 6858 cjones
          // set the status for the replica
911
          if ( replicaEntryIndex != -1 ) {
912 6876 cjones
              targetReplica = replicas.get(replicaEntryIndex);
913 7231 cjones
914
              // don't allow status to change from COMPLETED to anything other
915
              // than INVALIDATED: prevents overwrites from race conditions
916 7600 cjones
              if ( targetReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
917
            	   !status.equals(ReplicationStatus.INVALIDATED)) {
918 7231 cjones
            	  throw new InvalidRequest("4730", "Status state change from " +
919
            			  targetReplica.getReplicationStatus() + " to " +
920
            			  status.toString() + "is prohibited for identifier " +
921
            			  pid.getValue() + " and target node " +
922
            			  targetReplica.getReplicaMemberNode().getValue());
923
              }
924
925 9315 tao
              if(targetReplica.getReplicationStatus().equals(status)) {
926
                  //There is no change in the status, we do nothing.
927
                  return true;
928
              }
929
930 6858 cjones
              targetReplica.setReplicationStatus(status);
931 7514 cjones
932 6858 cjones
              logMetacat.debug("Set the replication status for " +
933
                  targetReplica.getReplicaMemberNode().getValue() + " to " +
934 7231 cjones
                  targetReplica.getReplicationStatus() + " for identifier " +
935
                  pid.getValue());
936 6644 cjones
937 6858 cjones
          } else {
938 6876 cjones
              // this is a new entry, create it
939
              targetReplica.setReplicaMemberNode(targetNode);
940
              targetReplica.setReplicationStatus(status);
941
              targetReplica.setReplicaVerified(Calendar.getInstance().getTime());
942
              replicas.add(targetReplica);
943
944 6644 cjones
          }
945
946 6858 cjones
          systemMetadata.setReplicaList(replicas);
947
948
          // update the metadata
949
          try {
950
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
951
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
952
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
953 7179 cjones
954 7600 cjones
              if ( !status.equals(ReplicationStatus.QUEUED) &&
955
            	   !status.equals(ReplicationStatus.REQUESTED)) {
956 7179 cjones
957
                logMetacat.trace("METRICS:\tREPLICATION:\tEND REQUEST:\tPID:\t" + pid.getValue() +
958
                          "\tNODE:\t" + targetNode.getValue() +
959
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
960
961
                logMetacat.trace("METRICS:\tREPLICATION:\t" + status.toString().toUpperCase() +
962
                          "\tPID:\t"  + pid.getValue() +
963
                          "\tNODE:\t" + targetNode.getValue() +
964
                          "\tSIZE:\t" + systemMetadata.getSize().intValue());
965
              }
966
967 7600 cjones
              if ( status.equals(ReplicationStatus.FAILED) && failure != null ) {
968 6858 cjones
                  logMetacat.warn("Replication failed for identifier " + pid.getValue() +
969
                      " on target node " + targetNode + ". The exception was: " +
970
                      failure.getMessage());
971
              }
972 7514 cjones
973
			  // update the replica nodes about the completed replica when complete
974 7600 cjones
              if (status.equals(ReplicationStatus.COMPLETED)) {
975 8439 cjones
				notifyReplicaNodes(systemMetadata);
976 7514 cjones
			}
977
978 6869 cjones
          } catch (RuntimeException e) {
979 6858 cjones
              throw new ServiceFailure("4700", e.getMessage());
980
981 6644 cjones
          }
982
983 6867 cjones
    } catch (RuntimeException e) {
984
        String msg = "There was a RuntimeException getting the lock for " +
985
            pid.getValue();
986
        logMetacat.info(msg);
987
988
    } finally {
989 6858 cjones
        lock.unlock();
990
        logMetacat.debug("Unlocked identifier " + pid.getValue());
991 6593 cjones
992 6858 cjones
    }
993 6676 cjones
994 6644 cjones
      return true;
995 6410 cjones
  }
996
997 7514 cjones
/**
998 6410 cjones
   * Return the checksum of the object given the identifier
999
   *
1000
   * @param session - the Session object containing the credentials for the Subject
1001
   * @param pid - the object identifier for the given object
1002
   *
1003
   * @return checksum - the checksum of the object
1004
   *
1005
   * @throws InvalidToken
1006
   * @throws ServiceFailure
1007
   * @throws NotAuthorized
1008
   * @throws NotFound
1009
   * @throws NotImplemented
1010
   */
1011 6471 jones
  @Override
1012 6410 cjones
  public Checksum getChecksum(Session session, Identifier pid)
1013
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
1014 6622 leinfelder
    NotImplemented {
1015 7029 leinfelder
1016
	boolean isAuthorized = false;
1017
	try {
1018
		isAuthorized = isAuthorized(session, pid, Permission.READ);
1019
	} catch (InvalidRequest e) {
1020
		throw new ServiceFailure("1410", e.getDescription());
1021
	}
1022
    if (!isAuthorized) {
1023 6568 cjones
        throw new NotAuthorized("1400", Permission.READ + " not allowed on " + pid.getValue());
1024 6410 cjones
    }
1025 6568 cjones
1026 6410 cjones
    SystemMetadata systemMetadata = null;
1027 6568 cjones
    Checksum checksum = null;
1028
1029 6410 cjones
    try {
1030 6869 cjones
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1031
1032
        if (systemMetadata == null ) {
1033 8903 tao
            String error ="";
1034
            String localId = null;
1035
            try {
1036
                localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1037
1038
             } catch (Exception e) {
1039
                logMetacat.warn("Couldn't find the local id for the pid "+pid.getValue());
1040
            }
1041
1042
            if(localId != null && EventLog.getInstance().isDeleted(localId)) {
1043
                error = DELETEDMESSAGE;
1044 8971 tao
            } else if (localId == null && EventLog.getInstance().isDeleted(pid.getValue())) {
1045
                error = DELETEDMESSAGE;
1046 8903 tao
            }
1047
            throw new NotFound("1420", "Couldn't find an object identified by " + pid.getValue()+". "+error);
1048 6869 cjones
        }
1049 6568 cjones
        checksum = systemMetadata.getChecksum();
1050 6869 cjones
1051
    } catch (RuntimeException e) {
1052 6568 cjones
        throw new ServiceFailure("1410", "An error occurred getting the checksum for " +
1053
            pid.getValue() + ". The error message was: " + e.getMessage());
1054
1055 6410 cjones
    }
1056
1057
    return checksum;
1058
  }
1059 6177 cjones
1060 6410 cjones
  /**
1061
   * Resolve the location of a given object
1062
   *
1063
   * @param session - the Session object containing the credentials for the Subject
1064
   * @param pid - the object identifier for the given object
1065
   *
1066
   * @return objectLocationList - the list of nodes known to contain the object
1067
   *
1068
   * @throws InvalidToken
1069
   * @throws ServiceFailure
1070
   * @throws NotAuthorized
1071
   * @throws NotFound
1072
   * @throws NotImplemented
1073
   */
1074 6471 jones
  @Override
1075 6410 cjones
  public ObjectLocationList resolve(Session session, Identifier pid)
1076 6622 leinfelder
    throws InvalidToken, ServiceFailure, NotAuthorized,
1077 6410 cjones
    NotFound, NotImplemented {
1078 6177 cjones
1079 6410 cjones
    throw new NotImplemented("4131", "resolve not implemented");
1080 6303 leinfelder
1081 6410 cjones
  }
1082 6177 cjones
1083 6410 cjones
  /**
1084 7464 leinfelder
   * Metacat does not implement this method at the CN level
1085 6410 cjones
   */
1086 6471 jones
  @Override
1087 6410 cjones
  public ObjectList search(Session session, String queryType, String query)
1088
    throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
1089
    NotImplemented {
1090 6177 cjones
1091 7464 leinfelder
		  throw new NotImplemented("4281", "Metacat does not implement CN.search");
1092
1093
//    ObjectList objectList = null;
1094
//    try {
1095
//        objectList =
1096
//          IdentifierManager.getInstance().querySystemMetadata(
1097
//              null, //startTime,
1098
//              null, //endTime,
1099
//              null, //objectFormat,
1100
//              false, //replicaStatus,
1101
//              0, //start,
1102
//              1000 //count
1103
//              );
1104
//
1105
//    } catch (Exception e) {
1106
//      throw new ServiceFailure("4310", "Error querying system metadata: " + e.getMessage());
1107
//    }
1108
//
1109
//      return objectList;
1110
1111 6410 cjones
  }
1112
1113
  /**
1114
   * Returns the object format registered in the DataONE Object Format
1115
   * Vocabulary for the given format identifier
1116
   *
1117
   * @param fmtid - the identifier of the format requested
1118
   *
1119
   * @return objectFormat - the object format requested
1120
   *
1121
   * @throws ServiceFailure
1122
   * @throws NotFound
1123
   * @throws InsufficientResources
1124
   * @throws NotImplemented
1125
   */
1126 6471 jones
  @Override
1127 6410 cjones
  public ObjectFormat getFormat(ObjectFormatIdentifier fmtid)
1128 6803 leinfelder
    throws ServiceFailure, NotFound, NotImplemented {
1129 6410 cjones
1130
      return ObjectFormatService.getInstance().getFormat(fmtid);
1131
1132
  }
1133 6177 cjones
1134 9189 tao
    @Override
1135
    public ObjectFormatIdentifier addFormat(Session session, ObjectFormatIdentifier formatId, ObjectFormat format)
1136
            throws ServiceFailure, NotFound, NotImplemented, NotAuthorized, InvalidToken {
1137
1138
        logMetacat.debug("CNodeService.addFormat() called.\n" +
1139
                "format ID: " + format.getFormatId() + "\n" +
1140
                "format name: " + format.getFormatName() + "\n" +
1141
                "format type: " + format.getFormatType() );
1142
1143
        // FIXME remove:
1144
        if (true)
1145
            throw new NotImplemented("0000", "Implementation underway... Will need testing too...");
1146
1147
        if (!isAdminAuthorized(session))
1148
            throw new NotAuthorized("0000", "Not authorized to call addFormat()");
1149
1150
        String separator = ".";
1151
        try {
1152
            separator = PropertyService.getProperty("document.accNumSeparator");
1153
        } catch (PropertyNotFoundException e) {
1154
            logMetacat.warn("Unable to find property \"document.accNumSeparator\"\n" + e.getMessage());
1155
        }
1156
1157
        // find pids of last and next ObjectFormatList
1158
        String OBJECT_FORMAT_DOCID = ObjectFormatService.OBJECT_FORMAT_DOCID;
1159
        int lastRev = -1;
1160
        try {
1161
            lastRev = DBUtil.getLatestRevisionInDocumentTable(OBJECT_FORMAT_DOCID);
1162
        } catch (SQLException e) {
1163
            throw new ServiceFailure("0000", "Unable to locate last revision of the object format list.\n" + e.getMessage());
1164
        }
1165
        int nextRev = lastRev + 1;
1166
        String lastDocID = OBJECT_FORMAT_DOCID + separator + lastRev;
1167
        String nextDocID = OBJECT_FORMAT_DOCID + separator + nextRev;
1168
1169
        Identifier lastPid = new Identifier();
1170
        lastPid.setValue(lastDocID);
1171
        Identifier nextPid = new Identifier();
1172
        nextPid.setValue(nextDocID);
1173
1174
        logMetacat.debug("Last ObjectFormatList document ID: " + lastDocID + "\n"
1175
                + "Next ObjectFormatList document ID: " + nextDocID);
1176
1177
        // add new format to the current ObjectFormatList
1178
        ObjectFormatList objectFormatList = ObjectFormatService.getInstance().listFormats();
1179
        List<ObjectFormat> innerList = objectFormatList.getObjectFormatList();
1180
        innerList.add(format);
1181
1182
        // get existing (last) sysmeta and make a copy
1183
        SystemMetadata lastSysmeta = getSystemMetadata(session, lastPid);
1184
        SystemMetadata nextSysmeta = new SystemMetadata();
1185
        try {
1186
            BeanUtils.copyProperties(nextSysmeta, lastSysmeta);
1187
        } catch (IllegalAccessException | InvocationTargetException e) {
1188
            throw new ServiceFailure("0000", "Unable to create system metadata for updated object format list.\n" + e.getMessage());
1189
        }
1190
1191
        // create the new object format list, and update the old sysmeta with obsoletedBy
1192
        createNewObjectFormatList(session, lastPid, nextPid, objectFormatList, nextSysmeta);
1193
        updateOldObjectFormatList(session, lastPid, nextPid, lastSysmeta);
1194
1195
        // TODO add to ObjectFormatService local cache?
1196
1197
        return formatId;
1198
    }
1199
1200
    /**
1201
     * Creates the object for the next / updated version of the ObjectFormatList.
1202
     *
1203
     * @param session
1204
     * @param lastPid
1205
     * @param nextPid
1206
     * @param objectFormatList
1207
     * @param lastSysmeta
1208
     */
1209
    private void createNewObjectFormatList(Session session, Identifier lastPid, Identifier nextPid,
1210
            ObjectFormatList objectFormatList, SystemMetadata lastSysmeta)
1211
                    throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented {
1212
1213
        PipedInputStream is = new PipedInputStream();
1214
        PipedOutputStream os = null;
1215
1216
        try {
1217
            os = new PipedOutputStream(is);
1218
            TypeMarshaller.marshalTypeToOutputStream(objectFormatList, os);
1219
        } catch (JiBXException | IOException e) {
1220
            throw new ServiceFailure("0000", "Unable to marshal object format list.\n" + e.getMessage());
1221
        } finally {
1222
            try {
1223
                os.flush();
1224
                os.close();
1225
            } catch (IOException ioe) {
1226
                throw new ServiceFailure("0000", "Unable to marshal object format list.\n" + ioe.getMessage());
1227
            }
1228
        }
1229
1230
        BigInteger docSize = lastSysmeta.getSize();
1231
        try {
1232
            docSize = BigInteger.valueOf(is.available());
1233
        } catch (IOException e) {
1234
            logMetacat.warn("Unable to set an accurate size for the new object format list.", e);
1235
        }
1236
1237
        lastSysmeta.setIdentifier(nextPid);
1238
        lastSysmeta.setObsoletes(lastPid);
1239
        lastSysmeta.setSize(docSize);
1240
        lastSysmeta.setSubmitter(session.getSubject());
1241
        lastSysmeta.setDateUploaded(new Date());
1242
1243
        // create new object format list
1244
        try {
1245
            create(session, nextPid, is, lastSysmeta);
1246
        } catch (IdentifierNotUnique | UnsupportedType | InsufficientResources
1247
                | InvalidSystemMetadata | InvalidRequest e) {
1248
            throw new ServiceFailure("0000", "Unable to create() new object format list" + e.getMessage());
1249
        }
1250
    }
1251
1252
    /**
1253
     * Updates the SystemMetadata for the old version of the ObjectFormatList
1254
     * by setting the obsoletedBy value to the pid of the new version of the
1255
     * ObjectFormatList.
1256
     *
1257
     * @param session
1258
     * @param lastPid
1259
     * @param obsoletedByPid
1260
     * @param lastSysmeta
1261
     * @throws ServiceFailure
1262
     */
1263
    private void updateOldObjectFormatList(Session session, Identifier lastPid, Identifier obsoletedByPid, SystemMetadata lastSysmeta)
1264
            throws ServiceFailure {
1265
1266
        lastSysmeta.setObsoletedBy(obsoletedByPid);
1267
1268
        try {
1269
            this.updateSystemMetadata(session, lastPid, lastSysmeta);
1270
        } catch (NotImplemented | NotAuthorized | ServiceFailure | InvalidRequest
1271
                | InvalidSystemMetadata | InvalidToken e) {
1272
            throw new ServiceFailure("0000", "Unable to update metadata of old object format list.\n" + e.getMessage());
1273
        }
1274
    }
1275 6410 cjones
  /**
1276 6177 cjones
   * Returns a list of all object formats registered in the DataONE Object
1277
   * Format Vocabulary
1278 6410 cjones
    *
1279
   * @return objectFormatList - The list of object formats registered in
1280
   *                            the DataONE Object Format Vocabulary
1281
   *
1282
   * @throws ServiceFailure
1283
   * @throws NotImplemented
1284
   * @throws InsufficientResources
1285
   */
1286 6471 jones
  @Override
1287 6410 cjones
  public ObjectFormatList listFormats()
1288 6803 leinfelder
    throws ServiceFailure, NotImplemented {
1289 6177 cjones
1290 6410 cjones
    return ObjectFormatService.getInstance().listFormats();
1291
  }
1292 6177 cjones
1293 6410 cjones
  /**
1294 6177 cjones
   * Returns a list of nodes that have been registered with the DataONE infrastructure
1295 6410 cjones
    *
1296
   * @return nodeList - List of nodes from the registry
1297
   *
1298
   * @throws ServiceFailure
1299
   * @throws NotImplemented
1300
   */
1301 6471 jones
  @Override
1302 6410 cjones
  public NodeList listNodes()
1303
    throws NotImplemented, ServiceFailure {
1304 6177 cjones
1305 6410 cjones
    throw new NotImplemented("4800", "listNodes not implemented");
1306
  }
1307 6177 cjones
1308 6410 cjones
  /**
1309 6177 cjones
   * Provides a mechanism for adding system metadata independently of its
1310
   * associated object, such as when adding system metadata for data objects.
1311 6410 cjones
    *
1312
   * @param session - the Session object containing the credentials for the Subject
1313
   * @param pid - The identifier of the object to register the system metadata against
1314
   * @param sysmeta - The system metadata to be registered
1315
   *
1316
   * @return true if the registration succeeds
1317
   *
1318
   * @throws NotImplemented
1319
   * @throws NotAuthorized
1320
   * @throws ServiceFailure
1321
   * @throws InvalidRequest
1322
   * @throws InvalidSystemMetadata
1323
   */
1324 6471 jones
  @Override
1325 6575 cjones
  public Identifier registerSystemMetadata(Session session, Identifier pid,
1326
      SystemMetadata sysmeta)
1327
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1328
      InvalidSystemMetadata {
1329 6177 cjones
1330 6702 cjones
      // The lock to be used for this identifier
1331 6859 cjones
      Lock lock = null;
1332 6702 cjones
1333 6575 cjones
      // TODO: control who can call this?
1334
      if (session == null) {
1335
          //TODO: many of the thrown exceptions do not use the correct error codes
1336
          //check these against the docs and correct them
1337
          throw new NotAuthorized("4861", "No Session - could not authorize for registration." +
1338
                  "  If you are not logged in, please do so and retry the request.");
1339 9265 tao
      } else {
1340
          //only CN is allwoed
1341
          if(!isCNAdmin(session)) {
1342
                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());
1343
          }
1344 6575 cjones
      }
1345 9070 tao
      // the identifier can't be an SID
1346
      try {
1347
          if(IdentifierManager.getInstance().systemMetadataSIDExists(pid)) {
1348
              throw new InvalidRequest("4863", "The provided identifier "+pid.getValue()+" is a series id which is not allowed.");
1349
          }
1350
      } catch (SQLException sqle) {
1351
          throw new ServiceFailure("4862", "Couldn't determine if the pid "+pid.getValue()+" is a series id since "+sqle.getMessage());
1352
      }
1353 6575 cjones
1354
      // verify that guid == SystemMetadata.getIdentifier()
1355
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() +
1356
          "|" + sysmeta.getIdentifier().getValue());
1357
      if (!pid.getValue().equals(sysmeta.getIdentifier().getValue())) {
1358
          throw new InvalidRequest("4863",
1359
              "The identifier in method call (" + pid.getValue() +
1360
              ") does not match identifier in system metadata (" +
1361
              sysmeta.getIdentifier().getValue() + ").");
1362
      }
1363 9067 tao
1364
      //check if the sid is legitimate in the system metadata
1365 9170 tao
      //checkSidInModifyingSystemMetadata(sysmeta, "4864", "4862");
1366
      Identifier sid = sysmeta.getSeriesId();
1367
      if(sid != null) {
1368
          if (!isValidIdentifier(sid)) {
1369
              throw new InvalidRequest("4863", "The series id in the system metadata is invalid in the request.");
1370
          }
1371
      }
1372 6188 leinfelder
1373 6575 cjones
      try {
1374 6703 cjones
          lock = HazelcastService.getInstance().getLock(sysmeta.getIdentifier().getValue());
1375 6863 cjones
          lock.lock();
1376 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1377 6863 cjones
          logMetacat.debug("Checking if identifier exists...");
1378
          // Check that the identifier does not already exist
1379
          if (HazelcastService.getInstance().getSystemMetadataMap().containsKey(pid)) {
1380
              throw new InvalidRequest("4863",
1381
                  "The identifier is already in use by an existing object.");
1382 6575 cjones
1383 6863 cjones
          }
1384
1385
          // insert the system metadata into the object store
1386
          logMetacat.debug("Starting to insert SystemMetadata...");
1387
          try {
1388
              sysmeta.setSerialVersion(BigInteger.ONE);
1389
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1390
              HazelcastService.getInstance().getSystemMetadataMap().put(sysmeta.getIdentifier(), sysmeta);
1391
1392 6869 cjones
          } catch (RuntimeException e) {
1393 6863 cjones
            logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
1394
              throw new ServiceFailure("4862", "Error inserting system metadata: " +
1395
                  e.getClass() + ": " + e.getMessage());
1396
1397
          }
1398
1399 6869 cjones
      } catch (RuntimeException e) {
1400 6575 cjones
          throw new ServiceFailure("4862", "Error inserting system metadata: " +
1401 6863 cjones
                  e.getClass() + ": " + e.getMessage());
1402 6575 cjones
1403 6863 cjones
      }  finally {
1404
          lock.unlock();
1405
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1406
1407
      }
1408 6466 cjones
1409 6575 cjones
1410
      logMetacat.debug("Returning from registerSystemMetadata");
1411 8553 leinfelder
1412
      try {
1413
    	  String localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1414
    	  EventLog.getInstance().log(request.getRemoteAddr(),
1415
    	          request.getHeader("User-Agent"), session.getSubject().getValue(),
1416
    	          localId, "registerSystemMetadata");
1417
      } catch (McdbDocNotFoundException e) {
1418
    	  // do nothing, no localId to log with
1419
    	  logMetacat.warn("Could not log 'registerSystemMetadata' event because no localId was found for pid: " + pid.getValue());
1420 9024 tao
      } catch (SQLException ee) {
1421
          // do nothing, no localId to log with
1422
          logMetacat.warn("Could not log 'registerSystemMetadata' event because the localId couldn't be identified for pid: " + pid.getValue());
1423 8553 leinfelder
      }
1424
1425
1426 6575 cjones
      return pid;
1427 6410 cjones
  }
1428
1429
  /**
1430 6177 cjones
   * Given an optional scope and format, reserves and returns an identifier
1431
   * within that scope and format that is unique and will not be
1432
   * used by any other sessions.
1433 6410 cjones
    *
1434
   * @param session - the Session object containing the credentials for the Subject
1435
   * @param pid - The identifier of the object to register the system metadata against
1436
   * @param scope - An optional string to be used to qualify the scope of
1437
   *                the identifier namespace, which is applied differently
1438
   *                depending on the format requested. If scope is not
1439
   *                supplied, a default scope will be used.
1440
   * @param format - The optional name of the identifier format to be used,
1441
   *                  drawn from a DataONE-specific vocabulary of identifier
1442
   *                 format names, including several common syntaxes such
1443
   *                 as DOI, LSID, UUID, and LSRN, among others. If the
1444
   *                 format is not supplied by the caller, the CN service
1445
   *                 will use a default identifier format, which may change
1446
   *                 over time.
1447
   *
1448
   * @return true if the registration succeeds
1449
   *
1450
   * @throws InvalidToken
1451
   * @throws ServiceFailure
1452
   * @throws NotAuthorized
1453
   * @throws IdentifierNotUnique
1454
   * @throws NotImplemented
1455
   */
1456 6471 jones
  @Override
1457 6622 leinfelder
  public Identifier reserveIdentifier(Session session, Identifier pid)
1458 6410 cjones
  throws InvalidToken, ServiceFailure,
1459 6378 leinfelder
        NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest {
1460 6177 cjones
1461 6410 cjones
    throw new NotImplemented("4191", "reserveIdentifier not implemented on this node");
1462
  }
1463
1464 6471 jones
  @Override
1465 6410 cjones
  public Identifier generateIdentifier(Session session, String scheme, String fragment)
1466
  throws InvalidToken, ServiceFailure,
1467 6378 leinfelder
        NotAuthorized, NotImplemented, InvalidRequest {
1468 6410 cjones
    throw new NotImplemented("4191", "generateIdentifier not implemented on this node");
1469
  }
1470
1471
  /**
1472
    * Checks whether the pid is reserved by the subject in the session param
1473
    * If the reservation is held on the pid by the subject, we return true.
1474
    *
1475
   * @param session - the Session object containing the Subject
1476
   * @param pid - The identifier to check
1477
   *
1478
   * @return true if the reservation exists for the subject/pid
1479
   *
1480
   * @throws InvalidToken
1481
   * @throws ServiceFailure
1482
   * @throws NotFound - when the pid is not found (in use or in reservation)
1483
   * @throws NotAuthorized - when the subject does not hold a reservation on the pid
1484
   * @throws IdentifierNotUnique - when the pid is in use
1485
   * @throws NotImplemented
1486
   */
1487 6177 cjones
1488 6471 jones
  @Override
1489 6934 leinfelder
  public boolean hasReservation(Session session, Subject subject, Identifier pid)
1490 6410 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, IdentifierNotUnique,
1491
      NotImplemented, InvalidRequest {
1492
1493
      throw new NotImplemented("4191", "hasReservation not implemented on this node");
1494
  }
1495 6339 leinfelder
1496 6410 cjones
  /**
1497 6177 cjones
   * Changes ownership (RightsHolder) of the specified object to the
1498
   * subject specified by userId
1499 6410 cjones
    *
1500
   * @param session - the Session object containing the credentials for the Subject
1501
   * @param pid - Identifier of the object to be modified
1502
   * @param userId - The subject that will be taking ownership of the specified object.
1503
   *
1504
   * @return pid - the identifier of the modified object
1505
   *
1506
   * @throws ServiceFailure
1507
   * @throws InvalidToken
1508
   * @throws NotFound
1509
   * @throws NotAuthorized
1510
   * @throws NotImplemented
1511
   * @throws InvalidRequest
1512
   */
1513 6471 jones
  @Override
1514 6803 leinfelder
  public Identifier setRightsHolder(Session session, Identifier pid, Subject userId,
1515 6593 cjones
      long serialVersion)
1516
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1517 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
1518 6593 cjones
1519 6702 cjones
      // The lock to be used for this identifier
1520 6859 cjones
      Lock lock = null;
1521 6702 cjones
1522 6593 cjones
      // get the subject
1523
      Subject subject = session.getSubject();
1524
1525 9093 tao
      String serviceFailureCode = "4490";
1526
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
1527
      if(sid != null) {
1528
          pid = sid;
1529
      }
1530
1531 6593 cjones
      // are we allowed to do this?
1532 7068 cjones
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1533
          throw new NotAuthorized("4440", "not allowed by "
1534
                  + subject.getValue() + " on " + pid.getValue());
1535
1536 6869 cjones
      }
1537
1538
      SystemMetadata systemMetadata = null;
1539 6593 cjones
      try {
1540 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1541 7467 leinfelder
          lock.lock();
1542 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1543
1544 6858 cjones
          try {
1545
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1546
1547
              // does the request have the most current system metadata?
1548
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1549
                 String msg = "The requested system metadata version number " +
1550
                     serialVersion + " differs from the current version at " +
1551
                     systemMetadata.getSerialVersion().longValue() +
1552
                     ". Please get the latest copy in order to modify it.";
1553 6869 cjones
                 throw new VersionMismatch("4443", msg);
1554 6858 cjones
              }
1555
1556 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1557 6858 cjones
              throw new NotFound("4460", "No record found for: " + pid.getValue());
1558
1559 6593 cjones
          }
1560 6858 cjones
1561
          // set the new rights holder
1562
          systemMetadata.setRightsHolder(userId);
1563 6593 cjones
1564 6858 cjones
          // update the metadata
1565
          try {
1566
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1567
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1568
              HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
1569 7076 cjones
              notifyReplicaNodes(systemMetadata);
1570 6858 cjones
1571 6869 cjones
          } catch (RuntimeException e) {
1572
              throw new ServiceFailure("4490", e.getMessage());
1573 6593 cjones
1574 6858 cjones
          }
1575 6593 cjones
1576 6869 cjones
      } catch (RuntimeException e) {
1577 6858 cjones
          throw new ServiceFailure("4490", e.getMessage());
1578 6644 cjones
1579
      } finally {
1580 6702 cjones
          lock.unlock();
1581 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1582 6858 cjones
1583 6644 cjones
      }
1584
1585 6869 cjones
      return pid;
1586 6410 cjones
  }
1587 6177 cjones
1588 6410 cjones
  /**
1589
   * Verify that a replication task is authorized by comparing the target node's
1590
   * Subject (from the X.509 certificate-derived Session) with the list of
1591
   * subjects in the known, pending replication tasks map.
1592
   *
1593
   * @param originatingNodeSession - Session information that contains the
1594
   *                                 identity of the calling user
1595
   * @param targetNodeSubject - Subject identifying the target node
1596
   * @param pid - the identifier of the object to be replicated
1597
   * @param replicatePermission - the execute permission to be granted
1598
   *
1599
   * @throws ServiceFailure
1600
   * @throws NotImplemented
1601
   * @throws InvalidToken
1602
   * @throws NotAuthorized
1603
   * @throws InvalidRequest
1604
   * @throws NotFound
1605
   */
1606 6471 jones
  @Override
1607 6409 cjones
  public boolean isNodeAuthorized(Session originatingNodeSession,
1608 6777 leinfelder
    Subject targetNodeSubject, Identifier pid)
1609 6410 cjones
    throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
1610
    NotFound, InvalidRequest {
1611 6702 cjones
1612 6644 cjones
    boolean isAllowed = false;
1613
    SystemMetadata sysmeta = null;
1614 6463 cjones
    NodeReference targetNode = null;
1615
1616 6644 cjones
    try {
1617
      // get the target node reference from the nodes list
1618
      CNode cn = D1Client.getCN();
1619
      List<Node> nodes = cn.listNodes().getNodeList();
1620 6665 cjones
1621 6657 cjones
      if ( nodes != null ) {
1622
        for (Node node : nodes) {
1623 6665 cjones
1624 7141 leinfelder
        	if (node.getSubjectList() != null) {
1625
1626
	            for (Subject nodeSubject : node.getSubjectList()) {
1627
1628
	                if ( nodeSubject.equals(targetNodeSubject) ) {
1629
	                    targetNode = node.getIdentifier();
1630
	                    logMetacat.debug("targetNode is : " + targetNode.getValue());
1631
	                    break;
1632
	                }
1633
	            }
1634
        	}
1635 6657 cjones
1636 6665 cjones
            if ( targetNode != null) { break; }
1637 6657 cjones
        }
1638
1639
      } else {
1640
          String msg = "Couldn't get the node list from the CN";
1641
          logMetacat.debug(msg);
1642
          throw new ServiceFailure("4872", msg);
1643
1644 6644 cjones
      }
1645 6757 cjones
1646
      // can't find a node listed with the given subject
1647
      if ( targetNode == null ) {
1648
          String msg = "There is no Member Node registered with a node subject " +
1649
              "matching " + targetNodeSubject.getValue();
1650
          logMetacat.info(msg);
1651 7062 leinfelder
          throw new NotAuthorized("4871", msg);
1652 6757 cjones
1653
      }
1654
1655 6657 cjones
      logMetacat.debug("Getting system metadata for identifier " + pid.getValue());
1656
1657 6644 cjones
      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1658 6463 cjones
1659 6657 cjones
      if ( sysmeta != null ) {
1660
1661
          List<Replica> replicaList = sysmeta.getReplicaList();
1662
1663
          if ( replicaList != null ) {
1664
1665
              // find the replica with the status set to 'requested'
1666
              for (Replica replica : replicaList) {
1667
                  ReplicationStatus status = replica.getReplicationStatus();
1668
                  NodeReference listedNode = replica.getReplicaMemberNode();
1669 6757 cjones
                  if ( listedNode != null && targetNode != null ) {
1670
                      logMetacat.debug("Comparing " + listedNode.getValue()
1671
                              + " to " + targetNode.getValue());
1672
1673
                      if (listedNode.getValue().equals(targetNode.getValue())
1674
                              && status.equals(ReplicationStatus.REQUESTED)) {
1675
                          isAllowed = true;
1676
                          break;
1677 6657 cjones
1678 6757 cjones
                      }
1679 6657 cjones
                  }
1680
              }
1681 6568 cjones
          }
1682 6665 cjones
          logMetacat.debug("The " + targetNode.getValue() + " is allowed " +
1683
              "to replicate: " + isAllowed + " for " + pid.getValue());
1684
1685 6657 cjones
1686
      } else {
1687
          logMetacat.debug("System metadata for identifier " + pid.getValue() +
1688 8903 tao
          " is null.");
1689
          String error ="";
1690
          String localId = null;
1691
          try {
1692
              localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1693
1694
           } catch (Exception e) {
1695
              logMetacat.warn("Couldn't find the local id for the pid "+pid.getValue());
1696
          }
1697 6657 cjones
1698 8903 tao
          if(localId != null && EventLog.getInstance().isDeleted(localId)) {
1699
              error = DELETEDMESSAGE;
1700 8971 tao
          } else if (localId == null && EventLog.getInstance().isDeleted(pid.getValue())) {
1701
              error = DELETEDMESSAGE;
1702 8903 tao
          }
1703
          throw new NotFound("4874", "Couldn't find an object identified by " + pid.getValue()+". "+error);
1704
1705 6568 cjones
      }
1706 6484 cjones
1707 6662 cjones
    } catch (RuntimeException e) {
1708 6665 cjones
    	  ServiceFailure sf = new ServiceFailure("4872",
1709
                "Runtime Exception: Couldn't determine if node is allowed: " +
1710 7140 leinfelder
                e.getMessage());
1711 6665 cjones
    	  sf.initCause(e);
1712 6659 leinfelder
        throw sf;
1713 6636 cjones
1714 6644 cjones
    }
1715
1716
    return isAllowed;
1717 6410 cjones
1718 6384 cjones
  }
1719
1720 6569 cjones
  /**
1721 6570 cjones
   * Adds a new object to the Node, where the object is a science metadata object.
1722 6569 cjones
   *
1723
   * @param session - the Session object containing the credentials for the Subject
1724
   * @param pid - The object identifier to be created
1725
   * @param object - the object bytes
1726
   * @param sysmeta - the system metadata that describes the object
1727
   *
1728
   * @return pid - the object identifier created
1729
   *
1730
   * @throws InvalidToken
1731
   * @throws ServiceFailure
1732
   * @throws NotAuthorized
1733
   * @throws IdentifierNotUnique
1734
   * @throws UnsupportedType
1735
   * @throws InsufficientResources
1736
   * @throws InvalidSystemMetadata
1737
   * @throws NotImplemented
1738
   * @throws InvalidRequest
1739
   */
1740
  public Identifier create(Session session, Identifier pid, InputStream object,
1741
    SystemMetadata sysmeta)
1742
    throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
1743
    UnsupportedType, InsufficientResources, InvalidSystemMetadata,
1744
    NotImplemented, InvalidRequest {
1745 9068 tao
1746
   // verify the pid is valid format
1747
      if (!isValidIdentifier(pid)) {
1748
          throw new InvalidRequest("4891", "The provided identifier is invalid.");
1749
      }
1750 6702 cjones
      // The lock to be used for this identifier
1751 6859 cjones
      Lock lock = null;
1752 6917 cjones
1753 6570 cjones
      try {
1754 6869 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1755 9111 tao
          lock.lock();
1756 6869 cjones
          // are we allowed?
1757 6570 cjones
          boolean isAllowed = false;
1758 7142 leinfelder
          isAllowed = isAdminAuthorized(session);
1759 8360 tao
1760
          // additional check if it is the authoritative node if it is not the admin
1761
          if(!isAllowed) {
1762
              isAllowed = isAuthoritativeMNodeAdmin(session, pid);
1763
          }
1764 6570 cjones
1765
          // proceed if we're called by a CN
1766
          if ( isAllowed ) {
1767 9067 tao
              //check if the series id is legitimate. It uses the same rules of the method registerSystemMetadata
1768 9170 tao
              //checkSidInModifyingSystemMetadata(sysmeta, "4896", "4893");
1769
              Identifier sid = sysmeta.getSeriesId();
1770
              if(sid != null) {
1771
                  if (!isValidIdentifier(sid)) {
1772
                      throw new InvalidRequest("4891", "The series id in the system metadata is invalid in the request.");
1773
                  }
1774
              }
1775 6570 cjones
              // create the coordinating node version of the document
1776 6867 cjones
              logMetacat.debug("Locked identifier " + pid.getValue());
1777 6570 cjones
              sysmeta.setSerialVersion(BigInteger.ONE);
1778
              sysmeta.setDateSysMetadataModified(Calendar.getInstance().getTime());
1779 8770 leinfelder
              //sysmeta.setArchived(false); // this is a create op, not update
1780 6917 cjones
1781
              // the CN should have set the origin and authoritative member node fields
1782
              try {
1783
                  sysmeta.getOriginMemberNode().getValue();
1784
                  sysmeta.getAuthoritativeMemberNode().getValue();
1785
1786
              } catch (NullPointerException npe) {
1787
                  throw new InvalidSystemMetadata("4896",
1788
                      "Both the origin and authoritative member node identifiers need to be set.");
1789
1790
              }
1791 6570 cjones
              pid = super.create(session, pid, object, sysmeta);
1792
1793
          } else {
1794
              String msg = "The subject listed as " + session.getSubject().getValue() +
1795
                  " isn't allowed to call create() on a Coordinating Node.";
1796
              logMetacat.info(msg);
1797
              throw new NotAuthorized("1100", msg);
1798
          }
1799
1800 6676 cjones
      } catch (RuntimeException e) {
1801 6570 cjones
          // Convert Hazelcast runtime exceptions to service failures
1802
          String msg = "There was a problem creating the object identified by " +
1803
              pid.getValue() + ". There error message was: " + e.getMessage();
1804 6676 cjones
          throw new ServiceFailure("4893", msg);
1805 6570 cjones
1806
      } finally {
1807 6805 leinfelder
    	  if (lock != null) {
1808
	          lock.unlock();
1809
	          logMetacat.debug("Unlocked identifier " + pid.getValue());
1810
    	  }
1811 6570 cjones
      }
1812
1813 6569 cjones
      return pid;
1814
1815
  }
1816
1817 6571 cjones
  /**
1818
   * Set access for a given object using the object identifier and a Subject
1819
   * under a given Session.
1820
   *
1821
   * @param session - the Session object containing the credentials for the Subject
1822
   * @param pid - the object identifier for the given object to apply the policy
1823
   * @param policy - the access policy to be applied
1824
   *
1825
   * @return true if the application of the policy succeeds
1826
   * @throws InvalidToken
1827
   * @throws ServiceFailure
1828
   * @throws NotFound
1829
   * @throws NotAuthorized
1830
   * @throws NotImplemented
1831
   * @throws InvalidRequest
1832
   */
1833
  public boolean setAccessPolicy(Session session, Identifier pid,
1834 6593 cjones
      AccessPolicy accessPolicy, long serialVersion)
1835 6571 cjones
      throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1836 6869 cjones
      NotImplemented, InvalidRequest, VersionMismatch {
1837 6571 cjones
1838 9066 tao
   // do we have a valid pid?
1839
      if (pid == null || pid.getValue().trim().equals("")) {
1840
          throw new InvalidRequest("4402", "The provided identifier was invalid.");
1841
1842
      }
1843
1844
      String serviceFailureCode = "4430";
1845
      Identifier sid = getPIDForSID(pid, serviceFailureCode);
1846
      if(sid != null) {
1847
          pid = sid;
1848
      }
1849 6702 cjones
      // The lock to be used for this identifier
1850 6859 cjones
      Lock lock = null;
1851 6869 cjones
      SystemMetadata systemMetadata = null;
1852 6702 cjones
1853 6571 cjones
      boolean success = false;
1854
1855
      // get the subject
1856
      Subject subject = session.getSubject();
1857
1858 7068 cjones
      // are we allowed to do this?
1859
      if (!isAuthorized(session, pid, Permission.CHANGE_PERMISSION)) {
1860
          throw new NotAuthorized("4420", "not allowed by "
1861
                  + subject.getValue() + " on " + pid.getValue());
1862 6571 cjones
      }
1863
1864
      try {
1865 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1866 6702 cjones
          lock.lock();
1867 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1868
1869 6858 cjones
          try {
1870
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1871 6571 cjones
1872 6869 cjones
              if ( systemMetadata == null ) {
1873
                  throw new NotFound("4400", "Couldn't find an object identified by " + pid.getValue());
1874
1875
              }
1876 6858 cjones
              // does the request have the most current system metadata?
1877
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1878
                 String msg = "The requested system metadata version number " +
1879
                     serialVersion + " differs from the current version at " +
1880
                     systemMetadata.getSerialVersion().longValue() +
1881
                     ". Please get the latest copy in order to modify it.";
1882 6869 cjones
                 throw new VersionMismatch("4402", msg);
1883
1884 6858 cjones
              }
1885
1886 6869 cjones
          } catch (RuntimeException e) {
1887 6858 cjones
              // convert Hazelcast RuntimeException to NotFound
1888
              throw new NotFound("4400", "No record found for: " + pid);
1889
1890 6593 cjones
          }
1891 6858 cjones
1892
          // set the access policy
1893
          systemMetadata.setAccessPolicy(accessPolicy);
1894 6593 cjones
1895 6858 cjones
          // update the system metadata
1896
          try {
1897
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
1898
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
1899
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
1900 7076 cjones
              notifyReplicaNodes(systemMetadata);
1901
1902 6869 cjones
          } catch (RuntimeException e) {
1903 6858 cjones
              // convert Hazelcast RuntimeException to ServiceFailure
1904
              throw new ServiceFailure("4430", e.getMessage());
1905
1906
          }
1907 6571 cjones
1908 6869 cjones
      } catch (RuntimeException e) {
1909 6571 cjones
          throw new ServiceFailure("4430", e.getMessage());
1910 6858 cjones
1911 6571 cjones
      } finally {
1912 6702 cjones
          lock.unlock();
1913 6717 cjones
          logMetacat.debug("Unlocked identifier " + pid.getValue());
1914 6571 cjones
1915
      }
1916 6858 cjones
1917 6571 cjones
1918
    // TODO: how do we know if the map was persisted?
1919
    success = true;
1920
1921
    return success;
1922
  }
1923
1924 6578 cjones
  /**
1925
   * Full replacement of replication metadata in the system metadata for the
1926
   * specified object, changes date system metadata modified
1927
   *
1928
   * @param session - the Session object containing the credentials for the Subject
1929
   * @param pid - the object identifier for the given object to apply the policy
1930
   * @param replica - the replica to be updated
1931
   * @return
1932
   * @throws NotImplemented
1933
   * @throws NotAuthorized
1934
   * @throws ServiceFailure
1935
   * @throws InvalidRequest
1936
   * @throws NotFound
1937 6869 cjones
   * @throws VersionMismatch
1938 6578 cjones
   */
1939 6869 cjones
  @Override
1940 6578 cjones
  public boolean updateReplicationMetadata(Session session, Identifier pid,
1941 6593 cjones
      Replica replica, long serialVersion)
1942 6578 cjones
      throws NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest,
1943 6869 cjones
      NotFound, VersionMismatch {
1944 6578 cjones
1945 6702 cjones
      // The lock to be used for this identifier
1946 6859 cjones
      Lock lock = null;
1947 6702 cjones
1948 6578 cjones
      // get the subject
1949
      Subject subject = session.getSubject();
1950
1951
      // are we allowed to do this?
1952 9265 tao
      if(session == null) {
1953
          throw new NotAuthorized("4851", "Session cannot be null. It is not authorized for updating the replication metadata of the object "+pid.getValue());
1954
      } else {
1955
          if(!isCNAdmin(session)) {
1956
              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());
1957
        }
1958
      }
1959
      /*try {
1960 7068 cjones
1961
          // what is the controlling permission?
1962
          if (!isAuthorized(session, pid, Permission.WRITE)) {
1963
              throw new NotAuthorized("4851", "not allowed by "
1964
                      + subject.getValue() + " on " + pid.getValue());
1965
          }
1966
1967 6578 cjones
1968
      } catch (InvalidToken e) {
1969
          throw new NotAuthorized("4851", "not allowed by " + subject.getValue() +
1970
                  " on " + pid.getValue());
1971
1972 9265 tao
      }*/
1973 6578 cjones
1974
      SystemMetadata systemMetadata = null;
1975 6858 cjones
      try {
1976 6703 cjones
          lock = HazelcastService.getInstance().getLock(pid.getValue());
1977 6702 cjones
          lock.lock();
1978 6867 cjones
          logMetacat.debug("Locked identifier " + pid.getValue());
1979 6578 cjones
1980 6858 cjones
          try {
1981
              systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1982
1983
              // does the request have the most current system metadata?
1984
              if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
1985
                 String msg = "The requested system metadata version number " +
1986
                     serialVersion + " differs from the current version at " +
1987
                     systemMetadata.getSerialVersion().longValue() +
1988
                     ". Please get the latest copy in order to modify it.";
1989 6869 cjones
                 throw new VersionMismatch("4855", msg);
1990 6858 cjones
              }
1991
1992 6869 cjones
          } catch (RuntimeException e) { // Catch is generic since HZ throws RuntimeException
1993
              throw new NotFound("4854", "No record found for: " + pid.getValue() +
1994
                  " : " + e.getMessage());
1995 6858 cjones
1996 6593 cjones
          }
1997 6858 cjones
1998
          // set the status for the replica
1999
          List<Replica> replicas = systemMetadata.getReplicaList();
2000
          NodeReference replicaNode = replica.getReplicaMemberNode();
2001 7231 cjones
          ReplicationStatus replicaStatus = replica.getReplicationStatus();
2002 6858 cjones
          int index = 0;
2003
          for (Replica listedReplica: replicas) {
2004
2005
              // remove the replica that we are replacing
2006
              if ( replicaNode.getValue().equals(listedReplica.getReplicaMemberNode().getValue())) {
2007 7231 cjones
                      // don't allow status to change from COMPLETED to anything other
2008
                      // than INVALIDATED: prevents overwrites from race conditions
2009 7600 cjones
                	  if ( !listedReplica.getReplicationStatus().equals(replicaStatus) &&
2010
                	       listedReplica.getReplicationStatus().equals(ReplicationStatus.COMPLETED) &&
2011
            		       !replicaStatus.equals(ReplicationStatus.INVALIDATED) ) {
2012 7231 cjones
                	  throw new InvalidRequest("4853", "Status state change from " +
2013
                			  listedReplica.getReplicationStatus() + " to " +
2014
                			  replicaStatus.toString() + "is prohibited for identifier " +
2015
                			  pid.getValue() + " and target node " +
2016
                			  listedReplica.getReplicaMemberNode().getValue());
2017
2018
            	  }
2019 6858 cjones
                  replicas.remove(index);
2020
                  break;
2021
2022
              }
2023
              index++;
2024
          }
2025 6593 cjones
2026 6858 cjones
          // add the new replica item
2027
          replicas.add(replica);
2028
          systemMetadata.setReplicaList(replicas);
2029 6578 cjones
2030 6858 cjones
          // update the metadata
2031
          try {
2032
              systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
2033
              systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
2034
              HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
2035 7514 cjones
2036
              // inform replica nodes of the change if the status is complete
2037 7600 cjones
              if ( replicaStatus.equals(ReplicationStatus.COMPLETED) ) {
2038 8439 cjones
            	  notifyReplicaNodes(systemMetadata);
2039 7514 cjones
2040
              }
2041 6869 cjones
          } catch (RuntimeException e) {
2042
              logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
2043 6858 cjones
              throw new ServiceFailure("4852", e.getMessage());
2044 6578 cjones
2045
          }
2046 6858 cjones
2047 6869 cjones
      } catch (RuntimeException e) {
2048
          logMetacat.info("Unknown RuntimeException thrown: " + e.getCause().getMessage());
2049
          throw new ServiceFailure("4852", e.getMessage());
2050
2051
      } finally {
2052
          lock.unlock();
2053
          logMetacat.debug("Unlocked identifier " + pid.getValue());
2054
2055
      }
2056 6578 cjones
2057
      return true;
2058
2059
  }
2060 6622 leinfelder
2061 6869 cjones
  /**
2062
   *
2063
   */
2064
  @Override
2065 6858 cjones
  public ObjectList listObjects(Session session, Date startTime,
2066 9247 tao
      Date endTime, ObjectFormatIdentifier formatid, NodeReference nodeId,Identifier identifier,
2067 6858 cjones
      Integer start, Integer count)
2068 6644 cjones
      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
2069
      ServiceFailure {
2070 9249 tao
2071
      return super.listObjects(session, startTime, endTime, formatid, identifier, nodeId, start, count);
2072 6644 cjones
  }
2073 6803 leinfelder
2074 7012 cjones
2075
 	/**
2076
 	 * Returns a list of checksum algorithms that are supported by DataONE.
2077
 	 * @return cal  the list of checksum algorithms
2078
 	 *
2079
 	 * @throws ServiceFailure
2080
 	 * @throws NotImplemented
2081
 	 */
2082 6869 cjones
  @Override
2083 7012 cjones
  public ChecksumAlgorithmList listChecksumAlgorithms()
2084 6803 leinfelder
			throws ServiceFailure, NotImplemented {
2085
		ChecksumAlgorithmList cal = new ChecksumAlgorithmList();
2086
		cal.addAlgorithm("MD5");
2087
		cal.addAlgorithm("SHA-1");
2088 7012 cjones
		return cal;
2089
2090 6803 leinfelder
	}
2091 7073 cjones
2092
  /**
2093
   * Notify replica Member Nodes of system metadata changes for a given pid
2094
   *
2095
   * @param currentSystemMetadata - the up to date system metadata
2096
   */
2097
  public void notifyReplicaNodes(SystemMetadata currentSystemMetadata) {
2098
2099
      Session session = null;
2100
      List<Replica> replicaList = currentSystemMetadata.getReplicaList();
2101 9294 tao
      //MNode mn = null;
2102 7073 cjones
      NodeReference replicaNodeRef = null;
2103
      CNode cn = null;
2104
      NodeType nodeType = null;
2105
      List<Node> nodeList = null;
2106
2107
      try {
2108
          cn = D1Client.getCN();
2109
          nodeList = cn.listNodes().getNodeList();
2110
2111
      } catch (Exception e) { // handle BaseException and other I/O issues
2112
2113
          // swallow errors since the call is not critical
2114
          logMetacat.error("Can't inform MNs of system metadata changes due " +
2115
              "to communication issues with the CN: " + e.getMessage());
2116
2117
      }
2118
2119
      if ( replicaList != null ) {
2120
2121
          // iterate through the replicas and inform  MN replica nodes
2122
          for (Replica replica : replicaList) {
2123 9294 tao
              String replicationVersion = null;
2124 7073 cjones
              replicaNodeRef = replica.getReplicaMemberNode();
2125
              try {
2126
                  if (nodeList != null) {
2127
                      // find the node type
2128
                      for (Node node : nodeList) {
2129 8450 cjones
                          if ( node.getIdentifier().getValue().equals(replicaNodeRef.getValue()) ) {
2130 7073 cjones
                              nodeType = node.getType();
2131 9294 tao
                              D1NodeVersionChecker checker = new D1NodeVersionChecker(replicaNodeRef);
2132
                              replicationVersion = checker.getVersion("MNRead");
2133 7073 cjones
                              break;
2134
2135
                          }
2136
                      }
2137
                  }
2138
2139
                  // notify only MNs
2140 9294 tao
                  if (replicationVersion != null && nodeType != null && nodeType == NodeType.MN) {
2141
                      if(replicationVersion.equalsIgnoreCase(D1NodeVersionChecker.V2)) {
2142
                          //connect to a v2 mn
2143
                          MNode mn = D1Client.getMN(replicaNodeRef);
2144
                          mn.systemMetadataChanged(session,
2145
                              currentSystemMetadata.getIdentifier(),
2146
                              currentSystemMetadata.getSerialVersion().longValue(),
2147
                              currentSystemMetadata.getDateSysMetadataModified());
2148
                      } else if (replicationVersion.equalsIgnoreCase(D1NodeVersionChecker.V1)) {
2149
                          //connect to a v1 mn
2150
                          org.dataone.client.v1.MNode mn = org.dataone.client.v1.itk.D1Client.getMN(replicaNodeRef);
2151
                          mn.systemMetadataChanged(session,
2152
                                  currentSystemMetadata.getIdentifier(),
2153
                                  currentSystemMetadata.getSerialVersion().longValue(),
2154
                                  currentSystemMetadata.getDateSysMetadataModified());
2155
                      }
2156
2157 7073 cjones
                  }
2158
2159
              } catch (Exception e) { // handle BaseException and other I/O issues
2160
2161
                  // swallow errors since the call is not critical
2162
                  logMetacat.error("Can't inform "
2163
                          + replicaNodeRef.getValue()
2164
                          + " of system metadata changes due "
2165
                          + "to communication issues with the CN: "
2166
                          + e.getMessage());
2167
2168
              }
2169
          }
2170
      }
2171
  }
2172 9177 tao
2173 9192 tao
  /**
2174
   * Update the system metadata of the specified pid.
2175
   */
2176
  @Override
2177
  public boolean updateSystemMetadata(Session session, Identifier pid,
2178
          SystemMetadata sysmeta) throws NotImplemented, NotAuthorized,
2179
          ServiceFailure, InvalidRequest, InvalidSystemMetadata, InvalidToken {
2180
   if(sysmeta == null) {
2181
       throw  new InvalidRequest("4863", "The system metadata object should NOT be null in the updateSystemMetadata request.");
2182
   }
2183
   if(pid == null || pid.getValue() == null) {
2184
       throw new InvalidRequest("4863", "Please specify the id in the updateSystemMetadata request ") ;
2185
   }
2186
2187
   if (session == null) {
2188
       //TODO: many of the thrown exceptions do not use the correct error codes
2189
       //check these against the docs and correct them
2190
       throw new NotAuthorized("4861", "No Session - could not authorize for updating system metadata." +
2191
               "  If you are not logged in, please do so and retry the request.");
2192
   } else {
2193
         //only CN is allwoed
2194
         if(!isCNAdmin(session)) {
2195
               throw new NotAuthorized("4861", "The client -"+ session.getSubject().getValue()+ "is not authorized for updating the system metadata of the object "+pid.getValue());
2196
         }
2197
   }
2198
    //update the system metadata locally
2199
    boolean success = super.updateSystemMetadata(session, pid, sysmeta);
2200
    return success;
2201
  }
2202
2203 9189 tao
    @Override
2204
    public boolean synchronize(Session session, Identifier pid) throws NotAuthorized, InvalidRequest, NotImplemented{
2205
        throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2206
2207 9177 tao
    }
2208 7144 leinfelder
2209
	@Override
2210 8810 leinfelder
	public QueryEngineDescription getQueryEngineDescription(Session session,
2211
			String queryEngine) throws InvalidToken, ServiceFailure, NotAuthorized,
2212
			NotImplemented, NotFound {
2213
		throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2214 7144 leinfelder
2215
	}
2216
2217
	@Override
2218 8810 leinfelder
	public QueryEngineList listQueryEngines(Session session) throws InvalidToken,
2219
			ServiceFailure, NotAuthorized, NotImplemented {
2220
		throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2221 7144 leinfelder
2222
	}
2223
2224
	@Override
2225 8810 leinfelder
	public InputStream query(Session session, String queryEngine, String query)
2226
			throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
2227
			NotImplemented, NotFound {
2228
		throw new NotImplemented("0000", "CN query services are not implemented in Metacat.");
2229 7144 leinfelder
2230
	}
2231
2232
	@Override
2233 8810 leinfelder
	public Node getCapabilities() throws NotImplemented, ServiceFailure {
2234
		throw new NotImplemented("0000", "The CN capabilities are not stored in Metacat.");
2235 7144 leinfelder
	}
2236 9189 tao
2237 6177 cjones
}