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

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

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

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

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

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

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

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

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

    
284

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

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

    
498
            // Execute the insert statement
499
            PreparedStatement stmt = dbConn.prepareStatement(sql);
500
            ResultSet rs = stmt.executeQuery();
501
            if (rs.next()) 
502
            {
503
                String docname = rs.getString(1);
504
                String doctype = rs.getString(2);
505
                String user_owner = rs.getString(3);
506
                String user_updated = rs.getString(4);
507
                String server_location = rs.getString(5);
508
                int rev = rs.getInt(6);
509
                String date_created = rs.getString(7);
510
                String date_updated = rs.getString(8);
511
                h.put("docid", localId);
512
                h.put("docname", docname);
513
                h.put("doctype", doctype);
514
                h.put("user_owner", user_owner);
515
                h.put("user_updated", user_updated);
516
                h.put("server_location", server_location);
517
                h.put("rev", new Integer(rev).toString());
518
                h.put("date_created", date_created);
519
                h.put("date_updated", date_updated);
520
                
521
                stmt.close();
522
            } 
523
            else
524
            {
525
                stmt.close();
526
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
527
                throw new McdbDocNotFoundException("2Could not find document " + localId);
528
            }
529
            
530
            String sql2 = "select principal_name, permission, perm_type, perm_order from xml_access " +
531
            "where docid like '" + localId + "'";
532
            logMetacat.debug("executing sql: " + sql2);
533
            PreparedStatement stmt2 = dbConn.prepareStatement(sql2);
534
            rs = stmt2.executeQuery();
535
            Vector accessVector = new Vector();
536
            while(rs.next())
537
            {
538
                Hashtable accessHash = new Hashtable();
539
                String principal_name = rs.getString(1);
540
                String permission = rs.getString(2);
541
                String permissionType = rs.getString(3);
542
                String permissionOrder = rs.getString(4);
543
                accessHash.put("principal_name", principal_name);
544
                accessHash.put("permission", permission);
545
                accessHash.put("permission_type", permissionType);
546
                accessHash.put("permission_order", permissionOrder);
547
                logMetacat.debug("accessHash: " + accessHash.toString());
548
                accessVector.add(accessHash);
549
            }
550
            h.put("access", accessVector);
551
        } 
552
        catch (SQLException e) 
553
        {
554
            e.printStackTrace();
555
            logMetacat.error("Error while getting document info for localid " + localId + " : "  
556
                    + e.getMessage());
557
        } 
558
        finally 
559
        {
560
            // Return database connection to the pool
561
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
562
        }
563
        return h;
564
    }
565
    
566
    /**
567
     * return the newest rev for a given localId
568
     * @param localId
569
     * @return
570
     */
571
    public int getLatestRevForLocalId(String localId)
572
        throws McdbDocNotFoundException
573
    {
574
        try
575
        {
576
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
577
            localId = acc.getDocid();
578
        }
579
        catch(Exception e)
580
        {
581
            //do nothing. just try the localId as it is
582
        }
583
        int rev = 0;
584
        String sql = "select rev from xml_documents where docid like '" + localId + "'";
585
        DBConnection dbConn = null;
586
        int serialNumber = -1;
587
        try 
588
        {
589
            // Get a database connection from the pool
590
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLatestRevForLocalId");
591
            serialNumber = dbConn.getCheckOutSerialNumber();
592

    
593
            // Execute the insert statement
594
            PreparedStatement stmt = dbConn.prepareStatement(sql);
595
            ResultSet rs = stmt.executeQuery();
596
            if (rs.next()) 
597
            {
598
                rev = rs.getInt(1);
599
                stmt.close();
600
            } 
601
            else
602
            {
603
                stmt.close();
604
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
605
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
606
            }
607
        } 
608
        catch (SQLException e) 
609
        {
610
            logMetacat.error("Error while looking up the guid: " 
611
                    + e.getMessage());
612
        } 
613
        finally 
614
        {
615
            // Return database connection to the pool
616
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
617
        }
618
        return rev;
619
    }
620
    
621
    /**
622
     * return all local ids in the object store that do not have associated
623
     * system metadata
624
     */
625
    public List<String> getLocalIdsWithNoSystemMetadata()
626
    {
627
        Vector<String> ids = new Vector<String>();
628
        String sql = "select docid, rev from xml_documents " +
629
        		"where docid not in " +
630
        		"(select docid from identifier where guid in (select guid from systemmetadata)))";
631
        DBConnection dbConn = null;
632
        int serialNumber = -1;
633
        try 
634
        {
635
            // Get a database connection from the pool
636
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
637
            serialNumber = dbConn.getCheckOutSerialNumber();
638

    
639
            // Execute the insert statement
640
            PreparedStatement stmt = dbConn.prepareStatement(sql);
641
            ResultSet rs = stmt.executeQuery();
642
            while (rs.next()) 
643
            {
644
                String localid = rs.getString(1);
645
                String rev = rs.getString(2);
646
                localid += "." + rev;
647
                logMetacat.debug("id to add SM for: " + localid);
648
                ids.add(localid);
649
            } 
650
            stmt.close();
651
        } 
652
        catch (SQLException e) 
653
        {
654
            logMetacat.error("Error while looking up the guid: " 
655
                    + e.getMessage());
656
        } 
657
        finally 
658
        {
659
            // Return database connection to the pool
660
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
661
        }
662
        
663
        return ids;
664
    }
