Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2010 Regents of the University of California and the
4
 *             National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: jones $'
7
 *     '$Date: 2010-02-03 17:58:12 -0900 (Wed, 03 Feb 2010) $'
8
 * '$Revision: 5211 $'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 */
24

    
25
package edu.ucsb.nceas.metacat;
26

    
27
import java.math.BigInteger;
28
import java.sql.PreparedStatement;
29
import java.sql.ResultSet;
30
import java.sql.SQLException;
31
import java.sql.Timestamp;
32
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.Hashtable;
35
import java.util.List;
36
import java.util.Vector;
37

    
38
import org.apache.log4j.Logger;
39
import org.dataone.client.ObjectFormatCache;
40
import org.dataone.service.exceptions.InvalidSystemMetadata;
41
import org.dataone.service.exceptions.NotFound;
42
import org.dataone.service.types.v1.AccessPolicy;
43
import org.dataone.service.types.v1.AccessRule;
44
import org.dataone.service.types.v1.Checksum;
45
import org.dataone.service.types.v1.Identifier;
46
import org.dataone.service.types.v1.NodeReference;
47
import org.dataone.service.types.v1.ObjectFormatIdentifier;
48
import org.dataone.service.types.v1.ObjectInfo;
49
import org.dataone.service.types.v1.ObjectList;
50
import org.dataone.service.types.v1.Permission;
51
import org.dataone.service.types.v1.Replica;
52
import org.dataone.service.types.v1.ReplicationPolicy;
53
import org.dataone.service.types.v1.ReplicationStatus;
54
import org.dataone.service.types.v1.Subject;
55
import org.dataone.service.types.v1.SystemMetadata;
56

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

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

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

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

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

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

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

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

    
284

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1102
            // remove existing values first
1103
            String delete = "delete from systemMetadataReplicationStatus " + 
1104
            "where guid = ?";
1105
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1106
	        //data values
1107
	        stmt.setString(1, guid);
1108
	        //execute
1109
	        int deletedCount = stmt.executeUpdate();
1110
	        stmt.close();
1111
            
1112
	        if (replicas != null) {
1113
	            for (Replica replica: replicas) {
1114
		            // Execute the insert statement
1115
		            String insert = "insert into systemMetadataReplicationStatus " + 
1116
		                "(guid, member_node, status, date_verified) " +
1117
		                "values (?, ?, ?, ?)";
1118
		            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1119
		            
1120
		            //data values
1121
		            String memberNode = replica.getReplicaMemberNode().getValue();
1122
		            String status = replica.getReplicationStatus().toString();
1123
		            java.sql.Date sqlDate = new java.sql.Date(replica.getReplicaVerified().getTime());
1124
		            insertStatement.setString(1, guid);
1125
		            insertStatement.setString(2, memberNode);
1126
		            insertStatement.setString(3, status);
1127
		            insertStatement.setDate(4, sqlDate);
1128
	
1129
		            //execute
1130
		            int rows = insertStatement.executeUpdate();
1131
		            insertStatement.close();
1132
	            }
1133
	        }
1134
        } catch (SQLException e) {
1135
            logMetacat.error("SQL error while adding systemMetadataReplicationStatus for: " + guid, e); 
1136
        } finally {
1137
            // Return database connection to the pool
1138
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1139
        }
1140
    }
1141
    
1142
    /**
1143
     * Insert the system metadata fields into the db
1144
     * @param sm
1145
     * @throws McdbDocNotFoundException 
1146
     * @throws SQLException 
1147
     * @throws InvalidSystemMetadata 
1148
     */
1149
    public void updateSystemMetadata(SystemMetadata sm) 
1150
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1151
    	
1152
      Boolean replicationAllowed = false;
1153
		  Integer numberReplicas = -1;
1154
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1155
    	if (replicationPolicy != null) {
1156
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1157
    		numberReplicas = replicationPolicy.getNumberReplicas();
1158
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1159
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1160
    	}
