Project

General

Profile

1 5282 jones
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2010 Regents of the University of California and the
4
 *             National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: jones $'
7
 *     '$Date: 2010-02-03 17:58:12 -0900 (Wed, 03 Feb 2010) $'
8
 * '$Revision: 5211 $'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 */
24
25
package edu.ucsb.nceas.metacat;
26
27 6384 cjones
import java.math.BigInteger;
28 5282 jones
import java.sql.PreparedStatement;
29
import java.sql.ResultSet;
30
import java.sql.SQLException;
31 5895 berkley
import java.sql.Timestamp;
32 6107 leinfelder
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.Hashtable;
35
import java.util.List;
36
import java.util.Vector;
37 5282 jones
38
import org.apache.log4j.Logger;
39 8810 leinfelder
import org.dataone.client.v2.formats.ObjectFormatCache;
40 7010 cjones
import org.dataone.service.exceptions.BaseException;
41 6904 cjones
import org.dataone.service.exceptions.InvalidSystemMetadata;
42 6366 leinfelder
import org.dataone.service.types.v1.AccessPolicy;
43
import org.dataone.service.types.v1.AccessRule;
44
import org.dataone.service.types.v1.Checksum;
45
import org.dataone.service.types.v1.Identifier;
46
import org.dataone.service.types.v1.NodeReference;
47
import org.dataone.service.types.v1.ObjectFormatIdentifier;
48
import org.dataone.service.types.v1.ObjectInfo;
49
import org.dataone.service.types.v1.ObjectList;
50
import org.dataone.service.types.v1.Permission;
51
import org.dataone.service.types.v1.Replica;
52
import org.dataone.service.types.v1.ReplicationPolicy;
53
import org.dataone.service.types.v1.ReplicationStatus;
54
import org.dataone.service.types.v1.Subject;
55 8810 leinfelder
import org.dataone.service.types.v2.SystemMetadata;
56 5282 jones
57 6108 leinfelder
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessAccess;
58 5282 jones
import edu.ucsb.nceas.metacat.database.DBConnection;
59
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
60 7438 leinfelder
import edu.ucsb.nceas.metacat.database.DatabaseService;
61 9119 tao
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
62 5887 berkley
import edu.ucsb.nceas.metacat.properties.PropertyService;
63 6108 leinfelder
import edu.ucsb.nceas.metacat.shared.AccessException;
64 6299 leinfelder
import edu.ucsb.nceas.metacat.shared.ServiceException;
65 5286 jones
import edu.ucsb.nceas.metacat.util.DocumentUtil;
66 6299 leinfelder
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
67 7475 leinfelder
import edu.ucsb.nceas.utilities.access.AccessControlInterface;
68
import edu.ucsb.nceas.utilities.access.XMLAccessDAO;
69 5282 jones
70
/**
71
 * Manage the relationship between Metacat local identifiers (LocalIDs) that are
72 6099 leinfelder
 * codified as the (docid, rev) pair with globally unique string identifiers
73 5282 jones
 * (GUIDs) that are opaque strings.  This class provides methods to manage these
74
 * identifiers, and to search for and look up LocalIDs based on their GUID and
75
 * vice versa. IdentifierManager is a singleton.
76
 *
77
 * @author Matthew Jones
78
 */
79
public class IdentifierManager {
80
81 5334 berkley
    public static final String TYPE_SYSTEM_METADATA = "systemmetadata";
82
    public static final String TYPE_IDENTIFIER = "identifier";
83
84 5282 jones
    /**
85
     * The single instance of the manager that is always returned.
86
     */
87
    private static IdentifierManager self = null;
88 6099 leinfelder
    private Logger logMetacat = Logger.getLogger(IdentifierManager.class);
89 5282 jones
90
    /**
91
     * A private constructor that initializes the class when getInstance() is
92
     * called.
93
     */
94 6099 leinfelder
    private IdentifierManager() {}
95 5282 jones
96
    /**
97
     * Return the single instance of the manager after initializing it if it
98
     * wasn't previously initialized.
99
     *
100
     * @return the single IdentifierManager instance
101
     */
102
    public static IdentifierManager getInstance()
103
    {
104
        if (self == null) {
105
            self = new IdentifierManager();
106
        }
107
        return self;
108
    }
109
110 6097 leinfelder
    public SystemMetadata asSystemMetadata(Date dateUploaded, String rightsHolder,
111
            String checksum, String checksumAlgorithm, String originMemberNode,
112
            String authoritativeMemberNode, Date dateModified, String submitter,
113 6561 leinfelder
            String guid, String fmtidStr, BigInteger size, BigInteger serialVersion) {
114 6097 leinfelder
        SystemMetadata sysMeta = new SystemMetadata();
115
116
        Identifier sysMetaId = new Identifier();
117
        sysMetaId.setValue(guid);
118
        sysMeta.setIdentifier(sysMetaId);
119
        sysMeta.setDateUploaded(dateUploaded);
120
        Subject rightsHolderSubject = new Subject();
121
        rightsHolderSubject.setValue(rightsHolder);
122
        sysMeta.setRightsHolder(rightsHolderSubject);
123
        Checksum checksumObject = new Checksum();
124
        checksumObject.setValue(checksum);
125 6397 leinfelder
        checksumObject.setAlgorithm(checksumAlgorithm);
126 6097 leinfelder
        sysMeta.setChecksum(checksumObject);
127
        NodeReference omn = new NodeReference();
128
        omn.setValue(originMemberNode);
129
        sysMeta.setOriginMemberNode(omn);
130
        NodeReference amn = new NodeReference();
131
        amn.setValue(authoritativeMemberNode);
132
        sysMeta.setAuthoritativeMemberNode(amn);
133
        sysMeta.setDateSysMetadataModified(dateModified);
134
        Subject submitterSubject = new Subject();
135
        submitterSubject.setValue(submitter);
136
        sysMeta.setSubmitter(submitterSubject);
137 7010 cjones
        ObjectFormatIdentifier fmtid = null;
138 6124 cjones
        try {
139 7010 cjones
        	ObjectFormatIdentifier formatId = new ObjectFormatIdentifier();
140
        	formatId.setValue(fmtidStr);
141
        	fmtid = ObjectFormatCache.getInstance().getFormat(formatId).getFormatId();
142 6561 leinfelder
        	sysMeta.setFormatId(fmtid);
143 7010 cjones
144
        } catch (BaseException nfe) {
145
            logMetacat.error("The objectFormat " + fmtidStr +
146 6384 cjones
          	" is not registered. Setting the default format id.");
147 7010 cjones
            fmtid = new ObjectFormatIdentifier();
148
            fmtid.setValue("application/octet-stream");
149
            sysMeta.setFormatId(fmtid);
150
151 6124 cjones
        }
152 6097 leinfelder
        sysMeta.setSize(size);
153 6561 leinfelder
        sysMeta.setSerialVersion(serialVersion);
154 6097 leinfelder
155
        return sysMeta;
156
    }
157
158 5282 jones
    /**
159 5895 berkley
     * return a hash of all of the info that is in the systemmetadata table
160
     * @param localId
161
     * @return
162
     */
163
    public Hashtable<String, String> getSystemMetadataInfo(String localId)
164
    throws McdbDocNotFoundException
165
    {
166
        try
167
        {
168
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
169
            localId = acc.getDocid();
170
        }
171
        catch(Exception e)
172
        {
173
            //do nothing. just try the localId as it is
174
        }
175
        Hashtable<String, String> h = new Hashtable<String, String>();
176
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
177 5944 berkley
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size " +
178 5895 berkley
          "from systemmetadata where docid = ?";
179
        DBConnection dbConn = null;
180
        int serialNumber = -1;
181
        try
182
        {
183
            // Get a database connection from the pool
184
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getDocumentInfo");
185
            serialNumber = dbConn.getCheckOutSerialNumber();
186
187
            // Execute the insert statement
188
            PreparedStatement stmt = dbConn.prepareStatement(sql);
189
            stmt.setString(1, localId);
190
            ResultSet rs = stmt.executeQuery();
191
            if (rs.next())
192
            {
193
                String guid = rs.getString(1);
194
                Timestamp dateUploaded = rs.getTimestamp(2);
195
                String rightsHolder = rs.getString(3);
196
                String checksum = rs.getString(4);
197
                String checksumAlgorithm = rs.getString(5);
198
                String originMemberNode = rs.getString(6);
199
                String authoritativeMemberNode = rs.getString(7);
200
                Timestamp dateModified = rs.getTimestamp(8);
201
                String submitter = rs.getString(9);
202 5917 berkley
                String objectFormat = rs.getString(10);
203
                long size = new Long(rs.getString(11)).longValue();
204 5895 berkley
205
                h.put("guid", guid);
206
                h.put("date_uploaded", new Long(dateUploaded.getTime()).toString());
207
                h.put("rights_holder", rightsHolder);
208
                h.put("checksum", checksum);
209
                h.put("checksum_algorithm", checksumAlgorithm);
210
                h.put("origin_member_node", originMemberNode);
211
                h.put("authoritative_member_node", authoritativeMemberNode);
212
                h.put("date_modified", new Long(dateModified.getTime()).toString());
213
                h.put("submitter", submitter);
214 5917 berkley
                h.put("object_format", objectFormat);
215
                h.put("size", new Long(size).toString());
216 5895 berkley
217
                stmt.close();
218
            }
219
            else
220
            {
221
                stmt.close();
222
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
223
                throw new McdbDocNotFoundException("2Could not find document " + localId);
224
            }
225
226
        }
227
        catch (SQLException e)
228
        {
229
            e.printStackTrace();
230
            logMetacat.error("Error while getting system metadata info for localid " + localId + " : "
231
                    + e.getMessage());
232
        }
233
        finally
234
        {
235
            // Return database connection to the pool
236
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
237
        }
238
        return h;
239
    }
240
241
    /**
242 6097 leinfelder
     * return a hash of all of the info that is in the systemmetadata table
243 6099 leinfelder
     * @param guid
244 6097 leinfelder
     * @return
245 6108 leinfelder
     * @throws McdbDocNotFoundException
246 6097 leinfelder
     */
247 6099 leinfelder
    public SystemMetadata getSystemMetadata(String guid)
248 6097 leinfelder
    	throws McdbDocNotFoundException
249
    {
250 6099 leinfelder
251 6097 leinfelder
        SystemMetadata sysMeta = new SystemMetadata();
252
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
253 6375 leinfelder
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size, " +
254 9038 tao
          "replication_allowed, number_replicas, obsoletes, obsoleted_by, serial_version, archived, series_id " +
255 6099 leinfelder
          "from systemmetadata where guid = ?";
256 6097 leinfelder
        DBConnection dbConn = null;
257
        int serialNumber = -1;
258 6533 cjones
        Boolean replicationAllowed = new Boolean(false);
259
        BigInteger numberOfReplicas = new BigInteger("-1");
260 6561 leinfelder
        BigInteger serialVersion = new BigInteger("-1");
261 7428 leinfelder
        Boolean archived = new Boolean(false);
262 6561 leinfelder
263 6097 leinfelder
        try
264
        {
265
            // Get a database connection from the pool
266
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadata");
267
            serialNumber = dbConn.getCheckOutSerialNumber();
268
269
            // Execute the statement
270
            PreparedStatement stmt = dbConn.prepareStatement(sql);
271 6099 leinfelder
            stmt.setString(1, guid);
272 6097 leinfelder
            ResultSet rs = stmt.executeQuery();
273
            if (rs.next())
274
            {
275
                Timestamp dateUploaded = rs.getTimestamp(2);
276
                String rightsHolder = rs.getString(3);
277
                String checksum = rs.getString(4);
278
                String checksumAlgorithm = rs.getString(5);
279
                String originMemberNode = rs.getString(6);
280
                String authoritativeMemberNode = rs.getString(7);
281
                Timestamp dateModified = rs.getTimestamp(8);
282
                String submitter = rs.getString(9);
283 6296 cjones
                String fmtidStr = rs.getString(10);
284 6384 cjones
                BigInteger size = new BigInteger(rs.getString(11));
285 6535 cjones
                replicationAllowed = new Boolean(rs.getBoolean(12));
286 6533 cjones
                numberOfReplicas = new BigInteger(rs.getString(13));
287
                String obsoletes = rs.getString(14);
288
                String obsoletedBy = rs.getString(15);
289 6561 leinfelder
                serialVersion = new BigInteger(rs.getString(16));
290 7428 leinfelder
                archived = new Boolean(rs.getBoolean(17));
291 9038 tao
                String series_id = rs.getString(18);
292 6375 leinfelder
293 6097 leinfelder
                Identifier sysMetaId = new Identifier();
294
                sysMetaId.setValue(guid);
295
                sysMeta.setIdentifier(sysMetaId);
296 6561 leinfelder
                sysMeta.setSerialVersion(serialVersion);
297 6097 leinfelder
                sysMeta.setDateUploaded(dateUploaded);
298
                Subject rightsHolderSubject = new Subject();
299
                rightsHolderSubject.setValue(rightsHolder);
300
                sysMeta.setRightsHolder(rightsHolderSubject);
301
                Checksum checksumObject = new Checksum();
302
                checksumObject.setValue(checksum);
303 6397 leinfelder
                checksumObject.setAlgorithm(checksumAlgorithm);
304 6097 leinfelder
                sysMeta.setChecksum(checksumObject);
305 6519 leinfelder
                if (originMemberNode != null) {
306
	                NodeReference omn = new NodeReference();
307
	                omn.setValue(originMemberNode);
308
	                sysMeta.setOriginMemberNode(omn);
309
                }
310
                if (authoritativeMemberNode != null) {
311
	                NodeReference amn = new NodeReference();
312
	                amn.setValue(authoritativeMemberNode);
313
	                sysMeta.setAuthoritativeMemberNode(amn);
314
                }
315 6097 leinfelder
                sysMeta.setDateSysMetadataModified(dateModified);
316 7639 leinfelder
                if (submitter != null) {
317
	                Subject submitterSubject = new Subject();
318
	                submitterSubject.setValue(submitter);
319
	                sysMeta.setSubmitter(submitterSubject);
320
                }
321 7023 leinfelder
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
322
                fmtid.setValue(fmtidStr);
323
            	sysMeta.setFormatId(fmtid);
324 6097 leinfelder
                sysMeta.setSize(size);
325 6423 leinfelder
                if (obsoletes != null) {
326
	                Identifier obsoletesId = new Identifier();
327
	                obsoletesId.setValue(obsoletes);
328
	                sysMeta.setObsoletes(obsoletesId);
329
                }
330
                if (obsoletedBy != null) {
331
		            Identifier obsoletedById = new Identifier();
332
		            obsoletedById.setValue(obsoletedBy);
333
		            sysMeta.setObsoletedBy(obsoletedById);
334
                }
335 7428 leinfelder
                sysMeta.setArchived(archived);
336 9038 tao
                if(series_id != null) {
337
                    Identifier seriesId = new Identifier();
338
                    seriesId.setValue(series_id);
339
                    sysMeta.setSeriesId(seriesId);
340
                }
341 6097 leinfelder
                stmt.close();
342
            }
343
            else
344
            {
345
                stmt.close();
346
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
347 6099 leinfelder
                throw new McdbDocNotFoundException("Could not find " + guid);
348 6097 leinfelder
            }
349
350
        }
351
        catch (SQLException e)
352
        {
353
            e.printStackTrace();
354 6099 leinfelder
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "
355 6097 leinfelder
                    + e.getMessage());
356
        }
357
        finally
358
        {
359
            // Return database connection to the pool
360
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
361
        }
362 6377 leinfelder
363 6533 cjones
        // populate the replication policy
364 6107 leinfelder
        ReplicationPolicy replicationPolicy = new ReplicationPolicy();
365 6533 cjones
        if ( numberOfReplicas != null  && numberOfReplicas.intValue() != -1 ) {
366
            replicationPolicy.setNumberReplicas(numberOfReplicas.intValue());
367
368
        }
369
370
        if ( replicationAllowed != null ) {
371
            replicationPolicy.setReplicationAllowed(replicationAllowed);
372
373
        }
374 6107 leinfelder
        replicationPolicy.setBlockedMemberNodeList(getReplicationPolicy(guid, "blocked"));
375
        replicationPolicy.setPreferredMemberNodeList(getReplicationPolicy(guid, "preferred"));
376 6533 cjones
		    sysMeta.setReplicationPolicy(replicationPolicy);
377 6107 leinfelder
378 6533 cjones
		    // look up replication status
379
		    sysMeta.setReplicaList(getReplicationStatus(guid));
380 6108 leinfelder
381 6533 cjones
		    // look up access policy
382
		    try {
383
		    	sysMeta.setAccessPolicy(getAccessPolicy(guid));
384
		    } catch (AccessException e) {
385
		    	throw new McdbDocNotFoundException(e);
386
		    }
387 6107 leinfelder
388 6097 leinfelder
        return sysMeta;
389
    }
