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

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

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

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

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

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

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

    
261
        try 
262
        {
263
            // Get a database connection from the pool
264
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadata");
265
            serialNumber = dbConn.getCheckOutSerialNumber();
266

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

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

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

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

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

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

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

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

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

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

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

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

    
925
		DBConnection dbConn = null;
926
		int serialNumber = -1;
927
		try {
928
			// Get a database connection from the pool
929
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
930
			serialNumber = dbConn.getCheckOutSerialNumber();
931

    
932
			// Execute the insert statement
933
			PreparedStatement stmt = dbConn.prepareStatement(query);
934
			stmt.setString(1, guid);
935
			ResultSet rs = stmt.executeQuery();
936
			if (rs.next()) {
937
				exists = true;
938
			}
939

    
940
		} catch (SQLException e) {
941
			logMetacat.error("Error while looking up the system metadata: "
942
					+ e.getMessage());
943
		} finally {
944
			// Return database connection to the pool
945
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
946
		}
947

    
948
		return exists;
949
	}
950
    
951
    /**
952
     * creates a system metadata mapping and adds additional fields from sysmeta
953
     * to the table for quick searching.
954
     * 
955
     * @param guid the id to insert
956
     * @param localId the systemMetadata object to get the local id for
957
     * @throws McdbDocNotFoundException 
958
     * @throws SQLException 
959
     * @throws InvalidSystemMetadata 
960
     */
961
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta) 
962
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
963
    	String guid = sysmeta.getIdentifier().getValue();
964
    	
965
    	 // Get a database connection from the pool
966
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
967
        int serialNumber = dbConn.getCheckOutSerialNumber();
968
        
969
        try {
970
        	// use a single transaction for it all
971
        	dbConn.setAutoCommit(false);
972
        	
973
	    	// insert the record if needed
974
        	if (!IdentifierManager.getInstance().systemMetadataExists(guid)) {
975
    	        insertSystemMetadata(guid, dbConn);
976
			}
977
	        // update with the values
978
	        updateSystemMetadata(sysmeta, dbConn);
979
	        
980
	        // commit if we got here with no errors
981
	        dbConn.commit();
982
        } catch (Exception e) {
983
            e.printStackTrace();
984
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
985
            dbConn.rollback();
986
        } finally {
987
            // Return database connection to the pool
988
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
989
        }
990
        
991
        
992
    }
993
        
994
    
995
    /**
996
     * update a mapping
997
     * @param guid
998
     * @param localId
999
     */
1000
    public void updateMapping(String guid, String localId)
1001
    {
1002
    	
1003
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1004
        int serialNumber = -1;
1005
        DBConnection dbConn = null;
1006
        try {
1007
            // Parse the localId into scope and rev parts
1008
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1009
            String docid = acc.getDocid();
1010
            int rev = 1;
1011
            if(acc.getRev() != null)
1012
            {
1013
              rev = (new Integer(acc.getRev()).intValue());
1014
            }
1015

    
1016
            // Get a database connection from the pool
1017
            dbConn = 
1018
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1019
            serialNumber = dbConn.getCheckOutSerialNumber();
1020

    
1021
            // Execute the update statement
1022
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1023
            PreparedStatement stmt = dbConn.prepareStatement(query);
1024
            stmt.setString(1, docid);
1025
            stmt.setInt(2, rev);
1026
            stmt.setString(3, guid);
1027
            int rows = stmt.executeUpdate();
1028

    
1029
            stmt.close();
1030
        } catch (SQLException e) {
1031
            e.printStackTrace();
1032
            logMetacat.error("SQL error while updating a mapping identifier: " 
1033
                    + e.getMessage());
1034
        } catch (NumberFormatException e) {
1035
            e.printStackTrace();
1036
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1037
                    + e.getMessage());
1038
        } catch (AccessionNumberException e) {
1039
            e.printStackTrace();
1040
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1041
                    + e.getMessage());
1042
        } finally {
1043
            // Return database connection to the pool
1044
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1045
        }
1046
        logMetacat.debug("done updating mapping");
1047
    }
1048
        
1049
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1050
        String checksum, String checksumAlgorithm, String originMemberNode, 
1051
        String authoritativeMemberNode, long modifiedDate, String submitter, 
1052
        String guid, String objectFormat, BigInteger size, boolean archived,
