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.ObjectFormatCache;
40
import org.dataone.service.exceptions.InvalidSystemMetadata;
41
import org.dataone.service.exceptions.NotFound;
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.v1.SystemMetadata;
56

    
57
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
58
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessAccess;
59
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
60
import edu.ucsb.nceas.metacat.database.DBConnection;
61
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
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

    
68
/**
69
 * Manage the relationship between Metacat local identifiers (LocalIDs) that are
70
 * codified as the (docid, rev) pair with globally unique string identifiers
71
 * (GUIDs) that are opaque strings.  This class provides methods to manage these
72
 * identifiers, and to search for and look up LocalIDs based on their GUID and
73
 * vice versa. IdentifierManager is a singleton.
74
 * 
75
 * @author Matthew Jones
76
 */
77
public class IdentifierManager {
78
    
79
    public static final String TYPE_SYSTEM_METADATA = "systemmetadata";
80
    public static final String TYPE_IDENTIFIER = "identifier";
81
  
82
    /**
83
     * The single instance of the manager that is always returned.
84
     */
85
    private static IdentifierManager self = null;
86
    private Logger logMetacat = Logger.getLogger(IdentifierManager.class);
87

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

    
94
    /**
95
     * Return the single instance of the manager after initializing it if it
96
     * wasn't previously initialized.
97
     * 
98
     * @return the single IdentifierManager instance
99
     */
100
    public static IdentifierManager getInstance()
101
    {
102
        if (self == null) {
103
            self = new IdentifierManager();
104
        }
105
        return self;
106
    }
107
    
108
    public SystemMetadata asSystemMetadata(Date dateUploaded, String rightsHolder,
109
            String checksum, String checksumAlgorithm, String originMemberNode,
110
            String authoritativeMemberNode, Date dateModified, String submitter, 
111
            String guid, String fmtidStr, BigInteger size, BigInteger serialVersion) {
112
        SystemMetadata sysMeta = new SystemMetadata();
113

    
114
        Identifier sysMetaId = new Identifier();
115
        sysMetaId.setValue(guid);
116
        sysMeta.setIdentifier(sysMetaId);
117
        sysMeta.setDateUploaded(dateUploaded);
118
        Subject rightsHolderSubject = new Subject();
119
        rightsHolderSubject.setValue(rightsHolder);
120
        sysMeta.setRightsHolder(rightsHolderSubject);
121
        Checksum checksumObject = new Checksum();
122
        checksumObject.setValue(checksum);
123
        checksumObject.setAlgorithm(checksumAlgorithm);
124
        sysMeta.setChecksum(checksumObject);
125
        NodeReference omn = new NodeReference();
126
        omn.setValue(originMemberNode);
127
        sysMeta.setOriginMemberNode(omn);
128
        NodeReference amn = new NodeReference();
129
        amn.setValue(authoritativeMemberNode);
130
        sysMeta.setAuthoritativeMemberNode(amn);
131
        sysMeta.setDateSysMetadataModified(dateModified);
132
        Subject submitterSubject = new Subject();
133
        submitterSubject.setValue(submitter);
134
        sysMeta.setSubmitter(submitterSubject);
135
        try {
136
        	ObjectFormatIdentifier fmtid = 
137
        		ObjectFormatCache.getInstance().getFormat(fmtidStr).getFormatId();
138
        	sysMeta.setFormatId(fmtid);
139
        } catch (NotFound nfe) {
140
          logMetacat.error("The objectFormat " + fmtidStr +
141
          	" is not registered. Setting the default format id.");
142
          ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
143
          fmtid.setValue("application/octet-stream");
144
          sysMeta.setFormatId(fmtid);
145
        }
146
        sysMeta.setSize(size);
147
        sysMeta.setSerialVersion(serialVersion);
148
        
149
        return sysMeta;
150
    }
151
    
152
    /**
153
     * return a hash of all of the info that is in the systemmetadata table
154
     * @param localId
155
     * @return
156
     */
157
    public Hashtable<String, String> getSystemMetadataInfo(String localId)
158
    throws McdbDocNotFoundException
159
    {
160
        try
161
        {
162
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
163
            localId = acc.getDocid();
164
        }
165
        catch(Exception e)
166
        {
167
            //do nothing. just try the localId as it is
168
        }
169
        Hashtable<String, String> h = new Hashtable<String, String>();
170
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
171
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size " +
172
          "from systemmetadata where docid = ?";
173
        DBConnection dbConn = null;
174
        int serialNumber = -1;
175
        try 
176
        {
177
            // Get a database connection from the pool
178
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getDocumentInfo");
179
            serialNumber = dbConn.getCheckOutSerialNumber();
180

    
181
            // Execute the insert statement
182
            PreparedStatement stmt = dbConn.prepareStatement(sql);
183
            stmt.setString(1, localId);
184
            ResultSet rs = stmt.executeQuery();
185
            if (rs.next()) 
186
            {
187
                String guid = rs.getString(1);
188
                Timestamp dateUploaded = rs.getTimestamp(2);
189
                String rightsHolder = rs.getString(3);
190
                String checksum = rs.getString(4);
191
                String checksumAlgorithm = rs.getString(5);
192
                String originMemberNode = rs.getString(6);
193
                String authoritativeMemberNode = rs.getString(7);
194
                Timestamp dateModified = rs.getTimestamp(8);
195
                String submitter = rs.getString(9);
196
                String objectFormat = rs.getString(10);
197
                long size = new Long(rs.getString(11)).longValue();
198
                
199
                h.put("guid", guid);
200
                h.put("date_uploaded", new Long(dateUploaded.getTime()).toString());
201
                h.put("rights_holder", rightsHolder);
202
                h.put("checksum", checksum);
203
                h.put("checksum_algorithm", checksumAlgorithm);
204
                h.put("origin_member_node", originMemberNode);
205
                h.put("authoritative_member_node", authoritativeMemberNode);
206
                h.put("date_modified", new Long(dateModified.getTime()).toString());
207
                h.put("submitter", submitter);
208
                h.put("object_format", objectFormat);
209
                h.put("size", new Long(size).toString());
210
                
211
                stmt.close();
212
            } 
213
            else
214
            {
215
                stmt.close();
216
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
217
                throw new McdbDocNotFoundException("2Could not find document " + localId);
218
            }
219
            
220
        } 
221
        catch (SQLException e) 
222
        {
223
            e.printStackTrace();
224
            logMetacat.error("Error while getting system metadata info for localid " + localId + " : "  
225
                    + e.getMessage());
226
        } 
227
        finally 
228
        {
229
            // Return database connection to the pool
230
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
231
        }
232
        return h;
233
    }
234
    
235
    /**
236
     * return a hash of all of the info that is in the systemmetadata table
237
     * @param guid
238
     * @return
239
     * @throws McdbDocNotFoundException 
240
     */
241
    public SystemMetadata getSystemMetadata(String guid)
242
    	throws McdbDocNotFoundException
243
    {
244
        
245
        SystemMetadata sysMeta = new SystemMetadata();
246
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
247
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size, " +
248
          "replication_allowed, number_replicas, obsoletes, obsoleted_by, serial_version " +
249
          "from systemmetadata where guid = ?";
250
        DBConnection dbConn = null;
251
        int serialNumber = -1;
252
        Boolean replicationAllowed = new Boolean(false);
253
        BigInteger numberOfReplicas = new BigInteger("-1");
254
        BigInteger serialVersion = new BigInteger("-1");
255

    
256
        try 
257
        {
258
            // Get a database connection from the pool
259
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadata");
260
            serialNumber = dbConn.getCheckOutSerialNumber();
261

    
262
            // Execute the statement
263
            PreparedStatement stmt = dbConn.prepareStatement(sql);
264
            stmt.setString(1, guid);
265
            ResultSet rs = stmt.executeQuery();
266
            if (rs.next()) 
267
            {
268
                Timestamp dateUploaded = rs.getTimestamp(2);
269
                String rightsHolder = rs.getString(3);
270
                String checksum = rs.getString(4);
271
                String checksumAlgorithm = rs.getString(5);
272
                String originMemberNode = rs.getString(6);
273
                String authoritativeMemberNode = rs.getString(7);
274
                Timestamp dateModified = rs.getTimestamp(8);
275
                String submitter = rs.getString(9);
276
                String fmtidStr = rs.getString(10);
277
                BigInteger size = new BigInteger(rs.getString(11));
278
                replicationAllowed = new Boolean(rs.getBoolean(12));
279
                numberOfReplicas = new BigInteger(rs.getString(13));
280
                String obsoletes = rs.getString(14);
281
                String obsoletedBy = rs.getString(15);
282
                serialVersion = new BigInteger(rs.getString(16));
283

    
284

    
285
                Identifier sysMetaId = new Identifier();
286
                sysMetaId.setValue(guid);
287
                sysMeta.setIdentifier(sysMetaId);
288
                sysMeta.setSerialVersion(serialVersion);
289
                sysMeta.setDateUploaded(dateUploaded);
290
                Subject rightsHolderSubject = new Subject();
291
                rightsHolderSubject.setValue(rightsHolder);
292
                sysMeta.setRightsHolder(rightsHolderSubject);
293
                Checksum checksumObject = new Checksum();
294
                checksumObject.setValue(checksum);
295
                checksumObject.setAlgorithm(checksumAlgorithm);
296
                sysMeta.setChecksum(checksumObject);
297
                if (originMemberNode != null) {
298
	                NodeReference omn = new NodeReference();
299
	                omn.setValue(originMemberNode);
300
	                sysMeta.setOriginMemberNode(omn);
301
                }
302
                if (authoritativeMemberNode != null) {
303
	                NodeReference amn = new NodeReference();
304
	                amn.setValue(authoritativeMemberNode);
305
	                sysMeta.setAuthoritativeMemberNode(amn);
306
                }
307
                sysMeta.setDateSysMetadataModified(dateModified);
308
                Subject submitterSubject = new Subject();
309
                submitterSubject.setValue(submitter);
310
                sysMeta.setSubmitter(submitterSubject);
311
                try {
312
                	ObjectFormatIdentifier fmtid = 
313
                		ObjectFormatCache.getInstance().getFormat(fmtidStr).getFormatId();
314
                	sysMeta.setFormatId(fmtid);
315
                } catch (NotFound nfe) {
316
                  logMetacat.error("The objectFormat " + fmtidStr +
317
                  	" is not registered. Setting the default format id.");
318
                  ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
319
                  fmtid.setValue("application/octet-stream");
320
                  sysMeta.setFormatId(fmtid);
321
                }
322
                sysMeta.setSize(size);
323
                if (obsoletes != null) {
324
	                Identifier obsoletesId = new Identifier();
325
	                obsoletesId.setValue(obsoletes);
326
	                sysMeta.setObsoletes(obsoletesId);
327
                }
328
                if (obsoletedBy != null) {
329
		            Identifier obsoletedById = new Identifier();
330
		            obsoletedById.setValue(obsoletedBy);
331
		            sysMeta.setObsoletedBy(obsoletedById);
332
                }
333
                stmt.close();
334
            } 
335
            else
336
            {
337
                stmt.close();
338
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
339
                throw new McdbDocNotFoundException("Could not find " + guid);
340
            }
341
            
342
        } 
343
        catch (SQLException e) 
344
        {
345
            e.printStackTrace();
346
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "  
347
                    + e.getMessage());
348
        } 
349
        finally 
350
        {
351
            // Return database connection to the pool
352
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
353
        }
354

    
355
        // populate the replication policy
356
        ReplicationPolicy replicationPolicy = new ReplicationPolicy();
357
        if ( numberOfReplicas != null  && numberOfReplicas.intValue() != -1 ) {
358
            replicationPolicy.setNumberReplicas(numberOfReplicas.intValue());
359
            
360
        }
361
        
362
        if ( replicationAllowed != null ) {
363
            replicationPolicy.setReplicationAllowed(replicationAllowed);
364
            
365
        }
366
        replicationPolicy.setBlockedMemberNodeList(getReplicationPolicy(guid, "blocked"));
367
        replicationPolicy.setPreferredMemberNodeList(getReplicationPolicy(guid, "preferred"));
368
		    sysMeta.setReplicationPolicy(replicationPolicy);
369
		
370
		    // look up replication status
371
		    sysMeta.setReplicaList(getReplicationStatus(guid));
372
		
373
		    // look up access policy
374
		    try {
375
		    	sysMeta.setAccessPolicy(getAccessPolicy(guid));
376
		    } catch (AccessException e) {
377
		    	throw new McdbDocNotFoundException(e);
378
		    }
379
        
380
        return sysMeta;
381
    }