390
391
392 6107 leinfelder
    private List<NodeReference> getReplicationPolicy(String guid, String policy)
393
		throws McdbDocNotFoundException {
394
395
		List<NodeReference> nodes = new ArrayList<NodeReference>();
396
		String sql = "select guid, policy, member_node " +
397 7392 leinfelder
			"from smReplicationPolicy where guid = ? and policy = ?";
398 6107 leinfelder
	    DBConnection dbConn = null;
399
	    int serialNumber = -1;
400
	    try {
401
	        // Get a database connection from the pool
402
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicationPolicy");
403
	        serialNumber = dbConn.getCheckOutSerialNumber();
404
405
	        // Execute the statement
406
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
407
	        stmt.setString(1, guid);
408
	        stmt.setString(2, policy);
409
	        ResultSet rs = stmt.executeQuery();
410
	        while (rs.next())
411
	        {
412
	            String memberNode = rs.getString(3);
413
	            NodeReference node = new NodeReference();
414
	            node.setValue(memberNode);
415
	            nodes.add(node);
416
417
	        }
418
	        stmt.close();
419
420
	    } catch (SQLException e) {
421
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
422
	    }
423
	    finally {
424
	        // Return database connection to the pool
425
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
426
	    }
427
428
	    return nodes;
429
	}
430 6097 leinfelder
431 6107 leinfelder
    private List<Replica> getReplicationStatus(String guid) throws McdbDocNotFoundException {
432
433
		List<Replica> replicas = new ArrayList<Replica>();
434
		String sql = "select guid, member_node, status, date_verified " +
435 7392 leinfelder
			"from smReplicationStatus where guid = ?";
436 6107 leinfelder
	    DBConnection dbConn = null;
437
	    int serialNumber = -1;
438
	    try {
439
	        // Get a database connection from the pool
440
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicas");
441
	        serialNumber = dbConn.getCheckOutSerialNumber();
442
443
	        // Execute the statement
444
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
445
	        stmt.setString(1, guid);
446
	        ResultSet rs = stmt.executeQuery();
447
	        while (rs.next())
448
	        {
449
	            String memberNode = rs.getString(2);
450
	            String status = rs.getString(3);
451 7399 cjones
	            java.sql.Timestamp verified = rs.getTimestamp(4);
452 6107 leinfelder
453
	            Replica replica = new Replica();
454
	            NodeReference node = new NodeReference();
455
	            node.setValue(memberNode);
456
	            replica.setReplicaMemberNode(node);
457 6454 leinfelder
	            replica.setReplicationStatus(ReplicationStatus.valueOf(status));
458 6107 leinfelder
	            replica.setReplicaVerified(new Date(verified.getTime()));
459
	            replicas.add(replica);
460
	        }
461
	        stmt.close();
462
463
	    } catch (SQLException e) {
464
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
465
	    }
466
	    finally {
467
	        // Return database connection to the pool
468
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
469
	    }
470
471
	    return replicas;
472
	}
473
474 5378 berkley
475
    /**
476
     * return the newest rev for a given localId
477
     * @param localId
478
     * @return
479
     */
480
    public int getLatestRevForLocalId(String localId)
481
        throws McdbDocNotFoundException
482
    {
483 5798 berkley
        try
484
        {
485
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
486
            localId = acc.getDocid();
487
        }
488
        catch(Exception e)
489
        {
490
            //do nothing. just try the localId as it is
491
        }
492 5378 berkley
        int rev = 0;
493 6595 leinfelder
        String sql = "select rev from xml_documents where docid like ? ";
494 5378 berkley
        DBConnection dbConn = null;
495
        int serialNumber = -1;
496
        try
497
        {
498
            // Get a database connection from the pool
499
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLatestRevForLocalId");
500
            serialNumber = dbConn.getCheckOutSerialNumber();
501
502
            // Execute the insert statement
503
            PreparedStatement stmt = dbConn.prepareStatement(sql);
504 6595 leinfelder
            stmt.setString(1, localId);
505 5378 berkley
            ResultSet rs = stmt.executeQuery();
506
            if (rs.next())
507
            {
508
                rev = rs.getInt(1);
509
                stmt.close();
510
            }
511
            else
512
            {
513
                stmt.close();
514
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
515 5798 berkley
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
516 5378 berkley
            }
517
        }
518
        catch (SQLException e)
519
        {
520
            logMetacat.error("Error while looking up the guid: "
521
                    + e.getMessage());
522
        }
523
        finally
524
        {
525
            // Return database connection to the pool
526
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
527
        }
528
        return rev;
529
    }