1053
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1054
        String obsoletedBy, BigInteger serialVersion, DBConnection dbConn) throws SQLException  {
1055
  
1056
        // Execute the insert statement
1057
        String query = "update " + TYPE_SYSTEM_METADATA + 
1058
            " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1059
            "origin_member_node, authoritive_member_node, date_modified, " +
1060
            "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1061
            "obsoletes, obsoleted_by, serial_version) " +
1062
            "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1063
        PreparedStatement stmt = dbConn.prepareStatement(query);
1064
        
1065
        //data values
1066
        stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1067
        stmt.setString(2, rightsHolder);
1068
        stmt.setString(3, checksum);
1069
        stmt.setString(4, checksumAlgorithm);
1070
        stmt.setString(5, originMemberNode);
1071
        stmt.setString(6, authoritativeMemberNode);
1072
        stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1073
        stmt.setString(8, submitter);
1074
        stmt.setString(9, objectFormat);
1075
        stmt.setString(10, size.toString());
1076
        stmt.setBoolean(11, archived);
1077
        stmt.setBoolean(12, replicationAllowed);
1078
        stmt.setInt(13, numberReplicas);
1079
        stmt.setString(14, obsoletes);
1080
        stmt.setString(15, obsoletedBy);
1081
        stmt.setString(16, serialVersion.toString());
1082

    
1083
        //where clause
1084
        stmt.setString(17, guid);
1085
        logMetacat.debug("stmt: " + stmt.toString());
1086
        //execute
1087
        int rows = stmt.executeUpdate();
1088

    
1089
        stmt.close();
1090
               
1091
    }
1092
    
1093
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1094
    {
1095
           
1096
        // remove existing values first
1097
        String delete = "delete from smReplicationPolicy " + 
1098
        "where guid = ? and policy = ?";
1099
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1100
        //data values
1101
        stmt.setString(1, guid);
1102
        stmt.setString(2, policy);
1103
        //execute
1104
        int deletedCount = stmt.executeUpdate();
1105
        stmt.close();
1106
        
1107
        for (String memberNode: memberNodes) {
1108
            // Execute the insert statement
1109
            String insert = "insert into smReplicationPolicy " + 
1110
                "(guid, policy, member_node) " +
1111
                "values (?, ?, ?)";
1112
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1113
            
1114
            //data values
1115
            insertStatement.setString(1, guid);
1116
            insertStatement.setString(2, policy);
1117
            insertStatement.setString(3, memberNode);
1118
            
1119
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1120

    
1121
            //execute
1122
            int rows = insertStatement.executeUpdate();
1123
            insertStatement.close();
1124
        }
1125
        
1126
    }
1127
    
1128
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1129
       
1130
        // remove existing values first
1131
        String delete = "delete from smReplicationStatus " + 
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 smReplicationStatus " + 
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.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1152
	            insertStatement.setString(1, guid);
1153
	            insertStatement.setString(2, memberNode);
1154
	            insertStatement.setString(3, status);
1155
	            insertStatement.setTimestamp(4, sqlDate);
1156

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

    
1302
    	// use GUID to look up the access
1303
        XMLAccessAccess accessController  = new XMLAccessAccess();
1304
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1305
        
