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

    
907
		DBConnection dbConn = null;
908
		int serialNumber = -1;
909
		try {
910
			// Get a database connection from the pool
911
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
912
			serialNumber = dbConn.getCheckOutSerialNumber();
913

    
914
			// Execute the insert statement
915
			PreparedStatement stmt = dbConn.prepareStatement(query);
916
			stmt.setString(1, guid);
917
			ResultSet rs = stmt.executeQuery();
918
			if (rs.next()) {
919
				exists = true;
920
			}
921

    
922
		} catch (SQLException e) {
923
			logMetacat.error("Error while looking up the system metadata: "
924
					+ e.getMessage());
925
		} finally {
926
			// Return database connection to the pool
927
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
928
		}
929

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

    
975
            // Get a database connection from the pool
976
            dbConn = 
977
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
978
            serialNumber = dbConn.getCheckOutSerialNumber();
979

    
980
            // Execute the update statement
981
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
982
            PreparedStatement stmt = dbConn.prepareStatement(query);
983
            stmt.setString(1, docid);
984
            stmt.setInt(2, rev);
985
            stmt.setString(3, guid);
986
            int rows = stmt.executeUpdate();
987

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

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

    
1051
            //where clause
1052
            stmt.setString(17, guid);
1053
            logMetacat.debug("stmt: " + stmt.toString());
1054
            //execute
1055
            int rows = stmt.executeUpdate();
1056

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

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

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

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

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

    
1429
            boolean f1 = false;
1430
            boolean f2 = false;
1431
            boolean f3 = false;
1432

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

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

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

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

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

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

    
1492
            // logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1493

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

    
1503
            int countIndex = 0;
1504

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

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

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

    
1532
                ObjectInfo oi = new ObjectInfo();
1533

    
1534
                Identifier id = new Identifier();
1535
                id.setValue(guid);
1536
                oi.setIdentifier(id);
1537

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

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

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

    
1558
                oi.setSize(size);
1559

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

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

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

    
1578
        ol.setStart(start);
1579
        ol.setCount(ol.sizeObjectInfoList());
1580
        ol.setTotal(total);
1581

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

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

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

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

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

    
1649
            // Parse the localId into scope and rev parts
1650
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1651
            String docid = acc.getDocid();
1652
            int rev = 1;
1653
            if (acc.getRev() != null) {
1654
              rev = (new Integer(acc.getRev()).intValue());
1655
            }
1656

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

    
1661
            // Execute the insert statement
1662
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
1663
            PreparedStatement stmt = dbConn.prepareStatement(query);
1664
            stmt.setString(1, guid);
1665
            stmt.setString(2, docid);
1666
            stmt.setInt(3, rev);
1667
            logMetacat.debug("remove mapping query: " + stmt.toString());
1668
            int rows = stmt.executeUpdate();
1669

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

    
1700
            // Get a database connection from the pool
1701
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1702
            serialNumber = dbConn.getCheckOutSerialNumber();
1703

    
1704
            // Execute the insert statement
1705
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1706
            PreparedStatement stmt = dbConn.prepareStatement(query);
1707
            stmt.setString(1, guid);
1708
            logMetacat.debug("system metadata query: " + stmt.toString());
1709
            int rows = stmt.executeUpdate();
1710

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

    
1731
            // Get a database connection from the pool
1732
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1733
            serialNumber = dbConn.getCheckOutSerialNumber();
1734

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

    
1788
            // Execute the insert statement
1789
            String query = "update " + TYPE_SYSTEM_METADATA + 
1790
                " set authoritive_member_node = ? " +
1791
                " where authoritive_member_node = ?";
1792
            PreparedStatement stmt = dbConn.prepareStatement(query);
1793
            
1794
            //data values
1795
            stmt.setString(1, newMemberNodeId);
1796
            stmt.setString(2, existingMemberNodeId);
1797

    
1798
            logMetacat.debug("stmt: " + stmt.toString());
1799
            //execute
1800
            int rows = stmt.executeUpdate();
1801

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

    
(37-37/64)