Project

General

Profile

1
/**
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
import java.math.BigInteger;
28
import java.sql.PreparedStatement;
29
import java.sql.ResultSet;
30
import java.sql.SQLException;
31
import java.sql.Timestamp;
32
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

    
38
import org.apache.log4j.Logger;
39
import org.dataone.client.v2.formats.ObjectFormatCache;
40
import org.dataone.service.exceptions.BaseException;
41
import org.dataone.service.exceptions.InvalidSystemMetadata;
42
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
import org.dataone.service.types.v2.SystemMetadata;
56

    
57
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessAccess;
58
import edu.ucsb.nceas.metacat.database.DBConnection;
59
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
60
import edu.ucsb.nceas.metacat.database.DatabaseService;
61
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
62
import edu.ucsb.nceas.metacat.properties.PropertyService;
63
import edu.ucsb.nceas.metacat.shared.AccessException;
64
import edu.ucsb.nceas.metacat.shared.ServiceException;
65
import edu.ucsb.nceas.metacat.util.DocumentUtil;
66
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
67
import edu.ucsb.nceas.utilities.access.AccessControlInterface;
68
import edu.ucsb.nceas.utilities.access.XMLAccessDAO;
69

    
70
/**
71
 * Manage the relationship between Metacat local identifiers (LocalIDs) that are
72
 * codified as the (docid, rev) pair with globally unique string identifiers
73
 * (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
    public static final String TYPE_SYSTEM_METADATA = "systemmetadata";
82
    public static final String TYPE_IDENTIFIER = "identifier";
83
  
84
    /**
85
     * The single instance of the manager that is always returned.
86
     */
87
    private static IdentifierManager self = null;
88
    private Logger logMetacat = Logger.getLogger(IdentifierManager.class);
89

    
90
    /**
91
     * A private constructor that initializes the class when getInstance() is
92
     * called.
93
     */
94
    private IdentifierManager() {}
95

    
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
    public SystemMetadata asSystemMetadata(Date dateUploaded, String rightsHolder,
111
            String checksum, String checksumAlgorithm, String originMemberNode,
112
            String authoritativeMemberNode, Date dateModified, String submitter, 
113
            String guid, String fmtidStr, BigInteger size, BigInteger serialVersion) {
114
        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
        checksumObject.setAlgorithm(checksumAlgorithm);
126
        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
        ObjectFormatIdentifier fmtid = null;
138
        try {
139
        	ObjectFormatIdentifier formatId = new ObjectFormatIdentifier();
140
        	formatId.setValue(fmtidStr);
141
        	fmtid = ObjectFormatCache.getInstance().getFormat(formatId).getFormatId();
142
        	sysMeta.setFormatId(fmtid);
143
        	
144
        } catch (BaseException nfe) {
145
            logMetacat.error("The objectFormat " + fmtidStr +
146
          	" is not registered. Setting the default format id.");
147
            fmtid = new ObjectFormatIdentifier();
148
            fmtid.setValue("application/octet-stream");
149
            sysMeta.setFormatId(fmtid);
150
            
151
        }
152
        sysMeta.setSize(size);
153
        sysMeta.setSerialVersion(serialVersion);
154
        
155
        return sysMeta;
156
    }
157
    
158
    /**
159
     * 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
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size " +
178
          "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
                String objectFormat = rs.getString(10);
203
                long size = new Long(rs.getString(11)).longValue();
204
                
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
                h.put("object_format", objectFormat);
215
                h.put("size", new Long(size).toString());
216
                
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
     * return a hash of all of the info that is in the systemmetadata table
243
     * @param guid
244
     * @return
245
     * @throws McdbDocNotFoundException 
246
     */
247
    public SystemMetadata getSystemMetadata(String guid)
248
    	throws McdbDocNotFoundException
