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
     * NOTE: looks in the identifier and system metadata table for a match
749
     * (in that order)
750
     * 
751
     * @param guid the global identifier to look up
752
     * @return boolean true if the identifier exists
753
     */
754
    public boolean identifierExists(String guid)
755
    {
756
        boolean idExists = false;
757
        try {
758
            String id = getLocalId(guid);
759
            if (id != null) {
760
                idExists = true;
761
            }
762
        } catch (McdbDocNotFoundException e) {
763
        	// try system metadata only
764
        	try {
765
        		idExists = systemMetadataExists(guid);
766
            } catch (Exception e2) {
767
            	idExists = false;
768
            }
769
        }
770
        return idExists;
771
    }
772
    
773
    /**
774
     * Determine if an identifier mapping exists already, 
775
     * returning true if so.
776
     * 
777
     * @param guid the global identifier to look up
778
     * @return boolean true if the identifier exists
779
     */
780
    public boolean mappingExists(String guid)
781
    {
782
        boolean idExists = false;
783
        try {
784
            String id = getLocalId(guid);
785
            if (id != null) {
786
                idExists = true;
787
            }
788
        } catch (McdbDocNotFoundException e) {
789
        	// nope!
790
        }
791
        return idExists;
792
    }
793
    
794
    /**
795
     * 
796
     * @param guid
797
     * @param rev
798
     * @return
799
     */
800
    public String generateLocalId(String guid, int rev)
801
    {
802
        return generateLocalId(guid, rev, false);
803
    }
804

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

    
913
		DBConnection dbConn = null;
914
		int serialNumber = -1;
915
		try {
916
			// Get a database connection from the pool
917
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
918
			serialNumber = dbConn.getCheckOutSerialNumber();
919

    
920
			// Execute the insert statement
921
			PreparedStatement stmt = dbConn.prepareStatement(query);
922
			stmt.setString(1, guid);
923
			ResultSet rs = stmt.executeQuery();
924
			if (rs.next()) {
925
				exists = true;
926
			}
927

    
928
		} catch (SQLException e) {
929
			logMetacat.error("Error while looking up the system metadata: "
930
					+ e.getMessage());
931
		} finally {
932
			// Return database connection to the pool
933
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
934
		}
935

    
936
		return exists;
937
	}
938
    
939
    /**
940
     * creates a system metadata mapping and adds additional fields from sysmeta
941
     * to the table for quick searching.
942
     * 
943
     * @param guid the id to insert
944
     * @param localId the systemMetadata object to get the local id for
945
     * @throws McdbDocNotFoundException 
946
     * @throws SQLException 
947
     * @throws InvalidSystemMetadata 
948
     */
949
    public void insertSystemMetadata(SystemMetadata sysmeta) 
950
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
951
    	String guid = sysmeta.getIdentifier().getValue();
952
    	// insert the record
953
        insertSystemMetadata(guid);
954
        // update with the values
955
        updateSystemMetadata(sysmeta);
956
        
957
    }
958
        
959
    
960
    /**
961
     * update a mapping
962
     * @param guid
963
     * @param localId
964
     */
965
    public void updateMapping(String guid, String localId)
966
    {
967
    	
968
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
969
        int serialNumber = -1;
970
        DBConnection dbConn = null;
971
        try {
972
            // Parse the localId into scope and rev parts
973
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
974
            String docid = acc.getDocid();
975
            int rev = 1;
976
            if(acc.getRev() != null)
977
            {
978
              rev = (new Integer(acc.getRev()).intValue());
979
            }
980

    
981
            // Get a database connection from the pool
982
            dbConn = 
983
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
984
            serialNumber = dbConn.getCheckOutSerialNumber();
985

    
986
            // Execute the update statement
987
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
988
            PreparedStatement stmt = dbConn.prepareStatement(query);
989
            stmt.setString(1, docid);
990
            stmt.setInt(2, rev);
991
            stmt.setString(3, guid);
992
            int rows = stmt.executeUpdate();
993

    
994
            stmt.close();
995
        } catch (SQLException e) {
996
            e.printStackTrace();
997
            logMetacat.error("SQL error while updating a mapping identifier: " 
998
                    + e.getMessage());
999
        } catch (NumberFormatException e) {
1000
            e.printStackTrace();
1001
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1002
                    + e.getMessage());
1003
        } catch (AccessionNumberException e) {
1004
            e.printStackTrace();
1005
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1006
                    + e.getMessage());