382
    
383
    
384
    private List<NodeReference> getReplicationPolicy(String guid, String policy)
385
		throws McdbDocNotFoundException {
386
		
387
		List<NodeReference> nodes = new ArrayList<NodeReference>();
388
		String sql = "select guid, policy, member_node " +
389
			"from systemMetadataReplicationPolicy where guid = ? and policy = ?";
390
	    DBConnection dbConn = null;
391
	    int serialNumber = -1;
392
	    try {
393
	        // Get a database connection from the pool
394
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicationPolicy");
395
	        serialNumber = dbConn.getCheckOutSerialNumber();
396
	
397
	        // Execute the statement
398
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
399
	        stmt.setString(1, guid);
400
	        stmt.setString(2, policy);
401
	        ResultSet rs = stmt.executeQuery();
402
	        while (rs.next()) 
403
	        {
404
	            String memberNode = rs.getString(3);
405
	            NodeReference node = new NodeReference();
406
	            node.setValue(memberNode);
407
	            nodes.add(node);
408
	        
409
	        } 
410
	        stmt.close();
411
	        
412
	    } catch (SQLException e) {
413
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
414
	    } 
415
	    finally {
416
	        // Return database connection to the pool
417
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
418
	    }
419
	    
420
	    return nodes;
421
	}
422
    
