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 = new ObjectFormatIdentifier();
319
                fmtid.setValue(fmtidStr);
320
            	sysMeta.setFormatId(fmtid);
321
                sysMeta.setSize(size);
322
                if (obsoletes != null) {
323
	                Identifier obsoletesId = new Identifier();
324
	                obsoletesId.setValue(obsoletes);
325
	                sysMeta.setObsoletes(obsoletesId);
326
                }
327
                if (obsoletedBy != null) {
328
		            Identifier obsoletedById = new Identifier();
329
		            obsoletedById.setValue(obsoletedBy);
330
		            sysMeta.setObsoletedBy(obsoletedById);
331
                }
332
                stmt.close();
333
            } 
334
            else
335
            {
336
                stmt.close();
337
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
338
                throw new McdbDocNotFoundException("Could not find " + guid);
339
            }
340
            
341
        } 
342
        catch (SQLException e) 
343
        {
344
            e.printStackTrace();
345
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "  
346
                    + e.getMessage());
347
        } 
348
        finally 
349
        {
350
            // Return database connection to the pool
351
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
352
        }
353

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1480
            int countIndex = 0;
1481

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

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

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

    
1509
                ObjectInfo oi = new ObjectInfo();
1510

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

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

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

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

    
1535
                oi.setSize(size);
1536

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

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

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

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

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

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

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

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

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

    
1626
            // Parse the localId into scope and rev parts
1627
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1628
            String docid = acc.getDocid();
1629
            int rev = 1;
1630
            if (acc.getRev() != null) {
1631
              rev = (new Integer(acc.getRev()).intValue());
1632
            }
1633

    
1634
            // Get a database connection from the pool
1635
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
1636
            serialNumber = dbConn.getCheckOutSerialNumber();
1637

    
1638
            // Execute the insert statement
1639
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
1640
            PreparedStatement stmt = dbConn.prepareStatement(query);
1641
            stmt.setString(1, guid);
1642
            stmt.setString(2, docid);
1643
            stmt.setInt(3, rev);
1644
            logMetacat.debug("remove mapping query: " + stmt.toString());
1645
            int rows = stmt.executeUpdate();
1646

    
1647
            stmt.close();
1648
        } catch (SQLException e) {
1649
            e.printStackTrace();
1650
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1651
                    + e.getMessage());
1652
        } catch (NumberFormatException e) {
1653
            e.printStackTrace();
1654
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1655
                    + e.getMessage());
1656
        } catch (AccessionNumberException e) {
1657
            e.printStackTrace();
1658
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1659
                    + e.getMessage());
1660
        } finally {
1661
            // Return database connection to the pool
1662
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1663
        }
1664
    }
1665
    
1666
    /**
1667
     * create the systemmetadata record
1668
     * @param guid
1669
     */
1670
    private void insertSystemMetadata(String guid)
1671
    {        
1672
        
1673
        int serialNumber = -1;
1674
        DBConnection dbConn = null;
1675
        try {
1676

    
1677
            // Get a database connection from the pool
1678
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1679
            serialNumber = dbConn.getCheckOutSerialNumber();
1680

    
1681
            // Execute the insert statement
1682
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1683
            PreparedStatement stmt = dbConn.prepareStatement(query);
1684
            stmt.setString(1, guid);
1685
            logMetacat.debug("system metadata query: " + stmt.toString());
1686
            int rows = stmt.executeUpdate();
1687

    
1688
            stmt.close();
1689
        } catch (Exception e) {
1690
            e.printStackTrace();
1691
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1692
        } finally {
1693
            // Return database connection to the pool
1694
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1695
        }
1696
    }
1697
    
1698
    public void deleteSystemMetadata(String guid)
1699
    {        
1700
        
1701
        int serialNumber = -1;
1702
        DBConnection dbConn = null;
1703
        String query = null;
1704
        PreparedStatement stmt = null;
1705
        int rows = 0;
1706
        try {
1707

    
1708
            // Get a database connection from the pool
1709
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1710
            serialNumber = dbConn.getCheckOutSerialNumber();
1711

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

    
1765
            // Execute the insert statement
1766
            String query = "update " + TYPE_SYSTEM_METADATA + 
1767
                " set authoritive_member_node = ? " +
1768
                " where authoritive_member_node = ?";
1769
            PreparedStatement stmt = dbConn.prepareStatement(query);
1770
            
1771
            //data values
1772
            stmt.setString(1, newMemberNodeId);
1773
            stmt.setString(2, existingMemberNodeId);
1774

    
1775
            logMetacat.debug("stmt: " + stmt.toString());
1776
            //execute
1777
            int rows = stmt.executeUpdate();
1778

    
1779
            stmt.close();
1780
        } catch (SQLException e) {
1781
            e.printStackTrace();
1782
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1783
                    + e.getMessage());
1784
        } catch (NumberFormatException e) {
1785
            e.printStackTrace();
1786
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
1787
                    + e.getMessage());
1788
        } finally {
1789
            // Return database connection to the pool
1790
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1791
        }
1792
    }
1793
}
1794

    
(37-37/64)