249
    {
250
        
251
        SystemMetadata sysMeta = new SystemMetadata();
252
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
253
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size, " +
254
          "replication_allowed, number_replicas, obsoletes, obsoleted_by, serial_version, archived, series_id " +
255
          "from systemmetadata where guid = ?";
256
        DBConnection dbConn = null;
257
        int serialNumber = -1;
258
        Boolean replicationAllowed = new Boolean(false);
259
        BigInteger numberOfReplicas = new BigInteger("-1");
260
        BigInteger serialVersion = new BigInteger("-1");
261
        Boolean archived = new Boolean(false);
262

    
263
        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
            stmt.setString(1, guid);
272
            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
                String fmtidStr = rs.getString(10);
284
                BigInteger size = new BigInteger(rs.getString(11));
285
                replicationAllowed = new Boolean(rs.getBoolean(12));
286
                numberOfReplicas = new BigInteger(rs.getString(13));
287
                String obsoletes = rs.getString(14);
288
                String obsoletedBy = rs.getString(15);
289
                serialVersion = new BigInteger(rs.getString(16));
290
                archived = new Boolean(rs.getBoolean(17));
291
                String series_id = rs.getString(18);
292

    
293
                Identifier sysMetaId = new Identifier();
294
                sysMetaId.setValue(guid);
295
                sysMeta.setIdentifier(sysMetaId);
296
                sysMeta.setSerialVersion(serialVersion);
297
                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
                checksumObject.setAlgorithm(checksumAlgorithm);
304
                sysMeta.setChecksum(checksumObject);
305
                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
                sysMeta.setDateSysMetadataModified(dateModified);
316
                if (submitter != null) {
317
	                Subject submitterSubject = new Subject();
318
	                submitterSubject.setValue(submitter);
319
	                sysMeta.setSubmitter(submitterSubject);
320
                }
321
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
322
                fmtid.setValue(fmtidStr);
323
            	sysMeta.setFormatId(fmtid);
324
                sysMeta.setSize(size);
325
                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
                sysMeta.setArchived(archived);
336
                if(series_id != null) {
337
                    Identifier seriesId = new Identifier();
338
                    seriesId.setValue(series_id);
339
                    sysMeta.setSeriesId(seriesId);
340
                }
341
                stmt.close();
342
            } 
343
            else
344
            {
345
                stmt.close();
346
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
347
                throw new McdbDocNotFoundException("Could not find " + guid);
348
            }
349
            
350
        } 
351
        catch (SQLException e) 
352
        {
353
            e.printStackTrace();
354
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "  
355
                    + e.getMessage());
356
        } 
357
        finally 
358
        {
359
            // Return database connection to the pool
360
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
361
        }
362

    
363
        // populate the replication policy
364
        ReplicationPolicy replicationPolicy = new ReplicationPolicy();
365
        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
        replicationPolicy.setBlockedMemberNodeList(getReplicationPolicy(guid, "blocked"));
375
        replicationPolicy.setPreferredMemberNodeList(getReplicationPolicy(guid, "preferred"));
376
		    sysMeta.setReplicationPolicy(replicationPolicy);
377
		
378
		    // look up replication status
379
		    sysMeta.setReplicaList(getReplicationStatus(guid));
380
		
381
		    // look up access policy
382
		    try {
383
		    	sysMeta.setAccessPolicy(getAccessPolicy(guid));
384
		    } catch (AccessException e) {
385
		    	throw new McdbDocNotFoundException(e);
386
		    }
387
        
388
        return sysMeta;
389
    }
390
    
391
    
392
    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
			"from smReplicationPolicy where guid = ? and policy = ?";
398
	    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
    
431
    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
			"from smReplicationStatus where guid = ?";
436
	    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
	            java.sql.Timestamp verified = rs.getTimestamp(4);
452
	            
453
	            Replica replica = new Replica();	            
454
	            NodeReference node = new NodeReference();
455
	            node.setValue(memberNode);
456
	            replica.setReplicaMemberNode(node);
457
	            replica.setReplicationStatus(ReplicationStatus.valueOf(status));
458
	            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
    
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
        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
        int rev = 0;
493
        String sql = "select rev from xml_documents where docid like ? ";
494
        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
            stmt.setString(1, localId);
505
            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
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
516
            }
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
     * return all local ids in the object store that do not have associated
533
     * system metadata
534
     */
535
    public List<String> getLocalIdsWithNoSystemMetadata(boolean includeRevisions, int serverLocation)