423
    private List<Replica> getReplicationStatus(String guid) throws McdbDocNotFoundException {
424
		
425
		List<Replica> replicas = new ArrayList<Replica>();
426
		String sql = "select guid, member_node, status, date_verified " +
427
			"from systemMetadataReplicationStatus where guid = ?";
428
	    DBConnection dbConn = null;
429
	    int serialNumber = -1;
430
	    try {
431
	        // Get a database connection from the pool
432
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicas");
433
	        serialNumber = dbConn.getCheckOutSerialNumber();
434
	
435
	        // Execute the statement
436
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
437
	        stmt.setString(1, guid);
438
	        ResultSet rs = stmt.executeQuery();
439
	        while (rs.next()) 
440
	        {
441
	            String memberNode = rs.getString(2);
442
	            String status = rs.getString(3);
443
	            java.sql.Date verified = rs.getDate(4);
444
	            
445
	            Replica replica = new Replica();	            
446
	            NodeReference node = new NodeReference();
447
	            node.setValue(memberNode);
448
	            replica.setReplicaMemberNode(node);
449
	            replica.setReplicationStatus(ReplicationStatus.valueOf(status));
450
	            replica.setReplicaVerified(new Date(verified.getTime()));
451
	            replicas.add(replica);
452
	        } 
453
	        stmt.close();
454
	        
455
	    } catch (SQLException e) {
456
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
457
	    } 
458
	    finally {
459
	        // Return database connection to the pool
460
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
461
	    }
462
	    
463
	    return replicas;
464
	}
465
    
466
    
467
    /**
468
     * return the newest rev for a given localId
469
     * @param localId
470
     * @return
471
     */
472
    public int getLatestRevForLocalId(String localId)
473
        throws McdbDocNotFoundException
474
    {
475
        try
476
        {
477
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
478
            localId = acc.getDocid();
479
        }
480
        catch(Exception e)
481
        {
482
            //do nothing. just try the localId as it is
483
        }
484
        int rev = 0;
485
        String sql = "select rev from xml_documents where docid like ? ";
486
        DBConnection dbConn = null;
487
        int serialNumber = -1;
488
        try 
489
        {
490
            // Get a database connection from the pool
491
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLatestRevForLocalId");
492
            serialNumber = dbConn.getCheckOutSerialNumber();
493

    
494
            // Execute the insert statement
495
            PreparedStatement stmt = dbConn.prepareStatement(sql);
496
            stmt.setString(1, localId);
497
            ResultSet rs = stmt.executeQuery();
498
            if (rs.next()) 
499
            {
500
                rev = rs.getInt(1);
501
                stmt.close();
502
            } 
503
            else
504
            {
505
                stmt.close();
506
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
507
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
508
            }
509
        } 
510
        catch (SQLException e) 
511
        {
512
            logMetacat.error("Error while looking up the guid: " 
513
                    + e.getMessage());
514
        } 
515
        finally 
516
        {
517
            // Return database connection to the pool
518
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
519
        }
520
        return rev;
521
    }
522
    
523
    /**
524
     * return all local ids in the object store that do not have associated
525
     * system metadata
526
     */
527
    public List<String> getLocalIdsWithNoSystemMetadata(boolean includeRevisions)
528
    {
529
        Vector<String> ids = new Vector<String>();
530
        String sql = "select docid, rev from xml_documents " +
531
        		"where docid not in " +
532
        		"(select docid from identifier where guid in (select guid from systemmetadata))";
533
        
534
        String revisionSql = "select docid, rev from xml_revisions " +
535
				"where docid not in " +
536
				"(select docid from identifier where guid in (select guid from systemmetadata))";
537
        
538
        if (includeRevisions) {
539
        	sql = sql + " UNION ALL " + revisionSql;
540
        }
541
        
542
        DBConnection dbConn = null;
543
        int serialNumber = -1;
544
        try 
545
        {
546
            // Get a database connection from the pool
547
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
548
            serialNumber = dbConn.getCheckOutSerialNumber();
549

    
550
            // Execute the insert statement
551
            PreparedStatement stmt = dbConn.prepareStatement(sql);
552
            ResultSet rs = stmt.executeQuery();
553
            while (rs.next()) 
554
            {
555
                String localid = rs.getString(1);
556
                String rev = rs.getString(2);
557
                localid += "." + rev;
558
                logMetacat.debug("id to add SM for: " + localid);
559
                ids.add(localid);
560
            } 
561
            stmt.close();
562
        } 
563
        catch (SQLException e) 
564
        {
565
            logMetacat.error("Error while looking up the guid: " 
566
                    + e.getMessage());
567
        } 
568
        finally 
569
        {
570
            // Return database connection to the pool
571
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
572
        }
573
        
574
        return ids;
575
    }
576
    
577
    /**
578
     * return a listing of all local ids in the object store
579
     * @return a list of all local ids in metacat
580
     */
581
    public List<String> getAllLocalIds()
582
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
583
    //    throws Exception
584
    {
585
        Vector<String> ids = new Vector<String>();
586
        String sql = "select docid from xml_documents";
587
        DBConnection dbConn = null;
588
        int serialNumber = -1;
589
        try 
590
        {
591
            // Get a database connection from the pool
592
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
593
            serialNumber = dbConn.getCheckOutSerialNumber();
594

    
595
            // Execute the insert statement
596
            PreparedStatement stmt = dbConn.prepareStatement(sql);
597
            ResultSet rs = stmt.executeQuery();
598
            while (rs.next()) 
599
            {
600
                String localid = rs.getString(1);
601
                ids.add(localid);
602
            } 
603
            stmt.close();
604
        } 
605
        catch (SQLException e) 
606
        {
607
            logMetacat.error("Error while looking up the guid: " 
608
                    + e.getMessage());
609
        } 
610
        finally 
611
        {
612
            // Return database connection to the pool
613
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
614
        }
615
        return ids;
616
    }
617
    
618
    
619
    /**
620
     * return a listing of all guids in the object store
621
     * @return a list of all GUIDs in metacat
622
     */
623
    public List<String> getAllGUIDs()
624
    {
625
        Vector<String> guids = new Vector<String>();
626
        String sql = "select guid from identifier";
627
        DBConnection dbConn = null;
628
        int serialNumber = -1;
629
        try 
630
        {
631
            // Get a database connection from the pool
632
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllGUIDs");
633
            serialNumber = dbConn.getCheckOutSerialNumber();
634

    
635
            // Execute the insert statement
636
            PreparedStatement stmt = dbConn.prepareStatement(sql);
637
            ResultSet rs = stmt.executeQuery();
638
            while (rs.next()) 
639
            {
640
                String guid = rs.getString(1);
641
                guids.add(guid);
642
            } 
643
            stmt.close();
644
        } 
645
        catch (SQLException e) 
646
        {
647
            logMetacat.error("Error while retrieving the guid: " 
648
                    + e.getMessage());
649
        } 
650
        finally 
651
        {
652
            // Return database connection to the pool
653
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
654
        }
655
        return guids;
656
    }
657
    
658
    
659
    
660
    /**
661
     * returns a list of system metadata-only guids since the given date
662
     * @return a list of system ids in metacat that do not correspond to objects
663
     * TODO: need to check which server they are on
664
     */
665
    public List<String> getUpdatedSystemMetadataIds(Date since)
