Project

General

Profile

1 6179 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 6228 cjones
import java.io.IOException;
27 6179 cjones
import java.io.InputStream;
28 6228 cjones
import java.security.NoSuchAlgorithmException;
29 6250 cjones
import java.sql.SQLException;
30 6600 cjones
import java.util.ArrayList;
31 6525 leinfelder
import java.util.Calendar;
32 6179 cjones
import java.util.Date;
33 6250 cjones
import java.util.List;
34 6389 leinfelder
import java.util.Timer;
35 6179 cjones
36 6542 leinfelder
import javax.servlet.http.HttpServletRequest;
37
38 6258 cjones
import org.apache.commons.io.IOUtils;
39 6179 cjones
import org.apache.log4j.Logger;
40 6528 cjones
import org.dataone.client.CNode;
41 6332 leinfelder
import org.dataone.client.D1Client;
42
import org.dataone.client.MNode;
43 6552 leinfelder
import org.dataone.client.auth.CertificateManager;
44
import org.dataone.configuration.Settings;
45 6179 cjones
import org.dataone.service.exceptions.IdentifierNotUnique;
46
import org.dataone.service.exceptions.InsufficientResources;
47
import org.dataone.service.exceptions.InvalidRequest;
48
import org.dataone.service.exceptions.InvalidSystemMetadata;
49
import org.dataone.service.exceptions.InvalidToken;
50
import org.dataone.service.exceptions.NotAuthorized;
51
import org.dataone.service.exceptions.NotFound;
52
import org.dataone.service.exceptions.NotImplemented;
53
import org.dataone.service.exceptions.ServiceFailure;
54 6185 leinfelder
import org.dataone.service.exceptions.SynchronizationFailed;
55 6179 cjones
import org.dataone.service.exceptions.UnsupportedType;
56 6622 leinfelder
import org.dataone.service.exceptions.VersionMismatch;
57 6366 leinfelder
import org.dataone.service.mn.tier1.v1.MNCore;
58
import org.dataone.service.mn.tier1.v1.MNRead;
59
import org.dataone.service.mn.tier2.v1.MNAuthorization;
60
import org.dataone.service.mn.tier3.v1.MNStorage;
61
import org.dataone.service.mn.tier4.v1.MNReplication;
62 6573 cjones
import org.dataone.service.types.v1.AccessPolicy;
63 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
64
import org.dataone.service.types.v1.DescribeResponse;
65
import org.dataone.service.types.v1.Event;
66
import org.dataone.service.types.v1.Group;
67
import org.dataone.service.types.v1.Identifier;
68
import org.dataone.service.types.v1.Log;
69
import org.dataone.service.types.v1.LogEntry;
70
import org.dataone.service.types.v1.MonitorInfo;
71
import org.dataone.service.types.v1.MonitorList;
72
import org.dataone.service.types.v1.Node;
73 6600 cjones
import org.dataone.service.types.v1.NodeList;
74 6366 leinfelder
import org.dataone.service.types.v1.NodeReference;
75
import org.dataone.service.types.v1.NodeState;
76
import org.dataone.service.types.v1.NodeType;
77
import org.dataone.service.types.v1.ObjectFormatIdentifier;
78
import org.dataone.service.types.v1.ObjectList;
79
import org.dataone.service.types.v1.Permission;
80
import org.dataone.service.types.v1.Ping;
81 6528 cjones
import org.dataone.service.types.v1.ReplicationStatus;
82 6366 leinfelder
import org.dataone.service.types.v1.Schedule;
83
import org.dataone.service.types.v1.Service;
84
import org.dataone.service.types.v1.Services;
85
import org.dataone.service.types.v1.Session;
86
import org.dataone.service.types.v1.Subject;
87 6600 cjones
import org.dataone.service.types.v1.SubjectList;
88 6366 leinfelder
import org.dataone.service.types.v1.Synchronization;
89
import org.dataone.service.types.v1.SystemMetadata;
90
import org.dataone.service.types.v1.util.ChecksumUtil;
91 6476 jones
import org.dataone.service.util.Constants;
92 6179 cjones
93 6250 cjones
import edu.ucsb.nceas.metacat.DocumentImpl;
94 6234 cjones
import edu.ucsb.nceas.metacat.EventLog;
95 6230 cjones
import edu.ucsb.nceas.metacat.IdentifierManager;
96 6234 cjones
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
97 6389 leinfelder
import edu.ucsb.nceas.metacat.MetacatHandler;
98 6250 cjones
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
99 6260 cjones
import edu.ucsb.nceas.metacat.database.DBConnection;
100
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
101 6648 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
102 6340 cjones
import edu.ucsb.nceas.metacat.properties.PropertyService;
103 6542 leinfelder
import edu.ucsb.nceas.metacat.util.SystemUtil;
104 6340 cjones
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
105 6230 cjones
106 6179 cjones
/**
107
 * Represents Metacat's implementation of the DataONE Member Node
108
 * service API. Methods implement the various MN* interfaces, and methods common
109
 * to both Member Node and Coordinating Node interfaces are found in the
110
 * D1NodeService base class.
111 6288 cjones
 *
112
 * Implements:
113
 * MNCore.ping()
114
 * MNCore.getLogRecords()
115
 * MNCore.getObjectStatistics()
116
 * MNCore.getOperationStatistics()
117
 * MNCore.getStatus()
118
 * MNCore.getCapabilities()
119
 * MNRead.get()
120
 * MNRead.getSystemMetadata()
121
 * MNRead.describe()
122
 * MNRead.getChecksum()
123
 * MNRead.listObjects()
124
 * MNRead.synchronizationFailed()
125
 * MNAuthorization.isAuthorized()
126
 * MNAuthorization.setAccessPolicy()
127
 * MNStorage.create()
128
 * MNStorage.update()
129
 * MNStorage.delete()
130
 * MNReplication.replicate()
131
 *
132 6179 cjones
 */