536
    {
537
        Vector<String> ids = new Vector<String>();
538
        String sql = "select docid, rev from xml_documents " +
539
        		"where docid not in " +
540
        		"(select docid from identifier where guid in (select guid from systemmetadata))";
541
        if (serverLocation > 0) {
542
        	sql = sql + " and server_location = ? ";
543
        }
544
        
545
        String revisionSql = "select docid, rev from xml_revisions " +
546
				"where docid not in " +
547
				"(select docid from identifier where guid in (select guid from systemmetadata))";
548
        if (serverLocation > 0) {
549
        	revisionSql = revisionSql + " and server_location = ? ";
550
        }
551
        
552
        if (includeRevisions) {
553
        	sql = sql + " UNION ALL " + revisionSql;
554
        }
555
        
556
        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
            // 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
            ResultSet rs = stmt.executeQuery();
574
            while (rs.next()) 
575
            {
576
                String localid = rs.getString(1);
577
                String rev = rs.getString(2);
578
                localid += "." + rev;
579
                logMetacat.debug("id to add SM for: " + localid);
580
                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
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
604
    //    throws Exception
605
    {
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
    
640
    /**
641
     * return a listing of all guids in the object store
642
     * @return a list of all GUIDs in metacat
643
     */
644
    public List<String> getAllSystemMetadataGUIDs()
645
    {
646
        Vector<String> guids = new Vector<String>();
647
        String sql = "select guid from systemmetadata";
648
        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
     * 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

    
703
            // 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
    
727
    /**
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

    
735
        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
    
768
    /**
769
     * Determine if an identifier exists already, returning true if so.
770
     * NOTE: looks in the identifier and system metadata table for a match
771
     * (in that order)
772
     * 
773
     * @param guid the global identifier to look up
774
     * @return boolean true if the identifier exists
775
     */
776
    public boolean identifierExists(String guid) throws SQLException
777
    {
778
        boolean idExists = false;
779
        try {
780
            String id = getLocalId(guid);
781
            if (id != null) {
782
                idExists = true;
783
            }
784
        } catch (McdbDocNotFoundException e) {
785
        	// try system metadata only
786
        	    //this will check if the guid field on the system metadata table has the id
787
        		idExists = systemMetadataPIDExists(guid);
788
        		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
        }
795
        return idExists;
796
    }
797
    
798
    /**
799
     * Determine if an identifier mapping exists already, 
800
     * returning true if so.
801
     * 
802
     * @param guid the global identifier to look up
803
     * @return boolean true if the identifier exists
804
     */
805
    public boolean mappingExists(String guid) throws SQLException
806
    {
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
     * @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

    
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
     * identifier mapping table.  
836
     * 
837
     * REMOVED feature: If the incoming guid has the syntax of a
838
     * Metacat docid (scope.id.rev), then simply use it.
839
     * 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
     * 
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
    public String generateLocalId(String guid, int rev, boolean isSystemMetadata) 
847
    {
848
        String localId = "";
849
        boolean conformsToDocidFormat = false;
850
        
851
        // 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
        // Check if the guid passed in is already in docid (scope.id.rev) format
854
//        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
        
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
        logMetacat.debug("creating mapping in generateLocalId");
877
        if(!isSystemMetadata)
878
        { //don't do this if we're generating for system metadata
879
            createMapping(guid, localId);
880
        }
881
        
882
        return localId;
883
    }
884
    
885
    /**
886
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
887
     * if the docid, rev is not found in the identifiers or systemmetadata tables
888
     *
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
        logMetacat.debug("getting guid for " + docid);
898
        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
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
906
            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
            if (rs.next()) 
914
            {
915
                guid = rs.getString(1);
916
            } 
917
            else
918
            {
919
            	throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
920
            }
921
            
922
        } 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
    
933
    /**
934
     * Get the pid of the head (current) version of objects match the specified sid.
935
     * 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
     * @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
     * @throws SQLException 
944
     */
945
    public Identifier getHeadPID(Identifier sid) throws SQLException {
946
        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
            String sql = "select guid from systemMetadata where series_id = ? order by date_uploaded DESC";
950
            DBConnection dbConn = null;
951
            int serialNumber = -1;
952
            int endsCount = 0;
953
            boolean hasError = false;
954
            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
                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
                {
967
                    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
                            logMetacat.debug(""+guidStr+" is 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
                                    logMetacat.debug(""+guidStr+" is 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
                                    logMetacat.debug(""+guidStr+" is 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
                        logMetacat.info("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
                        logMetacat.info("It is NOT an ideal for sid "+sid.getValue());
1031
                        pid = firstOne;
1032
                    }
1033
                } else {
1034
                    //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
                }
1037
                
1038
            } catch (SQLException e) {
1039
                logMetacat.error("Error while get the head pid for the sid "+sid.getValue()+" : " 
1040
                        + e.getMessage());
1041
                throw e;
1042
            } finally {
1043
                // Return database connection to the pool
1044
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1045
            }
1046
        }
1047
        return pid;
1048
    }
1049
    
1050
    /**
1051
     * 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
     * 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
    public boolean systemMetadataSIDExists(String sid) throws SQLException {
1070
        boolean exists = false;
1071
        logMetacat.debug("Check if the  sid: " + sid +" exists on the series_id field of the system metadata table.");
1072
        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
    /**
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
    public boolean systemMetadataPIDExists(String guid) throws SQLException {
1117
		logMetacat.debug("looking up system metadata for guid " + guid);
1118
		boolean exists = false;
1119
		String query = "select guid from systemmetadata where guid = ?";
1120
		DBConnection dbConn = null;
1121
		int serialNumber = -1;
1122
		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

    
1128
	            // 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

    
1136
	        } 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
		}
1145
		return exists;
1146
	}
1147
    
1148
    /**
1149
     * 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
     * @throws McdbDocNotFoundException 
1155
     * @throws SQLException 
1156
     * @throws InvalidSystemMetadata 
1157
     */
1158
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta) 
1159
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1160
    	String guid = sysmeta.getIdentifier().getValue();
1161
    	
1162
    	 // Get a database connection from the pool
1163
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1164
        int serialNumber = dbConn.getCheckOutSerialNumber();
1165
        
1166
        try {
1167
        	// use a single transaction for it all
1168
        	dbConn.setAutoCommit(false);
1169
        	
1170
	    	// insert the record if needed
1171
        	if (!IdentifierManager.getInstance().systemMetadataPIDExists(guid)) {
1172
    	        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
    }
1190
        
1191
    
1192
    /**
1193
     * update a mapping
1194
     * @param guid
1195
     * @param localId
1196
     */
1197
    public void updateMapping(String guid, String localId)
1198
    {
1199
    	
1200
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1201
        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
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1216
            serialNumber = dbConn.getCheckOutSerialNumber();
1217

    
1218
            // Execute the update statement
1219
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1220
            PreparedStatement stmt = dbConn.prepareStatement(query);
1221
            stmt.setString(1, docid);
1222
            stmt.setInt(2, rev);
1223
            stmt.setString(3, guid);
1224
            int rows = stmt.executeUpdate();
1225

    
1226
            stmt.close();
1227
        } catch (SQLException e) {
1228
            e.printStackTrace();
1229
            logMetacat.error("SQL error while updating a mapping identifier: " 
1230
                    + e.getMessage());
1231
        } catch (NumberFormatException e) {
1232
            e.printStackTrace();
1233
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1234
                    + e.getMessage());
1235
        } catch (AccessionNumberException e) {
1236
            e.printStackTrace();
1237
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1238
                    + e.getMessage());
1239
        } finally {
1240
            // Return database connection to the pool
1241
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1242
        }
1243
        logMetacat.debug("done updating mapping");
1244
    }
1245
        
1246
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1247
        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
        String obsoletedBy, BigInteger serialVersion, String seriesId, DBConnection dbConn) throws SQLException  {
1252
  
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
            "obsoletes, obsoleted_by, serial_version, series_id) " +
1259
            "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1260
        PreparedStatement stmt = dbConn.prepareStatement(query);
1261
        
1262
        //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
        stmt.setString(17, seriesId);
1280

    
1281

    
1282
        //where clause
1283
        stmt.setString(18, guid);
1284
        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
        String delete = "delete from smReplicationPolicy " + 
1297
        "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
        
1306
        for (String memberNode: memberNodes) {
1307
            // Execute the insert statement
1308
            String insert = "insert into smReplicationPolicy " + 
1309
                "(guid, policy, member_node) " +
1310
                "values (?, ?, ?)";
1311
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1312
            
1313
            //data values
1314
            insertStatement.setString(1, guid);
1315
            insertStatement.setString(2, policy);
1316
            insertStatement.setString(3, memberNode);
1317
            
1318
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1319

    
1320
            //execute
1321
            int rows = insertStatement.executeUpdate();
1322
            insertStatement.close();
1323
        }
1324
        
1325
    }
1326
    
1327
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1328
       
1329
        // remove existing values first
1330
        String delete = "delete from smReplicationStatus " + 
1331
        "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
        
1339
        if (replicas != null) {
1340
            for (Replica replica: replicas) {
1341
	            // Execute the insert statement
1342
	            String insert = "insert into smReplicationStatus " + 
1343
	                "(guid, member_node, status, date_verified) " +
1344
	                "values (?, ?, ?, ?)";
1345
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1346
	            
1347
	            //data values
1348
	            String memberNode = replica.getReplicaMemberNode().getValue();
1349
	            String status = replica.getReplicationStatus().toString();
1350
	            java.sql.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1351
	            insertStatement.setString(1, guid);
1352
	            insertStatement.setString(2, memberNode);
1353
	            insertStatement.setString(3, status);
1354
	            insertStatement.setTimestamp(4, sqlDate);
1355

    
1356
	            logMetacat.debug("smReplicationStatus sql: " + insertStatement.toString());
1357
	            
1358
	            //execute
1359
	            int rows = insertStatement.executeUpdate();
1360
	            insertStatement.close();
1361
            }
1362
        }
1363
       
1364
    }
1365
    
1366
    /**
1367
     * Insert the system metadata fields into the db
1368
     * @param sm
1369
     * @throws McdbDocNotFoundException 
1370
     * @throws SQLException 
1371
     * @throws InvalidSystemMetadata 
1372
     * @throws AccessException 
1373
     */
1374
    public void updateSystemMetadata(SystemMetadata sm, DBConnection dbConn) 
1375
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata, AccessException {
1376
    	
1377
      Boolean replicationAllowed = false;
1378
		  Integer numberReplicas = -1;
1379
    	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
    	
1387
    	// the main systemMetadata fields
1388
		  updateSystemMetadataFields(
1389
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1390
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1391
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1392
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1393
				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
		    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
		    sm.getSerialVersion(),
1406
		    sm.getSeriesId() == null ? null: sm.getSeriesId().getValue(),
1407
		    dbConn
1408
        );
1409
        
1410
        String guid = sm.getIdentifier().getValue();
1411
        
1412
        // save replication policies
1413
        if (replicationPolicy != null) {
1414
		    List<String> nodes = null;
1415
		    String policy = null;
1416
		    
1417
		    // 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
			    this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1425
		    }
1426
		    
1427
		    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
		        this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1434
		    }
1435
        }