1007
        } finally {
1008
            // Return database connection to the pool
1009
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1010
        }
1011
        logMetacat.debug("done updating mapping");
1012
    }
1013
        
1014
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1015
        String checksum, String checksumAlgorithm, String originMemberNode, 
1016
        String authoritativeMemberNode, long modifiedDate, String submitter, 
1017
        String guid, String objectFormat, BigInteger size, boolean archived,
1018
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1019
        String obsoletedBy, BigInteger serialVersion) throws SQLException  {
1020
        
1021
        DBConnection dbConn = null;
1022
        int serialNumber = -1;
1023
        
1024
        try {
1025
            // Get a database connection from the pool
1026
            dbConn = 
1027
                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1028
            serialNumber = dbConn.getCheckOutSerialNumber();
1029

    
1030
            // Execute the insert statement
1031
            String query = "update " + TYPE_SYSTEM_METADATA + 
1032
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1033
                "origin_member_node, authoritive_member_node, date_modified, " +
1034
                "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1035
                "obsoletes, obsoleted_by, serial_version) " +
1036
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1037
            PreparedStatement stmt = dbConn.prepareStatement(query);
1038
            
1039
            //data values
1040
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1041
            stmt.setString(2, rightsHolder);
1042
            stmt.setString(3, checksum);
1043
            stmt.setString(4, checksumAlgorithm);
1044
            stmt.setString(5, originMemberNode);
1045
            stmt.setString(6, authoritativeMemberNode);
1046
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1047
            stmt.setString(8, submitter);
1048
            stmt.setString(9, objectFormat);
1049
            stmt.setString(10, size.toString());
1050
            stmt.setBoolean(11, archived);
1051
            stmt.setBoolean(12, replicationAllowed);
1052
            stmt.setInt(13, numberReplicas);
1053
            stmt.setString(14, obsoletes);
1054
            stmt.setString(15, obsoletedBy);
1055
            stmt.setString(16, serialVersion.toString());
1056

    
1057
            //where clause
1058
            stmt.setString(17, guid);
1059
            logMetacat.debug("stmt: " + stmt.toString());
1060
            //execute
1061
            int rows = stmt.executeUpdate();
1062

    
1063
            stmt.close();
1064
            
1065
        } catch (SQLException e) {
1066
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1067
                    + e.getMessage());
1068
            throw e;
1069
            
1070
        } finally {
1071
            // Return database connection to the pool
1072
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1073
        }
1074
    }
1075
    
1076
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
1077
    {
1078
        DBConnection dbConn = null;
1079
        int serialNumber = -1;
1080
        
1081
        try {
1082
            // Get a database connection from the pool
1083
            dbConn = 
1084
                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
1085
            serialNumber = dbConn.getCheckOutSerialNumber();
1086

    
1087
            // remove existing values first
1088
            String delete = "delete from systemMetadataReplicationPolicy " + 
1089
            "where guid = ? and policy = ?";
1090
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1091
	        //data values
1092
	        stmt.setString(1, guid);
1093
	        stmt.setString(2, policy);
1094
	        //execute
1095
	        int deletedCount = stmt.executeUpdate();
1096
	        stmt.close();
1097
            
1098
            for (String memberNode: memberNodes) {
1099
	            // Execute the insert statement
1100
	            String insert = "insert into systemMetadataReplicationPolicy " + 
1101
	                "(guid, policy, member_node) " +
1102
	                "values (?, ?, ?)";
1103
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1104
	            
1105
	            //data values
1106
	            insertStatement.setString(1, guid);
1107
	            insertStatement.setString(2, policy);
1108
	            insertStatement.setString(3, memberNode);
1109
	            //execute
1110
	            int rows = insertStatement.executeUpdate();
1111
	            insertStatement.close();
1112
            }
1113
        } catch (SQLException e) {
1114
            logMetacat.error("SQL error while adding systemMetadataReplicationPolicy for: " + guid, e); 
1115
        } finally {
1116
            // Return database connection to the pool
1117
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1118
        }
1119
    }
1120
    