1161

    
1162
    	// ensure certain system metadata fields are populated
1163
    	try {
1164
          sm.getIdentifier().getValue();
1165
          sm.getSerialVersion().intValue();
1166
          sm.getDateUploaded().getTime();
1167
          sm.getRightsHolder().getValue();
1168
          sm.getChecksum().getValue();
1169
          sm.getChecksum().getAlgorithm();
1170
          sm.getOriginMemberNode().getValue();
1171
          sm.getAuthoritativeMemberNode().getValue();
1172
          sm.getDateSysMetadataModified().getTime();
1173
          // sm.getSubmitter().getValue(); // filled in with identifier
1174
          sm.getFormatId().getValue();
1175
          sm.getArchived().booleanValue();
1176
    	    
1177
    	} catch (NullPointerException npe) {
1178
    	    throw new InvalidSystemMetadata("0000", npe.getMessage());
1179
    	    
1180
    	}
1181
    	
1182
    	// the main systemMetadata fields
1183
		  updateSystemMetadataFields(
1184
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1185
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1186
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1187
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1188
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1189
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1190
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1191
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1192
		    sm.getIdentifier().getValue(),
1193
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1194
		    sm.getSize(),
1195
		    sm.getArchived() == null ? false: sm.getArchived(),
1196
		    replicationAllowed, 
1197
		    numberReplicas,
1198
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1199
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1200
		    sm.getSerialVersion()
1201
        );
1202
        
1203
        String guid = sm.getIdentifier().getValue();
1204
        
1205
        // save replication policies
1206
        if (replicationPolicy != null) {
1207
		    List<String> nodes = null;
1208
		    String policy = null;
1209
		    
1210
		    // check for null 
1211
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1212
			    nodes = new ArrayList<String>();
1213
			    policy = "blocked";
1214
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1215
			    	nodes.add(node.getValue());
1216
			    }
1217
			    this.insertReplicationPolicy(guid, policy, nodes);
1218
		    }
1219
		    
1220
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1221
			    nodes = new ArrayList<String>();
1222
			    policy = "preferred";
1223
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1224
			    	nodes.add(node.getValue());
1225
			    }
1226
		        this.insertReplicationPolicy(guid, policy, nodes);
1227
		    }
1228
        }
1229
        
1230
        // save replica information
1231
        this.insertReplicationStatus(guid, sm.getReplicaList());
1232
        
1233
        // save access policy
1234
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1235
        if (accessPolicy != null) {
1236
        	try {
1237
				this.insertAccessPolicy(guid, accessPolicy);
1238
			} catch (AccessException e) {
1239
				throw new McdbDocNotFoundException(e);
1240
			}
1241
        }
1242
    }
1243
    
1244
    /**
1245
     * Creates Metacat access rules and inserts them
1246
     * @param accessPolicy
1247
     * @throws McdbDocNotFoundException
1248
     * @throws AccessException
1249
     */
1250
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1251
    	
1252
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1253
        XMLAccessAccess accessController  = new XMLAccessAccess();
1254
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1255
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1256
        if (existingAccess != null && existingAccess.size() > 0) {
1257
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1258
        }
1259
        
1260
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1261
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1262
        	List<Subject> subjects = accessRule.getSubjectList();
1263
        	List<Permission> permissions = accessRule.getPermissionList();
1264
        	for (Subject subject: subjects) {
1265
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1266
        		accessDAO.setPrincipalName(subject.getValue());
1267
    			accessDAO.setGuid(guid);
1268
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1269
				accessDAO.setPermOrder(existingPermOrder);
1270
    			if (permissions != null) {
1271
	    			for (Permission permission: permissions) {
1272
	    				Long metacatPermission = new Long(convertPermission(permission));
1273
	        			accessDAO.addPermission(metacatPermission);
1274
	    			}
1275
    			}
1276
    			accessDAOs.add(accessDAO);
1277
        	}
