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.BaseException;
41
import org.dataone.service.exceptions.InvalidSystemMetadata;
42
import org.dataone.service.exceptions.NotFound;
43
import org.dataone.service.exceptions.NotImplemented;
44
import org.dataone.service.exceptions.ServiceFailure;
45
import org.dataone.service.types.v1.AccessPolicy;
46
import org.dataone.service.types.v1.AccessRule;
47
import org.dataone.service.types.v1.Checksum;
48
import org.dataone.service.types.v1.Identifier;
49
import org.dataone.service.types.v1.NodeReference;
50
import org.dataone.service.types.v1.ObjectFormatIdentifier;
51
import org.dataone.service.types.v1.ObjectInfo;
52
import org.dataone.service.types.v1.ObjectList;
53
import org.dataone.service.types.v1.Permission;
54
import org.dataone.service.types.v1.Replica;
55
import org.dataone.service.types.v1.ReplicationPolicy;
56
import org.dataone.service.types.v1.ReplicationStatus;
57
import org.dataone.service.types.v1.Subject;
58
import org.dataone.service.types.v1.SystemMetadata;
59

    
60
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
61
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessAccess;
62
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
63
import edu.ucsb.nceas.metacat.database.DBConnection;
64
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
65
import edu.ucsb.nceas.metacat.properties.PropertyService;
66
import edu.ucsb.nceas.metacat.shared.AccessException;
67
import edu.ucsb.nceas.metacat.shared.ServiceException;
68
import edu.ucsb.nceas.metacat.util.DocumentUtil;
69
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
70

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

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

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

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

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

    
291

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

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

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

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

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

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

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

    
725
        List<String> ids = new Vector<String>();
726
        String sql = 
727
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
728
        DBConnection dbConn = null;
729
        int serialNumber = -1;
730
        try 
731
        {
732
            // Get a database connection from the pool
733
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
734
            serialNumber = dbConn.getCheckOutSerialNumber();
735

    
736
            // Execute the insert statement
737
            PreparedStatement stmt = dbConn.prepareStatement(sql);
738
            ResultSet rs = stmt.executeQuery();
739
            if (rs.next()) {
740
            	maxDate = rs.getDate(1);
741
            } 
742
            stmt.close();
743
        } 
744
        catch (SQLException e) 
745
        {
746
            logMetacat.error("Error while looking up the latest update date: " 
747
                    + e.getMessage());
748
        } 
749
        finally 
750
        {
751
            // Return database connection to the pool
752
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
753
        }
754
        return maxDate;
755
    }
756

    
757
    
758
    /**
759
     * Determine if an identifier exists already, returning true if so.
760
     * 
761
     * @param guid the global identifier to look up
762
     * @return boolean true if the identifier exists
763
     */
764
    public boolean identifierExists(String guid)
765
    {
766
        boolean idExists = false;
767
        try {
768
            String id = getLocalId(guid);
769
            if (id != null) {
770
                idExists = true;
771
            }
772
        } catch (McdbDocNotFoundException e) {
773
        	// try system metadata only
774
        	try {
775
        		idExists = systemMetadataExists(guid);
776
            } catch (Exception e2) {
777
            	idExists = false;
778
            }
779
        }
780
        return idExists;
781
    }
782
    
783
    /**
784
     * 
785
     * @param guid
786
     * @param rev
787
     * @return
788
     */
789
    public String generateLocalId(String guid, int rev)
790
    {
791
        return generateLocalId(guid, rev, false);
792
    }
793

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

    
896
		DBConnection dbConn = null;
897
		int serialNumber = -1;
898
		try {
899
			// Get a database connection from the pool
900
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
901
			serialNumber = dbConn.getCheckOutSerialNumber();
902

    
903
			// Execute the insert statement
904
			PreparedStatement stmt = dbConn.prepareStatement(query);
905
			stmt.setString(1, guid);
906
			ResultSet rs = stmt.executeQuery();
907
			if (rs.next()) {
908
				exists = true;
909
			}
910

    
911
		} catch (SQLException e) {
912
			logMetacat.error("Error while looking up the system metadata: "
913
					+ e.getMessage());
914
		} finally {
915
			// Return database connection to the pool
916
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
917
		}
918

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

    
964
            // Get a database connection from the pool
965
            dbConn = 
966
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
967
            serialNumber = dbConn.getCheckOutSerialNumber();
968

    
969
            // Execute the update statement
970
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
971
            PreparedStatement stmt = dbConn.prepareStatement(query);
972
            stmt.setString(1, docid);
973
            stmt.setInt(2, rev);
974
            stmt.setString(3, guid);