530
531
    /**
532 5377 berkley
     * return all local ids in the object store that do not have associated
533 6099 leinfelder
     * system metadata
534 5377 berkley
     */
535 7168 leinfelder
    public List<String> getLocalIdsWithNoSystemMetadata(boolean includeRevisions, int serverLocation)
536 5377 berkley
    {
537
        Vector<String> ids = new Vector<String>();
538 6099 leinfelder
        String sql = "select docid, rev from xml_documents " +
539
        		"where docid not in " +
540 6720 leinfelder
        		"(select docid from identifier where guid in (select guid from systemmetadata))";
541 7168 leinfelder
        if (serverLocation > 0) {
542
        	sql = sql + " and server_location = ? ";
543
        }
544 6704 leinfelder
545 6745 leinfelder
        String revisionSql = "select docid, rev from xml_revisions " +
546 6704 leinfelder
				"where docid not in " +
547 6720 leinfelder
				"(select docid from identifier where guid in (select guid from systemmetadata))";
548 7168 leinfelder
        if (serverLocation > 0) {
549
        	revisionSql = revisionSql + " and server_location = ? ";
550
        }
551 6704 leinfelder
552
        if (includeRevisions) {
553
        	sql = sql + " UNION ALL " + revisionSql;
554
        }
555
556 5377 berkley
        DBConnection dbConn = null;
557
        int serialNumber = -1;
558
        try
559
        {
560
            // Get a database connection from the pool
561
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
562
            serialNumber = dbConn.getCheckOutSerialNumber();
563
564
            // Execute the insert statement
565
            PreparedStatement stmt = dbConn.prepareStatement(sql);
566 7168 leinfelder
            // set params based on what we have in the query string
567
            if (serverLocation > 0) {
568
            	stmt.setInt(1, serverLocation);
569
            	if (includeRevisions) {
570
            		stmt.setInt(2, serverLocation);
571
            	}
572
            }
573 5377 berkley
            ResultSet rs = stmt.executeQuery();
574
            while (rs.next())
575
            {
576
                String localid = rs.getString(1);
577 5798 berkley
                String rev = rs.getString(2);
578
                localid += "." + rev;
579 6099 leinfelder
                logMetacat.debug("id to add SM for: " + localid);
580 5377 berkley
                ids.add(localid);
581
            }
582
            stmt.close();
583
        }
584
        catch (SQLException e)
585
        {
586
            logMetacat.error("Error while looking up the guid: "
587
                    + e.getMessage());
588
        }
589
        finally
590
        {
591
            // Return database connection to the pool
592
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
593
        }
594
595
        return ids;
596
    }
597
598
    /**
599
     * return a listing of all local ids in the object store
600
     * @return a list of all local ids in metacat
601
     */
602
    public List<String> getAllLocalIds()
603 6416 rnahf
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
604
    //    throws Exception
605 5377 berkley
    {
606
        Vector<String> ids = new Vector<String>();
607
        String sql = "select docid from xml_documents";
608
        DBConnection dbConn = null;
609
        int serialNumber = -1;
610
        try
611
        {
612
            // Get a database connection from the pool
613
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
614
            serialNumber = dbConn.getCheckOutSerialNumber();
615
616
            // Execute the insert statement
617
            PreparedStatement stmt = dbConn.prepareStatement(sql);
618
            ResultSet rs = stmt.executeQuery();
619
            while (rs.next())
620
            {
621
                String localid = rs.getString(1);
622
                ids.add(localid);
623
            }
624
            stmt.close();
625
        }
626
        catch (SQLException e)
627
        {
628
            logMetacat.error("Error while looking up the guid: "
629
                    + e.getMessage());
630
        }
631
        finally
632
        {
633
            // Return database connection to the pool
634
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
635
        }
636
        return ids;
637
    }
638
639 6416 rnahf
640 6118 leinfelder
    /**
641 6416 rnahf
     * return a listing of all guids in the object store
642
     * @return a list of all GUIDs in metacat
643
     */
644 7187 leinfelder
    public List<String> getAllSystemMetadataGUIDs()
645 6416 rnahf
    {
646
        Vector<String> guids = new Vector<String>();
647 7187 leinfelder
        String sql = "select guid from systemmetadata";
648 6416 rnahf
        DBConnection dbConn = null;
649
        int serialNumber = -1;
650
        try
651
        {
652
            // Get a database connection from the pool
653
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllGUIDs");
654
            serialNumber = dbConn.getCheckOutSerialNumber();
655
656
            // Execute the insert statement
657
            PreparedStatement stmt = dbConn.prepareStatement(sql);
658
            ResultSet rs = stmt.executeQuery();
659
            while (rs.next())
660
            {
661
                String guid = rs.getString(1);
662
                guids.add(guid);
663
            }
664
            stmt.close();
665
        }
666
        catch (SQLException e)
667
        {
668
            logMetacat.error("Error while retrieving the guid: "
669
                    + e.getMessage());
670
        }
671
        finally
672
        {
673
            // Return database connection to the pool
674
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
675
        }
676
        return guids;
677
    }
678
679
680
681
    /**
682 6118 leinfelder
     * returns a list of system metadata-only guids since the given date
683
     * @return a list of system ids in metacat that do not correspond to objects
684
     * TODO: need to check which server they are on
685
     */
686
    public List<String> getUpdatedSystemMetadataIds(Date since)
687
       throws Exception
688
    {
689
        List<String> ids = new Vector<String>();
690
        String sql =
691
        	"select guid from " + TYPE_SYSTEM_METADATA +
692
        	" where guid not in " +
693
        	" (select guid from " + TYPE_IDENTIFIER + ") " +
694
        	" and date_modified > ?";
695
        DBConnection dbConn = null;
696
        int serialNumber = -1;
697
        try
698
        {
699
            // Get a database connection from the pool
700
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getUpdatedSystemMetadataIds");
701
            serialNumber = dbConn.getCheckOutSerialNumber();
702 6099 leinfelder
703 6118 leinfelder
            // Execute the insert statement
704
            PreparedStatement stmt = dbConn.prepareStatement(sql);
705
            stmt.setDate(1, new java.sql.Date(since.getTime()));
706
            ResultSet rs = stmt.executeQuery();
707
            while (rs.next())
708
            {
709
                String guid = rs.getString(1);
710
                ids.add(guid);
711
            }
712
            stmt.close();
713
        }
714
        catch (SQLException e)
715
        {
716
            logMetacat.error("Error while looking up the updated guids: "
717
                    + e.getMessage());
718
        }
719
        finally
720
        {
721
            // Return database connection to the pool
722
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
723
        }
724
        return ids;
725
    }
726 5282 jones
727 6459 leinfelder
    /**
728
     * returns a list of system metadata-only guids since the given date
729
     * @return a list of system ids in metacat that do not correspond to objects
730
     * TODO: need to check which server they are on
731
     */
732
    public Date getLastModifiedDate() throws Exception {
733
        Date maxDate = null;
734 6118 leinfelder
735 6459 leinfelder
        List<String> ids = new Vector<String>();
736
        String sql =
737
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
738
        DBConnection dbConn = null;
739
        int serialNumber = -1;
740
        try
741
        {
742
            // Get a database connection from the pool
743
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
744
            serialNumber = dbConn.getCheckOutSerialNumber();
745
746
            // Execute the insert statement
747
            PreparedStatement stmt = dbConn.prepareStatement(sql);
748
            ResultSet rs = stmt.executeQuery();
749
            if (rs.next()) {
750
            	maxDate = rs.getDate(1);
751
            }
752
            stmt.close();
753
        }
754
        catch (SQLException e)
755
        {
756
            logMetacat.error("Error while looking up the latest update date: "
757
                    + e.getMessage());
758
        }
759
        finally
760
        {
761
            // Return database connection to the pool
762
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
763
        }
764
        return maxDate;
765
    }
766
767 6118 leinfelder
768 5282 jones
    /**
769
     * Determine if an identifier exists already, returning true if so.
770 7045 leinfelder
     * NOTE: looks in the identifier and system metadata table for a match
771
     * (in that order)
772 5282 jones
     *
773
     * @param guid the global identifier to look up
774
     * @return boolean true if the identifier exists
775
     */
776 9017 tao
    public boolean identifierExists(String guid) throws SQLException
777 5282 jones
    {
778
        boolean idExists = false;
779
        try {
780
            String id = getLocalId(guid);
781
            if (id != null) {
782
                idExists = true;
783
            }
784
        } catch (McdbDocNotFoundException e) {
785 6123 leinfelder
        	// try system metadata only
786 9017 tao
        	    //this will check if the guid field on the system metadata table has the id
787 9030 tao
        		idExists = systemMetadataPIDExists(guid);
788 9017 tao
        		if(!idExists) {
789
        		    //if the guid field of the system metadata table doesn't have the id,
790
        		    //we will check if the serial_id field of the system metadata table has it
791
        		    idExists=systemMetadataSIDExists(guid);
792
        		}
793
794 5282 jones
        }
795
        return idExists;
796
    }
797
798
    /**
799 7045 leinfelder
     * Determine if an identifier mapping exists already,
800
     * returning true if so.
801 5282 jones
     *
802 7045 leinfelder
     * @param guid the global identifier to look up
803
     * @return boolean true if the identifier exists
804
     */
805 9024 tao
    public boolean mappingExists(String guid) throws SQLException
806 7045 leinfelder
    {
807
        boolean idExists = false;
808
        try {
809
            String id = getLocalId(guid);
810
            if (id != null) {
811
                idExists = true;
812
            }
813
        } catch (McdbDocNotFoundException e) {
814
        	// nope!
815
        }
816
        return idExists;
817
    }
818
819
    /**
820
     *
821 5453 berkley
     * @param guid
822
     * @param rev
823
     * @return
824
     */
825
    public String generateLocalId(String guid, int rev)
826
    {
827
        return generateLocalId(guid, rev, false);
828
    }