133 6599 cjones
public class MNodeService extends D1NodeService
134
    implements MNAuthorization, MNCore, MNRead, MNReplication, MNStorage {
135 6179 cjones
136 6475 jones
    /* the logger instance */
137
    private Logger logMetacat = null;
138 6241 cjones
139 6475 jones
    /**
140
     * Singleton accessor to get an instance of MNodeService.
141
     *
142
     * @return instance - the instance of MNodeService
143
     */
144 6542 leinfelder
    public static MNodeService getInstance(HttpServletRequest request) {
145
        return new MNodeService(request);
146 6179 cjones
    }
147
148 6475 jones
    /**
149
     * Constructor, private for singleton access
150
     */
151 6542 leinfelder
    private MNodeService(HttpServletRequest request) {
152
        super(request);
153 6475 jones
        logMetacat = Logger.getLogger(MNodeService.class);
154 6552 leinfelder
155
        // set the Member Node certificate file location
156
        CertificateManager.getInstance().setCertificateLocation(Settings.getConfiguration().getString("D1Client.certificate.file"));
157 6310 cjones
    }
158 6475 jones
159
    /**
160
     * Deletes an object from the Member Node, where the object is either a
161
     * data object or a science metadata object.
162
     *
163
     * @param session - the Session object containing the credentials for the Subject
164
     * @param pid - The object identifier to be deleted
165
     *
166
     * @return pid - the identifier of the object used for the deletion
167
     *
168
     * @throws InvalidToken
169
     * @throws ServiceFailure
170
     * @throws NotAuthorized
171
     * @throws NotFound
172
     * @throws NotImplemented
173
     * @throws InvalidRequest
174
     */
175
    @Override
176
    public Identifier delete(Session session, Identifier pid)
177 6610 cjones
        throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
178 6475 jones
179
        String localId = null;
180
        boolean allowed = false;
181 6532 leinfelder
        String username = Constants.SUBJECT_PUBLIC;
182 6475 jones
        String[] groupnames = null;
183 6645 leinfelder
        if (session == null) {
184
        	throw new InvalidToken("1330", "No session has been provided");
185
        } else {
186 6475 jones
            username = session.getSubject().getValue();
187 6532 leinfelder
            if (session.getSubjectInfo() != null) {
188
                List<Group> groupList = session.getSubjectInfo().getGroupList();
189 6475 jones
                if (groupList != null) {
190
                    groupnames = new String[groupList.size()];
191
                    for (int i = 0; i > groupList.size(); i++) {
192
                        groupnames[i] = groupList.get(i).getGroupName();
193
                    }
194
                }
195
            }
196
        }
197
198
        // do we have a valid pid?
199
        if (pid == null || pid.getValue().trim().equals("")) {
200 6610 cjones
            throw new ServiceFailure("1350", "The provided identifier was invalid.");
201 6475 jones
        }
202
203
        // check for the existing identifier
204
        try {
205
            localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
206
        } catch (McdbDocNotFoundException e) {
207 6610 cjones
            throw new NotFound("1340", "The object with the provided " + "identifier was not found.");
208 6475 jones
        }
209
210
        // does the subject have DELETE (a D1 CHANGE_PERMISSION level) priveleges on the pid?
211
        allowed = isAuthorized(session, pid, Permission.CHANGE_PERMISSION);
212 6610 cjones
213 6475 jones
214
        if (allowed) {
215
            try {
216
                // delete the document
217
                DocumentImpl.delete(localId, username, groupnames, null);
218 6542 leinfelder
                EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), username, localId, Event.DELETE.xmlValue());
219 6475 jones
220 6648 leinfelder
                // remove the system metadata for it
221
                HazelcastService.getInstance().getSystemMetadataMap().remove(pid);
222
223 6475 jones
            } catch (McdbDocNotFoundException e) {
224 6610 cjones
                throw new NotFound("1340", "The provided identifier was invalid.");
225 6475 jones
226
            } catch (SQLException e) {
227
                throw new ServiceFailure("1350", "There was a problem deleting the object." + "The error message was: " + e.getMessage());
228
229
            } catch (InsufficientKarmaException e) {
230
                throw new NotAuthorized("1320", "The provided identity does not have " + "permission to DELETE objects on the Member Node.");
231
232
            } catch (Exception e) { // for some reason DocumentImpl throws a general Exception
233
                throw new ServiceFailure("1350", "There was a problem deleting the object." + "The error message was: " + e.getMessage());
234
            }
235
236
        } else {
237
            throw new NotAuthorized("1320", "The provided identity does not have " + "permission to DELETE objects on the Member Node.");
238
        }
239
240
        return pid;
241 6250 cjones
    }
242
243 6475 jones
    /**
244
     * Updates an existing object by creating a new object identified by
245
     * newPid on the Member Node which explicitly obsoletes the object
246
     * identified by pid through appropriate changes to the SystemMetadata
247
     * of pid and newPid
248
     *
249
     * @param session - the Session object containing the credentials for the Subject
250
     * @param pid - The identifier of the object to be updated
251
     * @param object - the new object bytes
252
     * @param sysmeta - the new system metadata describing the object
253
     *
254
     * @return newPid - the identifier of the new object
255
     *
256
     * @throws InvalidToken
257
     * @throws ServiceFailure
258
     * @throws NotAuthorized
259
     * @throws NotFound
260
     * @throws NotImplemented
261
     * @throws IdentifierNotUnique
262
     * @throws UnsupportedType
263
     * @throws InsufficientResources
264
     * @throws InvalidSystemMetadata
265
     * @throws InvalidRequest
266
     */
267
    @Override
268 6575 cjones
    public Identifier update(Session session, Identifier pid, InputStream object,
269
        Identifier newPid, SystemMetadata sysmeta)
270
        throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
271
        UnsupportedType, InsufficientResources, NotFound,