665
    
666
    /**
667
     * return a listing of all local ids in the object store
668
     * @return a list of all local ids in metacat
669
     */
670
    public List<String> getAllLocalIds()
671
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
672
    //    throws Exception
673
    {
674
        Vector<String> ids = new Vector<String>();
675
        String sql = "select docid from xml_documents";
676
        DBConnection dbConn = null;
677
        int serialNumber = -1;
678
        try 
679
        {
680
            // Get a database connection from the pool
681
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
682
            serialNumber = dbConn.getCheckOutSerialNumber();
683

    
684
            // Execute the insert statement
685
            PreparedStatement stmt = dbConn.prepareStatement(sql);
686
            ResultSet rs = stmt.executeQuery();
687
            while (rs.next()) 
688
            {
689
                String localid = rs.getString(1);
690
                ids.add(localid);
691
            } 
692
            stmt.close();
693
        } 
694
        catch (SQLException e) 
695
        {
696
            logMetacat.error("Error while looking up the guid: " 
697
                    + e.getMessage());
698
        } 
699
        finally 
700
        {
701
            // Return database connection to the pool
702
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
703
        }
704
        return ids;
705
    }
706
    
707
    
708
    /**
709
     * return a listing of all guids in the object store
710
     * @return a list of all GUIDs in metacat
711
     */
712
    public List<String> getAllGUIDs()
713
    {
714
        Vector<String> guids = new Vector<String>();
715
        String sql = "select guid from identifier";
716
        DBConnection dbConn = null;
717
        int serialNumber = -1;
718
        try 
719
        {
720
            // Get a database connection from the pool
721
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllGUIDs");
722
            serialNumber = dbConn.getCheckOutSerialNumber();
723

    
724
            // Execute the insert statement
725
            PreparedStatement stmt = dbConn.prepareStatement(sql);
726
            ResultSet rs = stmt.executeQuery();
727
            while (rs.next()) 
728
            {
729
                String guid = rs.getString(1);
730
                guids.add(guid);
731
            } 
732
            stmt.close();
733
        } 
734
        catch (SQLException e) 
735
        {
736
            logMetacat.error("Error while retrieving the guid: " 
737
                    + e.getMessage());
738
        } 
739
        finally 
740
        {
741
            // Return database connection to the pool
742
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
743
        }
744
        return guids;
745
    }
746
    
747
    
748
    
749
    /**
750
     * returns a list of system metadata-only guids since the given date
751
     * @return a list of system ids in metacat that do not correspond to objects
752
     * TODO: need to check which server they are on
753
     */
754
    public List<String> getUpdatedSystemMetadataIds(Date since)
755
       throws Exception
756
    {
757
        List<String> ids = new Vector<String>();
758
        String sql = 
759
        	"select guid from " + TYPE_SYSTEM_METADATA +
760
        	" where guid not in " +
761
        	" (select guid from " + TYPE_IDENTIFIER + ") " +
762
        	" and date_modified > ?";
763
        DBConnection dbConn = null;
764
        int serialNumber = -1;
765
        try 
766
        {
767
            // Get a database connection from the pool
768
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getUpdatedSystemMetadataIds");
769
            serialNumber = dbConn.getCheckOutSerialNumber();
770

    
771
            // Execute the insert statement
772
            PreparedStatement stmt = dbConn.prepareStatement(sql);
773
            stmt.setDate(1, new java.sql.Date(since.getTime()));
774
            ResultSet rs = stmt.executeQuery();
775
            while (rs.next()) 
776
            {
777
                String guid = rs.getString(1);
778
                ids.add(guid);
779
            } 
780
            stmt.close();
781
        } 
782
        catch (SQLException e) 
783
        {
784
            logMetacat.error("Error while looking up the updated guids: " 
785
                    + e.getMessage());
786
        } 
787
        finally 
788
        {
789
            // Return database connection to the pool
790
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
791
        }
792
        return ids;
793
    }
794
    
795
    /**
796
     * returns a list of system metadata-only guids since the given date
797
     * @return a list of system ids in metacat that do not correspond to objects
798
     * TODO: need to check which server they are on
799
     */
800
    public Date getLastModifiedDate() throws Exception {
801
        Date maxDate = null;
802

    
803
        List<String> ids = new Vector<String>();
804
        String sql = 
805
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
806
        DBConnection dbConn = null;
807
        int serialNumber = -1;
808
        try 
809
        {
810
            // Get a database connection from the pool
811
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
812
            serialNumber = dbConn.getCheckOutSerialNumber();
813

    
814
            // Execute the insert statement
815
            PreparedStatement stmt = dbConn.prepareStatement(sql);
816
            ResultSet rs = stmt.executeQuery();
817
            if (rs.next()) {
818
            	maxDate = rs.getDate(1);
819
            } 
820
            stmt.close();
821
        } 
822
        catch (SQLException e) 
823
        {
824
            logMetacat.error("Error while looking up the latest update date: " 
825
                    + e.getMessage());
826
        } 
827
        finally 
828
        {
829
            // Return database connection to the pool
830
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
831
        }
832
        return maxDate;
833
    }