1436
        
1437
        // save replica information
1438
        this.insertReplicationStatus(guid, sm.getReplicaList(), dbConn);
1439
        
1440
        // save access policy
1441
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1442
        if (accessPolicy != null) {
1443
			this.insertAccessPolicy(guid, accessPolicy);
1444
        }
1445
    }
1446
    
1447
    /**
1448
     * 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
    	// 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
    	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
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1469
        		accessDAO.setPrincipalName(subject.getValue());
1470
    			accessDAO.setGuid(guid);
1471
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1472
				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
    			}
1479
    			accessDAOs.add(accessDAO);
1480
        	}
1481
        }
1482
        
1483
        
1484
        // 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
        
1489
        
1490
    }
1491
    
1492
    /**
1493
     * Lookup access policy from Metacat
1494
     * @param guid
1495
     * @return
1496
     * @throws McdbDocNotFoundException
1497
     * @throws AccessException
1498
     */
1499
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1500
        AccessPolicy accessPolicy = new AccessPolicy();
1501

    
1502
    	// use GUID to look up the access
1503
        XMLAccessAccess accessController  = new XMLAccessAccess();
1504
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1505
        
1506
        for (XMLAccessDAO accessDAO: accessDAOs) {
1507
        	// 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
	        	// 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
	        	accessRule.setPermissionList(permissions);
1517
	        	Subject subject = new Subject();
1518
	        	subject.setValue(accessDAO.getPrincipalName());
1519
	        	accessRule.addSubject(subject);
1520
	            accessPolicy.addAllow(accessRule);
1521
        	}