829 5286 jones
830
    /**
831
     * Given a global identifier (guid), create a suitable local identifier that
832
     * follows Metacat's docid semantics and format (scope.id.rev), and create
833
     * a mapping between these two identifiers.  This effectively reserves both
834
     * the global and the local identifier, as they will now be present in the
835 7070 leinfelder
     * identifier mapping table.
836
     *
837
     * REMOVED feature: If the incoming guid has the syntax of a
838 5286 jones
     * Metacat docid (scope.id.rev), then simply use it.
839 7070 leinfelder
     * WHY: because "test.1.001" becomes "test.1.1" which is not correct for DataONE
840
     * identifier use (those revision numbers are just chartacters and should not be interpreted)
841 5286 jones
     *
842
     * @param guid the global string identifier
843
     * @param rev the revision number to be used in the localId
844
     * @return String containing the localId to be used for Metacat operations
845
     */
846 5453 berkley
    public String generateLocalId(String guid, int rev, boolean isSystemMetadata)
847 5286 jones
    {
848
        String localId = "";
849
        boolean conformsToDocidFormat = false;
850
851 7070 leinfelder
        // BRL -- do not allow Metacat-conforming IDs to be used:
852
        // test.1.001 becomes test.1.1 which is NOT correct for DataONE identifiers
853 5286 jones
        // Check if the guid passed in is already in docid (scope.id.rev) format
854 7070 leinfelder
//        try {
855
//            AccessionNumber acc = new AccessionNumber(guid, "NONE");
856
//            if (new Integer(acc.getRev()).intValue() > 0) {
857
//                conformsToDocidFormat = true;
858
//            }
859
//        } catch (NumberFormatException e) {
860
//            // No action needed, simply detecting invalid AccessionNumbers
861
//        } catch (AccessionNumberException e) {
862
//            // No action needed, simply detecting invalid AccessionNumbers
863
//        } catch (SQLException e) {
864
//            // No action needed, simply detecting invalid AccessionNumbers
865
//        }
866 5286 jones
867
        if (conformsToDocidFormat) {
868
            // if it conforms, use it for both guid and localId
869
            localId = guid;
870
        } else {
871
            // if not, then generate a new unique localId
872
            localId = DocumentUtil.generateDocumentId(rev);
873
        }
874
875
        // Register this new pair in the identifier mapping table
876 6099 leinfelder
        logMetacat.debug("creating mapping in generateLocalId");
877 5453 berkley
        if(!isSystemMetadata)
878
        { //don't do this if we're generating for system metadata
879
            createMapping(guid, localId);
880
        }
881 5286 jones
882
        return localId;
883
    }
884 5322 berkley
885
    /**
886
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
887 5452 berkley
     * if the docid, rev is not found in the identifiers or systemmetadata tables
888 5322 berkley
     *
889
     * @param docid the docid to look up
890
     * @param rev the revision of the docid to look up
891
     * @return String containing the mapped guid
892
     * @throws McdbDocNotFoundException if the docid, rev is not found
893
     */
894
    public String getGUID(String docid, int rev)
895
      throws McdbDocNotFoundException
896
    {
897 6099 leinfelder
        logMetacat.debug("getting guid for " + docid);
898 5322 berkley
        String query = "select guid from identifier where docid = ? and rev = ?";
899
        String guid = null;
900
901
        DBConnection dbConn = null;
902
        int serialNumber = -1;
903
        try {
904
            // Get a database connection from the pool
905 5377 berkley
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
906 5322 berkley
            serialNumber = dbConn.getCheckOutSerialNumber();
907
908
            // Execute the insert statement
909
            PreparedStatement stmt = dbConn.prepareStatement(query);
910
            stmt.setString(1, docid);
911
            stmt.setInt(2, rev);
912
            ResultSet rs = stmt.executeQuery();
913 5451 berkley
            if (rs.next())
914
            {
915 5322 berkley
                guid = rs.getString(1);
916 5451 berkley
            }
917
            else
918
            {
919 6104 leinfelder
            	throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
920 5322 berkley
            }
921 5451 berkley
922 5322 berkley
        } catch (SQLException e) {
923
            logMetacat.error("Error while looking up the guid: "
924
                    + e.getMessage());
925
        } finally {
926
            // Return database connection to the pool
927
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
928
        }
929
930
        return guid;
931
    }
932 5333 berkley
933 9015 tao
    /**
934
     * Get the pid of the head (current) version of objects match the specified sid.
935 9119 tao
     * 1. locate all candidate chain-ends for S1:
936
     *      determined by:  seriesId == S1 AND (obsoletedBy == null  OR obsoletedBy.seriesId != S1) // these are the type1 and type2 ends
937
     *      If obsoletedBy is missing, we generally consider it a type 2 end except:
938
     *      there is another object in the chain (has the same series id) that obsoletes the missing object.
939
     * 2. if only 1 candidate chain-end, return it as the HEAD
940
     * 3. otherwise return the one in the chain with the latest dateUploaded value.
941 9015 tao
     * @param sid specified sid which should match.
942
     * @return the pid of the head version. The null will be returned if there is no pid found.
943 9016 tao
     * @throws SQLException
944 9015 tao
     */
945 9016 tao
    public Identifier getHeadPID(Identifier sid) throws SQLException {
946 9015 tao
        Identifier pid = null;
947
        if(sid != null && sid.getValue() != null && !sid.getValue().trim().equals("")) {
948
            logMetacat.debug("getting pid of the head version for matching the sid: " + sid.getValue());
949 9119 tao
            String sql = "select guid from systemMetadata where series_id = ? order by date_uploaded DESC";
950 9015 tao
            DBConnection dbConn = null;
951
            int serialNumber = -1;
952 9119 tao
            int endsCount = 0;
953
            boolean hasError = false;
954 9015 tao
            try {
955
                // Get a database connection from the pool
956
                dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getHeadPID");
957
                serialNumber = dbConn.getCheckOutSerialNumber();
958
                // Execute the insert statement
959
                PreparedStatement stmt = dbConn.prepareStatement(sql);
960
                stmt.setString(1, sid.getValue());
961
                ResultSet rs = stmt.executeQuery();
962 9119 tao
                boolean hasNext = rs.next();
963
                boolean first = true;
964
                Identifier firstOne = new Identifier();//since the sql using the desc order, the first one has the latest upload date.
965
                if (hasNext)
966 9015 tao
                {
967 9119 tao
                    while(hasNext) {
968
                        String guidStr = rs.getString(1);
969
                        Identifier guid = new Identifier();
970
                        guid.setValue(guidStr);
971
                        if(first) {
972
                            firstOne = guid;
973
                            first =false;
974
                        }
975
                        SystemMetadata sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(guid);
976
                        if(sysmeta.getObsoletedBy() == null) {
977
                            //type 1 end
978
                            System.out.println("has a type 1 end for sid "+sid.getValue());
979
                            pid = guid;
980
                            endsCount++;
981
                        } else {
982
                            Identifier obsoletedBy = sysmeta.getObsoletedBy();
983
                            SystemMetadata obsoletedBySysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletedBy);
984
                            if(obsoletedBySysmeta != null) {
985
                                Identifier sidInObsoletedBy = obsoletedBySysmeta.getSeriesId();
986
                                if(sidInObsoletedBy == null|| !sidInObsoletedBy.equals(sid)) {
987
                                    // type 2 end
988
                                    System.out.println("has a type 2 end for sid "+sid.getValue());
989
                                    pid = guid;
990
                                    endsCount++;
991
                                }
992
                            } else {
993
                                //obsoletedBySysmeta doesn't exist; it means the object is missing
994
                                //generally, we consider it we generally consider it a type 2 end except:
995
                                 //there is another object in the chain (has the same series id) that obsoletes the missing object.
996
                                String sql2 = "select guid from systemMetadata where  obsoletes = ? and series_id = ?";
997
                                PreparedStatement stmt2 = dbConn.prepareStatement(sql2);
998
                                stmt2.setString(1, obsoletedBy.getValue());
999
                                stmt2.setString(2, sid.getValue());
1000
                                ResultSet result = stmt2.executeQuery();
1001
                                boolean next = result.next();
1002
                                int count = 0;
1003
                                while(next) {
1004
                                    count++;
1005
                                    next = result.next();
1006
                                }
1007
                                if(count == 0) {
1008
                                    //the exception (another object in the chain (has the same series id) that obsoletes the missing object) doesn't exist
1009
                                    // it is a type 2 end
1010
                                    System.out.println("has a type 2 end for sid "+sid.getValue());
1011
                                    pid = guid;
1012
                                    endsCount++;
1013
                                } else if (count ==1) {
1014
                                    // it is not end, do nothing;
1015
                                } else {
1016
                                    // something is wrong - there are more than one objects obsolete the missing object!
1017
                                    hasError = true;
1018
                                    break;
1019
                                }
1020
                            }
1021
                        }
1022
                        hasNext = rs.next();
1023
                    }
1024
                    if(endsCount == 1) {
1025
                        //it has one end and it is an ideal chain. We already assign the guid to the pid. So do nothing.
1026
                        System.out.println("It is an ideal for sid "+sid.getValue());
1027
                    }
1028
                    if(hasError || endsCount >1) {
1029
                        // it is not an ideal chain, use the one with latest upload date(the first one in the result set since we have the desc order)
1030
                        System.out.println("It is NOT an ideal for sid "+sid.getValue());
1031
                        pid = firstOne;
1032
                    }
1033 9026 tao
                } else {
1034 9119 tao
                    //it is not a sid or at least we don't have anything to match it.
1035
                    //do nothing, so null will be returned
1036 9026 tao
                }
1037 9015 tao
1038
            } catch (SQLException e) {
1039
                logMetacat.error("Error while get the head pid for the sid "+sid.getValue()+" : "
1040
                        + e.getMessage());
1041 9016 tao
                throw e;
1042 9015 tao
            } finally {
1043
                // Return database connection to the pool
1044
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1045
            }
1046
        }
1047
        return pid;
1048
    }
1049
1050 9016 tao
    /**
1051 9032 tao
     * Check if the specified sid object exists on the serial id field on the system metadata table
1052
     * @param sid
1053
     * @return true if it exists; false otherwise.
1054
     * @throws SQLException
1055
     */
1056
    public boolean systemMetadataSIDExists(Identifier sid) throws SQLException {
1057
        if (sid != null && sid.getValue() != null && !sid.getValue().trim().equals("")) {
1058
            return systemMetadataSIDExists(sid.getValue());
1059
        } else {
1060
            return false;
1061
        }
1062
    }
1063
1064
    /**
1065 9016 tao
     * Check if the specified sid exists on the serial id field on the system metadata table
1066
     * @param id
1067
     * @return true if it exists; false otherwise.
1068
     */