834

    
835
    
836
    /**
837
     * Determine if an identifier exists already, returning true if so.
838
     * 
839
     * @param guid the global identifier to look up
840
     * @return boolean true if the identifier exists
841
     */
842
    public boolean identifierExists(String guid)
843
    {
844
        boolean idExists = false;
845
        try {
846
            String id = getLocalId(guid);
847
            if (id != null) {
848
                idExists = true;
849
            }
850
        } catch (McdbDocNotFoundException e) {
851
        	// try system metadata only
852
        	try {
853
        		idExists = systemMetadataExists(guid);
854
            } catch (Exception e2) {
855
            	idExists = false;
856
            }
857
        }
858
        return idExists;
859
    }
860
    
861
    /**
862
     * 
863
     * @param guid
864
     * @param rev
865
     * @return
866
     */
867
    public String generateLocalId(String guid, int rev)
868
    {
869
        return generateLocalId(guid, rev, false);
870
    }
871

    
872
    /**
873
     * Given a global identifier (guid), create a suitable local identifier that
874
     * follows Metacat's docid semantics and format (scope.id.rev), and create
875
     * a mapping between these two identifiers.  This effectively reserves both
876
     * the global and the local identifier, as they will now be present in the
877
     * identifier mapping table.  If the incoming guid has the syntax of a
878
     * Metacat docid (scope.id.rev), then simply use it.
879
     * 
880
     * @param guid the global string identifier
881
     * @param rev the revision number to be used in the localId
882
     * @return String containing the localId to be used for Metacat operations
883
     */
884
    public String generateLocalId(String guid, int rev, boolean isSystemMetadata) 
885
    {
886
        String localId = "";
887
        boolean conformsToDocidFormat = false;
888
        
889
        // Check if the guid passed in is already in docid (scope.id.rev) format
890
        try {
891
            AccessionNumber acc = new AccessionNumber(guid, "NONE");
892
            if (new Integer(acc.getRev()).intValue() > 0) {
893
                conformsToDocidFormat = true;
894
            }
895
        } catch (NumberFormatException e) {
896
            // No action needed, simply detecting invalid AccessionNumbers
897
        } catch (AccessionNumberException e) {
898
            // No action needed, simply detecting invalid AccessionNumbers
899
        } catch (SQLException e) {
900
            // No action needed, simply detecting invalid AccessionNumbers
901
        }
902
        
903
        if (conformsToDocidFormat) {
904
            // if it conforms, use it for both guid and localId
905
            localId = guid;
906
        } else {
907
            // if not, then generate a new unique localId
908
            localId = DocumentUtil.generateDocumentId(rev);
909
        }
910
        
911
        // Register this new pair in the identifier mapping table
912
        logMetacat.debug("creating mapping in generateLocalId");
913
        if(!isSystemMetadata)
914
        { //don't do this if we're generating for system metadata
915
            createMapping(guid, localId);
916
        }
917
        
918
        return localId;
919
    }
920
    
921
    /**
922
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
923
     * if the docid, rev is not found in the identifiers or systemmetadata tables
924
     *
925
     * @param docid the docid to look up
926
     * @param rev the revision of the docid to look up
927
     * @return String containing the mapped guid
928
     * @throws McdbDocNotFoundException if the docid, rev is not found
929
     */
930
    public String getGUID(String docid, int rev)
931
      throws McdbDocNotFoundException
932
    {
933
        logMetacat.debug("getting guid for " + docid);
934
        String query = "select guid from identifier where docid = ? and rev = ?";
935
        String guid = null;
936
        
937
        DBConnection dbConn = null;
938
        int serialNumber = -1;
939
        try {
940
            // Get a database connection from the pool
941
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
942
            serialNumber = dbConn.getCheckOutSerialNumber();
943
            
944
            // Execute the insert statement
945
            PreparedStatement stmt = dbConn.prepareStatement(query);
946
            stmt.setString(1, docid);
947
            stmt.setInt(2, rev);
948
            ResultSet rs = stmt.executeQuery();
949
            if (rs.next()) 
950
            {
951
                guid = rs.getString(1);
952
            } 
953
            else
954
            {
955
            	throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
956
            }
957
            
958
        } catch (SQLException e) {
959
            logMetacat.error("Error while looking up the guid: " 
960
                    + e.getMessage());
961
        } finally {
962
            // Return database connection to the pool
963
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
964
        }
965
        
966
        return guid;
967
    }
968
    