1278
        }
1279
        
1280
        
1281
        // remove all existing allow records
1282
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1283
        // add the ones we can for this guid
1284
        accessController.insertAccess(guid, accessDAOs);
1285
        
1286
        
1287
    }
1288
    
1289
    /**
1290
     * Lookup access policy from Metacat
1291
     * @param guid
1292
     * @return
1293
     * @throws McdbDocNotFoundException
1294
     * @throws AccessException
1295
     */
1296
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1297
        AccessPolicy accessPolicy = new AccessPolicy();
1298

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

    
1422
        try {
1423
            String sql = "select guid, date_uploaded, rights_holder, checksum, "
1424
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1425
                    + "date_modified, submitter, object_format, size from systemmetadata";
1426

    
1427
            boolean f1 = false;
1428
            boolean f2 = false;
1429
            boolean f3 = false;
1430

    
1431
            if (startTime != null) {
1432
                sql += " where systemmetadata.date_modified >= ?";
1433
                f1 = true;
1434
            }
1435

    
1436
            if (endTime != null) {
1437
                if (!f1) {
1438
                    sql += " where systemmetadata.date_modified < ?";
1439
                } else {
1440
                    sql += " and systemmetadata.date_modified < ?";
1441
                }
1442
                f2 = true;
1443
            }
1444

    
1445
            if (objectFormatId != null) {
1446
                if (!f1 && !f2) {
1447
                    sql += " where object_format = ?";
1448
                } else {
1449
                    sql += " and object_format = ?";
1450
                }
1451
                f3 = true;
1452
            }
1453

    
1454
            if (replicaStatus) {
1455
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.memberNodeId");
1456
                if (!f1 && !f2 && !f3) {
1457
                    sql += " where authoritive_member_node != '" +
1458
                        currentNodeId.trim() + "'";
1459
                } else {
1460
                    sql += " and authoritive_member_node != '" +
1461
                        currentNodeId.trim() + "'";
1462
                }
1463
            }
1464

    
1465
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1466
            serialNumber = dbConn.getCheckOutSerialNumber();
1467
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1468

    
1469
            if (f1 && f2 && f3) {
1470
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1471
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1472
                stmt.setString(3, objectFormatId.getValue());
1473
            } else if (f1 && f2 && !f3) {
1474
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1475
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1476
            } else if (f1 && !f2 && f3) {
1477
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1478
                stmt.setString(2, objectFormatId.getValue());
1479
            } else if (f1 && !f2 && !f3) {
1480
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1481
            } else if (!f1 && f2 && f3) {
1482
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1483
                stmt.setString(2, objectFormatId.getValue());
1484
            } else if (!f1 && !f2 && f3) {
1485
                stmt.setString(1, objectFormatId.getValue());
1486
            } else if (!f1 && f2 && !f3) {
1487
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1488
            }
1489

    
1490
            // logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1491

    
1492
            ResultSet rs = stmt.executeQuery();
1493
            for (int i = 0; i < start; i++) {
1494
                if (rs.next()) {
1495
                    total++;
1496
                } else {
1497
                    break;
1498
                }
1499
            }
1500

    
1501
            int countIndex = 0;
1502

    
1503
            while (rs.next()) {                
1504
                total++;
1505
                if (countIndex >= count) {
1506
                    // allow unlimited (negative number for count)
1507
                    if (count > 0) {
1508
                        break;
1509
                    }
1510
                }
1511

    
1512
                String guid = rs.getString(1);
1513
                // logMetacat.debug("query found doc with guid " + guid);
1514
                // Timestamp dateUploaded = rs.getTimestamp(2);
1515
                // String rightsHolder = rs.getString(3);
1516
                String checksum = rs.getString(4);
1517
                String checksumAlgorithm = rs.getString(5);
1518
                // String originMemberNode = rs.getString(6);
1519
                // String authoritiveMemberNode = rs.getString(7);
1520
                Timestamp dateModified = rs.getTimestamp(8);
1521
                // String submitter = rs.getString(9);
1522
                String fmtidStr = rs.getString(10);
1523
                String sz = rs.getString(11);
1524
                BigInteger size = new BigInteger("0");
1525

    
1526
                if (sz != null && !sz.trim().equals("")) {
1527
                    size = new BigInteger(rs.getString(11));
1528
                }
1529

    
1530
                ObjectInfo oi = new ObjectInfo();
1531

    
1532
                Identifier id = new Identifier();
1533
                id.setValue(guid);
1534
                oi.setIdentifier(id);
1535

    
1536
                if (dateModified != null) {
1537
                    oi.setDateSysMetadataModified(new Date(dateModified.getTime()));
1538
                }
1539

    
1540
                Checksum cs = new Checksum();
1541
                cs.setValue(checksum);
1542
                try {
1543
                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1544
                    cs.setAlgorithm(checksumAlgorithm);
1545
                } catch (Exception e) {
1546
                    logMetacat.error("could not parse checksum algorithm", e);
1547
                    continue;
1548
                }
1549
                oi.setChecksum(cs);
1550

    
1551
                // set the format type
1552
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1553
                fmtid.setValue(fmtidStr);
1554
                oi.setFormatId(fmtid);
1555

    
1556
                oi.setSize(size);
1557

    
1558
                // when requested count == 0, return an empty object list
1559
                if (count != 0) {
1560
                    ol.addObjectInfo(oi);                    
1561
                }
1562
                countIndex++;
1563
            }
1564

    
1565
            // expend the resultset to get the total count of possible rows
1566
            while (rs.next()) {
1567
                total++;
1568
            }
1569
        }