1069 9017 tao
    public boolean systemMetadataSIDExists(String sid) throws SQLException {
1070 9016 tao
        boolean exists = false;
1071 9032 tao
        logMetacat.debug("Check if the  sid: " + sid +" exists on the series_id field of the system metadata table.");
1072 9016 tao
        if(sid != null && !sid.trim().equals("")) {
1073
            String sql = "select guid from systemMetadata where series_id = ?";
1074
            DBConnection dbConn = null;
1075
            int serialNumber = -1;
1076
            try {
1077
                // Get a database connection from the pool
1078
                dbConn = DBConnectionPool.getDBConnection("IdentifierManager.serialIdExists");
1079
                serialNumber = dbConn.getCheckOutSerialNumber();
1080
                // Execute the insert statement
1081
                PreparedStatement stmt = dbConn.prepareStatement(sql);
1082
                stmt.setString(1, sid);
1083
                ResultSet rs = stmt.executeQuery();
1084
                if (rs.next())
1085
                {
1086
                    exists = true;
1087
                }
1088
1089
            } catch (SQLException e) {
1090
                logMetacat.error("Error while checking if the sid "+sid+" exists on the series_id field of the system metadata table: "
1091
                        + e.getMessage());
1092
                throw e;
1093
            } finally {
1094
                // Return database connection to the pool
1095
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1096
            }
1097
        }
1098
        return exists;
1099
    }
1100
1101 9032 tao
    /**
1102
     * Determine if the specified identifier object exists or not.
1103
     * @param pid - the specified identifier
1104
     * @return true if it is exists.
1105
     * @throws SQLException
1106
     * @throws NullPointerException
1107
     */
1108
    public boolean systemMetadataPIDExists(Identifier pid) throws SQLException {
1109
        if (pid != null && pid.getValue() != null && !pid.getValue().trim().equals("")) {
1110
            return systemMetadataPIDExists(pid.getValue());
1111
        } else {
1112
            return false;
1113
        }
1114
    }
1115
1116 9030 tao
    public boolean systemMetadataPIDExists(String guid) throws SQLException {
1117 6123 leinfelder
		logMetacat.debug("looking up system metadata for guid " + guid);
1118
		boolean exists = false;
1119 6337 leinfelder
		String query = "select guid from systemmetadata where guid = ?";
1120 6123 leinfelder
		DBConnection dbConn = null;
1121
		int serialNumber = -1;
1122 9032 tao
		if(guid != null && !guid.trim().equals("")) {
1123
		    try {
1124
	            // Get a database connection from the pool
1125
	            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
1126
	            serialNumber = dbConn.getCheckOutSerialNumber();
1127 6123 leinfelder
1128 9032 tao
	            // Execute the insert statement
1129
	            PreparedStatement stmt = dbConn.prepareStatement(query);
1130
	            stmt.setString(1, guid);
1131
	            ResultSet rs = stmt.executeQuery();
1132
	            if (rs.next()) {
1133
	                exists = true;
1134
	            }
1135 6123 leinfelder
1136 9032 tao
	        } catch (SQLException e) {
1137
	            logMetacat.error("Error while looking up the system metadata: "
1138
	                    + e.getMessage());
1139
	            throw e;
1140
	        } finally {
1141
	            // Return database connection to the pool
1142
	            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1143
	        }
1144 6123 leinfelder
		}
1145
		return exists;
1146
	}
1147
1148 5333 berkley
    /**
1149 5887 berkley
     * creates a system metadata mapping and adds additional fields from sysmeta
1150
     * to the table for quick searching.
1151
     *
1152
     * @param guid the id to insert
1153
     * @param localId the systemMetadata object to get the local id for
1154 6108 leinfelder
     * @throws McdbDocNotFoundException
1155 6892 cjones
     * @throws SQLException
1156 6904 cjones
     * @throws InvalidSystemMetadata
1157 5887 berkley
     */
1158 7188 leinfelder
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta)
1159 6904 cjones
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1160 6277 leinfelder
    	String guid = sysmeta.getIdentifier().getValue();
1161 7188 leinfelder
1162
    	 // Get a database connection from the pool
1163
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1164
        int serialNumber = dbConn.getCheckOutSerialNumber();
1165 6892 cjones
1166 7188 leinfelder
        try {
1167
        	// use a single transaction for it all
1168
        	dbConn.setAutoCommit(false);
1169
1170
	    	// insert the record if needed
1171 9030 tao
        	if (!IdentifierManager.getInstance().systemMetadataPIDExists(guid)) {
1172 7188 leinfelder
    	        insertSystemMetadata(guid, dbConn);
1173
			}
1174
	        // update with the values
1175
	        updateSystemMetadata(sysmeta, dbConn);
1176
1177
	        // commit if we got here with no errors
1178
	        dbConn.commit();
1179
        } catch (Exception e) {
1180
            e.printStackTrace();
1181
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1182
            dbConn.rollback();
1183
        } finally {
1184
            // Return database connection to the pool
1185
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1186
        }
1187
1188
1189 5887 berkley
    }
1190 6099 leinfelder
1191 5887 berkley
1192
    /**
1193 6079 leinfelder
     * update a mapping
1194
     * @param guid
1195
     * @param localId
1196
     */
1197
    public void updateMapping(String guid, String localId)
1198
    {
1199
1200 6099 leinfelder
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1201 5350 berkley
        int serialNumber = -1;
1202
        DBConnection dbConn = null;
1203
        try {
1204
            // Parse the localId into scope and rev parts
1205
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1206
            String docid = acc.getDocid();
1207
            int rev = 1;
1208
            if(acc.getRev() != null)
1209
            {
1210
              rev = (new Integer(acc.getRev()).intValue());
1211
            }
1212
1213
            // Get a database connection from the pool
1214
            dbConn =
1215 6079 leinfelder
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1216 5350 berkley
            serialNumber = dbConn.getCheckOutSerialNumber();
1217
1218 6099 leinfelder
            // Execute the update statement
1219 6595 leinfelder
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1220 5350 berkley
            PreparedStatement stmt = dbConn.prepareStatement(query);
1221
            stmt.setString(1, docid);
1222
            stmt.setInt(2, rev);
1223 6595 leinfelder
            stmt.setString(3, guid);
1224 5350 berkley
            int rows = stmt.executeUpdate();
1225
1226
            stmt.close();
1227
        } catch (SQLException e) {
1228
            e.printStackTrace();
1229 6079 leinfelder
            logMetacat.error("SQL error while updating a mapping identifier: "
1230 5350 berkley
                    + e.getMessage());
1231
        } catch (NumberFormatException e) {
1232
            e.printStackTrace();
1233 6079 leinfelder
            logMetacat.error("NumberFormat error while updating a mapping identifier: "
1234 5350 berkley
                    + e.getMessage());
1235
        } catch (AccessionNumberException e) {
1236
            e.printStackTrace();
1237 6079 leinfelder
            logMetacat.error("AccessionNumber error while updating a mapping identifier: "
1238 5350 berkley
                    + e.getMessage());
1239
        } finally {
1240
            // Return database connection to the pool
1241
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1242
        }
1243 6099 leinfelder
        logMetacat.debug("done updating mapping");
1244 5350 berkley
    }
1245 6099 leinfelder
1246
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1247 6892 cjones
        String checksum, String checksumAlgorithm, String originMemberNode,
1248
        String authoritativeMemberNode, long modifiedDate, String submitter,
1249
        String guid, String objectFormat, BigInteger size, boolean archived,
1250
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1251 8810 leinfelder
        String obsoletedBy, BigInteger serialVersion, String seriesId, DBConnection dbConn) throws SQLException  {
1252 7188 leinfelder
1253
        // Execute the insert statement
1254
        String query = "update " + TYPE_SYSTEM_METADATA +
1255
            " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1256
            "origin_member_node, authoritive_member_node, date_modified, " +
1257
            "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1258 8810 leinfelder
            "obsoletes, obsoleted_by, serial_version, series_id) " +
1259
            "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1260 7188 leinfelder
        PreparedStatement stmt = dbConn.prepareStatement(query);
1261 6892 cjones
1262 7188 leinfelder
        //data values
1263
        stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1264
        stmt.setString(2, rightsHolder);
1265
        stmt.setString(3, checksum);
1266
        stmt.setString(4, checksumAlgorithm);
1267
        stmt.setString(5, originMemberNode);
1268
        stmt.setString(6, authoritativeMemberNode);
1269
        stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1270
        stmt.setString(8, submitter);
1271
        stmt.setString(9, objectFormat);
1272
        stmt.setString(10, size.toString());
1273
        stmt.setBoolean(11, archived);
1274
        stmt.setBoolean(12, replicationAllowed);
1275
        stmt.setInt(13, numberReplicas);
1276
        stmt.setString(14, obsoletes);
1277
        stmt.setString(15, obsoletedBy);
1278
        stmt.setString(16, serialVersion.toString());
1279 8810 leinfelder
        stmt.setString(17, seriesId);
1280 7188 leinfelder
1281 8810 leinfelder
1282 7188 leinfelder
        //where clause
1283 8810 leinfelder
        stmt.setString(18, guid);
1284 7188 leinfelder
        logMetacat.debug("stmt: " + stmt.toString());
1285
        //execute
1286
        int rows = stmt.executeUpdate();
1287
1288
        stmt.close();
1289
1290
    }
1291
1292
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1293
    {
1294
1295
        // remove existing values first
1296 7392 leinfelder
        String delete = "delete from smReplicationPolicy " +
1297 7188 leinfelder
        "where guid = ? and policy = ?";
1298
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1299
        //data values
1300
        stmt.setString(1, guid);
1301
        stmt.setString(2, policy);
1302
        //execute
1303
        int deletedCount = stmt.executeUpdate();
1304
        stmt.close();
1305 5957 berkley
1306 7188 leinfelder
        for (String memberNode: memberNodes) {
1307 5887 berkley
            // Execute the insert statement
1308 7392 leinfelder
            String insert = "insert into smReplicationPolicy " +
1309 7188 leinfelder
                "(guid, policy, member_node) " +
1310
                "values (?, ?, ?)";
1311
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1312 5887 berkley
1313
            //data values
1314 7188 leinfelder
            insertStatement.setString(1, guid);
1315
            insertStatement.setString(2, policy);
1316
            insertStatement.setString(3, memberNode);
1317
1318 7392 leinfelder
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1319 6375 leinfelder
1320 5887 berkley
            //execute
1321 7188 leinfelder
            int rows = insertStatement.executeUpdate();
1322
            insertStatement.close();
1323 5887 berkley
        }
1324 7188 leinfelder
1325 5887 berkley
    }