975
            int rows = stmt.executeUpdate();
976

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

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

    
1040
            //where clause
1041
            stmt.setString(17, guid);
1042
            logMetacat.debug("stmt: " + stmt.toString());
1043
            //execute
1044
            int rows = stmt.executeUpdate();
1045

    
1046
            stmt.close();
1047
            
1048
        } catch (SQLException e) {
1049
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1050
                    + e.getMessage());
1051
            throw e;
1052
            
1053
        } finally {
1054
            // Return database connection to the pool
1055
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1056
        }
1057
    }
1058
    
1059
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
1060
    {
1061
        DBConnection dbConn = null;
1062
        int serialNumber = -1;
1063
        
1064
        try {
1065
            // Get a database connection from the pool
1066
            dbConn = 
1067
                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
1068
            serialNumber = dbConn.getCheckOutSerialNumber();
1069

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

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

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

    
1413
        try {
1414
            String sql = "select guid, date_uploaded, rights_holder, checksum, "
1415
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1416
                    + "date_modified, submitter, object_format, size from systemmetadata";
1417

    
1418
            boolean f1 = false;
1419
            boolean f2 = false;
1420
            boolean f3 = false;
1421

    
1422
            if (startTime != null) {
1423
                sql += " where systemmetadata.date_modified >= ?";
1424
                f1 = true;
1425
            }
1426

    
1427
            if (endTime != null) {
1428
                if (!f1) {
1429
                    sql += " where systemmetadata.date_modified < ?";
1430
                } else {
1431
                    sql += " and systemmetadata.date_modified < ?";
1432
                }
1433
                f2 = true;
1434
            }
1435

    
1436
            if (objectFormatId != null) {
1437
                if (!f1 && !f2) {
1438
                    sql += " where object_format = ?";
1439
                } else {
1440
                    sql += " and object_format = ?";
1441
                }
1442
                f3 = true;
1443
            }
1444

    
1445
            if (replicaStatus) {
1446
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.memberNodeId");
1447
                if (!f1 && !f2 && !f3) {
1448
                    sql += " where authoritive_member_node != '" +
1449
                        currentNodeId.trim() + "'";
1450
                } else {
1451
                    sql += " and authoritive_member_node != '" +
1452
                        currentNodeId.trim() + "'";
1453
                }
1454
            }
1455

    
1456
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1457
            serialNumber = dbConn.getCheckOutSerialNumber();
1458
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1459

    
1460
            if (f1 && f2 && f3) {
1461
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1462
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1463
                stmt.setString(3, objectFormatId.getValue());
1464
            } else if (f1 && f2 && !f3) {
1465
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1466
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1467
            } else if (f1 && !f2 && f3) {
1468
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1469
                stmt.setString(2, objectFormatId.getValue());
1470
            } else if (f1 && !f2 && !f3) {
1471
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1472
            } else if (!f1 && f2 && f3) {
1473
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1474
                stmt.setString(2, objectFormatId.getValue());
1475
            } else if (!f1 && !f2 && f3) {
1476
                stmt.setString(1, objectFormatId.getValue());
1477
            } else if (!f1 && f2 && !f3) {
1478
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1479
            }
1480

    
1481
            // logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1482

    
1483
            ResultSet rs = stmt.executeQuery();
1484
            for (int i = 0; i < start; i++) {
1485
                if (rs.next()) {
1486
                    total++;
1487
                } else {
1488
                    break;
1489
                }
1490
            }
1491

    
1492
            int countIndex = 0;
1493

    
1494
            while (rs.next()) {                
1495
                total++;
1496
                if (countIndex >= count) {
1497
                    // allow unlimited (negative number for count)
1498
                    if (count > 0) {
1499
                        break;
1500
                    }
1501
                }
1502

    
1503
                String guid = rs.getString(1);
1504
                // logMetacat.debug("query found doc with guid " + guid);
1505
                // Timestamp dateUploaded = rs.getTimestamp(2);
1506
                // String rightsHolder = rs.getString(3);
1507
                String checksum = rs.getString(4);
1508
                String checksumAlgorithm = rs.getString(5);
1509
                // String originMemberNode = rs.getString(6);
1510
                // String authoritiveMemberNode = rs.getString(7);
1511
                Timestamp dateModified = rs.getTimestamp(8);
1512
                // String submitter = rs.getString(9);
1513
                String fmtidStr = rs.getString(10);
1514
                String sz = rs.getString(11);
1515
                BigInteger size = new BigInteger("0");
1516

    
1517
                if (sz != null && !sz.trim().equals("")) {
1518
                    size = new BigInteger(rs.getString(11));
1519
                }
1520

    
1521
                ObjectInfo oi = new ObjectInfo();
1522

    
1523
                Identifier id = new Identifier();
1524
                id.setValue(guid);
1525
                oi.setIdentifier(id);
1526

    
1527
                if (dateModified != null) {
1528
                    oi.setDateSysMetadataModified(new Date(dateModified.getTime()));
1529
                }
1530

    
1531
                Checksum cs = new Checksum();
1532
                cs.setValue(checksum);
1533
                try {
1534
                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1535
                    cs.setAlgorithm(checksumAlgorithm);
1536
                } catch (Exception e) {
1537
                    logMetacat.error("could not parse checksum algorithm", e);
1538
                    continue;
1539
                }
1540
                oi.setChecksum(cs);
1541

    
1542
                // set the format type
1543
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1544
                fmtid.setValue(fmtidStr);
1545
                oi.setFormatId(fmtid);
1546

    
1547
                oi.setSize(size);
1548

    
1549
                // when requested count == 0, return an empty object list
1550
                if (count != 0) {
1551
                    ol.addObjectInfo(oi);                    
1552
                }
1553
                countIndex++;
1554
            }
1555

    
1556
            // expend the resultset to get the total count of possible rows
1557
            while (rs.next()) {
1558
                total++;
1559
            }
1560
        }
1561

    
1562
        finally {
1563
            // Return database connection to the pool
1564
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1565
        }
1566

    
1567
        ol.setStart(start);
1568
        ol.setCount(ol.sizeObjectInfoList());
1569
        ol.setTotal(total);
1570

    
1571
        return ol;
1572
    }
1573
    
1574
    /**
1575
     * create a mapping in the identifier table
1576
     * @param guid
1577
     * @param localId
1578
     */
1579
    public void createMapping(String guid, String localId)
1580
    {        
1581
        
1582
        int serialNumber = -1;
1583
        DBConnection dbConn = null;
1584
        try {
1585

    
1586
            // Parse the localId into scope and rev parts
1587
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1588
            String docid = acc.getDocid();
1589
            int rev = 1;
1590
            if (acc.getRev() != null) {
1591
              rev = (new Integer(acc.getRev()).intValue());
1592
            }
1593

    
1594
            // Get a database connection from the pool
1595
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1596
            serialNumber = dbConn.getCheckOutSerialNumber();
1597

    
1598
            // Execute the insert statement
1599
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1600
            PreparedStatement stmt = dbConn.prepareStatement(query);
1601
            stmt.setString(1, guid);
1602
            stmt.setString(2, docid);
1603
            stmt.setInt(3, rev);
1604
            logMetacat.debug("mapping query: " + stmt.toString());
1605
            int rows = stmt.executeUpdate();
1606

    
1607
            stmt.close();
1608
        } catch (SQLException e) {
1609
            e.printStackTrace();
1610
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1611
                    + e.getMessage());
1612
        } catch (NumberFormatException e) {
1613
            e.printStackTrace();
1614
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1615
                    + e.getMessage());
1616
        } catch (AccessionNumberException e) {
1617
            e.printStackTrace();
1618
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1619
                    + e.getMessage());