1570

    
1571
        finally {
1572
            // Return database connection to the pool
1573
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1574
        }
1575

    
1576
        ol.setStart(start);
1577
        ol.setCount(ol.sizeObjectInfoList());
1578
        ol.setTotal(total);
1579

    
1580
        return ol;
1581
    }
1582
    
1583
    /**
1584
     * create a mapping in the identifier table
1585
     * @param guid
1586
     * @param localId
1587
     */
1588
    public void createMapping(String guid, String localId)
1589
    {        
1590
        
1591
        int serialNumber = -1;
1592
        DBConnection dbConn = null;
1593
        try {
1594

    
1595
            // Parse the localId into scope and rev parts
1596
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1597
            String docid = acc.getDocid();
1598
            int rev = 1;
1599
            if (acc.getRev() != null) {
1600
              rev = (new Integer(acc.getRev()).intValue());
1601
            }
1602

    
1603
            // Get a database connection from the pool
1604
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1605
            serialNumber = dbConn.getCheckOutSerialNumber();
1606

    
1607
            // Execute the insert statement
1608
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1609
            PreparedStatement stmt = dbConn.prepareStatement(query);
1610
            stmt.setString(1, guid);
1611
            stmt.setString(2, docid);
1612
            stmt.setInt(3, rev);
1613
            logMetacat.debug("mapping query: " + stmt.toString());
1614
            int rows = stmt.executeUpdate();
1615

    
1616
            stmt.close();
1617
        } catch (SQLException e) {
1618
            e.printStackTrace();
1619
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1620
                    + e.getMessage());
1621
        } catch (NumberFormatException e) {
1622
            e.printStackTrace();
1623
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1624
                    + e.getMessage());
1625
        } catch (AccessionNumberException e) {
1626
            e.printStackTrace();
1627
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1628
                    + e.getMessage());
1629
        } finally {
1630
            // Return database connection to the pool
1631
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1632
        }
1633
    }
1634
    
1635
    /**
1636
     * create the systemmetadata record
1637
     * @param guid
1638
     */
1639
    private void insertSystemMetadata(String guid)