1326
1327 7188 leinfelder
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1328
1329
        // remove existing values first
1330 7392 leinfelder
        String delete = "delete from smReplicationStatus " +
1331 7188 leinfelder
        "where guid = ?";
1332
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1333
        //data values
1334
        stmt.setString(1, guid);
1335
        //execute
1336
        int deletedCount = stmt.executeUpdate();
1337
        stmt.close();
1338 6107 leinfelder
1339 7188 leinfelder
        if (replicas != null) {
1340
            for (Replica replica: replicas) {
1341 6107 leinfelder
	            // Execute the insert statement
1342 7392 leinfelder
	            String insert = "insert into smReplicationStatus " +
1343 7188 leinfelder
	                "(guid, member_node, status, date_verified) " +
1344
	                "values (?, ?, ?, ?)";
1345 6107 leinfelder
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1346
1347
	            //data values
1348 7188 leinfelder
	            String memberNode = replica.getReplicaMemberNode().getValue();
1349
	            String status = replica.getReplicationStatus().toString();
1350 7399 cjones
	            java.sql.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1351 6107 leinfelder
	            insertStatement.setString(1, guid);
1352 7188 leinfelder
	            insertStatement.setString(2, memberNode);
1353
	            insertStatement.setString(3, status);
1354 7399 cjones
	            insertStatement.setTimestamp(4, sqlDate);
1355 7188 leinfelder
1356 7392 leinfelder
	            logMetacat.debug("smReplicationStatus sql: " + insertStatement.toString());
1357 7102 leinfelder
1358 6107 leinfelder
	            //execute
1359
	            int rows = insertStatement.executeUpdate();
1360
	            insertStatement.close();
1361
            }
1362
        }
1363 7188 leinfelder
1364 6107 leinfelder
    }
1365
1366 5334 berkley
    /**
1367 5887 berkley
     * Insert the system metadata fields into the db
1368
     * @param sm
1369 6108 leinfelder
     * @throws McdbDocNotFoundException
1370 6892 cjones
     * @throws SQLException
1371 6904 cjones
     * @throws InvalidSystemMetadata
1372 7188 leinfelder
     * @throws AccessException
1373 5887 berkley
     */
1374 7188 leinfelder
    public void updateSystemMetadata(SystemMetadata sm, DBConnection dbConn)
1375
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata, AccessException {
1376 6107 leinfelder
1377 6892 cjones
      Boolean replicationAllowed = false;
1378
		  Integer numberReplicas = -1;
1379 6107 leinfelder
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1380
    	if (replicationPolicy != null) {
1381
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1382
    		numberReplicas = replicationPolicy.getNumberReplicas();
1383
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1384
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1385
    	}
1386 6904 cjones
1387 6107 leinfelder
    	// the main systemMetadata fields
1388 6892 cjones
		  updateSystemMetadataFields(
1389 6311 leinfelder
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1390
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(),
1391
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(),
1392 6397 leinfelder
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(),
1393 6311 leinfelder
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1394
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(),
1395
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1396
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(),
1397 6904 cjones
		    sm.getIdentifier().getValue(),
1398
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1399
		    sm.getSize(),
1400
		    sm.getArchived() == null ? false: sm.getArchived(),
1401
		    replicationAllowed,
1402
		    numberReplicas,
1403
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1404
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1405 7188 leinfelder
		    sm.getSerialVersion(),
1406 8810 leinfelder
		    sm.getSeriesId() == null ? null: sm.getSeriesId().getValue(),
1407 7188 leinfelder
		    dbConn
1408 6561 leinfelder
        );
1409 6097 leinfelder
1410
        String guid = sm.getIdentifier().getValue();
1411
1412 6107 leinfelder
        // save replication policies
1413
        if (replicationPolicy != null) {
1414
		    List<String> nodes = null;
1415
		    String policy = null;
1416
1417 6494 leinfelder
		    // check for null
1418
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1419
			    nodes = new ArrayList<String>();
1420
			    policy = "blocked";
1421
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1422
			    	nodes.add(node.getValue());
1423
			    }
1424 7188 leinfelder
			    this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1425 6107 leinfelder
		    }
1426
1427 6494 leinfelder
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1428
			    nodes = new ArrayList<String>();
1429
			    policy = "preferred";
1430
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1431
			    	nodes.add(node.getValue());
1432
			    }
1433 7188 leinfelder
		        this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1434 6107 leinfelder
		    }
1435
        }
1436 6097 leinfelder
1437 6107 leinfelder
        // save replica information
1438 7188 leinfelder
        this.insertReplicationStatus(guid, sm.getReplicaList(), dbConn);
1439 6107 leinfelder
1440 6108 leinfelder
        // save access policy
1441
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1442
        if (accessPolicy != null) {
1443 7188 leinfelder
			this.insertAccessPolicy(guid, accessPolicy);
1444 6108 leinfelder
        }
1445 5887 berkley
    }
1446
1447
    /**
1448 6108 leinfelder
     * Creates Metacat access rules and inserts them
1449
     * @param accessPolicy
1450
     * @throws McdbDocNotFoundException
1451
     * @throws AccessException
1452
     */
1453
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1454
1455 6744 leinfelder
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1456
        XMLAccessAccess accessController  = new XMLAccessAccess();
1457
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1458
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1459
        if (existingAccess != null && existingAccess.size() > 0) {
1460
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1461
        }
1462
1463 6108 leinfelder
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1464
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1465
        	List<Subject> subjects = accessRule.getSubjectList();
1466
        	List<Permission> permissions = accessRule.getPermissionList();
1467
        	for (Subject subject: subjects) {
1468 6122 leinfelder
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1469
        		accessDAO.setPrincipalName(subject.getValue());
1470
    			accessDAO.setGuid(guid);
1471
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1472 6744 leinfelder
				accessDAO.setPermOrder(existingPermOrder);
1473
    			if (permissions != null) {
1474
	    			for (Permission permission: permissions) {
1475
	    				Long metacatPermission = new Long(convertPermission(permission));
1476
	        			accessDAO.addPermission(metacatPermission);
1477
	    			}
1478 6122 leinfelder
    			}
1479
    			accessDAOs.add(accessDAO);
1480 6108 leinfelder
        	}
1481
        }
1482
1483
1484 6744 leinfelder
        // remove all existing allow records
1485
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1486
        // add the ones we can for this guid
1487
        accessController.insertAccess(guid, accessDAOs);
1488 6108 leinfelder
1489 6744 leinfelder
1490 6108 leinfelder
    }
1491
1492
    /**
1493
     * Lookup access policy from Metacat
1494
     * @param guid
1495
     * @return
1496
     * @throws McdbDocNotFoundException
1497
     * @throws AccessException
1498
     */
1499 6720 leinfelder
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1500 6450 leinfelder
        AccessPolicy accessPolicy = new AccessPolicy();
1501
1502 6122 leinfelder
    	// use GUID to look up the access
1503 6744 leinfelder
        XMLAccessAccess accessController  = new XMLAccessAccess();
1504 6720 leinfelder
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1505
1506 6108 leinfelder
        for (XMLAccessDAO accessDAO: accessDAOs) {
1507 6744 leinfelder
        	// only add allow rule
1508
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1509
	        	AccessRule accessRule = new AccessRule();
1510
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1511 7088 leinfelder
	        	// cannot include if we have no permissions
1512
	        	if (permissions == null || permissions.isEmpty()) {
1513
	        		logMetacat.warn("skipping empty access rule permissions for " + guid);
1514
	        		continue;
1515
	        	}
1516 6744 leinfelder
	        	accessRule.setPermissionList(permissions);
1517
	        	Subject subject = new Subject();
1518
	        	subject.setValue(accessDAO.getPrincipalName());
1519
	        	accessRule.addSubject(subject);
1520
	            accessPolicy.addAllow(accessRule);
1521
        	}
1522 6108 leinfelder
        }
1523
        return accessPolicy;
1524
    }
1525
1526
    public int convertPermission(Permission permission) {
1527
    	if (permission.equals(Permission.READ)) {
1528
    		return AccessControlInterface.READ;
1529
    	}
1530
    	if (permission.equals(Permission.WRITE)) {
1531
    		return AccessControlInterface.WRITE;
1532
    	}
1533
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1534
    		return AccessControlInterface.CHMOD;
1535
    	}
1536
		return -1;
1537
    }
1538
1539 6722 leinfelder
    public List<Permission> convertPermission(int permission) {
1540 6744 leinfelder
1541 6722 leinfelder
    	List<Permission> permissions = new ArrayList<Permission>();
1542 6744 leinfelder
    	if (permission == AccessControlInterface.ALL) {
1543 6722 leinfelder
    		permissions.add(Permission.READ);
1544
    		permissions.add(Permission.WRITE);
1545 6744 leinfelder
    		permissions.add(Permission.CHANGE_PERMISSION);
1546 6722 leinfelder
    		return permissions;
1547 6108 leinfelder
    	}
1548 6744 leinfelder
1549
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1550 6722 leinfelder
    		permissions.add(Permission.CHANGE_PERMISSION);
1551 6108 leinfelder
    	}
1552 6744 leinfelder
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1553 6722 leinfelder
    		permissions.add(Permission.READ);
1554 6744 leinfelder
    	}
1555
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1556 6722 leinfelder
    		permissions.add(Permission.WRITE);
1557 6720 leinfelder
    	}
1558 6744 leinfelder
1559
		return permissions;
1560 6108 leinfelder
    }
1561
1562
    /**
1563 6099 leinfelder
     * Lookup a localId given the GUID. If
1564
     * the identifier is not found, throw an exception.
1565
     *
1566
     * @param guid the global identifier to look up
1567
     * @return String containing the corresponding LocalId
1568
     * @throws McdbDocNotFoundException if the identifier is not found
1569 5334 berkley
     */
1570 9024 tao
    public String getLocalId(String guid) throws McdbDocNotFoundException, SQLException {
1571 5334 berkley
1572
      String db_guid = "";
1573
      String docid = "";
1574
      int rev = 0;
1575
1576 6099 leinfelder
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1577 5334 berkley
1578
      DBConnection dbConn = null;
1579 5333 berkley
      int serialNumber = -1;
1580 5334 berkley
      try {
1581
          // Get a database connection from the pool
1582
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1583
          serialNumber = dbConn.getCheckOutSerialNumber();
1584
1585
          // Execute the insert statement
1586
          PreparedStatement stmt = dbConn.prepareStatement(query);
1587
          stmt.setString(1, guid);
1588
          ResultSet rs = stmt.executeQuery();
1589
          if (rs.next()) {
1590
              db_guid = rs.getString(1);
1591
              docid = rs.getString(2);
1592
              rev = rs.getInt(3);
1593
              assert(db_guid.equals(guid));
1594
          } else {
1595
              throw new McdbDocNotFoundException("Document not found:" + guid);
1596
          }
1597
          stmt.close();
1598
      } catch (SQLException e) {
1599
          logMetacat.error("Error while looking up the local identifier: "
1600
                  + e.getMessage());
1601 9024 tao
          throw e;
1602 5334 berkley
      } finally {
1603
          // Return database connection to the pool
1604
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1605
      }
1606
      return docid + "." + rev;
1607
    }