969
    public boolean systemMetadataExists(String guid) {
970
		logMetacat.debug("looking up system metadata for guid " + guid);
971
		boolean exists = false;
972
		String query = "select guid from systemmetadata where guid = ?";
973

    
974
		DBConnection dbConn = null;
975
		int serialNumber = -1;
976
		try {
977
			// Get a database connection from the pool
978
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
979
			serialNumber = dbConn.getCheckOutSerialNumber();
980

    
981
			// Execute the insert statement
982
			PreparedStatement stmt = dbConn.prepareStatement(query);
983
			stmt.setString(1, guid);
984
			ResultSet rs = stmt.executeQuery();
985
			if (rs.next()) {
986
				exists = true;
987
			}
988

    
989
		} catch (SQLException e) {
990
			logMetacat.error("Error while looking up the system metadata: "
991
					+ e.getMessage());
992
		} finally {
993
			// Return database connection to the pool
994
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
995
		}
996

    
997
		return exists;
998
	}
999
    
1000
    /**
1001
     * creates a system metadata mapping and adds additional fields from sysmeta
1002
     * to the table for quick searching.
1003
     * 
1004
     * @param guid the id to insert
1005
     * @param localId the systemMetadata object to get the local id for
1006
     * @throws McdbDocNotFoundException 
1007
     */
1008
    public void createSystemMetadata(SystemMetadata sysmeta) throws McdbDocNotFoundException
1009
    {
1010
    	String guid = sysmeta.getIdentifier().getValue();
1011
    	// insert the record
1012
        insertSystemMetadata(guid);
1013
        // update with the values
1014
        updateSystemMetadata(sysmeta);
1015
    }
1016
        
1017
    
1018
    /**
1019
     * update a mapping
1020
     * @param guid
1021
     * @param localId
1022
     */
1023
    public void updateMapping(String guid, String localId)
1024
    {
1025
    	
1026
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1027
        int serialNumber = -1;
1028
        DBConnection dbConn = null;
1029
        try {
1030
            // Parse the localId into scope and rev parts
1031
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1032
            String docid = acc.getDocid();
1033
            int rev = 1;
1034
            if(acc.getRev() != null)
1035
            {
1036
              rev = (new Integer(acc.getRev()).intValue());
1037
            }
1038

    
1039
            // Get a database connection from the pool
1040
            dbConn = 
1041
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1042
            serialNumber = dbConn.getCheckOutSerialNumber();
1043

    
1044
            // Execute the update statement
1045
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid='" + guid + "'";
1046
            PreparedStatement stmt = dbConn.prepareStatement(query);
1047
            stmt.setString(1, docid);
1048
            stmt.setInt(2, rev);
1049
            int rows = stmt.executeUpdate();
1050

    
1051
            stmt.close();
1052
        } catch (SQLException e) {
1053
            e.printStackTrace();
1054
            logMetacat.error("SQL error while updating a mapping identifier: " 
1055
                    + e.getMessage());
1056
        } catch (NumberFormatException e) {
1057
            e.printStackTrace();
1058
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1059
                    + e.getMessage());
1060
        } catch (AccessionNumberException e) {
1061
            e.printStackTrace();
1062
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1063
                    + e.getMessage());
1064
        } finally {
1065
            // Return database connection to the pool
1066
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1067
        }
1068
        logMetacat.debug("done updating mapping");
1069
    }
1070
        
1071
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1072
            String checksum, String checksumAlgorithm, String originMemberNode,
1073
            String authoritativeMemberNode, long modifiedDate, String submitter, 
1074
            String guid, String objectFormat, BigInteger size, boolean replicationAllowed,
1075
            int numberReplicas, String obsoletes, String obsoletedBy, BigInteger serialVersion)
1076
    {
1077
        DBConnection dbConn = null;
1078
        int serialNumber = -1;
1079
        
1080
        try {
1081
            // Get a database connection from the pool
1082
            dbConn = 
1083
                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1084
            serialNumber = dbConn.getCheckOutSerialNumber();
1085

    
1086
            // Execute the insert statement
1087
            String query = "update " + TYPE_SYSTEM_METADATA + 
1088
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1089
                "origin_member_node, authoritive_member_node, date_modified, " +
1090
                "submitter, object_format, size, replication_allowed, number_replicas, " +
1091
                "obsoletes, obsoleted_by, serial_version) " +
1092
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1093
            PreparedStatement stmt = dbConn.prepareStatement(query);
1094
            
1095
            //data values
1096
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1097
            stmt.setString(2, rightsHolder);
1098
            stmt.setString(3, checksum);
1099
            stmt.setString(4, checksumAlgorithm);
1100
            stmt.setString(5, originMemberNode);
1101
            stmt.setString(6, authoritativeMemberNode);
1102
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1103
            stmt.setString(8, submitter);
1104
            stmt.setString(9, objectFormat);
1105
            stmt.setString(10, size.toString());
1106
            stmt.setBoolean(11, replicationAllowed);
1107
            stmt.setInt(12, numberReplicas);
1108
            stmt.setString(13, obsoletes);
1109
            stmt.setString(14, obsoletedBy);
1110
            stmt.setString(15, serialVersion.toString());
1111

    
1112
            //where clause
1113
            stmt.setString(16, guid);
1114
            logMetacat.debug("stmt: " + stmt.toString());
1115
            //execute
1116
            int rows = stmt.executeUpdate();
1117

    
1118
            stmt.close();
1119
        } catch (SQLException e) {
1120
            e.printStackTrace();
1121
            logMetacat.error("insertAdditionalSystemMetadataFields: SQL error while creating a mapping to the system metadata identifier: " 
1122
                    + e.getMessage());
1123
        } catch (NumberFormatException e) {
1124
            e.printStackTrace();
1125
            logMetacat.error("insertAdditionalSystemMetadataFields: NumberFormat error while creating a mapping to the system metadata identifier: " 
1126
                    + e.getMessage());
1127
        } finally {
1128
            // Return database connection to the pool
1129
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1130
        }
1131
    }