272
        InvalidSystemMetadata, NotImplemented, InvalidRequest {
273 6250 cjones
274 6475 jones
        String localId = null;
275
        boolean allowed = false;
276
        boolean isScienceMetadata = false;
277 6645 leinfelder
278
        if (session == null) {
279
        	throw new InvalidToken("1210", "No session has been provided");
280
        }
281 6475 jones
        Subject subject = session.getSubject();
282
283
        // do we have a valid pid?
284
        if (pid == null || pid.getValue().trim().equals("")) {
285
            throw new InvalidRequest("1202", "The provided identifier was invalid.");
286 6575 cjones
287 6475 jones
        }
288
289
        // check for the existing identifier
290
        try {
291
            localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
292 6575 cjones
293 6475 jones
        } catch (McdbDocNotFoundException e) {
294 6575 cjones
            throw new InvalidRequest("1202", "The object with the provided " +
295
                "identifier was not found.");
296
297 6475 jones
        }
298 6518 leinfelder
299 6521 leinfelder
        // set the originating node
300
        NodeReference originMemberNode = this.getCapabilities().getIdentifier();
301
        sysmeta.setOriginMemberNode(originMemberNode);
302
303 6518 leinfelder
        // set the submitter to match the certificate
304
        sysmeta.setSubmitter(subject);
305 6525 leinfelder
        // set the dates
306
        Date now = Calendar.getInstance().getTime();
307 6575 cjones
        sysmeta.setDateSysMetadataModified(now);
308
        sysmeta.setDateUploaded(now);
309 6475 jones
310
        // does the subject have WRITE ( == update) priveleges on the pid?
311
        allowed = isAuthorized(session, pid, Permission.WRITE);
312
313
        if (allowed) {
314 6649 leinfelder
315
        	// check quality of SM
316
        	if (sysmeta.getObsoletedBy() != null) {
317
        		throw new InvalidSystemMetadata("1300", "Cannot include obsoletedBy when updating object");
318
        	}
319
        	if (sysmeta.getObsoletes() != null && !sysmeta.getObsoletes().getValue().equals(pid.getValue())) {
320
        		throw new InvalidSystemMetadata("1300", "The identifier provided in obsoletes does not match old Identifier");
321
        	}
322 6475 jones
323
            // get the existing system metadata for the object
324
            SystemMetadata existingSysMeta = getSystemMetadata(session, pid);
325
326
            // add the newPid to the obsoletedBy list for the existing sysmeta
327
            existingSysMeta.setObsoletedBy(newPid);
328
329
            // then update the existing system metadata
330
            updateSystemMetadata(existingSysMeta);
331
332
            // prep the new system metadata, add pid to the affected lists
333
            sysmeta.setObsoletes(pid);
334
            //sysmeta.addDerivedFrom(pid);
335
336
            isScienceMetadata = isScienceMetadata(sysmeta);
337
338
            // do we have XML metadata or a data object?
339
            if (isScienceMetadata) {
340
341
                // update the science metadata XML document
342
                // TODO: handle non-XML metadata/data documents (like netCDF)
343
                // TODO: don't put objects into memory using stream to string
344
                String objectAsXML = "";
345
                try {
346
                    objectAsXML = IOUtils.toString(object, "UTF-8");
347
                    localId = insertOrUpdateDocument(objectAsXML, newPid, session, "update");
348
                    // register the newPid and the generated localId
349
                    if (newPid != null) {
350
                        IdentifierManager.getInstance().createMapping(newPid.getValue(), localId);
351
352
                    }
353
354
                } catch (IOException e) {
355
                    String msg = "The Node is unable to create the object. " + "There was a problem converting the object to XML";
356
                    logMetacat.info(msg);
357
                    throw new ServiceFailure("1310", msg + ": " + e.getMessage());
358
359
                }
360
361
            } else {
362
363
                // update the data object
364
                localId = insertDataObject(object, newPid, session);
365
366
            }
367
368
            // and insert the new system metadata
369
            insertSystemMetadata(sysmeta);
370
371
            // log the update event
372 6542 leinfelder
            EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), subject.getValue(), localId, Event.UPDATE.toString());
373 6475 jones
374
        } else {
375
            throw new NotAuthorized("1200", "The provided identity does not have " + "permission to UPDATE the object identified by " + pid.getValue()
376
                    + " on the Member Node.");
377
        }
378
379
        return newPid;
380 6250 cjones
    }
381 6254 cjones
382 6475 jones
    public Identifier create(Session session, Identifier pid, InputStream object, SystemMetadata sysmeta) throws InvalidToken, ServiceFailure, NotAuthorized,
383
            IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, InvalidRequest {
384 6250 cjones
385 6575 cjones
      // check for null session
386 6530 leinfelder
        if (session == null) {
387 6575 cjones
          throw new InvalidToken("1110", "Session is required to WRITE to the Node.");
388 6530 leinfelder
        }
389 6518 leinfelder
        // set the submitter to match the certificate
390
        sysmeta.setSubmitter(session.getSubject());
391 6520 leinfelder
        // set the originating node
392
        NodeReference originMemberNode = this.getCapabilities().getIdentifier();
393
        sysmeta.setOriginMemberNode(originMemberNode);
394 6525 leinfelder
        // set the dates
395
        Date now = Calendar.getInstance().getTime();
396 6575 cjones
    sysmeta.setDateSysMetadataModified(now);
397
    sysmeta.setDateUploaded(now);
398 6518 leinfelder
        // call the shared impl
399 6475 jones
        return super.create(session, pid, object, sysmeta);
400
    }
401 6250 cjones
402 6475 jones
    /**
403
     * Called by a Coordinating Node to request that the Member Node create a
404
     * copy of the specified object by retrieving it from another Member
405
     * Node and storing it locally so that it can be made accessible to
406
     * the DataONE system.
407
     *
408
     * @param session - the Session object containing the credentials for the Subject
409
     * @param sysmeta - Copy of the CN held system metadata for the object
410
     * @param sourceNode - A reference to node from which the content should be
411
     *                     retrieved. The reference should be resolved by
412
     *                     checking the CN node registry.
413
     *
414
     * @return true if the replication succeeds
415
     *
416
     * @throws ServiceFailure
417
     * @throws NotAuthorized
418
     * @throws NotImplemented
419
     * @throws UnsupportedType
420
     * @throws InsufficientResources
421
     * @throws InvalidRequest
422
     */
423
    @Override
424 6528 cjones
    public boolean replicate(Session session, SystemMetadata sysmeta, NodeReference sourceNode)
425
        throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest,