1121
    private void insertReplicationStatus(String guid, List<Replica> replicas) {
1122
        DBConnection dbConn = null;
1123
        int serialNumber = -1;
1124
        
1125
        try {
1126
            // Get a database connection from the pool
1127
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertReplicas");
1128
            serialNumber = dbConn.getCheckOutSerialNumber();
1129

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

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

    
1430
        try {
1431
            String sql = "select guid, date_uploaded, rights_holder, checksum, "
1432
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1433
                    + "date_modified, submitter, object_format, size from systemmetadata";
1434

    
1435
            boolean f1 = false;
1436
            boolean f2 = false;
1437
            boolean f3 = false;
1438

    
1439
            if (startTime != null) {
1440
                sql += " where systemmetadata.date_modified >= ?";
1441
                f1 = true;
1442
            }
1443

    
1444
            if (endTime != null) {
1445
                if (!f1) {
1446
                    sql += " where systemmetadata.date_modified < ?";
1447
                } else {
1448
                    sql += " and systemmetadata.date_modified < ?";
1449
                }
1450
                f2 = true;
1451
            }
1452

    
1453
            if (objectFormatId != null) {
1454
                if (!f1 && !f2) {
1455
                    sql += " where object_format = ?";
1456
                } else {
1457
                    sql += " and object_format = ?";
1458
                }
1459
                f3 = true;
1460
            }
1461

    
1462
            if (replicaStatus) {
1463
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1464
                if (!f1 && !f2 && !f3) {
1465
                    sql += " where authoritive_member_node != '" +
1466
                        currentNodeId.trim() + "'";
1467
                } else {
1468
                    sql += " and authoritive_member_node != '" +
1469
                        currentNodeId.trim() + "'";
1470
                }
1471
            }
1472

    
1473
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1474
            serialNumber = dbConn.getCheckOutSerialNumber();
1475
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1476

    
1477
            if (f1 && f2 && f3) {
1478
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1479
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1480
                stmt.setString(3, objectFormatId.getValue());
1481
            } else if (f1 && f2 && !f3) {
1482
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1483
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1484
            } else if (f1 && !f2 && f3) {
1485
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1486
                stmt.setString(2, objectFormatId.getValue());
1487
            } else if (f1 && !f2 && !f3) {
1488
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1489
            } else if (!f1 && f2 && f3) {
1490
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1491
                stmt.setString(2, objectFormatId.getValue());
1492
            } else if (!f1 && !f2 && f3) {
1493
                stmt.setString(1, objectFormatId.getValue());
1494
            } else if (!f1 && f2 && !f3) {
1495
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1496
            }
1497

    
1498
            // logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1499

    
1500
            ResultSet rs = stmt.executeQuery();
1501
            for (int i = 0; i < start; i++) {
1502
                if (rs.next()) {
1503
                    total++;
1504
                } else {
1505
                    break;
1506
                }
1507
            }
1508

    
1509
            int countIndex = 0;
1510

    
1511
            while (rs.next()) {                
1512
                total++;
1513
                if (countIndex >= count) {
1514
                    // allow unlimited (negative number for count)
1515
                    if (count > 0) {
1516
                        break;
1517
                    }
1518
                }
1519

    
1520
                String guid = rs.getString(1);
1521
                // logMetacat.debug("query found doc with guid " + guid);
1522
                // Timestamp dateUploaded = rs.getTimestamp(2);
1523
                // String rightsHolder = rs.getString(3);
1524
                String checksum = rs.getString(4);
1525
                String checksumAlgorithm = rs.getString(5);
1526
                // String originMemberNode = rs.getString(6);
1527
                // String authoritiveMemberNode = rs.getString(7);
1528
                Timestamp dateModified = rs.getTimestamp(8);
1529
                // String submitter = rs.getString(9);
1530
                String fmtidStr = rs.getString(10);
1531
                String sz = rs.getString(11);
1532
                BigInteger size = new BigInteger("0");
1533

    
1534
                if (sz != null && !sz.trim().equals("")) {
1535
                    size = new BigInteger(rs.getString(11));
1536
                }
1537

    
1538
                ObjectInfo oi = new ObjectInfo();
1539

    
1540
                Identifier id = new Identifier();
1541
                id.setValue(guid);
1542
                oi.setIdentifier(id);
1543

    
1544
                if (dateModified != null) {
1545
                    oi.setDateSysMetadataModified(dateModified);
1546
                }
1547

    
1548
                Checksum cs = new Checksum();
1549
                cs.setValue(checksum);
1550
                try {
1551
                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1552
                    cs.setAlgorithm(checksumAlgorithm);
1553
                } catch (Exception e) {
1554
                    logMetacat.error("could not parse checksum algorithm", e);
1555
                    continue;
1556
                }
1557
                oi.setChecksum(cs);
1558

    
1559
                // set the format type
1560
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1561
                fmtid.setValue(fmtidStr);
1562
                oi.setFormatId(fmtid);
1563

    
1564
                oi.setSize(size);
1565

    
1566
                // when requested count == 0, return an empty object list
1567
                if (count != 0) {
1568
                    ol.addObjectInfo(oi);                    
1569
                }
1570
                countIndex++;
1571
            }
1572

    
1573
            // expend the resultset to get the total count of possible rows
1574
            while (rs.next()) {
1575
                total++;
1576
            }
1577
        }
1578

    
1579
        finally {
1580
            // Return database connection to the pool
1581
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1582
        }
1583

    
1584
        ol.setStart(start);
1585
        ol.setCount(ol.sizeObjectInfoList());
1586
        ol.setTotal(total);
1587

    
1588
        return ol;
1589
    }
1590
    
1591
    /**
1592
     * create a mapping in the identifier table
1593
     * @param guid
1594
     * @param localId
1595
     */
1596
    public void createMapping(String guid, String localId)
1597
    {        
1598
        
1599
        int serialNumber = -1;
1600
        DBConnection dbConn = null;
1601
        try {
1602

    
1603
            // Parse the localId into scope and rev parts
1604
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1605
            String docid = acc.getDocid();
1606
            int rev = 1;
1607
            if (acc.getRev() != null) {
1608
              rev = (new Integer(acc.getRev()).intValue());
1609
            }
1610

    
1611
            // Get a database connection from the pool
1612
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1613
            serialNumber = dbConn.getCheckOutSerialNumber();
1614

    
1615
            // Execute the insert statement
1616
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1617
            PreparedStatement stmt = dbConn.prepareStatement(query);
1618
            stmt.setString(1, guid);
1619
            stmt.setString(2, docid);
1620
            stmt.setInt(3, rev);
1621
            logMetacat.debug("mapping query: " + stmt.toString());
1622
            int rows = stmt.executeUpdate();
1623

    
1624
            stmt.close();
1625
        } catch (SQLException e) {
1626
            e.printStackTrace();
1627
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1628
                    + e.getMessage());
1629
        } catch (NumberFormatException e) {
1630
            e.printStackTrace();
1631
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1632
                    + e.getMessage());
1633
        } catch (AccessionNumberException e) {
1634
            e.printStackTrace();
1635
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1636
                    + e.getMessage());