666
       throws Exception
667
    {
668
        List<String> ids = new Vector<String>();
669
        String sql = 
670
        	"select guid from " + TYPE_SYSTEM_METADATA +
671
        	" where guid not in " +
672
        	" (select guid from " + TYPE_IDENTIFIER + ") " +
673
        	" and date_modified > ?";
674
        DBConnection dbConn = null;
675
        int serialNumber = -1;
676
        try 
677
        {
678
            // Get a database connection from the pool
679
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getUpdatedSystemMetadataIds");
680
            serialNumber = dbConn.getCheckOutSerialNumber();
681

    
682
            // Execute the insert statement
683
            PreparedStatement stmt = dbConn.prepareStatement(sql);
684
            stmt.setDate(1, new java.sql.Date(since.getTime()));
685
            ResultSet rs = stmt.executeQuery();
686
            while (rs.next()) 
687
            {
688
                String guid = rs.getString(1);
689
                ids.add(guid);
690
            } 
691
            stmt.close();
692
        } 
693
        catch (SQLException e) 
694
        {
695
            logMetacat.error("Error while looking up the updated guids: " 
696
                    + e.getMessage());
697
        } 
698
        finally 
699
        {
700
            // Return database connection to the pool
701
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
702
        }
703
        return ids;
704
    }
705
    
706
    /**
707
     * returns a list of system metadata-only guids since the given date
708
     * @return a list of system ids in metacat that do not correspond to objects
709
     * TODO: need to check which server they are on
710
     */
711
    public Date getLastModifiedDate() throws Exception {
712
        Date maxDate = null;
713

    
714
        List<String> ids = new Vector<String>();
715
        String sql = 
716
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
717
        DBConnection dbConn = null;
718
        int serialNumber = -1;
719
        try 
720
        {
721
            // Get a database connection from the pool
722
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
723
            serialNumber = dbConn.getCheckOutSerialNumber();
724

    
725
            // Execute the insert statement
726
            PreparedStatement stmt = dbConn.prepareStatement(sql);
727
            ResultSet rs = stmt.executeQuery();
728
            if (rs.next()) {
729
            	maxDate = rs.getDate(1);
730
            } 
731
            stmt.close();
732
        } 
733
        catch (SQLException e) 
734
        {
735
            logMetacat.error("Error while looking up the latest update date: " 
736
                    + e.getMessage());
737
        } 
738
        finally 
739
        {
740
            // Return database connection to the pool
741
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
742
        }
743
        return maxDate;
744
    }
745

    
746
    
747
    /**
748
     * Determine if an identifier exists already, returning true if so.
749
     * 
750
     * @param guid the global identifier to look up
751
     * @return boolean true if the identifier exists
752
     */
753
    public boolean identifierExists(String guid)
754
    {
755
        boolean idExists = false;
756
        try {
757
            String id = getLocalId(guid);
758
            if (id != null) {
759
                idExists = true;
760
            }
761
        } catch (McdbDocNotFoundException e) {
762
        	// try system metadata only
763
        	try {
764
        		idExists = systemMetadataExists(guid);
765
            } catch (Exception e2) {
766
            	idExists = false;
767
            }
768
        }
769
        return idExists;
770
    }
771
    
772
    /**
773
     * 
774
     * @param guid
775
     * @param rev
776
     * @return
777
     */
778
    public String generateLocalId(String guid, int rev)
779
    {
780
        return generateLocalId(guid, rev, false);
781
    }
782

    
783
    /**
784
     * Given a global identifier (guid), create a suitable local identifier that
785
     * follows Metacat's docid semantics and format (scope.id.rev), and create
786
     * a mapping between these two identifiers.  This effectively reserves both
787
     * the global and the local identifier, as they will now be present in the
788
     * identifier mapping table.  If the incoming guid has the syntax of a
789
     * Metacat docid (scope.id.rev), then simply use it.
790
     * 
791
     * @param guid the global string identifier
792
     * @param rev the revision number to be used in the localId
793
     * @return String containing the localId to be used for Metacat operations
794
     */
795
    public String generateLocalId(String guid, int rev, boolean isSystemMetadata) 
796
    {
797
        String localId = "";
798
        boolean conformsToDocidFormat = false;
799
        
800
        // Check if the guid passed in is already in docid (scope.id.rev) format
801
        try {
802
            AccessionNumber acc = new AccessionNumber(guid, "NONE");
803
            if (new Integer(acc.getRev()).intValue() > 0) {
804
                conformsToDocidFormat = true;
805
            }
806
        } catch (NumberFormatException e) {
807
            // No action needed, simply detecting invalid AccessionNumbers
808
        } catch (AccessionNumberException e) {
809
            // No action needed, simply detecting invalid AccessionNumbers
810
        } catch (SQLException e) {
811
            // No action needed, simply detecting invalid AccessionNumbers
812
        }
813
        
814
        if (conformsToDocidFormat) {
815
            // if it conforms, use it for both guid and localId
816
            localId = guid;
817
        } else {
818
            // if not, then generate a new unique localId
819
            localId = DocumentUtil.generateDocumentId(rev);
820
        }
821
        
822
        // Register this new pair in the identifier mapping table
823
        logMetacat.debug("creating mapping in generateLocalId");
824
        if(!isSystemMetadata)
825
        { //don't do this if we're generating for system metadata
826
            createMapping(guid, localId);
827
        }
828
        
829
        return localId;
830
    }
831
    
832
    /**
833
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
834
     * if the docid, rev is not found in the identifiers or systemmetadata tables
835
     *
836
     * @param docid the docid to look up
837
     * @param rev the revision of the docid to look up
838
     * @return String containing the mapped guid
839
     * @throws McdbDocNotFoundException if the docid, rev is not found
840
     */
841
    public String getGUID(String docid, int rev)
842
      throws McdbDocNotFoundException
843
    {
844
        logMetacat.debug("getting guid for " + docid);
845
        String query = "select guid from identifier where docid = ? and rev = ?";
846
        String guid = null;
847
        
848
        DBConnection dbConn = null;
849
        int serialNumber = -1;
850
        try {
851
            // Get a database connection from the pool
852
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
853
            serialNumber = dbConn.getCheckOutSerialNumber();
854
            
855
            // Execute the insert statement
856
            PreparedStatement stmt = dbConn.prepareStatement(query);
857
            stmt.setString(1, docid);
858
            stmt.setInt(2, rev);
859
            ResultSet rs = stmt.executeQuery();
860
            if (rs.next()) 
861
            {
862
                guid = rs.getString(1);
863
            } 
864
            else
865
            {
866
            	throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
867
            }
868
            
869
        } catch (SQLException e) {
870
            logMetacat.error("Error while looking up the guid: " 
871
                    + e.getMessage());
872
        } finally {
873
            // Return database connection to the pool
874
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
875
        }
876
        
877
        return guid;
878
    }
879
    