1522
        }
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
    public List<Permission> convertPermission(int permission) {
1540
    	
1541
    	List<Permission> permissions = new ArrayList<Permission>();
1542
    	if (permission == AccessControlInterface.ALL) {
1543
    		permissions.add(Permission.READ);
1544
    		permissions.add(Permission.WRITE);
1545
    		permissions.add(Permission.CHANGE_PERMISSION);
1546
    		return permissions;
1547
    	}
1548
    	
1549
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1550
    		permissions.add(Permission.CHANGE_PERMISSION);
1551
    	}
1552
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1553
    		permissions.add(Permission.READ);
1554
    	}
1555
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1556
    		permissions.add(Permission.WRITE);
1557
    	}
1558
    	
1559
		return permissions;
1560
    }
1561
    
1562
    /**
1563
     * 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
     */
1570
    public String getLocalId(String guid) throws McdbDocNotFoundException, SQLException {
1571
      
1572
      String db_guid = "";
1573
      String docid = "";
1574
      int rev = 0;
1575
      
1576
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1577
      
1578
      DBConnection dbConn = null;
1579
      int serialNumber = -1;
1580
      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
          throw e;
1602
      } finally {
1603
          // Return database connection to the pool
1604
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1605
      }
1606
      return docid + "." + rev;
1607
    }