1132
    
1133
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
1134
    {
1135
        DBConnection dbConn = null;
1136
        int serialNumber = -1;
1137
        
1138
        try {
1139
            // Get a database connection from the pool
1140
            dbConn = 
1141
                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
1142
            serialNumber = dbConn.getCheckOutSerialNumber();
1143

    
1144
            // remove existing values first
1145
            String delete = "delete from systemMetadataReplicationPolicy " + 
1146
            "where guid = ? and policy = ?";
1147
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1148
	        //data values
1149
	        stmt.setString(1, guid);
1150
	        stmt.setString(2, policy);
1151
	        //execute
1152
	        int deletedCount = stmt.executeUpdate();
1153
	        stmt.close();
1154
            
1155
            for (String memberNode: memberNodes) {
1156
	            // Execute the insert statement
1157
	            String insert = "insert into systemMetadataReplicationPolicy " + 
1158
	                "(guid, policy, member_node) " +
1159
	                "values (?, ?, ?)";
1160
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1161
	            
1162
	            //data values
1163
	            insertStatement.setString(1, guid);
1164
	            insertStatement.setString(2, policy);
1165
	            insertStatement.setString(3, memberNode);
1166
	            //execute
1167
	            int rows = insertStatement.executeUpdate();
1168
	            insertStatement.close();
1169
            }
1170
        } catch (SQLException e) {
1171
            logMetacat.error("SQL error while adding systemMetadataReplicationPolicy for: " + guid, e); 
1172
        } finally {
1173
            // Return database connection to the pool
1174
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1175
        }
1176
    }
1177
    
1178
    private void insertReplicationStatus(String guid, List<Replica> replicas) {
1179
        DBConnection dbConn = null;
1180
        int serialNumber = -1;
1181
        
1182
        try {
1183
            // Get a database connection from the pool
1184
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertReplicas");
1185
            serialNumber = dbConn.getCheckOutSerialNumber();
1186

    
1187
            // remove existing values first
1188
            String delete = "delete from systemMetadataReplicationStatus " + 
1189
            "where guid = ?";
1190
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1191
	        //data values
1192
	        stmt.setString(1, guid);
1193
	        //execute
1194
	        int deletedCount = stmt.executeUpdate();
1195
	        stmt.close();
1196
            
1197
	        if (replicas != null) {
1198
	            for (Replica replica: replicas) {
1199
		            // Execute the insert statement
1200
		            String insert = "insert into systemMetadataReplicationStatus " + 
1201
		                "(guid, member_node, status, date_verified) " +
1202
		                "values (?, ?, ?, ?)";
1203
		            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1204
		            
1205
		            //data values
1206
		            String memberNode = replica.getReplicaMemberNode().getValue();
1207
		            String status = replica.getReplicationStatus().toString();
1208
		            java.sql.Date sqlDate = new java.sql.Date(replica.getReplicaVerified().getTime());
1209
		            insertStatement.setString(1, guid);
1210
		            insertStatement.setString(2, memberNode);
1211
		            insertStatement.setString(3, status);
1212
		            insertStatement.setDate(4, sqlDate);
1213
	
1214
		            //execute
1215
		            int rows = insertStatement.executeUpdate();
1216
		            insertStatement.close();
1217
	            }
1218
	        }
1219
        } catch (SQLException e) {
1220
            logMetacat.error("SQL error while adding systemMetadataReplicationStatus for: " + guid, e); 
1221
        } finally {
1222
            // Return database connection to the pool
1223
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1224
        }
1225
    }
1226
    
1227
    /**
1228
     * Insert the system metadata fields into the db
1229
     * @param sm
1230
     * @throws McdbDocNotFoundException 
1231
     */
1232
    public void updateSystemMetadata(SystemMetadata sm) throws McdbDocNotFoundException {
1233
    	
1234
        Boolean replicationAllowed = false;
1235
		Integer numberReplicas = -1;
1236
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1237
    	if (replicationPolicy != null) {
1238
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1239
    		numberReplicas = replicationPolicy.getNumberReplicas();
1240
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1241
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1242
    	}
1243

    
1244
    	// the main systemMetadata fields
1245
		updateSystemMetadataFields(
1246
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1247
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1248
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1249
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1250
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1251
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1252
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1253
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1254
        sm.getIdentifier().getValue(),
1255
        sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1256
        sm.getSize(),
1257
        replicationAllowed, 
1258
        numberReplicas,
1259
        sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1260
        sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1261
        sm.getSerialVersion()
1262
        );
1263
        
1264
        String guid = sm.getIdentifier().getValue();
1265
        
1266
        // save replication policies
1267
        if (replicationPolicy != null) {
1268
		    List<String> nodes = null;
1269
		    String policy = null;
1270
		    
1271
		    // check for null 
1272
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1273
			    nodes = new ArrayList<String>();
1274
			    policy = "blocked";
1275
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1276
			    	nodes.add(node.getValue());
1277
			    }
1278
			    this.insertReplicationPolicy(guid, policy, nodes);
1279
		    }