880
    public boolean systemMetadataExists(String guid) {
881
		logMetacat.debug("looking up system metadata for guid " + guid);
882
		boolean exists = false;
883
		String query = "select guid from systemmetadata where guid = ?";
884

    
885
		DBConnection dbConn = null;
886
		int serialNumber = -1;
887
		try {
888
			// Get a database connection from the pool
889
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
890
			serialNumber = dbConn.getCheckOutSerialNumber();
891

    
892
			// Execute the insert statement
893
			PreparedStatement stmt = dbConn.prepareStatement(query);
894
			stmt.setString(1, guid);
895
			ResultSet rs = stmt.executeQuery();
896
			if (rs.next()) {
897
				exists = true;
898
			}
899

    
900
		} catch (SQLException e) {
901
			logMetacat.error("Error while looking up the system metadata: "
902
					+ e.getMessage());
903
		} finally {
904
			// Return database connection to the pool
905
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
906
		}
907

    
908
		return exists;
909
	}
910
    
911
    /**
912
     * creates a system metadata mapping and adds additional fields from sysmeta
913
     * to the table for quick searching.
914
     * 
915
     * @param guid the id to insert
916
     * @param localId the systemMetadata object to get the local id for
917
     * @throws McdbDocNotFoundException 
918
     * @throws SQLException 
919
     * @throws InvalidSystemMetadata 
920
     */
921
    public void createSystemMetadata(SystemMetadata sysmeta) 
922
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
923
    	String guid = sysmeta.getIdentifier().getValue();
924
    	// insert the record
925
        insertSystemMetadata(guid);
926
        // update with the values
927
        updateSystemMetadata(sysmeta);
928
        
929
    }
930
        
931
    
932
    /**
933
     * update a mapping
934
     * @param guid
935
     * @param localId
936
     */
937
    public void updateMapping(String guid, String localId)
938
    {
939
    	
940
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
941
        int serialNumber = -1;
942
        DBConnection dbConn = null;
943
        try {
944
            // Parse the localId into scope and rev parts
945
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
946
            String docid = acc.getDocid();
947
            int rev = 1;
948
            if(acc.getRev() != null)
949
            {
950
              rev = (new Integer(acc.getRev()).intValue());
951
            }
952

    
953
            // Get a database connection from the pool
954
            dbConn = 
955
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
956
            serialNumber = dbConn.getCheckOutSerialNumber();
957

    
958
            // Execute the update statement
959
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
960
            PreparedStatement stmt = dbConn.prepareStatement(query);
961
            stmt.setString(1, docid);
962
            stmt.setInt(2, rev);
963
            stmt.setString(3, guid);
964
            int rows = stmt.executeUpdate();
965

    
966
            stmt.close();
967
        } catch (SQLException e) {
968
            e.printStackTrace();
969
            logMetacat.error("SQL error while updating a mapping identifier: " 
970
                    + e.getMessage());
971
        } catch (NumberFormatException e) {
972
            e.printStackTrace();
973
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
974
                    + e.getMessage());
975
        } catch (AccessionNumberException e) {
976
            e.printStackTrace();
977
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
978
                    + e.getMessage());
979
        } finally {
980
            // Return database connection to the pool
981
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
982
        }
983
        logMetacat.debug("done updating mapping");
984
    }
985
        
986
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
987
        String checksum, String checksumAlgorithm, String originMemberNode, 
988
        String authoritativeMemberNode, long modifiedDate, String submitter, 
989
        String guid, String objectFormat, BigInteger size, boolean archived,
990
        boolean replicationAllowed, int numberReplicas, String obsoletes,
991
        String obsoletedBy, BigInteger serialVersion) throws SQLException  {
992
        
993
        DBConnection dbConn = null;
994
        int serialNumber = -1;
995
        
996
        try {
997
            // Get a database connection from the pool
998
            dbConn = 
999
                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1000
            serialNumber = dbConn.getCheckOutSerialNumber();
1001

    
1002
            // Execute the insert statement
1003
            String query = "update " + TYPE_SYSTEM_METADATA + 
1004
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1005
                "origin_member_node, authoritive_member_node, date_modified, " +
1006
                "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1007
                "obsoletes, obsoleted_by, serial_version) " +
1008
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1009
            PreparedStatement stmt = dbConn.prepareStatement(query);
1010
            
1011
            //data values
1012
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1013
            stmt.setString(2, rightsHolder);
1014
            stmt.setString(3, checksum);
1015
            stmt.setString(4, checksumAlgorithm);
1016
            stmt.setString(5, originMemberNode);
1017
            stmt.setString(6, authoritativeMemberNode);
1018
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1019
            stmt.setString(8, submitter);
1020
            stmt.setString(9, objectFormat);
1021
            stmt.setString(10, size.toString());
1022
            stmt.setBoolean(11, archived);
1023
            stmt.setBoolean(12, replicationAllowed);
1024
            stmt.setInt(13, numberReplicas);
1025
            stmt.setString(14, obsoletes);
1026
            stmt.setString(15, obsoletedBy);
1027
            stmt.setString(16, serialVersion.toString());
1028

    
1029
            //where clause
1030
            stmt.setString(17, guid);
1031
            logMetacat.debug("stmt: " + stmt.toString());
1032
            //execute
1033
            int rows = stmt.executeUpdate();
1034

    
1035
            stmt.close();
1036
            
1037
        } catch (SQLException e) {
1038
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1039
                    + e.getMessage());
1040
            throw e;
1041
            
1042
        } finally {
1043
            // Return database connection to the pool
1044
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1045
        }
1046
    }
1047
    
1048
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
1049
    {
1050
        DBConnection dbConn = null;
1051
        int serialNumber = -1;
1052
        
1053
        try {
1054
            // Get a database connection from the pool
1055
            dbConn = 
1056
                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
1057
            serialNumber = dbConn.getCheckOutSerialNumber();
1058

    
1059
            // remove existing values first
1060
            String delete = "delete from systemMetadataReplicationPolicy " + 
1061
            "where guid = ? and policy = ?";
1062
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1063
	        //data values
1064
	        stmt.setString(1, guid);
1065
	        stmt.setString(2, policy);
1066
	        //execute
1067
	        int deletedCount = stmt.executeUpdate();
1068
	        stmt.close();
1069
            
1070
            for (String memberNode: memberNodes) {
1071
	            // Execute the insert statement
1072
	            String insert = "insert into systemMetadataReplicationPolicy " + 
1073
	                "(guid, policy, member_node) " +
1074
	                "values (?, ?, ?)";
1075
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1076
	            
1077
	            //data values
1078
	            insertStatement.setString(1, guid);
1079
	            insertStatement.setString(2, policy);
1080
	            insertStatement.setString(3, memberNode);
1081
	            //execute
1082
	            int rows = insertStatement.executeUpdate();
1083
	            insertStatement.close();
1084
            }
1085
        } catch (SQLException e) {
1086
            logMetacat.error("SQL error while adding systemMetadataReplicationPolicy for: " + guid, e); 
1087
        } finally {
1088
            // Return database connection to the pool
1089
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1090
        }
1091
    }
1092
    