426
        InsufficientResources, UnsupportedType {
427 6663 leinfelder
428
    	// cannot be called by public
429
        if (session == null) {
430
        	throw new NotAuthorized("2152", "No session was provided.");
431
        }
432 6250 cjones
433 6540 cjones
        logMetacat.info("MNodeService.replicate() called with parameters: \n" +
434
            "\tSession.Subject      = " + session.getSubject().getValue() + "\n" +
435
            "\tSystemMetadata       = " + sysmeta.toString()              + "\n" +
436
            "\tSource NodeReference ="  + sourceNode.getValue());
437
438 6475 jones
        boolean result = false;
439 6651 cjones
        String nodeIdStr  = null;
440
        NodeReference nodeId = null;
441
442
        // get the local node id
443
        try {
444
            nodeIdStr = PropertyService.getProperty("dataone.memberNodeId");
445
            nodeId = new NodeReference();
446
            nodeId.setValue(nodeIdStr);
447
448
        } catch (PropertyNotFoundException e1) {
449
            logMetacat.error("Couldn't get dataone.memberNodeId property: " +
450
                e1.getMessage());
451
452
        }
453 6475 jones
        // TODO: check credentials
454
455
        // get the referenced object
456
        Identifier pid = sysmeta.getIdentifier();
457
458
        // get from the membernode
459
        // TODO: switch credentials for the server retrieval?
460
        MNode mn = D1Client.getMN(sourceNode);
461 6528 cjones
        CNode cn = D1Client.getCN();
462 6599 cjones
        long serialVersion = sysmeta.getSerialVersion().longValue();
463 6475 jones
        InputStream object = null;
464 6630 cjones
        Session thisNodeSession = null;
465 6552 leinfelder
466 6475 jones
        try {
467 6575 cjones
          // session should be null to use the default certificate location set in the Certificate manager
468 6630 cjones
            object = mn.getReplica(thisNodeSession, pid);
469 6540 cjones
            logMetacat.info("MNodeService.replicate() called for identifier " + pid.getValue());
470
471 6475 jones
        } catch (InvalidToken e) {
472
            e.printStackTrace();
473
            throw new ServiceFailure("2151", "Could not retrieve object to replicate (InvalidToken): " + e.getMessage());
474
        } catch (NotFound e) {
475
            e.printStackTrace();
476
            throw new ServiceFailure("2151", "Could not retrieve object to replicate (NotFound): " + e.getMessage());
477
        }
478
479
        // add it to local store
480
        Identifier retPid;
481
        try {
482 6575 cjones
          // skip the MN.create -- this mutates the system metadata and we dont want it to
483 6552 leinfelder
            retPid = super.create(session, pid, object, sysmeta);
484 6475 jones
            result = (retPid.getValue().equals(pid.getValue()));
485
        } catch (InvalidToken e) {
486
            e.printStackTrace();
487
            throw new ServiceFailure("2151", "Could not save object to local store (InvalidToken): " + e.getMessage());
488
        } catch (IdentifierNotUnique e) {
489
            e.printStackTrace();
490
            throw new ServiceFailure("2151", "Could not save object to local store (IdentifierNotUnique): " + e.getMessage());
491
        } catch (InvalidSystemMetadata e) {
492
            e.printStackTrace();
493
            throw new ServiceFailure("2151", "Could not save object to local store (InvalidSystemMetadata): " + e.getMessage());
494
        }
495
496 6528 cjones
        try {
497 6575 cjones
          // call the CN as the MN to set the replication status
498 6651 cjones
            cn.setReplicationStatus(thisNodeSession, pid, nodeId, ReplicationStatus.COMPLETED, serialVersion);
499 6528 cjones
500
        } catch (InvalidToken e) {
501
            // TODO Auto-generated catch block
502
            e.printStackTrace();
503
        } catch (NotFound e) {
504
            // TODO Auto-generated catch block
505
            e.printStackTrace();
506 6622 leinfelder
        } catch (VersionMismatch e) {
507
			// TODO Auto-generated catch block
508
			e.printStackTrace();
509
		}
510 6475 jones
        return result;
511
512 6250 cjones
    }
513 6179 cjones
514 6475 jones
    /**
515
     * This method provides a lighter weight mechanism than
516
     * MN_read.getSystemMetadata() for a client to determine basic
517
     * properties of the referenced object.
518
     *
519
     * @param session - the Session object containing the credentials for the Subject
520
     * @param pid - the identifier of the object to be described
521
     *
522
     * @return describeResponse - A set of values providing a basic description
523
     *                            of the object.
524
     *
525
     * @throws InvalidToken
526
     * @throws ServiceFailure
527
     * @throws NotAuthorized
528
     * @throws NotFound
529
     * @throws NotImplemented
530
     * @throws InvalidRequest
531
     */
532
    @Override
533 6610 cjones
    public DescribeResponse describe(Session session, Identifier pid)
534
        throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
535 6251 cjones
536 6575 cjones
      // get system metadata and construct the describe response
537 6475 jones
        SystemMetadata sysmeta = getSystemMetadata(session, pid);
538 6561 leinfelder
        DescribeResponse describeResponse = new DescribeResponse(sysmeta.getFormatId(), sysmeta.getSize(), sysmeta.getDateSysMetadataModified(),
539 6475 jones
                sysmeta.getChecksum());
540
541
        return describeResponse;
542
543 6259 cjones
    }
544 6258 cjones
545 6475 jones
    /**
546
     * Return the object identified by the given object identifier
547
     *
548
     * @param session - the Session object containing the credentials for the Subject
549
     * @param pid - the object identifier for the given object
550
     *
551
     * @return inputStream - the input stream of the given object
552
     *
553
     * @throws InvalidToken
554
     * @throws ServiceFailure
555
     * @throws NotAuthorized
556
     * @throws InvalidRequest
557
     * @throws NotImplemented
558
     */
559
    @Override
560 6610 cjones
    public InputStream get(Session session, Identifier pid)
561
    throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented {
562 6258 cjones
563 6475 jones
        return super.get(session, pid);
564 6258 cjones
565 6259 cjones
    }
566 6258 cjones
567 6475 jones
    /**
568
     * Returns a Checksum for the specified object using an accepted hashing algorithm
569
     *
570
     * @param session - the Session object containing the credentials for the Subject
571
     * @param pid - the object identifier for the given object
572
     * @param algorithm -  the name of an algorithm that will be used to compute
573
     *                     a checksum of the bytes of the object
574
     *
575
     * @return checksum - the checksum of the given object
576
     *
577
     * @throws InvalidToken
578
     * @throws ServiceFailure
579
     * @throws NotAuthorized
580
     * @throws NotFound
581
     * @throws InvalidRequest
582
     * @throws NotImplemented
583
     */
584
    @Override