1637
        } finally {
1638
            // Return database connection to the pool
1639
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1640
        }
1641
    }
1642
    
1643
    /**
1644
     * remove a mapping in the identifier table
1645
     * @param guid
1646
     * @param localId
1647
     */
1648
    public void removeMapping(String guid, String localId)
1649
    {        
1650
        
1651
        int serialNumber = -1;
1652
        DBConnection dbConn = null;
1653
        try {
1654

    
1655
            // Parse the localId into scope and rev parts
1656
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1657
            String docid = acc.getDocid();
1658
            int rev = 1;
1659
            if (acc.getRev() != null) {
1660
              rev = (new Integer(acc.getRev()).intValue());
1661
            }
1662

    
1663
            // Get a database connection from the pool
1664
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
1665
            serialNumber = dbConn.getCheckOutSerialNumber();
1666

    
1667
            // Execute the insert statement
1668
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
1669
            PreparedStatement stmt = dbConn.prepareStatement(query);
1670
            stmt.setString(1, guid);
1671
            stmt.setString(2, docid);
1672
            stmt.setInt(3, rev);
1673
            logMetacat.debug("remove mapping query: " + stmt.toString());
1674
            int rows = stmt.executeUpdate();
1675

    
1676
            stmt.close();
1677
        } catch (SQLException e) {
1678
            e.printStackTrace();
1679
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1680
                    + e.getMessage());
1681
        } catch (NumberFormatException e) {
1682
            e.printStackTrace();
1683
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1684
                    + e.getMessage());
1685
        } catch (AccessionNumberException e) {
1686
            e.printStackTrace();
1687
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1688
                    + e.getMessage());
1689
        } finally {
1690
            // Return database connection to the pool
1691
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1692
        }
1693
    }