1093
    private void insertReplicationStatus(String guid, List<Replica> replicas) {
1094
        DBConnection dbConn = null;
1095
        int serialNumber = -1;
1096
        
1097
        try {
1098
            // Get a database connection from the pool
1099
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertReplicas");
1100
            serialNumber = dbConn.getCheckOutSerialNumber();
1101

    
1102
            // remove existing values first
1103
            String delete = "delete from systemMetadataReplicationStatus " + 
1104
            "where guid = ?";
1105
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1106
	        //data values
1107
	        stmt.setString(1, guid);
1108
	        //execute
1109
	        int deletedCount = stmt.executeUpdate();
1110
	        stmt.close();
1111
            
1112
	        if (replicas != null) {
1113
	            for (Replica replica: replicas) {
1114
		            // Execute the insert statement
1115
		            String insert = "insert into systemMetadataReplicationStatus " + 
1116
		                "(guid, member_node, status, date_verified) " +
1117
		                "values (?, ?, ?, ?)";
1118
		            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1119
		            
1120
		            //data values
1121
		            String memberNode = replica.getReplicaMemberNode().getValue();
1122
		            String status = replica.getReplicationStatus().toString();
1123
		            java.sql.Date sqlDate = new java.sql.Date(replica.getReplicaVerified().getTime());
1124
		            insertStatement.setString(1, guid);
1125
		            insertStatement.setString(2, memberNode);
1126
		            insertStatement.setString(3, status);
1127
		            insertStatement.setDate(4, sqlDate);
1128
	
1129
		            //execute
1130
		            int rows = insertStatement.executeUpdate();
1131
		            insertStatement.close();
1132
	            }
1133
	        }
1134
        } catch (SQLException e) {
1135
            logMetacat.error("SQL error while adding systemMetadataReplicationStatus for: " + guid, e); 
1136
        } finally {
1137
            // Return database connection to the pool
1138
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1139
        }
1140
    }
1141
    
1142
    /**
1143
     * Insert the system metadata fields into the db
1144
     * @param sm
1145
     * @throws McdbDocNotFoundException 
1146
     * @throws SQLException 
1147
     * @throws InvalidSystemMetadata 
1148
     */
1149
    public void updateSystemMetadata(SystemMetadata sm) 
1150
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1151
    	
1152
      Boolean replicationAllowed = false;
1153
		  Integer numberReplicas = -1;
1154
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1155
    	if (replicationPolicy != null) {
1156
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1157
    		numberReplicas = replicationPolicy.getNumberReplicas();
1158
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1159
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1160
    	}
1161
    	
1162
    	// the main systemMetadata fields
1163
		  updateSystemMetadataFields(
1164
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1165
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1166
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1167
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1168
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1169
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1170
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1171
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1172
		    sm.getIdentifier().getValue(),
1173
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1174
		    sm.getSize(),
1175
		    sm.getArchived() == null ? false: sm.getArchived(),
1176
		    replicationAllowed, 
1177
		    numberReplicas,
1178
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1179
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1180
		    sm.getSerialVersion()
1181
        );
1182
        
1183
        String guid = sm.getIdentifier().getValue();
1184
        
1185
        // save replication policies
1186
        if (replicationPolicy != null) {
1187
		    List<String> nodes = null;
1188
		    String policy = null;
1189
		    
1190
		    // check for null 
1191
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1192
			    nodes = new ArrayList<String>();
1193
			    policy = "blocked";
1194
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1195
			    	nodes.add(node.getValue());
1196
			    }
1197
			    this.insertReplicationPolicy(guid, policy, nodes);
1198
		    }
1199
		    
1200
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1201
			    nodes = new ArrayList<String>();
1202
			    policy = "preferred";
1203
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1204
			    	nodes.add(node.getValue());
1205
			    }
1206
		        this.insertReplicationPolicy(guid, policy, nodes);
1207
		    }
1208
        }
1209
        
1210
        // save replica information
1211
        this.insertReplicationStatus(guid, sm.getReplicaList());
1212
        
1213
        // save access policy
1214
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1215
        if (accessPolicy != null) {
1216
        	try {
1217
				this.insertAccessPolicy(guid, accessPolicy);
1218
			} catch (AccessException e) {
1219
				throw new McdbDocNotFoundException(e);
1220
			}
1221
        }
1222
    }
1223
    
1224
    /**
1225
     * Creates Metacat access rules and inserts them
1226
     * @param accessPolicy
1227
     * @throws McdbDocNotFoundException
1228
     * @throws AccessException
1229
     */
1230
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1231
    	
1232
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1233
        XMLAccessAccess accessController  = new XMLAccessAccess();
1234
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1235
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1236
        if (existingAccess != null && existingAccess.size() > 0) {
1237
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1238
        }
1239
        
1240
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1241
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1242
        	List<Subject> subjects = accessRule.getSubjectList();
1243
        	List<Permission> permissions = accessRule.getPermissionList();
1244
        	for (Subject subject: subjects) {
1245
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1246
        		accessDAO.setPrincipalName(subject.getValue());
1247
    			accessDAO.setGuid(guid);
1248
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1249
				accessDAO.setPermOrder(existingPermOrder);
1250
    			if (permissions != null) {
1251
	    			for (Permission permission: permissions) {
1252
	    				Long metacatPermission = new Long(convertPermission(permission));
1253
	        			accessDAO.addPermission(metacatPermission);
1254
	    			}
1255
    			}
1256
    			accessDAOs.add(accessDAO);
1257
        	}
1258
        }
1259
        
1260
        
1261
        // remove all existing allow records
1262
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1263
        // add the ones we can for this guid
1264
        accessController.insertAccess(guid, accessDAOs);
1265
        
1266
        
1267
    }
1268
    
1269
    /**
1270
     * Lookup access policy from Metacat
1271
     * @param guid
1272
     * @return
1273
     * @throws McdbDocNotFoundException
1274
     * @throws AccessException
1275
     */
1276
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1277
        AccessPolicy accessPolicy = new AccessPolicy();
1278

    
1279
    	// use GUID to look up the access
1280
        XMLAccessAccess accessController  = new XMLAccessAccess();
1281
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1282
        
1283
        for (XMLAccessDAO accessDAO: accessDAOs) {
1284
        	// only add allow rule
1285
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1286
	        	AccessRule accessRule = new AccessRule();    	
1287
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1288
	        	accessRule.setPermissionList(permissions);
1289
	        	Subject subject = new Subject();
1290
	        	subject.setValue(accessDAO.getPrincipalName());
1291
	        	accessRule.addSubject(subject);
1292
	            accessPolicy.addAllow(accessRule);
1293
        	}
1294
        }
1295
        return accessPolicy;
1296
    }
1297
    
1298
    public int convertPermission(Permission permission) {
1299
    	if (permission.equals(Permission.READ)) {
1300
    		return AccessControlInterface.READ;
1301
    	}
1302
    	if (permission.equals(Permission.WRITE)) {
1303
    		return AccessControlInterface.WRITE;
1304
    	}
1305
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1306
    		return AccessControlInterface.CHMOD;
1307
    	}
1308
		return -1;
1309
    }
1310
    