1306
        for (XMLAccessDAO accessDAO: accessDAOs) {
1307
        	// only add allow rule
1308
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1309
	        	AccessRule accessRule = new AccessRule();    	
1310
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1311
	        	// cannot include if we have no permissions
1312
	        	if (permissions == null || permissions.isEmpty()) {
1313
	        		logMetacat.warn("skipping empty access rule permissions for " + guid);
1314
	        		continue;
1315
	        	}
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
            // handle special case quickly
1436
            String countSql = "select count(guid) from systemmetadata";
1437
            if (count == 0) {
1438
            	sql = countSql;
1439
            }
1440

    
1441
            boolean f1 = false;
1442
            boolean f2 = false;
1443
            boolean f3 = false;
1444

    
1445
            if (startTime != null) {
1446
                sql += " where systemmetadata.date_modified >= ?";
1447
                f1 = true;
1448
            }
1449

    
1450
            if (endTime != null) {
1451
                if (!f1) {
1452
                    sql += " where systemmetadata.date_modified < ?";
1453
                } else {
1454
                    sql += " and systemmetadata.date_modified < ?";
1455
                }
1456
                f2 = true;
1457
            }
1458

    
1459
            if (objectFormatId != null) {
1460
                if (!f1 && !f2) {
1461
                    sql += " where object_format = ?";
1462
                } else {
1463
                    sql += " and object_format = ?";
1464
                }
1465
                f3 = true;
1466
            }
1467

    
1468
            if (replicaStatus) {
1469
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1470
                if (!f1 && !f2 && !f3) {
1471
                    sql += " where authoritive_member_node != '" +
1472
                        currentNodeId.trim() + "'";
1473
                } else {
1474
                    sql += " and authoritive_member_node != '" +
1475
                        currentNodeId.trim() + "'";
1476
                }
1477
            }
1478

    
1479
            // order the results for slicing ops
1480
            if (count != 0) {
1481
            	sql += " order by guid ";
1482
            }
1483
            
1484
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1485
            serialNumber = dbConn.getCheckOutSerialNumber();
1486
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1487

    
1488
            if (f1 && f2 && f3) {
1489
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1490
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1491
                stmt.setString(3, objectFormatId.getValue());
1492
            } else if (f1 && f2 && !f3) {
1493
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1494
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1495
            } else if (f1 && !f2 && f3) {
1496
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1497
                stmt.setString(2, objectFormatId.getValue());
1498
            } else if (f1 && !f2 && !f3) {
1499
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1500
            } else if (!f1 && f2 && f3) {
1501
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1502
                stmt.setString(2, objectFormatId.getValue());
1503
            } else if (!f1 && !f2 && f3) {
1504
                stmt.setString(1, objectFormatId.getValue());
1505
            } else if (!f1 && f2 && !f3) {
1506
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1507
            }
1508

    
1509
            // logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1510

    
1511
            ResultSet rs = stmt.executeQuery();
1512
            // handle special count = 0 query here
1513
            if (count == 0) {
1514
            	while (rs.next()) {
1515
            		total = rs.getInt(1);
1516
            		break;
1517
            	}
1518
            	ol.setStart(start);
1519
                ol.setCount(count);
1520
                ol.setTotal(total);
1521
            }
1522
            else {
1523
            	// do the full query
1524
	            for (int i = 0; i < start; i++) {
1525
	                if (rs.next()) {
1526
	                    total++;
1527
	                } else {
1528
	                    break;
1529
	                }
1530
	            }
1531
	
1532
	            int countIndex = 0;
1533
	
1534
	            while (rs.next()) {                
1535
	                total++;
1536
	                if (countIndex >= count) {
1537
	                    // allow unlimited (negative number for count)
1538
	                    if (count > 0) {
1539
	                        break;
1540
	                    }
1541
	                }
1542
	
1543
	                String guid = rs.getString(1);
1544
	                // logMetacat.debug("query found doc with guid " + guid);
1545
	                // Timestamp dateUploaded = rs.getTimestamp(2);
1546
	                // String rightsHolder = rs.getString(3);
1547
	                String checksum = rs.getString(4);
1548
	                String checksumAlgorithm = rs.getString(5);
1549
	                // String originMemberNode = rs.getString(6);
1550
	                // String authoritiveMemberNode = rs.getString(7);
1551
	                Timestamp dateModified = rs.getTimestamp(8);
1552
	                // String submitter = rs.getString(9);
1553
	                String fmtidStr = rs.getString(10);
1554
	                String sz = rs.getString(11);
1555
	                BigInteger size = new BigInteger("0");
1556
	
1557
	                if (sz != null && !sz.trim().equals("")) {
1558
	                    size = new BigInteger(rs.getString(11));
1559
	                }
1560
	
1561
	                ObjectInfo oi = new ObjectInfo();
1562
	
1563
	                Identifier id = new Identifier();
1564
	                id.setValue(guid);
1565
	                oi.setIdentifier(id);
1566
	
1567
	                if (dateModified != null) {
1568
	                    oi.setDateSysMetadataModified(dateModified);
1569
	                }
1570
	
1571
	                Checksum cs = new Checksum();
1572
	                cs.setValue(checksum);
1573
	                try {
1574
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1575
	                    cs.setAlgorithm(checksumAlgorithm);
1576
	                } catch (Exception e) {
1577
	                    logMetacat.error("could not parse checksum algorithm", e);
1578
	                    continue;
1579
	                }
1580
	                oi.setChecksum(cs);
1581
	
1582
	                // set the format type
1583
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1584
	                fmtid.setValue(fmtidStr);
1585
	                oi.setFormatId(fmtid);
1586
	
1587
	                oi.setSize(size);
1588
	
1589
	                // when requested count == 0, return an empty object list
1590
	                if (count != 0) {
1591
	                    ol.addObjectInfo(oi);                    
1592
	                }
1593
	                countIndex++;
1594
	            }
1595
	
1596
	            // expend the resultset to get the total count of possible rows
1597
	            while (rs.next()) {
1598
	                total++;
1599
	            }
1600
	        }
1601
            
1602
            // set the objectList
1603
            ol.setStart(start);
1604
            ol.setCount(ol.sizeObjectInfoList());
1605
            ol.setTotal(total);
1606
        }