585 6610 cjones
    public Checksum getChecksum(Session session, Identifier pid, String algorithm)
586
        throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
587
        InvalidRequest, NotImplemented {
588 6258 cjones
589 6475 jones
        Checksum checksum = null;
590
591
        InputStream inputStream = get(session, pid);
592
593 6259 cjones
        try {
594 6475 jones
            checksum = ChecksumUtil.checksum(inputStream, algorithm);
595
596
        } catch (NoSuchAlgorithmException e) {
597
            throw new ServiceFailure("1410", "The checksum for the object specified by " + pid.getValue() + "could not be returned due to an internal error: "
598
                    + e.getMessage());
599 6259 cjones
        } catch (IOException e) {
600 6475 jones
            throw new ServiceFailure("1410", "The checksum for the object specified by " + pid.getValue() + "could not be returned due to an internal error: "
601
                    + e.getMessage());
602 6259 cjones
        }
603 6382 cjones
604 6475 jones
        if (checksum == null) {
605
            throw new ServiceFailure("1410", "The checksum for the object specified by " + pid.getValue() + "could not be returned.");
606
        }
607 6258 cjones
608 6475 jones
        return checksum;
609 6259 cjones
    }
610 6179 cjones
611 6475 jones
    /**
612
     * Return the system metadata for a given object
613
     *
614
     * @param session - the Session object containing the credentials for the Subject
615
     * @param pid - the object identifier for the given object
616
     *
617
     * @return inputStream - the input stream of the given system metadata object
618
     *
619
     * @throws InvalidToken
620
     * @throws ServiceFailure
621
     * @throws NotAuthorized
622
     * @throws NotFound
623
     * @throws InvalidRequest
624
     * @throws NotImplemented
625
     */
626
    @Override
627 6610 cjones
    public SystemMetadata getSystemMetadata(Session session, Identifier pid)
628
        throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
629
        NotImplemented {
630 6341 leinfelder
631 6475 jones
        return super.getSystemMetadata(session, pid);
632
    }
633 6341 leinfelder
634 6475 jones
    /**
635
     * Retrieve the list of objects present on the MN that match the calling parameters
636
     *
637
     * @param session - the Session object containing the credentials for the Subject
638
     * @param startTime - Specifies the beginning of the time range from which
639
     *                    to return object (>=)
640
     * @param endTime - Specifies the beginning of the time range from which
641
     *                  to return object (>=)
642
     * @param objectFormat - Restrict results to the specified object format
643
     * @param replicaStatus - Indicates if replicated objects should be returned in the list
644
     * @param start - The zero-based index of the first value, relative to the
645
     *                first record of the resultset that matches the parameters.
646
     * @param count - The maximum number of entries that should be returned in
647
     *                the response. The Member Node may return less entries
648
     *                than specified in this value.
649
     *
650
     * @return objectList - the list of objects matching the criteria
651
     *
652
     * @throws InvalidToken
653
     * @throws ServiceFailure
654
     * @throws NotAuthorized
655
     * @throws InvalidRequest
656
     * @throws NotImplemented
657
     */
658
    @Override
659
    public ObjectList listObjects(Session session, Date startTime, Date endTime, ObjectFormatIdentifier objectFormatId, Boolean replicaStatus, Integer start,
660
            Integer count) throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken {
661 6179 cjones
662 6475 jones
        ObjectList objectList = null;
663 6332 leinfelder
664 6475 jones
        try {
665
            objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, objectFormatId, replicaStatus, start, count);
666
        } catch (Exception e) {
667
            throw new ServiceFailure("1580", "Error querying system metadata: " + e.getMessage());
668
        }
669 6332 leinfelder
670 6475 jones
        return objectList;
671 6229 cjones
    }
672 6179 cjones
673 6475 jones
    /**
674 6476 jones
     * Return a description of the node's capabilities and services.
675 6475 jones
     *
676
     * @return node - the technical capabilities of the Member Node
677
     *
678
     * @throws ServiceFailure
679
     * @throws NotAuthorized
680
     * @throws InvalidRequest
681
     * @throws NotImplemented
682
     */
683
    @Override
684 6610 cjones
    public Node getCapabilities()