1620
        } finally {
1621
            // Return database connection to the pool
1622
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1623
        }
1624
    }
1625
    
1626
    /**
1627
     * remove a mapping in the identifier table
1628
     * @param guid
1629
     * @param localId
1630
     */
1631
    public void removeMapping(String guid, String localId)
1632
    {        
1633
        
1634
        int serialNumber = -1;
1635
        DBConnection dbConn = null;
1636
        try {
1637

    
1638
            // Parse the localId into scope and rev parts
1639
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1640
            String docid = acc.getDocid();
1641
            int rev = 1;
1642
            if (acc.getRev() != null) {
1643
              rev = (new Integer(acc.getRev()).intValue());
1644
            }
1645

    
1646
            // Get a database connection from the pool
1647
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
1648
            serialNumber = dbConn.getCheckOutSerialNumber();
1649

    
1650
            // Execute the insert statement
1651
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
1652
            PreparedStatement stmt = dbConn.prepareStatement(query);
1653
            stmt.setString(1, guid);
1654
            stmt.setString(2, docid);
1655
            stmt.setInt(3, rev);
1656
            logMetacat.debug("remove mapping query: " + stmt.toString());
1657
            int rows = stmt.executeUpdate();
1658

    
1659
            stmt.close();
1660
        } catch (SQLException e) {
1661
            e.printStackTrace();
1662
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1663
                    + e.getMessage());
1664
        } catch (NumberFormatException e) {
1665
            e.printStackTrace();
1666
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1667
                    + e.getMessage());