1608
1609 5377 berkley
    /**
1610 5895 berkley
     * query the systemmetadata table based on the given parameters
1611
     * @param startTime
1612
     * @param endTime
1613
     * @param objectFormat
1614
     * @param replicaStatus
1615
     * @param start
1616
     * @param count
1617
     * @return ObjectList
1618 6299 leinfelder
     * @throws SQLException
1619
     * @throws ServiceException
1620
     * @throws PropertyNotFoundException
1621 5895 berkley
     */
1622 6836 cjones
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1623
        ObjectFormatIdentifier objectFormatId, boolean replicaStatus,
1624 9072 tao
        int start, int count, Identifier identifier, boolean isSID)
1625 6836 cjones
        throws SQLException, PropertyNotFoundException, ServiceException {
1626 5895 berkley
        ObjectList ol = new ObjectList();
1627 5943 berkley
        DBConnection dbConn = null;
1628
        int serialNumber = -1;
1629 6836 cjones
1630 6299 leinfelder
        try {
1631 7452 leinfelder
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1632 6836 cjones
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1633
                    + "date_modified, submitter, object_format, size from systemmetadata";
1634 7410 leinfelder
1635
            // handle special case quickly
1636
            String countSql = "select count(guid) from systemmetadata";
1637 7452 leinfelder
1638
            // the clause
1639
            String whereClauseSql = "";
1640 6836 cjones
1641 5895 berkley
            boolean f1 = false;
1642
            boolean f2 = false;
1643
            boolean f3 = false;
1644 9072 tao
            boolean f4 = false;
1645 6836 cjones
1646 9072 tao
1647 6299 leinfelder
            if (startTime != null) {
1648 7452 leinfelder
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1649 5895 berkley
                f1 = true;
1650
            }
1651 6836 cjones
1652 6299 leinfelder
            if (endTime != null) {
1653
                if (!f1) {
1654 7452 leinfelder
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1655 6836 cjones
                } else {
1656 7452 leinfelder
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1657 5917 berkley
                }
1658 5895 berkley
                f2 = true;
1659
            }
1660 6836 cjones
1661 6337 leinfelder
            if (objectFormatId != null) {
1662 6299 leinfelder
                if (!f1 && !f2) {
1663 7452 leinfelder
                    whereClauseSql += " where object_format = ?";
1664 6836 cjones
                } else {
1665 7452 leinfelder
                    whereClauseSql += " and object_format = ?";
1666 5917 berkley
                }
1667 5895 berkley
                f3 = true;
1668
            }
1669 9072 tao
1670
            if(identifier != null && identifier.getValue() != null && !identifier.getValue().equals("")) {
1671
                if (!f1 && !f2 && !f3 ) {
1672
                    if(isSID) {
1673
                        whereClauseSql += " where series_id = ?";
1674
                    } else {
1675
                        whereClauseSql += " where guid = ?";
1676
                    }
1677
1678
                } else {
1679
                    if(isSID) {
1680
                        whereClauseSql += " and series_id = ?";
1681
                    } else {
1682
                        whereClauseSql += " and guid = ?";
1683
                    }
1684
                }
1685
                f4 = true;
1686
            }
1687 6836 cjones
1688 7447 cjones
            if (!replicaStatus) {
1689 7030 cjones
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1690 9072 tao
                if (!f1 && !f2 && !f3 && !f4) {
1691 7462 leinfelder
                    whereClauseSql += " where authoritive_member_node = '" +
1692 6836 cjones
                        currentNodeId.trim() + "'";
1693
                } else {
1694 7462 leinfelder
                    whereClauseSql += " and authoritive_member_node = '" +
1695 6836 cjones
                        currentNodeId.trim() + "'";
1696 5917 berkley
                }
1697 5895 berkley
            }
1698 7310 leinfelder
1699 9072 tao
1700
1701 7452 leinfelder
            // connection
1702 5943 berkley
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1703
            serialNumber = dbConn.getCheckOutSerialNumber();
1704 6836 cjones
1705 7452 leinfelder
            // the field query
1706
            String orderBySql = " order by guid ";
1707
            String fieldQuery = fieldSql + whereClauseSql + orderBySql;
1708
            String finalQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldQuery, start, count);
1709
            PreparedStatement fieldStmt = dbConn.prepareStatement(finalQuery);
1710
1711
            // construct the count query and statment
1712
            String countQuery = countSql + whereClauseSql;
1713
            PreparedStatement countStmt = dbConn.prepareStatement(countQuery);
1714
1715 9072 tao
            if (f1 && f2 && f3 && f4) {
1716 7452 leinfelder
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1717
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1718
                fieldStmt.setString(3, objectFormatId.getValue());
1719 9072 tao
                fieldStmt.setString(4, identifier.getValue());
1720 7452 leinfelder
                // count
1721
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1722
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1723
                countStmt.setString(3, objectFormatId.getValue());
1724 9072 tao
                countStmt.setString(4, identifier.getValue());
1725
            } if (f1 && f2 && f3 && !f4) {
1726 7452 leinfelder
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1727
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1728 9072 tao
                fieldStmt.setString(3, objectFormatId.getValue());
1729 7452 leinfelder
                // count
1730
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1731
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1732 9072 tao
                countStmt.setString(3, objectFormatId.getValue());
1733
            } else if (f1 && f2 && !f3 && f4) {
1734 7452 leinfelder
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1735 9072 tao
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1736
                fieldStmt.setString(3, identifier.getValue());
1737
                // count
1738
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1739
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1740
                countStmt.setString(3, identifier.getValue());
1741
            } else if (f1 && f2 && !f3 && !f4) {
1742
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1743
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1744
                // count
1745
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1746
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1747
            } else if (f1 && !f2 && f3 && f4) {
1748
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1749 7452 leinfelder
                fieldStmt.setString(2, objectFormatId.getValue());
1750 9072 tao
                fieldStmt.setString(3, identifier.getValue());
1751 7452 leinfelder
                // count
1752
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1753
                countStmt.setString(2, objectFormatId.getValue());
1754 9072 tao
                countStmt.setString(3, identifier.getValue());
1755
            } else if (f1 && !f2 && f3 && !f4) {
1756 7452 leinfelder
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1757 9072 tao
                fieldStmt.setString(2, objectFormatId.getValue());
1758 7452 leinfelder
                // count
1759
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1760 9072 tao
                countStmt.setString(2, objectFormatId.getValue());
1761
            } else if (f1 && !f2 && !f3 && f4) {
1762
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1763
                fieldStmt.setString(2, identifier.getValue());
1764
                // count
1765
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1766
                countStmt.setString(2, identifier.getValue());
1767
            } else if (f1 && !f2 && !f3 && !f4) {
1768
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1769
                // count
1770
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1771
            } else if (!f1 && f2 && f3 && f4) {
1772 7452 leinfelder
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1773
                fieldStmt.setString(2, objectFormatId.getValue());
1774 9072 tao
                fieldStmt.setString(3, identifier.getValue());
1775 7452 leinfelder
                // count
1776
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1777
                countStmt.setString(2, objectFormatId.getValue());
1778 9072 tao
                countStmt.setString(3, identifier.getValue());
1779
            } else if (!f1 && f2 && f3 && !f4) {
1780
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1781
                fieldStmt.setString(2, objectFormatId.getValue());
1782
                // count
1783
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1784
                countStmt.setString(2, objectFormatId.getValue());
1785
            } else if (!f1 && !f2 && f3 && f4) {
1786 7452 leinfelder
                fieldStmt.setString(1, objectFormatId.getValue());
1787 9072 tao
                fieldStmt.setString(2, identifier.getValue());
1788 7452 leinfelder
                // count
1789
                countStmt.setString(1, objectFormatId.getValue());
1790 9072 tao
                countStmt.setString(2, identifier.getValue());
1791
            } else if (!f1 && !f2 && f3 && !f4) {
1792
                fieldStmt.setString(1, objectFormatId.getValue());
1793
                // count
1794
                countStmt.setString(1, objectFormatId.getValue());
1795
            } else if (!f1 && f2 && !f3 && f4) {
1796 7452 leinfelder
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1797 9072 tao
                fieldStmt.setString(2, identifier.getValue());
1798 7452 leinfelder
                // count
1799
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1800 9072 tao
                countStmt.setString(2, identifier.getValue());
1801
            } else if (!f1 && f2 && !f3 && !f4) {
1802
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1803
                // count
1804
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1805
            } else if (!f1 && !f2 && !f3 && f4) {
1806
                fieldStmt.setString(1, identifier.getValue());
1807
                // count
1808
                countStmt.setString(1, identifier.getValue());
1809
            } else if (!f1 && !f2 && !f3 && !f4) {
1810
                //do nothing
1811 5895 berkley
            }
1812 6836 cjones
1813 7461 leinfelder
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
1814
1815
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
1816
1817 7452 leinfelder
            // get the total object count no matter what
1818
            int total = 0;
1819
            ResultSet totalResult = countStmt.executeQuery();
1820
            if (totalResult.next()) {
1821
            	total = totalResult.getInt(1);
1822 5895 berkley
            }
1823 7438 leinfelder
1824 7461 leinfelder
            logMetacat.debug("list objects total: " + total);
1825
1826 7452 leinfelder
        	// set the totals
1827
        	ol.setStart(start);
1828
            ol.setCount(count);
1829
            ol.setTotal(total);
1830
1831
            // retrieve the actual records if requested
1832
            if (count != 0) {
1833
1834
                ResultSet rs = fieldStmt.executeQuery();
1835 7410 leinfelder
	            while (rs.next()) {
1836 7438 leinfelder
1837 7410 leinfelder
	                String guid = rs.getString(1);
1838 7461 leinfelder
	                logMetacat.debug("query found object with guid " + guid);
1839 7410 leinfelder
	                // Timestamp dateUploaded = rs.getTimestamp(2);
1840
	                // String rightsHolder = rs.getString(3);
1841
	                String checksum = rs.getString(4);
1842
	                String checksumAlgorithm = rs.getString(5);
1843
	                // String originMemberNode = rs.getString(6);
1844
	                // String authoritiveMemberNode = rs.getString(7);
1845
	                Timestamp dateModified = rs.getTimestamp(8);
1846
	                // String submitter = rs.getString(9);
1847
	                String fmtidStr = rs.getString(10);
1848
	                String sz = rs.getString(11);
1849
	                BigInteger size = new BigInteger("0");
1850
1851
	                if (sz != null && !sz.trim().equals("")) {
1852
	                    size = new BigInteger(rs.getString(11));
1853
	                }
1854
1855
	                ObjectInfo oi = new ObjectInfo();
1856
1857
	                Identifier id = new Identifier();
1858
	                id.setValue(guid);
1859
	                oi.setIdentifier(id);
1860
1861
	                if (dateModified != null) {
1862
	                    oi.setDateSysMetadataModified(dateModified);
1863
	                }
1864
1865
	                Checksum cs = new Checksum();
1866
	                cs.setValue(checksum);
1867
	                try {
1868
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1869
	                    cs.setAlgorithm(checksumAlgorithm);
1870
	                } catch (Exception e) {
1871
	                    logMetacat.error("could not parse checksum algorithm", e);
1872
	                    continue;
1873
	                }
1874
	                oi.setChecksum(cs);
1875
1876
	                // set the format type
1877
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1878
	                fmtid.setValue(fmtidStr);
1879
	                oi.setFormatId(fmtid);
1880
1881
	                oi.setSize(size);
1882
1883 7438 leinfelder
	                ol.addObjectInfo(oi);
1884
1885 7410 leinfelder
	            }
1886 7452 leinfelder
1887 7461 leinfelder
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
1888
1889 7452 leinfelder
	            // set the actual count retrieved
1890
	            ol.setCount(ol.sizeObjectInfoList());
1891 7410 leinfelder
1892
	        }
1893
1894 5895 berkley
        }