685
        throws NotImplemented, ServiceFailure {
686 6179 cjones
687 6475 jones
        String nodeName = null;
688
        String nodeId = null;
689 6492 jones
        String subject = null;
690 6475 jones
        String nodeDesc = null;
691 6476 jones
        String nodeTypeString = null;
692
        NodeType nodeType = null;
693 6475 jones
        String mnCoreServiceVersion = null;
694
        String mnReadServiceVersion = null;
695
        String mnAuthorizationServiceVersion = null;
696
        String mnStorageServiceVersion = null;
697
        String mnReplicationServiceVersion = null;
698 6179 cjones
699 6475 jones
        boolean nodeSynchronize = false;
700
        boolean nodeReplicate = false;
701
        boolean mnCoreServiceAvailable = false;
702
        boolean mnReadServiceAvailable = false;
703
        boolean mnAuthorizationServiceAvailable = false;
704
        boolean mnStorageServiceAvailable = false;
705
        boolean mnReplicationServiceAvailable = false;
706 6179 cjones
707 6475 jones
        try {
708
            // get the properties of the node based on configuration information
709 6492 jones
            nodeName = PropertyService.getProperty("dataone.nodeName");
710 6475 jones
            nodeId = PropertyService.getProperty("dataone.memberNodeId");
711 6492 jones
            subject = PropertyService.getProperty("dataone.subject");
712 6475 jones
            nodeDesc = PropertyService.getProperty("dataone.nodeDescription");
713 6476 jones
            nodeTypeString = PropertyService.getProperty("dataone.nodeType");
714
            nodeType = NodeType.convert(nodeTypeString);
715 6475 jones
            nodeSynchronize = new Boolean(PropertyService.getProperty("dataone.nodeSynchronize")).booleanValue();
716
            nodeReplicate = new Boolean(PropertyService.getProperty("dataone.nodeReplicate")).booleanValue();
717
718
            mnCoreServiceVersion = PropertyService.getProperty("dataone.mnCore.serviceVersion");
719
            mnReadServiceVersion = PropertyService.getProperty("dataone.mnRead.serviceVersion");
720
            mnAuthorizationServiceVersion = PropertyService.getProperty("dataone.mnAuthorization.serviceVersion");
721
            mnStorageServiceVersion = PropertyService.getProperty("dataone.mnStorage.serviceVersion");
722
            mnReplicationServiceVersion = PropertyService.getProperty("dataone.mnReplication.serviceVersion");
723
724
            mnCoreServiceAvailable = new Boolean(PropertyService.getProperty("dataone.mnCore.serviceAvailable")).booleanValue();
725
            mnReadServiceAvailable = new Boolean(PropertyService.getProperty("dataone.mnRead.serviceAvailable")).booleanValue();
726
            mnAuthorizationServiceAvailable = new Boolean(PropertyService.getProperty("dataone.mnAuthorization.serviceAvailable")).booleanValue();
727
            mnStorageServiceAvailable = new Boolean(PropertyService.getProperty("dataone.mnStorage.serviceAvailable")).booleanValue();
728
            mnReplicationServiceAvailable = new Boolean(PropertyService.getProperty("dataone.mnReplication.serviceAvailable")).booleanValue();
729
730 6476 jones
            // Set the properties of the node based on configuration information and
731
            // calls to current status methods
732 6542 leinfelder
            String serviceName = SystemUtil.getContextURL() + "/" + PropertyService.getProperty("dataone.serviceName");
733 6476 jones
            Node node = new Node();
734 6542 leinfelder
            node.setBaseURL(serviceName + "/" + nodeTypeString);
735 6476 jones
            node.setDescription(nodeDesc);
736 6475 jones
737 6476 jones
            // set the node's health information
738
            node.setState(NodeState.UP);
739
740
            // set the ping response to the current value
741
            Ping canPing = new Ping();
742
            canPing.setSuccess(false);
743
            try {
744
                canPing.setSuccess(ping());
745
            } catch (InsufficientResources e) {
746
                e.printStackTrace();
747
            }
748 6610 cjones
749 6476 jones
            node.setPing(canPing);
750 6475 jones
751 6476 jones
            NodeReference identifier = new NodeReference();
752
            identifier.setValue(nodeId);
753
            node.setIdentifier(identifier);
754 6492 jones
            Subject s = new Subject();
755
            s.setValue(subject);
756
            node.addSubject(s);
757 6476 jones
            node.setName(nodeName);
758
            node.setReplicate(nodeReplicate);
759
            node.setSynchronize(nodeSynchronize);
760 6475 jones
761 6476 jones
            // services: MNAuthorization, MNCore, MNRead, MNReplication, MNStorage
762
            Services services = new Services();
763 6475 jones
764 6476 jones
            Service sMNCore = new Service();
765
            sMNCore.setName("MNCore");
766
            sMNCore.setVersion(mnCoreServiceVersion);
767
            sMNCore.setAvailable(mnCoreServiceAvailable);
768 6475 jones
769 6476 jones
            Service sMNRead = new Service();
770
            sMNRead.setName("MNRead");
771
            sMNRead.setVersion(mnReadServiceVersion);
772
            sMNRead.setAvailable(mnReadServiceAvailable);
773 6475 jones
774 6476 jones
            Service sMNAuthorization = new Service();
775
            sMNAuthorization.setName("MNAuthorization");
776
            sMNAuthorization.setVersion(mnAuthorizationServiceVersion);
777
            sMNAuthorization.setAvailable(mnAuthorizationServiceAvailable);
778 6475 jones
779 6476 jones
            Service sMNStorage = new Service();
780
            sMNStorage.setName("MNStorage");
781
            sMNStorage.setVersion(mnStorageServiceVersion);
782
            sMNStorage.setAvailable(mnStorageServiceAvailable);
783 6475 jones
784 6476 jones
            Service sMNReplication = new Service();
785
            sMNReplication.setName("MNReplication");
786
            sMNReplication.setVersion(mnReplicationServiceVersion);
787
            sMNReplication.setAvailable(mnReplicationServiceAvailable);
788 6475 jones
789 6476 jones
            services.addService(sMNRead);
790
            services.addService(sMNCore);
791
            services.addService(sMNAuthorization);
792
            services.addService(sMNStorage);
793
            services.addService(sMNReplication);
794
            node.setServices(services);
795 6475 jones
796 6476 jones
            // TODO: Allow the metacat admin to determine the schedule
797
            // Set the schedule for synchronization
798
            Synchronization synchronization = new Synchronization();
799
            Schedule schedule = new Schedule();
800
            Date now = new Date();
801
            schedule.setYear("*");
802
            schedule.setMon("*");
803
            schedule.setMday("*");
804 6512 jones
            schedule.setWday("?");
805 6476 jones
            schedule.setHour("*");
806 6512 jones
            schedule.setMin("0/3");
807
            schedule.setSec("10");
808 6476 jones
            synchronization.setSchedule(schedule);
809
            synchronization.setLastHarvested(now);
810
            synchronization.setLastCompleteHarvest(now);
811
            node.setSynchronization(synchronization);
812 6475 jones
813 6476 jones
            node.setType(nodeType);
814
            return node;
815 6475 jones
816 6476 jones
        } catch (PropertyNotFoundException pnfe) {
817
            String msg = "MNodeService.getCapabilities(): " + "property not found: " + pnfe.getMessage();
818
            logMetacat.error(msg);
819
            throw new ServiceFailure("2162", msg);
820
        }
821 6228 cjones
    }
822 6179 cjones
823 6475 jones
    /**
824
     * Returns the number of operations that have been serviced by the node
825
     * over time periods of one and 24 hours.
826
     *
827
     * @param session - the Session object containing the credentials for the Subject
828
     * @param period - An ISO8601 compatible DateTime range specifying the time
829
     *                 range for which to return operation statistics.
830
     * @param requestor - Limit to operations performed by given requestor identity.
831
     * @param event -  Enumerated value indicating the type of event being examined
832
     * @param format - Limit to events involving objects of the specified format
833
     *
834
     * @return the desired log records
835
     *
836
     * @throws InvalidToken
837
     * @throws ServiceFailure
838
     * @throws NotAuthorized
839
     * @throws InvalidRequest
840
     * @throws NotImplemented
841
     */
842 6610 cjones
    public MonitorList getOperationStatistics(Session session, Date startTime,
843
        Date endTime, Subject requestor, Event event, ObjectFormatIdentifier formatId)