1668
        } catch (AccessionNumberException e) {
1669
            e.printStackTrace();
1670
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1671
                    + e.getMessage());
1672
        } finally {
1673
            // Return database connection to the pool
1674
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1675
        }
1676
    }
1677
    
1678
    /**
1679
     * create the systemmetadata record
1680
     * @param guid
1681
     */
1682
    private void insertSystemMetadata(String guid)
1683
    {        
1684
        
1685
        int serialNumber = -1;
1686
        DBConnection dbConn = null;
1687
        try {
1688

    
1689
            // Get a database connection from the pool
1690
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1691
            serialNumber = dbConn.getCheckOutSerialNumber();
1692

    
1693
            // Execute the insert statement
1694
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1695
            PreparedStatement stmt = dbConn.prepareStatement(query);
1696
            stmt.setString(1, guid);
1697
            logMetacat.debug("system metadata query: " + stmt.toString());
1698
            int rows = stmt.executeUpdate();
1699

    
1700
            stmt.close();
1701
        } catch (Exception e) {
1702
            e.printStackTrace();
1703
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1704
        } finally {
1705
            // Return database connection to the pool
1706
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1707
        }
1708
    }
1709
    
1710
    public void deleteSystemMetadata(String guid)
1711
    {        
1712
        
1713
        int serialNumber = -1;
1714
        DBConnection dbConn = null;
1715
        String query = null;
1716
        PreparedStatement stmt = null;
1717
        int rows = 0;
1718
        try {
1719

    
1720
            // Get a database connection from the pool
1721
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1722
            serialNumber = dbConn.getCheckOutSerialNumber();
1723

    
1724
            // remove main system metadata entry
1725
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1726
            stmt = dbConn.prepareStatement(query);
1727
            stmt.setString(1, guid);
1728
            logMetacat.debug("delete system metadata: " + stmt.toString());
1729
            rows = stmt.executeUpdate();
1730
            stmt.close();
1731
            
1732
            // remove the systemMetadataReplicationPolicy
1733
            query = "delete from systemMetadataReplicationPolicy " + 
1734
            "where guid = ?";
1735
            stmt = dbConn.prepareStatement(query);
1736
            stmt.setString(1, guid);
1737
            logMetacat.debug("delete systemMetadataReplicationPolicy: " + stmt.toString());
1738
            rows = stmt.executeUpdate();
1739
            stmt.close();
1740
            
1741
            // remove the systemMetadataReplicationStatus
1742
            query = "delete from systemMetadataReplicationStatus " + 
1743
            "where guid = ?";
1744
            stmt = dbConn.prepareStatement(query);
1745
            stmt.setString(1, guid);
1746
            logMetacat.debug("delete systemMetadataReplicationStatus: " + stmt.toString());
1747
            rows = stmt.executeUpdate();
1748
            stmt.close();
1749
            
1750
            // TODO: remove the access?
1751
            // Metacat keeps "deleted" documents so we should not remove access rules.
1752
            
1753
        } catch (Exception e) {
1754
            e.printStackTrace();
1755
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1756
            try {
1757
				dbConn.rollback();
1758
			} catch (SQLException sqle) {
1759
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
1760
			}
1761
        } finally {
1762
            // Return database connection to the pool
1763
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1764
        }
1765
    }
1766
    
1767
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
1768
    {
1769
        DBConnection dbConn = null;
1770
        int serialNumber = -1;
1771
        
1772
        try {
1773
            // Get a database connection from the pool
1774
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
1775
            serialNumber = dbConn.getCheckOutSerialNumber();
1776

    
1777
            // Execute the insert statement
1778
            String query = "update " + TYPE_SYSTEM_METADATA + 
1779
                " set authoritive_member_node = ? " +
1780
                " where authoritive_member_node = ?";
1781
            PreparedStatement stmt = dbConn.prepareStatement(query);
1782
            
1783
            //data values
1784
            stmt.setString(1, newMemberNodeId);
1785
            stmt.setString(2, existingMemberNodeId);
1786

    
1787
            logMetacat.debug("stmt: " + stmt.toString());
1788
            //execute
1789
            int rows = stmt.executeUpdate();
1790

    
1791
            stmt.close();
1792
        } catch (SQLException e) {
1793
            e.printStackTrace();
1794
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1795
                    + e.getMessage());
1796
        } catch (NumberFormatException e) {
1797
            e.printStackTrace();
1798
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
1799
                    + e.getMessage());
1800
        } finally {
1801
            // Return database connection to the pool
1802
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1803
        }
1804
    }
1805
}
1806

    
(37-37/64)