1311
    public List<Permission> convertPermission(int permission) {
1312
    	
1313
    	List<Permission> permissions = new ArrayList<Permission>();
1314
    	if (permission == AccessControlInterface.ALL) {
1315
    		permissions.add(Permission.READ);
1316
    		permissions.add(Permission.WRITE);
1317
    		permissions.add(Permission.CHANGE_PERMISSION);
1318
    		return permissions;
1319
    	}
1320
    	
1321
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1322
    		permissions.add(Permission.CHANGE_PERMISSION);
1323
    	}
1324
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1325
    		permissions.add(Permission.READ);
1326
    	}
1327
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1328
    		permissions.add(Permission.WRITE);
1329
    	}
1330
    	
1331
		return permissions;
1332
    }
1333
    
1334
    /**
1335
     * Lookup a localId given the GUID. If
1336
     * the identifier is not found, throw an exception.
1337
     * 
1338
     * @param guid the global identifier to look up
1339
     * @return String containing the corresponding LocalId
1340
     * @throws McdbDocNotFoundException if the identifier is not found
1341
     */
1342
    public String getLocalId(String guid) throws McdbDocNotFoundException {
1343
      
1344
      String db_guid = "";
1345
      String docid = "";
1346
      int rev = 0;
1347
      
1348
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1349
      
1350
      DBConnection dbConn = null;
1351
      int serialNumber = -1;
1352
      try {
1353
          // Get a database connection from the pool
1354
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1355
          serialNumber = dbConn.getCheckOutSerialNumber();
1356
          
1357
          // Execute the insert statement
1358
          PreparedStatement stmt = dbConn.prepareStatement(query);
1359
          stmt.setString(1, guid);
1360
          ResultSet rs = stmt.executeQuery();
1361
          if (rs.next()) {
1362
              db_guid = rs.getString(1);
1363
              docid = rs.getString(2);
1364
              rev = rs.getInt(3);
1365
              assert(db_guid.equals(guid));
1366
          } else {
1367
              throw new McdbDocNotFoundException("Document not found:" + guid);
1368
          }
1369
          stmt.close();
1370
      } catch (SQLException e) {
1371
          logMetacat.error("Error while looking up the local identifier: " 
1372
                  + e.getMessage());
1373
      } finally {
1374
          // Return database connection to the pool
1375
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1376
      }
1377
      return docid + "." + rev;
1378
    }
1379
    
1380
    /**
1381
     * query the systemmetadata table based on the given parameters
1382
     * @param startTime
1383
     * @param endTime
1384
     * @param objectFormat
1385
     * @param replicaStatus
1386
     * @param start
1387
     * @param count
1388
     * @return ObjectList
1389
     * @throws SQLException 
1390
     * @throws ServiceException 
1391
     * @throws PropertyNotFoundException 
1392
     */
1393
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1394
        ObjectFormatIdentifier objectFormatId, boolean replicaStatus,
1395
        int start, int count) 
1396
        throws SQLException, PropertyNotFoundException, ServiceException {
1397
        ObjectList ol = new ObjectList();
1398
        int total = 0;
1399
        DBConnection dbConn = null;
1400
        int serialNumber = -1;
1401

    
1402
        try {
1403
            String sql = "select guid, date_uploaded, rights_holder, checksum, "
1404
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1405
                    + "date_modified, submitter, object_format, size from systemmetadata";
1406

    
1407
            boolean f1 = false;
1408
            boolean f2 = false;
1409
            boolean f3 = false;
1410

    
1411
            if (startTime != null) {
1412
                sql += " where systemmetadata.date_modified >= ?";
1413
                f1 = true;
1414
            }
1415

    
1416
            if (endTime != null) {
1417
                if (!f1) {
1418
                    sql += " where systemmetadata.date_modified < ?";
1419
                } else {
1420
                    sql += " and systemmetadata.date_modified < ?";
1421
                }
1422
                f2 = true;
1423
            }
1424

    
1425
            if (objectFormatId != null) {
1426
                if (!f1 && !f2) {
1427
                    sql += " where object_format = ?";
1428
                } else {
1429
                    sql += " and object_format = ?";
1430
                }
1431
                f3 = true;
1432
            }
1433

    
1434
            if (replicaStatus) {
1435
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.memberNodeId");
1436
                if (!f1 && !f2 && !f3) {
1437
                    sql += " where authoritive_member_node != '" +
1438
                        currentNodeId.trim() + "'";
1439
                } else {
1440
                    sql += " and authoritive_member_node != '" +
1441
                        currentNodeId.trim() + "'";
1442
                }
1443
            }
1444

    
1445
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1446
            serialNumber = dbConn.getCheckOutSerialNumber();
1447
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1448

    
1449
            if (f1 && f2 && f3) {
1450
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1451
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1452
                stmt.setString(3, objectFormatId.getValue());
1453
            } else if (f1 && f2 && !f3) {
1454
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1455
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1456
            } else if (f1 && !f2 && f3) {
1457
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1458
                stmt.setString(2, objectFormatId.getValue());
1459
            } else if (f1 && !f2 && !f3) {
1460
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1461
            } else if (!f1 && f2 && f3) {
1462
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1463
                stmt.setString(2, objectFormatId.getValue());
1464
            } else if (!f1 && !f2 && f3) {
1465
                stmt.setString(1, objectFormatId.getValue());
1466
            } else if (!f1 && f2 && !f3) {
1467
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1468
            }
1469

    
1470
            // logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1471

    
1472
            ResultSet rs = stmt.executeQuery();
1473
            for (int i = 0; i < start; i++) {
1474
                if (rs.next()) {
1475
                    total++;
1476
                } else {
1477
                    break;
1478
                }
1479
            }
1480

    
1481
            int countIndex = 0;
1482

    
1483
            while (rs.next()) {                
1484
                total++;
1485
                if (countIndex >= count) {
1486
                    // allow unlimited (negative number for count)
1487
                    if (count > 0) {
1488
                        break;
1489
                    }
1490
                }
1491

    
1492
                String guid = rs.getString(1);
1493
                // logMetacat.debug("query found doc with guid " + guid);
1494
                // Timestamp dateUploaded = rs.getTimestamp(2);
1495
                // String rightsHolder = rs.getString(3);
1496
                String checksum = rs.getString(4);
1497
                String checksumAlgorithm = rs.getString(5);
1498
                // String originMemberNode = rs.getString(6);
1499
                // String authoritiveMemberNode = rs.getString(7);
1500
                Timestamp dateModified = rs.getTimestamp(8);
1501
                // String submitter = rs.getString(9);
1502
                String fmtidStr = rs.getString(10);
1503
                String sz = rs.getString(11);
1504
                BigInteger size = new BigInteger("0");
1505

    
1506
                if (sz != null && !sz.trim().equals("")) {
1507
                    size = new BigInteger(rs.getString(11));
1508
                }
1509

    
1510
                ObjectInfo oi = new ObjectInfo();
1511

    
1512
                Identifier id = new Identifier();
1513
                id.setValue(guid);
1514
                oi.setIdentifier(id);
1515

    
1516
                if (dateModified != null) {
1517
                    oi.setDateSysMetadataModified(new Date(dateModified.getTime()));
1518
                }
1519

    
1520
                Checksum cs = new Checksum();
1521
                cs.setValue(checksum);
1522
                try {
1523
                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1524
                    cs.setAlgorithm(checksumAlgorithm);
1525
                } catch (Exception e) {
1526
                    logMetacat.error("could not parse checksum algorithm", e);
1527
                    continue;
1528
                }
1529
                oi.setChecksum(cs);
1530

    
1531
                // set the format type
1532
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1533
                fmtid.setValue(fmtidStr);
1534
                oi.setFormatId(fmtid);
1535

    
1536
                oi.setSize(size);
1537

    
1538
                // when requested count == 0, return an empty object list
1539
                if (count != 0) {
1540
                    ol.addObjectInfo(oi);                    
1541
                }
1542
                countIndex++;
1543
            }
1544

    
1545
            // expend the resultset to get the total count of possible rows
1546
            while (rs.next()) {
1547
                total++;
1548
            }
1549
        }
1550

    
1551
        finally {
1552
            // Return database connection to the pool
1553
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1554
        }
1555

    
1556
        ol.setStart(start);
1557
        ol.setCount(ol.sizeObjectInfoList());
1558
        ol.setTotal(total);
1559

    
1560
        return ol;
1561
    }