844
        throws NotImplemented, ServiceFailure, NotAuthorized, InsufficientResources, UnsupportedType {
845 6179 cjones
846 6475 jones
        MonitorList monitorList = new MonitorList();
847 6179 cjones
848 6475 jones
        try {
849 6179 cjones
850 6475 jones
            // get log records first
851
            Log logs = getLogRecords(session, startTime, endTime, event, 0, null);
852 6179 cjones
853 6475 jones
            // TODO: aggregate by day or hour -- needs clarification
854
            int count = 1;
855
            for (LogEntry logEntry : logs.getLogEntryList()) {
856
                Identifier pid = logEntry.getIdentifier();
857
                Date logDate = logEntry.getDateLogged();
858
                // if we are filtering by format
859
                if (formatId != null) {
860
                    SystemMetadata sysmeta = IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
861 6561 leinfelder
                    if (!sysmeta.getFormatId().getValue().equals(formatId.getValue())) {
862 6475 jones
                        // does not match
863
                        continue;
864
                    }
865
                }
866
                MonitorInfo item = new MonitorInfo();
867
                item.setCount(count);
868
                item.setDate(new java.sql.Date(logDate.getTime()));
869
                monitorList.addMonitorInfo(item);
870 6179 cjones
871 6475 jones
            }
872
        } catch (Exception e) {
873
            e.printStackTrace();
874
            throw new ServiceFailure("2081", "Could not retrieve statistics: " + e.getMessage());
875
        }
876 6345 cjones
877 6475 jones
        return monitorList;
878 6345 cjones
879 6340 cjones
    }
880
881 6475 jones
    /**
882
     * Low level “are you alive” operation. A valid ping response is
883
     * indicated by a HTTP status of 200.
884
     *
885
     * @return true if the service is alive
886
     *
887
     * @throws InvalidToken
888
     * @throws ServiceFailure
889
     * @throws NotImplemented
890
     */
891
    @Override
892 6610 cjones
    public boolean ping()
893
        throws NotImplemented, ServiceFailure, InsufficientResources {
894 6475 jones
895
        // test if we can get a database connection
896
        boolean alive = false;
897
        int serialNumber = -1;
898
        DBConnection dbConn = null;
899
        try {
900
            dbConn = DBConnectionPool.getDBConnection("MNodeService.ping");
901
            serialNumber = dbConn.getCheckOutSerialNumber();
902
            alive = true;
903
        } catch (SQLException e) {
904
            return alive;
905
        } finally {
906
            // Return the database connection
907
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
908
        }
909
910
        return alive;
911 6351 cjones
    }
912
913 6475 jones
    /**
914
     * A callback method used by a CN to indicate to a MN that it cannot
915
     * complete synchronization of the science metadata identified by pid.  Log
916
     * the event in the metacat event log.
917
     *
918
     * @param session
919
     * @param syncFailed
920
     *
921
     * @throws ServiceFailure
922
     * @throws NotAuthorized
923
     * @throws NotImplemented
924
     */
925
    @Override
926 6610 cjones
    public void synchronizationFailed(Session session, SynchronizationFailed syncFailed)
927
        throws NotImplemented, ServiceFailure, NotAuthorized {
928 6179 cjones
929 6475 jones
        String localId;
930 6331 leinfelder
931 6475 jones
        try {
932
            localId = IdentifierManager.getInstance().getLocalId(syncFailed.getPid());
933
        } catch (McdbDocNotFoundException e) {
934 6610 cjones
            throw new ServiceFailure("2161", "The identifier specified by " + syncFailed.getPid() + " was not found on this node.");
935 6179 cjones
936 6475 jones
        }
937
        // TODO: update the CN URL below when the CNRead.SynchronizationFailed
938
        // method is changed to include the URL as a parameter
939
        logMetacat.debug("Synchronization for the object identified by " + syncFailed.getPid() + " failed from " + syncFailed.getNodeId()
940
                + " Logging the event to the Metacat EventLog as a 'syncFailed' event.");
941
        // TODO: use the event type enum when the SYNCHRONIZATION_FAILED event is added
942 6532 leinfelder
        String principal = Constants.SUBJECT_PUBLIC;
943 6506 leinfelder
        if (session != null && session.getSubject() != null) {
944 6575 cjones
          principal = session.getSubject().getValue();
945 6506 leinfelder
        }
946
        try {
947 6575 cjones
          EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), principal, localId, "synchronization_failed");
948 6506 leinfelder
        } catch (Exception e) {
949
            throw new ServiceFailure("2161", "Could not log the error for: " + syncFailed.getPid());
950 6575 cjones
    }
951 6475 jones
        //EventLog.getInstance().log("CN URL WILL GO HERE",
952
        //  session.getSubject().getValue(), localId, Event.SYNCHRONIZATION_FAILED);
953 6179 cjones
954 6260 cjones
    }
955
956 6475 jones
    /**
957
     * Essentially a get() but with different logging behavior
958
     */
959
    @Override
960 6540 cjones
    public InputStream getReplica(Session session, Identifier pid)