1280
		    
1281
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1282
			    nodes = new ArrayList<String>();
1283
			    policy = "preferred";
1284
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1285
			    	nodes.add(node.getValue());
1286
			    }
1287
		        this.insertReplicationPolicy(guid, policy, nodes);
1288
		    }
1289
        }
1290
        
1291
        // save replica information
1292
        this.insertReplicationStatus(guid, sm.getReplicaList());
1293
        
1294
        // save access policy
1295
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1296
        if (accessPolicy != null) {
1297
        	try {
1298
				this.insertAccessPolicy(guid, accessPolicy);
1299
			} catch (AccessException e) {
1300
				throw new McdbDocNotFoundException(e);
1301
			}
1302
        }
1303
    }
1304
    
1305
    /**
1306
     * Creates Metacat access rules and inserts them
1307
     * @param accessPolicy
1308
     * @throws McdbDocNotFoundException
1309
     * @throws AccessException
1310
     */
1311
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1312
    	
1313
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1314
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1315
        	List<Subject> subjects = accessRule.getSubjectList();
1316
        	List<Permission> permissions = accessRule.getPermissionList();
1317
        	for (Subject subject: subjects) {
1318
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1319
        		accessDAO.setPrincipalName(subject.getValue());
1320
    			accessDAO.setGuid(guid);
1321
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1322
    			accessDAO.setPermOrder(AccessControlInterface.DENYFIRST);
1323
    			for (Permission permission: permissions) {
1324
    				Long metacatPermission = new Long(convertPermission(permission));
1325
        			accessDAO.addPermission(metacatPermission);
1326
    			}
1327
    			accessDAOs.add(accessDAO);
1328
        	}
1329
        }
1330
        
1331
        // use GUID to update
1332
        XMLAccessAccess accessController  = new XMLAccessAccess(true);
1333
        accessController.replaceAccess(guid, accessDAOs);
1334
        
1335
        
1336
    }
1337
    
1338
    /**
1339
     * Lookup access policy from Metacat
1340
     * @param guid
1341
     * @return
1342
     * @throws McdbDocNotFoundException
1343
     * @throws AccessException
1344
     */
1345
    private AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1346
        AccessPolicy accessPolicy = new AccessPolicy();
1347

    
1348
    	// use GUID to look up the access
1349
        XMLAccessAccess accessController  = new XMLAccessAccess(true);
1350
    	List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1351
        for (XMLAccessDAO accessDAO: accessDAOs) {
1352
        	AccessRule accessRule = new AccessRule();    	
1353
        	Permission permission = convertPermission(accessDAO.getPermission().intValue());
1354
        	accessRule.addPermission(permission);
1355
        	Subject subject = new Subject();
1356
        	subject.setValue(accessDAO.getPrincipalName());
1357
        	accessRule.addSubject(subject);
1358
            accessPolicy.addAllow(accessRule);
1359
        }
1360
        return accessPolicy;
1361
    }
1362
    
1363
    public int convertPermission(Permission permission) {
1364
    	if (permission.equals(Permission.READ)) {
1365
    		return AccessControlInterface.READ;
1366
    	}
1367
    	if (permission.equals(Permission.WRITE)) {
1368
    		return AccessControlInterface.WRITE;
1369
    	}
1370
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1371
    		return AccessControlInterface.CHMOD;
1372
    	}
1373
		return -1;
1374
    }
1375
    
1376
    public Permission convertPermission(int permission) {
1377
    	if (permission == AccessControlInterface.READ) {
1378
    		return Permission.READ;
1379
    	}
1380
    	if (permission == AccessControlInterface.WRITE) {
1381
    		return Permission.WRITE;
1382
    	}
1383
    	if (permission == AccessControlInterface.CHMOD) {
1384
    		return Permission.CHANGE_PERMISSION;
1385
    	}
1386
		return null;
1387
    }
1388
    
1389
    /**
1390
     * Lookup a localId given the GUID. If
1391
     * the identifier is not found, throw an exception.
1392
     * 
1393
     * @param guid the global identifier to look up
1394
     * @return String containing the corresponding LocalId
1395
     * @throws McdbDocNotFoundException if the identifier is not found
1396
     */