1562
    
1563
    /**
1564
     * create a mapping in the identifier table
1565
     * @param guid
1566
     * @param localId
1567
     */
1568
    public void createMapping(String guid, String localId)
1569
    {        
1570
        
1571
        int serialNumber = -1;
1572
        DBConnection dbConn = null;
1573
        try {
1574

    
1575
            // Parse the localId into scope and rev parts
1576
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1577
            String docid = acc.getDocid();
1578
            int rev = 1;
1579
            if (acc.getRev() != null) {
1580
              rev = (new Integer(acc.getRev()).intValue());
1581
            }
1582

    
1583
            // Get a database connection from the pool
1584
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1585
            serialNumber = dbConn.getCheckOutSerialNumber();
1586

    
1587
            // Execute the insert statement
1588
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1589
            PreparedStatement stmt = dbConn.prepareStatement(query);
1590
            stmt.setString(1, guid);
1591
            stmt.setString(2, docid);
1592
            stmt.setInt(3, rev);
1593
            logMetacat.debug("mapping query: " + stmt.toString());
1594
            int rows = stmt.executeUpdate();
1595

    
1596
            stmt.close();
1597
        } catch (SQLException e) {
1598
            e.printStackTrace();
1599
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1600
                    + e.getMessage());
1601
        } catch (NumberFormatException e) {
1602
            e.printStackTrace();
1603
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1604
                    + e.getMessage());
1605
        } catch (AccessionNumberException e) {
1606
            e.printStackTrace();
1607
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1608
                    + e.getMessage());
1609
        } finally {
1610
            // Return database connection to the pool
1611
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1612
        }
1613
    }
1614
    
1615
    /**
1616
     * create the systemmetadata record
1617
     * @param guid
1618
     */
1619
    private void insertSystemMetadata(String guid)
1620
    {        
1621
        
1622
        int serialNumber = -1;
1623
        DBConnection dbConn = null;
1624
        try {
1625

    
1626
            // Get a database connection from the pool
1627
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1628
            serialNumber = dbConn.getCheckOutSerialNumber();
1629

    
1630
            // Execute the insert statement
1631
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1632
            PreparedStatement stmt = dbConn.prepareStatement(query);
1633
            stmt.setString(1, guid);
1634
            logMetacat.debug("system metadata query: " + stmt.toString());
1635
            int rows = stmt.executeUpdate();
1636

    
1637
            stmt.close();
1638
        } catch (Exception e) {
1639
            e.printStackTrace();
1640
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1641
        } finally {
1642
            // Return database connection to the pool
1643
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1644
        }
1645
    }
1646
    
1647
    public void deleteSystemMetadata(String guid)
1648
    {        
1649
        
1650
        int serialNumber = -1;
1651
        DBConnection dbConn = null;
1652
        String query = null;
1653
        PreparedStatement stmt = null;
1654
        int rows = 0;
1655
        try {
1656

    
1657
            // Get a database connection from the pool
1658
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1659
            serialNumber = dbConn.getCheckOutSerialNumber();
1660

    
1661
            // remove main system metadata entry
1662
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1663
            stmt = dbConn.prepareStatement(query);
1664
            stmt.setString(1, guid);
1665
            logMetacat.debug("delete system metadata: " + stmt.toString());
1666
            rows = stmt.executeUpdate();
1667
            stmt.close();
1668
            
1669
            // remove the systemMetadataReplicationPolicy
1670
            query = "delete from systemMetadataReplicationPolicy " + 
1671
            "where guid = ?";
1672
            stmt = dbConn.prepareStatement(query);
1673
            stmt.setString(1, guid);
1674
            logMetacat.debug("delete systemMetadataReplicationPolicy: " + stmt.toString());
1675
            rows = stmt.executeUpdate();
1676
            stmt.close();
1677
            
1678
            // remove the systemMetadataReplicationStatus
1679
            query = "delete from systemMetadataReplicationStatus " + 
1680
            "where guid = ?";
1681
            stmt = dbConn.prepareStatement(query);
1682
            stmt.setString(1, guid);
1683
            logMetacat.debug("delete systemMetadataReplicationStatus: " + stmt.toString());
1684
            rows = stmt.executeUpdate();
1685
            stmt.close();
1686
            
1687
            // TODO: remove the access?
1688
            // Metacat keeps "deleted" documents so we should not remove access rules.
1689
            
1690
        } catch (Exception e) {
1691
            e.printStackTrace();
1692
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1693
            try {
1694
				dbConn.rollback();
1695
			} catch (SQLException sqle) {
1696
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
1697
			}
1698
        } finally {
1699
            // Return database connection to the pool
1700
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1701
        }
1702
    }
1703
    
1704
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
1705
    {
1706
        DBConnection dbConn = null;
1707
        int serialNumber = -1;
1708
        
1709
        try {
1710
            // Get a database connection from the pool
1711
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
1712
            serialNumber = dbConn.getCheckOutSerialNumber();
1713

    
1714
            // Execute the insert statement
1715
            String query = "update " + TYPE_SYSTEM_METADATA + 
1716
                " set authoritive_member_node = ? " +
1717
                " where authoritive_member_node = ?";
1718
            PreparedStatement stmt = dbConn.prepareStatement(query);
1719
            
1720
            //data values
1721
            stmt.setString(1, newMemberNodeId);
1722
            stmt.setString(2, existingMemberNodeId);
1723

    
1724
            logMetacat.debug("stmt: " + stmt.toString());
1725
            //execute
1726
            int rows = stmt.executeUpdate();
1727

    
1728
            stmt.close();
1729
        } catch (SQLException e) {
1730
            e.printStackTrace();
1731
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1732
                    + e.getMessage());
1733
        } catch (NumberFormatException e) {
1734
            e.printStackTrace();
1735
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
1736
                    + e.getMessage());
1737
        } finally {
1738
            // Return database connection to the pool
1739
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1740
        }
1741
    }
1742
}
1743

    
(37-37/64)