1694
    
1695
    /**
1696
     * create the systemmetadata record
1697
     * @param guid
1698
     */
1699
    private void insertSystemMetadata(String guid)
1700
    {        
1701
        
1702
        int serialNumber = -1;
1703
        DBConnection dbConn = null;
1704
        try {
1705

    
1706
            // Get a database connection from the pool
1707
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1708
            serialNumber = dbConn.getCheckOutSerialNumber();
1709

    
1710
            // Execute the insert statement
1711
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1712
            PreparedStatement stmt = dbConn.prepareStatement(query);
1713
            stmt.setString(1, guid);
1714
            logMetacat.debug("system metadata query: " + stmt.toString());
1715
            int rows = stmt.executeUpdate();
1716

    
1717
            stmt.close();
1718
        } catch (Exception e) {
1719
            e.printStackTrace();
1720
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1721
        } finally {
1722
            // Return database connection to the pool
1723
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1724
        }
1725
    }
1726
    
1727
    public void deleteSystemMetadata(String guid)
1728
    {        
1729
        
1730
        int serialNumber = -1;
1731
        DBConnection dbConn = null;
1732
        String query = null;
1733
        PreparedStatement stmt = null;
1734
        int rows = 0;
1735
        try {
1736

    
1737
            // Get a database connection from the pool
1738
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1739
            serialNumber = dbConn.getCheckOutSerialNumber();
1740

    
1741
            // remove main system metadata entry
1742
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1743
            stmt = dbConn.prepareStatement(query);
1744
            stmt.setString(1, guid);
1745
            logMetacat.debug("delete system metadata: " + stmt.toString());
1746
            rows = stmt.executeUpdate();
1747
            stmt.close();
1748
            
1749
            // remove the systemMetadataReplicationPolicy
1750
            query = "delete from systemMetadataReplicationPolicy " + 
1751
            "where guid = ?";
1752
            stmt = dbConn.prepareStatement(query);
1753
            stmt.setString(1, guid);
1754
            logMetacat.debug("delete systemMetadataReplicationPolicy: " + stmt.toString());
1755
            rows = stmt.executeUpdate();
1756
            stmt.close();
1757
            
1758
            // remove the systemMetadataReplicationStatus
1759
            query = "delete from systemMetadataReplicationStatus " + 
1760
            "where guid = ?";
1761
            stmt = dbConn.prepareStatement(query);
1762
            stmt.setString(1, guid);
1763
            logMetacat.debug("delete systemMetadataReplicationStatus: " + stmt.toString());
1764
            rows = stmt.executeUpdate();
1765
            stmt.close();
1766
            
1767
            // TODO: remove the access?
1768
            // Metacat keeps "deleted" documents so we should not remove access rules.
1769
            
1770
        } catch (Exception e) {
1771
            e.printStackTrace();
1772
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1773
            try {
1774
				dbConn.rollback();
1775
			} catch (SQLException sqle) {
1776
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
1777
			}
1778
        } finally {
1779
            // Return database connection to the pool
1780
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1781
        }
1782
    }
1783
    
1784
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
1785
    {
1786
        DBConnection dbConn = null;
1787
        int serialNumber = -1;
1788
        
1789
        try {
1790
            // Get a database connection from the pool
1791
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
1792
            serialNumber = dbConn.getCheckOutSerialNumber();
1793

    
1794
            // Execute the insert statement
1795
            String query = "update " + TYPE_SYSTEM_METADATA + 
1796
                " set authoritive_member_node = ? " +
1797
                " where authoritive_member_node = ?";
1798
            PreparedStatement stmt = dbConn.prepareStatement(query);
1799
            
1800
            //data values
1801
            stmt.setString(1, newMemberNodeId);
1802
            stmt.setString(2, existingMemberNodeId);
1803

    
1804
            logMetacat.debug("stmt: " + stmt.toString());
1805
            //execute
1806
            int rows = stmt.executeUpdate();
1807

    
1808
            stmt.close();
1809
        } catch (SQLException e) {
1810
            e.printStackTrace();
1811
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1812
                    + e.getMessage());
1813
        } catch (NumberFormatException e) {
1814
            e.printStackTrace();
1815
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
1816
                    + e.getMessage());
1817
        } finally {
1818
            // Return database connection to the pool
1819
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1820
        }
1821
    }
1822
}
1823

    
(37-37/64)