1607

    
1608
        finally {
1609
            // Return database connection to the pool
1610
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1611
        }
1612

    
1613
        return ol;
1614
    }
1615
    
1616
    /**
1617
     * create a mapping in the identifier table
1618
     * @param guid
1619
     * @param localId
1620
     */
1621
    public void createMapping(String guid, String localId)
1622
    {        
1623
        
1624
        int serialNumber = -1;
1625
        DBConnection dbConn = null;
1626
        try {
1627

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

    
1636
            // Get a database connection from the pool
1637
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1638
            serialNumber = dbConn.getCheckOutSerialNumber();
1639

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

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

    
1680
            // Parse the localId into scope and rev parts
1681
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1682
            String docid = acc.getDocid();
1683
            int rev = 1;
1684
            if (acc.getRev() != null) {
1685
              rev = (new Integer(acc.getRev()).intValue());
1686
            }
1687

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

    
1692
            // Execute the insert statement
1693
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
1694
            PreparedStatement stmt = dbConn.prepareStatement(query);
1695
            stmt.setString(1, guid);
1696
            stmt.setString(2, docid);
1697
            stmt.setInt(3, rev);
1698
            logMetacat.debug("remove mapping query: " + stmt.toString());
1699
            int rows = stmt.executeUpdate();
1700

    
1701
            stmt.close();
1702
        } catch (SQLException e) {
1703
            e.printStackTrace();
1704
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1705
                    + e.getMessage());
1706
        } catch (NumberFormatException e) {
1707
            e.printStackTrace();
1708
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1709
                    + e.getMessage());
1710
        } catch (AccessionNumberException e) {
1711
            e.printStackTrace();
1712
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1713
                    + e.getMessage());
1714
        } finally {
1715
            // Return database connection to the pool
1716
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1717
        }
1718
    }
1719
    
1720
    /**
1721
     * create the systemmetadata record
1722
     * @param guid
1723
     * @param dbConn 
1724
     * @throws SQLException 
1725
     */
1726
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
1727
    {        
1728

    
1729
        // Execute the insert statement
1730
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1731
        PreparedStatement stmt = dbConn.prepareStatement(query);
1732
        stmt.setString(1, guid);
1733
        logMetacat.debug("system metadata query: " + stmt.toString());
1734
        int rows = stmt.executeUpdate();
1735

    
1736
        stmt.close();
1737
        
1738
    }
1739
    
1740
    public void deleteSystemMetadata(String guid)
1741
    {        
1742
        
1743
        int serialNumber = -1;
1744
        DBConnection dbConn = null;
1745
        String query = null;
1746
        PreparedStatement stmt = null;
1747
        int rows = 0;
1748
        try {
1749

    
1750
            // Get a database connection from the pool
1751
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1752
            serialNumber = dbConn.getCheckOutSerialNumber();
1753

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

    
1807
            // Execute the insert statement
1808
            String query = "update " + TYPE_SYSTEM_METADATA + 
1809
                " set authoritive_member_node = ? " +
1810
                " where authoritive_member_node = ?";
1811
            PreparedStatement stmt = dbConn.prepareStatement(query);
1812
            
1813
            //data values
1814
            stmt.setString(1, newMemberNodeId);
1815
            stmt.setString(2, existingMemberNodeId);
1816

    
1817
            logMetacat.debug("stmt: " + stmt.toString());
1818
            //execute
1819
            int rows = stmt.executeUpdate();
1820

    
1821
            stmt.close();
1822
        } catch (SQLException e) {
1823
            e.printStackTrace();
1824
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1825
                    + e.getMessage());
1826
        } catch (NumberFormatException e) {
1827
            e.printStackTrace();
1828
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
1829
                    + e.getMessage());
1830
        } finally {
1831
            // Return database connection to the pool
1832
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1833
        }
1834
    }
1835
}
1836

    
(37-37/64)