1640
    {        
1641
        
1642
        int serialNumber = -1;
1643
        DBConnection dbConn = null;
1644
        try {
1645

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

    
1650
            // Execute the insert statement
1651
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1652
            PreparedStatement stmt = dbConn.prepareStatement(query);
1653
            stmt.setString(1, guid);
1654
            logMetacat.debug("system metadata query: " + stmt.toString());
1655
            int rows = stmt.executeUpdate();
1656

    
1657
            stmt.close();
1658
        } catch (Exception e) {
1659
            e.printStackTrace();
1660
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1661
        } finally {
1662
            // Return database connection to the pool
1663
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1664
        }
1665
    }
1666
    
1667
    public void deleteSystemMetadata(String guid)
1668
    {        
1669
        
1670
        int serialNumber = -1;
1671
        DBConnection dbConn = null;
1672
        String query = null;
1673
        PreparedStatement stmt = null;
1674
        int rows = 0;
1675
        try {
1676

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

    
1681
            // remove main system metadata entry
1682
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1683
            stmt = dbConn.prepareStatement(query);
1684
            stmt.setString(1, guid);
1685
            logMetacat.debug("delete system metadata: " + stmt.toString());
1686
            rows = stmt.executeUpdate();
1687
            stmt.close();
1688
            
1689
            // remove the systemMetadataReplicationPolicy
1690
            query = "delete from systemMetadataReplicationPolicy " + 
1691
            "where guid = ?";
1692
            stmt = dbConn.prepareStatement(query);
1693
            stmt.setString(1, guid);
1694
            logMetacat.debug("delete systemMetadataReplicationPolicy: " + stmt.toString());
1695
            rows = stmt.executeUpdate();
1696
            stmt.close();
1697
            
1698
            // remove the systemMetadataReplicationStatus
1699
            query = "delete from systemMetadataReplicationStatus " + 
1700
            "where guid = ?";
1701
            stmt = dbConn.prepareStatement(query);
1702
            stmt.setString(1, guid);
1703
            logMetacat.debug("delete systemMetadataReplicationStatus: " + stmt.toString());
1704
            rows = stmt.executeUpdate();
1705
            stmt.close();
1706
            
1707
            // TODO: remove the access?
1708
            // Metacat keeps "deleted" documents so we should not remove access rules.
1709
            
1710
        } catch (Exception e) {
1711
            e.printStackTrace();
1712
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1713
            try {
1714
				dbConn.rollback();
1715
			} catch (SQLException sqle) {
1716
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
1717
			}
1718
        } finally {
1719
            // Return database connection to the pool
1720
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1721
        }
1722
    }
1723
    
1724
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
1725
    {
1726
        DBConnection dbConn = null;
1727
        int serialNumber = -1;
1728
        
1729
        try {
1730
            // Get a database connection from the pool
1731
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
1732
            serialNumber = dbConn.getCheckOutSerialNumber();
1733

    
1734
            // Execute the insert statement
1735
            String query = "update " + TYPE_SYSTEM_METADATA + 
1736
                " set authoritive_member_node = ? " +
1737
                " where authoritive_member_node = ?";
1738
            PreparedStatement stmt = dbConn.prepareStatement(query);
1739
            
1740
            //data values
1741
            stmt.setString(1, newMemberNodeId);
1742
            stmt.setString(2, existingMemberNodeId);
1743

    
1744
            logMetacat.debug("stmt: " + stmt.toString());
1745
            //execute
1746
            int rows = stmt.executeUpdate();
1747

    
1748
            stmt.close();
1749
        } catch (SQLException e) {
1750
            e.printStackTrace();
1751
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1752
                    + e.getMessage());
1753
        } catch (NumberFormatException e) {
1754
            e.printStackTrace();
1755
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
1756
                    + e.getMessage());
1757
        } finally {
1758
            // Return database connection to the pool
1759
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1760
        }
1761
    }
1762
}
1763

    
(37-37/64)