1397
    public String getLocalId(String guid) throws McdbDocNotFoundException {
1398
      
1399
      String db_guid = "";
1400
      String docid = "";
1401
      int rev = 0;
1402
      
1403
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1404
      
1405
      DBConnection dbConn = null;
1406
      int serialNumber = -1;
1407
      try {
1408
          // Get a database connection from the pool
1409
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1410
          serialNumber = dbConn.getCheckOutSerialNumber();
1411
          
1412
          // Execute the insert statement
1413
          PreparedStatement stmt = dbConn.prepareStatement(query);
1414
          stmt.setString(1, guid);
1415
          ResultSet rs = stmt.executeQuery();
1416
          if (rs.next()) {
1417
              db_guid = rs.getString(1);
1418
              docid = rs.getString(2);
1419
              rev = rs.getInt(3);
1420
              assert(db_guid.equals(guid));
1421
          } else {
1422
              throw new McdbDocNotFoundException("Document not found:" + guid);
1423
          }
1424
          stmt.close();
1425
      } catch (SQLException e) {
1426
          logMetacat.error("Error while looking up the local identifier: " 
1427
                  + e.getMessage());
1428
      } finally {
1429
          // Return database connection to the pool
1430
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1431
      }
1432
      return docid + "." + rev;
1433
    }
1434
    
1435
    /**
1436
     * query the systemmetadata table based on the given parameters
1437
     * @param startTime
1438
     * @param endTime
1439
     * @param objectFormat
1440
     * @param replicaStatus
1441
     * @param start
1442
     * @param count
1443
     * @return ObjectList
1444
     * @throws SQLException 
1445
     * @throws ServiceException 
1446
     * @throws PropertyNotFoundException 
1447
     */
1448
    public ObjectList querySystemMetadata(Date startTime, Date endTime, 
1449
            ObjectFormatIdentifier objectFormatId, boolean replicaStatus, int start, int count) throws SQLException, PropertyNotFoundException, ServiceException
1450
    {
1451
        ObjectList ol = new ObjectList();
1452
        int total = 0;
1453
        DBConnection dbConn = null;
1454
        int serialNumber = -1;
1455
        
1456
        try {
1457
            String sql = "select guid, date_uploaded, rights_holder, checksum, " +
1458
                "checksum_algorithm, origin_member_node, authoritive_member_node, " +
1459
                "date_modified, submitter, object_format, size from systemmetadata";
1460
            
1461
            boolean f1 = false;
1462
            boolean f2 = false;
1463
            boolean f3 = false;
1464
            
1465
            if (startTime != null) {
1466
                sql += " where systemmetadata.date_modified > ?";
1467
                f1 = true;
1468
            }
1469
            
1470
            if (endTime != null) {
1471
                if (!f1) {
1472
                    sql += " where systemmetadata.date_modified < ?";
1473
                }
1474
                else {
1475
                    sql += " and systemmetadata.date_modified < ?";
1476
                }
1477
                f2 = true;
1478
            }
1479
            
1480
            if (objectFormatId != null) {
1481
                if (!f1 && !f2) {
1482
                    sql += " where object_format = ?";
1483
                }
1484
                else {
1485
                    sql += " and object_format = ?";
1486
                }
1487
                f3 = true;
1488
            }
1489
            
1490
            if (replicaStatus) {
1491
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.memberNodeId");
1492
                if (!f1 && !f2 && !f3) {
1493
                    sql += " where authoritive_member_node != '" + currentNodeId.trim() + "'";
1494
                }
1495
                else {
1496
                    sql += " and authoritive_member_node != '" + currentNodeId.trim() + "'";
1497
                }
1498
            }
1499
            
1500
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1501
            serialNumber = dbConn.getCheckOutSerialNumber();
1502
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1503
            
1504
            if (f1 && f2 && f3) {
1505
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1506
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1507
                stmt.setString(3, objectFormatId.getValue());
1508
            }
1509
            else if (f1 && f2 && !f3) {
1510
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1511
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1512
            }
1513
            else if (f1 && !f2 && f3) {
1514
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1515
                stmt.setString(2, objectFormatId.getValue());
1516
            }
1517
            else if (f1 && !f2 && !f3) {
1518
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1519
            }
1520
            else if (!f1 && f2 && f3) {
1521
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1522
                stmt.setString(2, objectFormatId.getValue());
1523
            }
1524
            else if (!f1 && !f2 && f3) {
1525
                stmt.setString(1, objectFormatId.getValue());
1526
            }
1527
            else if (!f1 && f2 && !f3) {
1528
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1529
            }
1530
            
1531
            //logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1532
            
1533
            ResultSet rs = stmt.executeQuery();
1534
            for (int i=0; i<start; i++) {
1535
                if (rs.next()) {
1536
                    total++;
1537
                } else {
1538
                    break;
1539
                }
1540
            }
1541
            
1542
            int countIndex = 0;
1543
                        
1544
            while (rs.next()) {
1545
                total++;
1546
                if (countIndex >= count) {
1547
                	// allow unlimited (negative number for count)
1548
                	if (count > 0) {
1549
                		break;
1550
                	}
1551
                }
1552
                                
1553
                String guid = rs.getString(1);
1554
                //logMetacat.debug("query found doc with guid " + guid);
1555
                //Timestamp dateUploaded = rs.getTimestamp(2);
1556
                //String rightsHolder = rs.getString(3);
1557
                String checksum = rs.getString(4);
1558
                String checksumAlgorithm = rs.getString(5);
1559
                //String originMemberNode = rs.getString(6);
1560
                //String authoritiveMemberNode = rs.getString(7);
1561
                Timestamp dateModified = rs.getTimestamp(8);
1562
                //String submitter = rs.getString(9);
1563
                String fmtidStr = rs.getString(10);
1564
                String sz = rs.getString(11);
1565
                BigInteger size = new BigInteger("0");
1566
                
1567
                if (sz != null && !sz.trim().equals("")) {
1568
                    size = new BigInteger(rs.getString(11));
1569
                }
1570
                
1571
                ObjectInfo oi = new ObjectInfo();
1572
                
1573
                Identifier id = new Identifier();
1574
                id.setValue(guid);
1575
                oi.setIdentifier(id);
1576
                
1577
                if (dateModified != null) {
1578
                	oi.setDateSysMetadataModified(new Date(dateModified.getTime()));
1579
                }
1580
                
1581
                Checksum cs = new Checksum();
1582
                cs.setValue(checksum);
1583
                try {
1584
                	//cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1585
                    cs.setAlgorithm(checksumAlgorithm);
1586
                } catch (Exception e) {
1587
					logMetacat.error("could not parse checksum algorithm", e);
1588
					continue;
1589
				}
1590
                oi.setChecksum(cs);
1591
                
1592
                // set the format type
1593
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1594
            	fmtid.setValue(fmtidStr);
1595
                oi.setFormatId(fmtid);
1596
                
1597
//                try {
1598
//	                oi.setFmtid(ObjectFormatCache.getInstance().getFormat(fmtidStr).getFmtid());
1599
//                } catch (NotFound e) {
1600
//                	logMetacat.error("could not find object format: " + fmtidStr, e);
1601
//                	// skip this one
1602
//                	continue;
1603
//				}
1604
                                
1605
                oi.setSize(size);
1606
                
1607
                ol.addObjectInfo(oi);
1608
                countIndex++;
1609
            }
1610
            
1611
            // expend the resultset to get the total count of possible rows
1612
            while (rs.next()) { 
1613
                total++;
1614
            }
1615
        }
1616
        
1617
        finally {
1618
            // Return database connection to the pool
1619
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1620
        }
1621
        
1622
        ol.setStart(start);
1623
        ol.setCount(ol.sizeObjectInfoList());
1624
        ol.setTotal(total);
1625
        
1626
        return ol;
1627
    }