961 6653 leinfelder
        throws NotAuthorized, NotImplemented, ServiceFailure, InvalidToken {
962 6179 cjones
963 6540 cjones
        logMetacat.info("MNodeService.getReplica() called.");
964
965 6653 leinfelder
        // cannot be called by public
966
        if (session == null) {
967
        	throw new InvalidToken("2183", "No session was provided.");
968
        }
969
970 6631 cjones
        logMetacat.info("MNodeService.getReplica() called with parameters: \n" +
971
             "\tSession.Subject      = " + session.getSubject().getValue() + "\n" +
972
             "\tIdentifier           = " + pid.getValue());
973
974 6475 jones
        InputStream inputStream = null; // bytes to be returned
975
        handler = new MetacatHandler(new Timer());
976
        boolean allowed = false;
977
        String localId; // the metacat docid for the pid
978 6179 cjones
979 6475 jones
        // get the local docid from Metacat
980
        try {
981
            localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
982
        } catch (McdbDocNotFoundException e) {
983 6610 cjones
            throw new ServiceFailure("2181", "The object specified by " +
984
                    pid.getValue() + " does not exist at this node.");
985
986 6475 jones
        }
987 6234 cjones
988 6552 leinfelder
        Subject targetNodeSubject = session.getSubject();
989 6185 leinfelder
990 6552 leinfelder
        // check for authorization to replicate, null session to act as this source MN
991 6610 cjones
        try {
992
            allowed = D1Client.getCN().isNodeAuthorized(null, targetNodeSubject, pid, Permission.REPLICATE);
993
        } catch (InvalidToken e1) {
994
            throw new ServiceFailure("2181", "Could not determine if node is authorized: "
995
                + e1.getMessage());
996
997
        } catch (NotFound e1) {
998
            throw new ServiceFailure("2181", "Could not determine if node is authorized: "
999
                    + e1.getMessage());
1000 6384 cjones
1001 6610 cjones
        } catch (InvalidRequest e1) {
1002
            throw new ServiceFailure("2181", "Could not determine if node is authorized: "
1003
                    + e1.getMessage());
1004
1005
        }
1006
1007 6540 cjones
        logMetacat.info("Called D1Client.isNodeAuthorized(). Allowed = " + allowed +
1008
            " for identifier " + pid.getValue());
1009
1010 6475 jones
        // if the person is authorized, perform the read
1011
        if (allowed) {
1012
            try {
1013
                inputStream = handler.read(localId);
1014
            } catch (Exception e) {
1015 6610 cjones
                throw new ServiceFailure("1020", "The object specified by " +
1016
                    pid.getValue() + "could not be returned due to error: " + e.getMessage());
1017 6475 jones
            }
1018
        }
1019 6384 cjones
1020 6475 jones
        // if we fail to set the input stream
1021
        if (inputStream == null) {
1022 6610 cjones
            throw new ServiceFailure("2181", "The object specified by " +
1023
                pid.getValue() + "does not exist at this node.");
1024 6475 jones
        }
1025
1026
        // log the replica event
1027
        String principal = null;
1028
        if (session.getSubject() != null) {
1029
            principal = session.getSubject().getValue();
1030
        }
1031 6576 cjones
        EventLog.getInstance().log(request.getRemoteAddr(),
1032
            request.getHeader("User-Agent"), principal, localId, "replicate");
1033 6475 jones
1034
        return inputStream;
1035
    }
1036
1037 6573 cjones
    /**
1038
     * Set the access policy
1039
     */
1040
    @Deprecated
1041
    @Override
1042
    public boolean setAccessPolicy(Session session, Identifier pid,
1043
        AccessPolicy policy)
1044
        throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
1045
        NotImplemented, InvalidRequest {
1046
1047
        throw new NotImplemented("4401", "This method is deprecated for Member Nodes.");
1048
1049
    }
1050
1051 6599 cjones
    /**
1052 6600 cjones
     * A method to notify the Member Node that the authoritative copy of
1053 6599 cjones
     * system metadata on the Coordinating Nodes has changed.
1054
     *
1055
     * @param session   Session information that contains the identity of the
1056
     *                  calling user as retrieved from the X.509 certificate
1057
     *                  which must be traceable to the CILogon service.
1058
     * @param serialVersion   The serialVersion of the system metadata
1059
     * @param dateSysMetaLastModified  The time stamp for when the system metadata was changed
1060
     * @throws NotImplemented
1061
     * @throws ServiceFailure
1062
     * @throws NotAuthorized
1063
     * @throws InvalidRequest
1064
     * @throws InvalidToken
1065
     */
1066
    public void systemMetadataChanged(Session session, Identifier pid,
1067
        long serialVersion, Date dateSysMetaLastModified)
1068
        throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest,
1069
        InvalidToken {
1070
1071 6600 cjones
        SystemMetadata currentLocalSysMeta = null;
1072
        SystemMetadata newSysMeta = null;
1073
        CNode cn = D1Client.getCN();
1074
        NodeList nodeList = null;
1075
        Subject callingSubject = null;
1076
        boolean allowed = false;
1077
1078
        // are we allowed to call this?
1079
        callingSubject = session.getSubject();
1080
        nodeList = cn.listNodes();
1081
1082
        for(Node node : nodeList.getNodeList()) {
1083
            // must be a CN
1084
            if ( node.getType().equals(NodeType.CN)) {
1085
               List<Subject> subjectList = node.getSubjectList();
1086
               // the calling subject must be in the subject list
1087
               if ( subjectList.contains(callingSubject)) {
1088
                   allowed = true;
1089
1090
               }
1091
1092
            }
1093
        }
1094
1095
        if (!allowed ) {
1096
            String msg = "The subject identified by " + callingSubject.getValue() +
1097
              " is not authorized to call this service.";
1098
            throw new NotAuthorized("1331", msg);
1099
1100
        }
1101
1102
        // compare what we have locally to what is sent in the change notification
1103
        try {
1104
            currentLocalSysMeta =
1105
                IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
1106
1107
        } catch (McdbDocNotFoundException e) {
1108
            String msg = "SystemMetadata for pid " + pid.getValue() +
1109
              " cpouldn't be updated because it couldn't be found locally: " +
1110
              e.getMessage();
1111
            logMetacat.warn(msg);
1112
1113
        }
1114
1115
        if (currentLocalSysMeta.getSerialVersion().longValue() < serialVersion ) {
1116
            try {
1117
                newSysMeta = cn.getSystemMetadata(null, pid);
1118
            } catch (NotFound e) {
1119
                // huh? you just said you had it
1120
                logMetacat.error("On updating the local copy of system metadata " +
1121
                    "for pid " + pid.getValue() +", the CN reports it is not found." +
1122
                    " The error message was: " + e.getMessage());
1123
1124
            }
1125
            // update the local copy of system metadata for the pid
1126
            try {
1127
                IdentifierManager.getInstance().updateSystemMetadata(newSysMeta);
1128
                logMetacat.info("Updated local copy of system metadata for pid " +
1129
                    pid.getValue() + " after change notification from the CN.");
1130
1131
            } catch (McdbDocNotFoundException e) {
1132
                String msg = "SystemMetadata for pid " + pid.getValue() +
1133
                  " cpouldn't be updated because it couldn't be found: " +
1134
                  e.getMessage();
1135
                logMetacat.warn(msg);
1136
1137
            }
1138
        }
1139
1140 6599 cjones
    }
1141
1142 6179 cjones
}