1895 6836 cjones
1896 6299 leinfelder
        finally {
1897 5943 berkley
            // Return database connection to the pool
1898
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1899
        }
1900 6836 cjones
1901 5895 berkley
        return ol;
1902
    }
1903
1904
    /**
1905 6099 leinfelder
     * create a mapping in the identifier table
1906 5377 berkley
     * @param guid
1907
     * @param localId
1908
     */
1909 6099 leinfelder
    public void createMapping(String guid, String localId)
1910 5453 berkley
    {
1911 5334 berkley
1912
        int serialNumber = -1;
1913 5333 berkley
        DBConnection dbConn = null;
1914
        try {
1915
1916
            // Parse the localId into scope and rev parts
1917
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1918
            String docid = acc.getDocid();
1919 5344 berkley
            int rev = 1;
1920 6099 leinfelder
            if (acc.getRev() != null) {
1921 5344 berkley
              rev = (new Integer(acc.getRev()).intValue());
1922
            }
1923 5333 berkley
1924
            // Get a database connection from the pool
1925 6099 leinfelder
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1926 5333 berkley
            serialNumber = dbConn.getCheckOutSerialNumber();
1927
1928
            // Execute the insert statement
1929 6099 leinfelder
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1930 5333 berkley
            PreparedStatement stmt = dbConn.prepareStatement(query);
1931
            stmt.setString(1, guid);
1932
            stmt.setString(2, docid);
1933
            stmt.setInt(3, rev);
1934 6099 leinfelder
            logMetacat.debug("mapping query: " + stmt.toString());
1935 5333 berkley
            int rows = stmt.executeUpdate();
1936
1937
            stmt.close();
1938
        } catch (SQLException e) {
1939 5344 berkley
            e.printStackTrace();
1940 6099 leinfelder
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: "
1941 5333 berkley
                    + e.getMessage());
1942
        } catch (NumberFormatException e) {
1943 5344 berkley
            e.printStackTrace();
1944 6099 leinfelder
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: "
1945 5333 berkley
                    + e.getMessage());
1946
        } catch (AccessionNumberException e) {
1947 5344 berkley
            e.printStackTrace();
1948 6099 leinfelder
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: "
1949 5333 berkley
                    + e.getMessage());
1950
        } finally {
1951
            // Return database connection to the pool
1952
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1953
        }
1954
    }
1955 6099 leinfelder
1956
    /**
1957 7017 leinfelder
     * remove a mapping in the identifier table
1958
     * @param guid
1959
     * @param localId
1960
     */
1961
    public void removeMapping(String guid, String localId)
1962
    {
1963
1964
        int serialNumber = -1;
1965
        DBConnection dbConn = null;
1966
        try {
1967
1968
            // Parse the localId into scope and rev parts
1969
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1970
            String docid = acc.getDocid();
1971
            int rev = 1;
1972
            if (acc.getRev() != null) {
1973
              rev = (new Integer(acc.getRev()).intValue());
1974
            }
1975
1976
            // Get a database connection from the pool
1977
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
1978
            serialNumber = dbConn.getCheckOutSerialNumber();
1979
1980
            // Execute the insert statement
1981
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
1982
            PreparedStatement stmt = dbConn.prepareStatement(query);
1983
            stmt.setString(1, guid);
1984
            stmt.setString(2, docid);
1985
            stmt.setInt(3, rev);
1986
            logMetacat.debug("remove mapping query: " + stmt.toString());
1987
            int rows = stmt.executeUpdate();
1988
1989
            stmt.close();
1990
        } catch (SQLException e) {
1991
            e.printStackTrace();
1992
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: "
1993
                    + e.getMessage());
1994
        } catch (NumberFormatException e) {
1995
            e.printStackTrace();
1996
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: "
1997
                    + e.getMessage());
1998
        } catch (AccessionNumberException e) {
1999
            e.printStackTrace();
2000
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: "
2001
                    + e.getMessage());
2002
        } finally {
2003
            // Return database connection to the pool
2004
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2005
        }
2006
    }
2007
2008
    /**
2009 6099 leinfelder
     * create the systemmetadata record
2010
     * @param guid
2011 7188 leinfelder
     * @param dbConn
2012
     * @throws SQLException
2013 6099 leinfelder
     */
2014 7188 leinfelder
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
2015 6099 leinfelder
    {
2016
2017 7188 leinfelder
        // Execute the insert statement
2018
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
2019
        PreparedStatement stmt = dbConn.prepareStatement(query);
2020
        stmt.setString(1, guid);
2021
        logMetacat.debug("system metadata query: " + stmt.toString());
2022
        int rows = stmt.executeUpdate();
2023 6099 leinfelder
2024 7188 leinfelder
        stmt.close();
2025
2026 6099 leinfelder
    }
2027 6277 leinfelder
2028 8852 tao
    public boolean deleteSystemMetadata(String guid)
2029 6277 leinfelder
    {
2030 8852 tao
        boolean success = false;
2031 6277 leinfelder
        int serialNumber = -1;
2032
        DBConnection dbConn = null;
2033 6648 leinfelder
        String query = null;
2034
        PreparedStatement stmt = null;
2035
        int rows = 0;
2036 6277 leinfelder
        try {
2037
2038 8852 tao
        	 // Get a database connection from the pool
2039 6648 leinfelder
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
2040 6277 leinfelder
            serialNumber = dbConn.getCheckOutSerialNumber();
2041 8852 tao
            dbConn.setAutoCommit(false);
2042
2043 7392 leinfelder
            // remove the smReplicationPolicy
2044
            query = "delete from smReplicationPolicy " +
2045 6648 leinfelder
            "where guid = ?";
2046
            stmt = dbConn.prepareStatement(query);
2047
            stmt.setString(1, guid);
2048 7392 leinfelder
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
2049 6648 leinfelder
            rows = stmt.executeUpdate();
2050
            stmt.close();
2051
2052 7392 leinfelder
            // remove the smReplicationStatus
2053
            query = "delete from smReplicationStatus " +
2054 6648 leinfelder
            "where guid = ?";
2055
            stmt = dbConn.prepareStatement(query);
2056
            stmt.setString(1, guid);
2057 7392 leinfelder
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
2058 6648 leinfelder
            rows = stmt.executeUpdate();
2059
            stmt.close();
2060
2061 8852 tao
            // remove main system metadata entry
2062
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
2063
            stmt = dbConn.prepareStatement(query);
2064
            stmt.setString(1, guid);
2065
            logMetacat.debug("delete system metadata: " + stmt.toString());
2066
            rows = stmt.executeUpdate();
2067
            stmt.close();
2068
2069
            dbConn.commit();
2070
            dbConn.setAutoCommit(true);
2071
            success = true;
2072 6744 leinfelder
            // TODO: remove the access?
2073 6648 leinfelder
            // Metacat keeps "deleted" documents so we should not remove access rules.
2074
2075 6277 leinfelder
        } catch (Exception e) {
2076
            e.printStackTrace();
2077
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
2078 6648 leinfelder
            try {
2079
				dbConn.rollback();
2080
			} catch (SQLException sqle) {
2081
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
2082
			}
2083 6277 leinfelder
        } finally {
2084
            // Return database connection to the pool
2085
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2086
        }
2087 8852 tao
        return success;
2088 6277 leinfelder
    }
2089 6862 leinfelder
2090
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
2091
    {
2092
        DBConnection dbConn = null;
2093
        int serialNumber = -1;
2094
2095
        try {
2096
            // Get a database connection from the pool
2097
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
2098
            serialNumber = dbConn.getCheckOutSerialNumber();
2099
2100
            // Execute the insert statement
2101
            String query = "update " + TYPE_SYSTEM_METADATA +
2102
                " set authoritive_member_node = ? " +
2103
                " where authoritive_member_node = ?";
2104
            PreparedStatement stmt = dbConn.prepareStatement(query);
2105
2106
            //data values
2107
            stmt.setString(1, newMemberNodeId);
2108
            stmt.setString(2, existingMemberNodeId);
2109
2110
            logMetacat.debug("stmt: " + stmt.toString());
2111
            //execute
2112
            int rows = stmt.executeUpdate();
2113
2114
            stmt.close();
2115
        } catch (SQLException e) {
2116
            e.printStackTrace();
2117
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: "
2118
                    + e.getMessage());
2119
        } catch (NumberFormatException e) {
2120
            e.printStackTrace();
2121
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: "
2122
                    + e.getMessage());
2123
        } finally {
2124
            // Return database connection to the pool
2125
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2126
        }
2127
    }
2128 5282 jones
}