1608
    
1609
    /**
1610
     * 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
     * @throws SQLException 
1619
     * @throws ServiceException 
1620
     * @throws PropertyNotFoundException 
1621
     */
1622
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1623
        ObjectFormatIdentifier objectFormatId, boolean replicaStatus,
1624
        int start, int count, Identifier identifier, boolean isSID) 
1625
        throws SQLException, PropertyNotFoundException, ServiceException {
1626
        ObjectList ol = new ObjectList();
1627
        DBConnection dbConn = null;
1628
        int serialNumber = -1;
1629

    
1630
        try {
1631
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1632
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1633
                    + "date_modified, submitter, object_format, size from systemmetadata";
1634
            
1635
            // handle special case quickly
1636
            String countSql = "select count(guid) from systemmetadata";
1637
            
1638
            // the clause
1639
            String whereClauseSql = "";
1640

    
1641
            boolean f1 = false;
1642
            boolean f2 = false;
1643
            boolean f3 = false;
1644
            boolean f4 = false;
1645

    
1646

    
1647
            if (startTime != null) {
1648
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1649
                f1 = true;
1650
            }
1651

    
1652
            if (endTime != null) {
1653
                if (!f1) {
1654
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1655
                } else {
1656
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1657
                }
1658
                f2 = true;
1659
            }
1660

    
1661
            if (objectFormatId != null) {
1662
                if (!f1 && !f2) {
1663
                    whereClauseSql += " where object_format = ?";
1664
                } else {
1665
                    whereClauseSql += " and object_format = ?";
1666
                }
1667
                f3 = true;
1668
            }
1669
            
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

    
1688
            if (!replicaStatus) {
1689
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1690
                if (!f1 && !f2 && !f3 && !f4) {
1691
                    whereClauseSql += " where authoritive_member_node = '" +
1692
                        currentNodeId.trim() + "'";
1693
                } else {
1694
                    whereClauseSql += " and authoritive_member_node = '" +
1695
                        currentNodeId.trim() + "'";
1696
                }
1697
            }
1698
            
1699
           
1700
            
1701
            // connection
1702
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1703
            serialNumber = dbConn.getCheckOutSerialNumber();
1704

    
1705
            // 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
            if (f1 && f2 && f3 && f4) {
1716
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1717
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1718
                fieldStmt.setString(3, objectFormatId.getValue());
1719
                fieldStmt.setString(4, identifier.getValue());
1720
                // count
1721
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1722
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1723
                countStmt.setString(3, objectFormatId.getValue());
1724
                countStmt.setString(4, identifier.getValue());
1725
            } if (f1 && f2 && f3 && !f4) {
1726
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1727
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1728
                fieldStmt.setString(3, objectFormatId.getValue());
1729
                // count
1730
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1731
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1732
                countStmt.setString(3, objectFormatId.getValue());
1733
            } else if (f1 && f2 && !f3 && f4) {
1734
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1735
                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
                fieldStmt.setString(2, objectFormatId.getValue());
1750
                fieldStmt.setString(3, identifier.getValue());
1751
                // count
1752
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1753
                countStmt.setString(2, objectFormatId.getValue());
1754
                countStmt.setString(3, identifier.getValue());
1755
            } else if (f1 && !f2 && f3 && !f4) {
1756
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1757
                fieldStmt.setString(2, objectFormatId.getValue());
1758
                // count
1759
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1760
                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
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1773
                fieldStmt.setString(2, objectFormatId.getValue());
1774
                fieldStmt.setString(3, identifier.getValue());
1775
                // count
1776
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1777
                countStmt.setString(2, objectFormatId.getValue());
1778
                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
                fieldStmt.setString(1, objectFormatId.getValue());
1787
                fieldStmt.setString(2, identifier.getValue());
1788
                // count
1789
                countStmt.setString(1, objectFormatId.getValue());
1790
                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
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1797
                fieldStmt.setString(2, identifier.getValue());
1798
                // count
1799
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1800
                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
            }
1812

    
1813
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
1814
            
1815
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
1816
            
1817
            // 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
            }
1823
            
1824
            logMetacat.debug("list objects total: " + total);
1825

    
1826
        	// 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
	            while (rs.next()) {                
1836
	                
1837
	                String guid = rs.getString(1);
1838
	                logMetacat.debug("query found object with guid " + guid);
1839
	                // 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
	                ol.addObjectInfo(oi);                    
1884

    
1885
	            }
1886
	            
1887
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
1888

    
1889
	            // set the actual count retrieved
1890
	            ol.setCount(ol.sizeObjectInfoList());
1891
	
1892
	        }