1628
    
1629
    /**
1630
     * create a mapping in the identifier table
1631
     * @param guid
1632
     * @param localId
1633
     */
1634
    public void createMapping(String guid, String localId)
1635
    {        
1636
        
1637
        int serialNumber = -1;
1638
        DBConnection dbConn = null;
1639
        try {
1640

    
1641
            // Parse the localId into scope and rev parts
1642
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1643
            String docid = acc.getDocid();
1644
            int rev = 1;
1645
            if (acc.getRev() != null) {
1646
              rev = (new Integer(acc.getRev()).intValue());
1647
            }
1648

    
1649
            // Get a database connection from the pool
1650
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1651
            serialNumber = dbConn.getCheckOutSerialNumber();
1652

    
1653
            // Execute the insert statement
1654
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1655
            PreparedStatement stmt = dbConn.prepareStatement(query);
1656
            stmt.setString(1, guid);
1657
            stmt.setString(2, docid);
1658
            stmt.setInt(3, rev);
1659
            logMetacat.debug("mapping query: " + stmt.toString());
1660
            int rows = stmt.executeUpdate();
1661

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

    
1692
            // Get a database connection from the pool
1693
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1694
            serialNumber = dbConn.getCheckOutSerialNumber();
1695

    
1696
            // Execute the insert statement
1697
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1698
            PreparedStatement stmt = dbConn.prepareStatement(query);
1699
            stmt.setString(1, guid);
1700
            logMetacat.debug("system metadata query: " + stmt.toString());
1701
            int rows = stmt.executeUpdate();
1702

    
1703
            stmt.close();
1704
        } catch (Exception e) {
1705
            e.printStackTrace();
1706
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1707
        } finally {
1708
            // Return database connection to the pool
1709
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1710
        }
1711
    }
1712
    
1713
    private void deleteSystemMetadata(String guid)
1714
    {        
1715
        
1716
        int serialNumber = -1;
1717
        DBConnection dbConn = null;
1718
        try {
1719

    
1720
            // Get a database connection from the pool
1721
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1722
            serialNumber = dbConn.getCheckOutSerialNumber();
1723

    
1724
            // Execute the statement
1725
            String query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1726
            PreparedStatement stmt = dbConn.prepareStatement(query);
1727
            stmt.setString(1, guid);
1728
            logMetacat.debug("delete system metadata: " + stmt.toString());
1729
            int rows = stmt.executeUpdate();
1730

    
1731
            stmt.close();
1732
        } catch (Exception e) {
1733
            e.printStackTrace();
1734
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1735
        } finally {
1736
            // Return database connection to the pool
1737
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1738
        }
1739
    }
1740
}
1741

    
(37-37/65)