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