1893
            
1894
        }
1895

    
1896
        finally {
1897
            // Return database connection to the pool
1898
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1899
        }
1900

    
1901
        return ol;
1902
    }
1903
    
1904
    /**
1905
     * create a mapping in the identifier table
1906
     * @param guid
1907
     * @param localId
1908
     */
1909
    public void createMapping(String guid, String localId)
1910
    {        
1911
        
1912
        int serialNumber = -1;
1913
        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
            int rev = 1;
1920
            if (acc.getRev() != null) {
1921
              rev = (new Integer(acc.getRev()).intValue());
1922
            }
1923

    
1924
            // Get a database connection from the pool
1925
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1926
            serialNumber = dbConn.getCheckOutSerialNumber();
1927

    
1928
            // Execute the insert statement
1929
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1930
            PreparedStatement stmt = dbConn.prepareStatement(query);
1931
            stmt.setString(1, guid);
1932
            stmt.setString(2, docid);
1933
            stmt.setInt(3, rev);
1934
            logMetacat.debug("mapping query: " + stmt.toString());
1935
            int rows = stmt.executeUpdate();
1936

    
1937
            stmt.close();
1938
        } catch (SQLException e) {
1939
            e.printStackTrace();
1940
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1941
                    + e.getMessage());
1942
        } catch (NumberFormatException e) {
1943
            e.printStackTrace();
1944
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1945
                    + e.getMessage());
1946
        } catch (AccessionNumberException e) {
1947
            e.printStackTrace();
1948
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1949
                    + e.getMessage());
1950
        } finally {
1951
            // Return database connection to the pool
1952
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1953
        }
1954
    }
1955
    
1956
    /**
1957
     * 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
     * create the systemmetadata record
2010
     * @param guid
2011
     * @param dbConn 
2012
     * @throws SQLException 
2013
     */
2014
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
2015
    {        
2016

    
2017
        // 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

    
2024
        stmt.close();
2025
        
2026
    }
2027
    
2028
    public boolean deleteSystemMetadata(String guid)
2029
    {        
2030
        boolean success = false;
2031
        int serialNumber = -1;
2032
        DBConnection dbConn = null;
2033
        String query = null;
2034
        PreparedStatement stmt = null;
2035
        int rows = 0;
2036
        try {
2037

    
2038
        	 // Get a database connection from the pool
2039
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
2040
            serialNumber = dbConn.getCheckOutSerialNumber();
2041
            dbConn.setAutoCommit(false);
2042
        	
2043
            // remove the smReplicationPolicy
2044
            query = "delete from smReplicationPolicy " + 
2045
            "where guid = ?";
2046
            stmt = dbConn.prepareStatement(query);
2047
            stmt.setString(1, guid);
2048
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
2049
            rows = stmt.executeUpdate();
2050
            stmt.close();
2051
            
2052
            // remove the smReplicationStatus
2053
            query = "delete from smReplicationStatus " + 
2054
            "where guid = ?";
2055
            stmt = dbConn.prepareStatement(query);
2056
            stmt.setString(1, guid);
2057
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
2058
            rows = stmt.executeUpdate();
2059
            stmt.close();
2060
            
2061
            // 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
            // TODO: remove the access?
2073
            // Metacat keeps "deleted" documents so we should not remove access rules.
2074
            
2075
        } catch (Exception e) {
2076
            e.printStackTrace();
2077
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
2078
            try {
2079
				dbConn.rollback();
2080
			} catch (SQLException sqle) {
2081
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
2082
			}
2083
        } finally {
2084
            // Return database connection to the pool
2085
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2086
        }
2087
        return success;
2088
    }
2089
    
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
}
2129

    
(36-36/63)