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.sql.PreparedStatement;
28
import java.sql.ResultSet;
29
import java.sql.SQLException;
30
import java.sql.Timestamp;
31
import java.util.ArrayList;
32
import java.util.Date;
33
import java.util.Hashtable;
34
import java.util.List;
35
import java.util.Vector;
36

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

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

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

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

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

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

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

    
258
            // Execute the statement
259
            PreparedStatement stmt = dbConn.prepareStatement(sql);
260
            stmt.setString(1, guid);
261
            ResultSet rs = stmt.executeQuery();
262
            if (rs.next()) 
263
            {
264
                Timestamp dateUploaded = rs.getTimestamp(2);
265
                String rightsHolder = rs.getString(3);
266
                String checksum = rs.getString(4);
267
                String checksumAlgorithm = rs.getString(5);
268
                String originMemberNode = rs.getString(6);
269
                String authoritativeMemberNode = rs.getString(7);
270
                Timestamp dateModified = rs.getTimestamp(8);
271
                String submitter = rs.getString(9);
272
                String fmtidStr = rs.getString(10);
273
                long size = new Long(rs.getString(11)).longValue();
274
                
275
                Identifier sysMetaId = new Identifier();
276
                sysMetaId.setValue(guid);
277
                sysMeta.setIdentifier(sysMetaId);
278
                sysMeta.setDateUploaded(dateUploaded);
279
                Subject rightsHolderSubject = new Subject();
280
                rightsHolderSubject.setValue(rightsHolder);
281
                sysMeta.setRightsHolder(rightsHolderSubject);
282
                Checksum checksumObject = new Checksum();
283
                checksumObject.setValue(checksum);
284
                checksumObject.setAlgorithm(ChecksumAlgorithm.convert(checksumAlgorithm));
285
                sysMeta.setChecksum(checksumObject);
286
                NodeReference omn = new NodeReference();
287
                omn.setValue(originMemberNode);
288
                sysMeta.setOriginMemberNode(omn);
289
                NodeReference amn = new NodeReference();
290
                amn.setValue(authoritativeMemberNode);
291
                sysMeta.setAuthoritativeMemberNode(amn);
292
                sysMeta.setDateSysMetadataModified(dateModified);
293
                Subject submitterSubject = new Subject();
294
                submitterSubject.setValue(submitter);
295
                sysMeta.setSubmitter(submitterSubject);
296
                try {
297
        	        sysMeta.setObjectFormat(ObjectFormatCache.getInstance().getFormat(fmtidStr));
298
                } catch (NotFound nfe) {
299
                  logMetacat.error("The objectFormat " + fmtidStr +
300
                  	" is not registered. Setting the default format.");
301
                  ObjectFormat of = new ObjectFormat();
302
                  ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
303
                  fmtid.setValue("application/octet-stream");
304
                  of.setFmtid(fmtid);
305
                  of.setFormatName("Octet Stream");
306
                  sysMeta.setObjectFormat(of);
307
                }
308
                sysMeta.setSize(size);
309
                
310
                stmt.close();
311
            } 
312
            else
313
            {
314
                stmt.close();
315
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
316
                throw new McdbDocNotFoundException("Could not find " + guid);
317
            }
318
            
319
        } 
320
        catch (SQLException e) 
321
        {
322
            e.printStackTrace();
323
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "  
324
                    + e.getMessage());
325
        } 
326
        finally 
327
        {
328
            // Return database connection to the pool
329
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
330
        }
331
        
332
        // look up provenance information
333
        sysMeta.setObsoleteList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "obsoletes"));
334
        sysMeta.setObsoletedByList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "obsoletedBy"));
335
        sysMeta.setDescribeList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "describes"));
336
        sysMeta.setDescribedByList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "describedBy"));
337
        sysMeta.setDerivedFromList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "derivedFrom"));
338
        
339
        // look up replication policy
340
        ReplicationPolicy replicationPolicy = new ReplicationPolicy();
341
        replicationPolicy.setBlockedMemberNodeList(getReplicationPolicy(guid, "blocked"));
342
        replicationPolicy.setPreferredMemberNodeList(getReplicationPolicy(guid, "preferred"));
343
		sysMeta.setReplicationPolicy(replicationPolicy);
344
		
345
		// look up replication status
346
		sysMeta.setReplicaList(getReplicationStatus(guid));
347
		
348
		// look up access policy
349
		try {
350
			sysMeta.setAccessPolicy(getAccessPolicy(guid));
351
		} catch (AccessException e) {
352
			throw new McdbDocNotFoundException(e);
353
		}
354
        
355
        return sysMeta;
356
    }
357
    
358
    private List<Identifier> getSystemMetadataProvenance(String guid, String relationship)
359
    	throws McdbDocNotFoundException {
360
    	
361
    	List<Identifier> identifiers = new ArrayList<Identifier>();
362
    	String sql = "select guid, relationship, target_guid " +
363
    		"from systemMetadataProvenance where guid = ? and relationship = ?";
364
	    DBConnection dbConn = null;
365
	    int serialNumber = -1;
366
	    try {
367
	        // Get a database connection from the pool
368
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadataProvenance");
369
	        serialNumber = dbConn.getCheckOutSerialNumber();
370
	
371
	        // Execute the statement
372
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
373
	        stmt.setString(1, guid);
374
	        stmt.setString(2, relationship);
375
	        ResultSet rs = stmt.executeQuery();
376
	        while (rs.next()) 
377
	        {
378
	            String targetGuid = rs.getString(3);
379
	            Identifier id = new Identifier();
380
	            id.setValue(targetGuid);
381
	            identifiers.add(id);
382
	        
383
	        } 
384
	        stmt.close();
385
	        
386
	    } 
387
	    catch (SQLException e) {
388
	        logMetacat.error("Error while getting system metadata provenance for guid " + guid, e);
389
	    } 
390
	    finally {
391
	        // Return database connection to the pool
392
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
393
	    }
394
	    
395
	    return identifiers;
396
	}
397
    
398
    private List<NodeReference> getReplicationPolicy(String guid, String policy)
399
		throws McdbDocNotFoundException {
400
		
401
		List<NodeReference> nodes = new ArrayList<NodeReference>();
402
		String sql = "select guid, policy, member_node " +
403
			"from systemMetadataReplicationPolicy where guid = ? and policy = ?";
404
	    DBConnection dbConn = null;
405
	    int serialNumber = -1;
406
	    try {
407
	        // Get a database connection from the pool
408
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicationPolicy");
409
	        serialNumber = dbConn.getCheckOutSerialNumber();
410
	
411
	        // Execute the statement
412
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
413
	        stmt.setString(1, guid);
414
	        stmt.setString(2, policy);
415
	        ResultSet rs = stmt.executeQuery();
416
	        while (rs.next()) 
417
	        {
418
	            String memberNode = rs.getString(3);
419
	            NodeReference node = new NodeReference();
420
	            node.setValue(memberNode);
421
	            nodes.add(node);
422
	        
423
	        } 
424
	        stmt.close();
425
	        
426
	    } catch (SQLException e) {
427
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
428
	    } 
429
	    finally {
430
	        // Return database connection to the pool
431
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
432
	    }
433
	    
434
	    return nodes;
435
	}
436
    
437
    private List<Replica> getReplicationStatus(String guid) throws McdbDocNotFoundException {
438
		
439
		List<Replica> replicas = new ArrayList<Replica>();
440
		String sql = "select guid, member_node, status, date_verified " +
441
			"from systemMetadataReplicationStatus where guid = ?";
442
	    DBConnection dbConn = null;
443
	    int serialNumber = -1;
444
	    try {
445
	        // Get a database connection from the pool
446
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicas");
447
	        serialNumber = dbConn.getCheckOutSerialNumber();
448
	
449
	        // Execute the statement
450
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
451
	        stmt.setString(1, guid);
452
	        ResultSet rs = stmt.executeQuery();
453
	        while (rs.next()) 
454
	        {
455
	            String memberNode = rs.getString(2);
456
	            String status = rs.getString(3);
457
	            java.sql.Date verified = rs.getDate(4);
458
	            
459
	            Replica replica = new Replica();	            
460
	            NodeReference node = new NodeReference();
461
	            node.setValue(memberNode);
462
	            replica.setReplicaMemberNode(node);
463
	            replica.setReplicationStatus(ReplicationStatus.convert(status));
464
	            replica.setReplicaVerified(new Date(verified.getTime()));
465
	            replicas.add(replica);
466
	        } 
467
	        stmt.close();
468
	        
469
	    } catch (SQLException e) {
470
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
471
	    } 
472
	    finally {
473
	        // Return database connection to the pool
474
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
475
	    }
476
	    
477
	    return replicas;
478
	}
479
    
480
    /**
481
     * return information on the document with localId.  These are the fields
482
     * from the xml_documents table.  They can be used to contstruct metadata 
483
     * about the object that is stored.
484
     * @param localId
485
     * @return
486
     * @throws McdbDocNotFoundException
487
     */
488
    public Hashtable<String, Object> getDocumentInfo(String localId)
489
        throws McdbDocNotFoundException
490
    {
491
        try
492
        {
493
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
494
            localId = acc.getDocid();
495
        }
496
        catch(Exception e)
497
        {
498
            //do nothing. just try the localId as it is
499
        }
500
        Hashtable<String, Object> h = new Hashtable<String, Object>();
501
        String sql = "select docname, doctype, user_owner, user_updated, " +
502
            "server_location, rev, date_created, date_updated from " + 
503
            "xml_documents where docid like '" + localId + "'";
504
        DBConnection dbConn = null;
505
        int serialNumber = -1;
506
        try 
507
        {
508
            // Get a database connection from the pool
509
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getDocumentInfo");
510
            serialNumber = dbConn.getCheckOutSerialNumber();
511

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

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

    
653
            // Execute the insert statement
654
            PreparedStatement stmt = dbConn.prepareStatement(sql);
655
            ResultSet rs = stmt.executeQuery();
656
            while (rs.next()) 
657
            {
658
                String localid = rs.getString(1);
659
                String rev = rs.getString(2);
660
                localid += "." + rev;
661
                logMetacat.debug("id to add SM for: " + localid);
662
                ids.add(localid);
663
            } 
664
            stmt.close();
665
        } 
666
        catch (SQLException e) 
667
        {
668
            logMetacat.error("Error while looking up the guid: " 
669
                    + e.getMessage());
670
        } 
671
        finally 
672
        {
673
            // Return database connection to the pool
674
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
675
        }
676
        
677
        return ids;
678
    }
679
    
680
    /**
681
     * return a listing of all local ids in the object store
682
     * @return a list of all local ids in metacat
683
     */
684
    public List<String> getAllLocalIds()
685
       throws Exception
686
    {
687
        Vector<String> ids = new Vector<String>();
688
        String sql = "select docid from xml_documents";
689
        DBConnection dbConn = null;
690
        int serialNumber = -1;
691
        try 
692
        {
693
            // Get a database connection from the pool
694
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
695
            serialNumber = dbConn.getCheckOutSerialNumber();
696

    
697
            // Execute the insert statement
698
            PreparedStatement stmt = dbConn.prepareStatement(sql);
699
            ResultSet rs = stmt.executeQuery();
700
            while (rs.next()) 
701
            {
702
                String localid = rs.getString(1);
703
                ids.add(localid);
704
            } 
705
            stmt.close();
706
        } 
707
        catch (SQLException e) 
708
        {
709
            logMetacat.error("Error while looking up the guid: " 
710
                    + e.getMessage());
711
        } 
712
        finally 
713
        {
714
            // Return database connection to the pool
715
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
716
        }
717
        return ids;
718
    }
719
    
720
    /**
721
     * returns a list of system metadata-only guids since the given date
722
     * @return a list of system ids in metacat that do not correspond to objects
723
     * TODO: need to check which server they are on
724
     */
725
    public List<String> getUpdatedSystemMetadataIds(Date since)
726
       throws Exception
727
    {
728
        List<String> ids = new Vector<String>();
729
        String sql = 
730
        	"select guid from " + TYPE_SYSTEM_METADATA +
731
        	" where guid not in " +
732
        	" (select guid from " + TYPE_IDENTIFIER + ") " +
733
        	" and date_modified > ?";
734
        DBConnection dbConn = null;
735
        int serialNumber = -1;
736
        try 
737
        {
738
            // Get a database connection from the pool
739
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getUpdatedSystemMetadataIds");
740
            serialNumber = dbConn.getCheckOutSerialNumber();
741

    
742
            // Execute the insert statement
743
            PreparedStatement stmt = dbConn.prepareStatement(sql);
744
            stmt.setDate(1, new java.sql.Date(since.getTime()));
745
            ResultSet rs = stmt.executeQuery();
746
            while (rs.next()) 
747
            {
748
                String guid = rs.getString(1);
749
                ids.add(guid);
750
            } 
751
            stmt.close();
752
        } 
753
        catch (SQLException e) 
754
        {
755
            logMetacat.error("Error while looking up the updated guids: " 
756
                    + e.getMessage());
757
        } 
758
        finally 
759
        {
760
            // Return database connection to the pool
761
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
762
        }
763
        return ids;
764
    }
765
    
766

    
767
    
768
    /**
769
     * Determine if an identifier exists already, returning true if so.
770
     * 
771
     * @param guid the global identifier to look up
772
     * @return boolean true if the identifier exists
773
     */
774
    public boolean identifierExists(String guid)
775
    {
776
        boolean idExists = false;
777
        try {
778
            String id = getLocalId(guid);
779
            if (id != null) {
780
                idExists = true;
781
            }
782
        } catch (McdbDocNotFoundException e) {
783
        	// try system metadata only
784
        	try {
785
        		boolean provisional = false;
786
        		idExists = systemMetadataExisits(guid, provisional);
787
            } catch (McdbDocNotFoundException e2) {
788
            	idExists = false;
789
            }
790
        }
791
        return idExists;
792
    }
793
    
794
    public boolean hasReservation(Identifier pid, Session session) {
795
    	// check if it was reserved
796
      	boolean reserved = false;
797
      	try {
798
    		// check that we reserved it
799
    		if (IdentifierManager.getInstance().systemMetadataExisits(pid.getValue(), true)) {    		    	
800
    	    	SystemMetadata provisionalMetadata = IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
801
    	    	Subject rightsHolder = provisionalMetadata.getRightsHolder();
802
    	    	// TODO: check groups?
803
    	    	if (session.getSubject().equals(rightsHolder)) {
804
    	    		reserved = true;
805
    	    	}
806
    		}
807
    	} catch (McdbDocNotFoundException e) {
808
    		reserved = false;
809
    	}
810
    	return reserved;
811
      }
812
    
813
    /**
814
     * 
815
     * @param guid
816
     * @param rev
817
     * @return
818
     */
819
    public String generateLocalId(String guid, int rev)
820
    {
821
        return generateLocalId(guid, rev, false);
822
    }
823

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

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

    
934
			// Execute the insert statement
935
			PreparedStatement stmt = dbConn.prepareStatement(query);
936
			stmt.setString(1, guid);
937
			stmt.setBoolean(2, provisional);
938
			ResultSet rs = stmt.executeQuery();
939
			if (rs.next()) {
940
				exists = true;
941
			} else {
942
				throw new McdbDocNotFoundException(
943
						"No system metadata registered for guid " + guid);
944
			}
945

    
946
		} catch (SQLException e) {
947
			logMetacat.error("Error while looking up the system metadata: "
948
					+ e.getMessage());
949
		} finally {
950
			// Return database connection to the pool
951
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
952
		}
953

    
954
		return exists;
955
	}
956
    
957
    /**
958
     * creates a system metadata mapping and adds additional fields from sysmeta
959
     * to the table for quick searching.
960
     * 
961
     * @param guid the id to insert
962
     * @param localId the systemMetadata object to get the local id for
963
     * @throws McdbDocNotFoundException 
964
     */
965
    public void createSystemMetadata(SystemMetadata sysmeta) throws McdbDocNotFoundException
966
    {
967
    	String guid = sysmeta.getIdentifier().getValue();
968
    	// remove any provisional records -- it is the responsibility of the caller to check this
969
    	try {
970
	    	if (systemMetadataExisits(guid, true)) {
971
	    		deleteSystemMetadata(guid);
972
	    	}
973
    	} catch (McdbDocNotFoundException e) {
974
			// ignore
975
		}
976
    	// insert the true record
977
        insertSystemMetadata(guid, false);
978
        updateSystemMetadata(sysmeta);
979
    }
980
        
981
    
982
    /**
983
     * update a mapping
984
     * @param guid
985
     * @param localId
986
     */
987
    public void updateMapping(String guid, String localId)
988
    {
989
    	
990
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
991
        int serialNumber = -1;
992
        DBConnection dbConn = null;
993
        try {
994
            // Parse the localId into scope and rev parts
995
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
996
            String docid = acc.getDocid();
997
            int rev = 1;
998
            if(acc.getRev() != null)
999
            {
1000
              rev = (new Integer(acc.getRev()).intValue());
1001
            }
1002

    
1003
            // Get a database connection from the pool
1004
            dbConn = 
1005
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1006
            serialNumber = dbConn.getCheckOutSerialNumber();
1007

    
1008
            // Execute the update statement
1009
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid='" + guid + "'";
1010
            PreparedStatement stmt = dbConn.prepareStatement(query);
1011
            stmt.setString(1, docid);
1012
            stmt.setInt(2, rev);
1013
            int rows = stmt.executeUpdate();
1014

    
1015
            stmt.close();
1016
        } catch (SQLException e) {
1017
            e.printStackTrace();
1018
            logMetacat.error("SQL error while updating a mapping identifier: " 
1019
                    + e.getMessage());
1020
        } catch (NumberFormatException e) {
1021
            e.printStackTrace();
1022
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1023
                    + e.getMessage());
1024
        } catch (AccessionNumberException e) {
1025
            e.printStackTrace();
1026
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1027
                    + e.getMessage());
1028
        } finally {
1029
            // Return database connection to the pool
1030
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1031
        }
1032
        logMetacat.debug("done updating mapping");
1033
    }
1034
        
1035
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1036
            String checksum, String checksumAlgorithm, String originMemberNode,
1037
            String authoritativeMemberNode, long modifiedDate, String submitter, 
1038
            String guid, String objectFormat, long size, boolean replicationAllowed,
1039
            int numberReplicas)
1040
    {
1041
        DBConnection dbConn = null;
1042
        int serialNumber = -1;
1043
        
1044
        try {
1045
            // Get a database connection from the pool
1046
            dbConn = 
1047
                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1048
            serialNumber = dbConn.getCheckOutSerialNumber();
1049

    
1050
            // Execute the insert statement
1051
            String query = "update " + TYPE_SYSTEM_METADATA + 
1052
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1053
                "origin_member_node, authoritive_member_node, date_modified, " +
1054
                "submitter, object_format, size, replication_allowed, number_replicas) " +
1055
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1056
            PreparedStatement stmt = dbConn.prepareStatement(query);
1057
            
1058
            //data values
1059
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1060
            stmt.setString(2, rightsHolder);
1061
            stmt.setString(3, checksum);
1062
            stmt.setString(4, checksumAlgorithm);
1063
            stmt.setString(5, originMemberNode);
1064
            stmt.setString(6, authoritativeMemberNode);
1065
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1066
            stmt.setString(8, submitter);
1067
            stmt.setString(9, objectFormat);
1068
            stmt.setString(10, new Long(size).toString());
1069
            stmt.setBoolean(11, replicationAllowed);
1070
            stmt.setInt(12, numberReplicas);
1071
            //where clause
1072
            stmt.setString(13, guid);
1073
            logMetacat.debug("stmt: " + stmt.toString());
1074
            //execute
1075
            int rows = stmt.executeUpdate();
1076

    
1077
            stmt.close();
1078
        } catch (SQLException e) {
1079
            e.printStackTrace();
1080
            logMetacat.error("insertAdditionalSystemMetadataFields: SQL error while creating a mapping to the system metadata identifier: " 
1081
                    + e.getMessage());
1082
        } catch (NumberFormatException e) {
1083
            e.printStackTrace();
1084
            logMetacat.error("insertAdditionalSystemMetadataFields: NumberFormat error while creating a mapping to the system metadata identifier: " 
1085
                    + e.getMessage());
1086
        } finally {
1087
            // Return database connection to the pool
1088
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1089
        }
1090
    }
1091
    
1092
    public void setProvisional(String guid, boolean provisional) {
1093
        DBConnection dbConn = null;
1094
        int serialNumber = -1;
1095
        
1096
        try {
1097
            // Get a database connection from the pool
1098
            dbConn = 
1099
                DBConnectionPool.getDBConnection("IdentifierManager.setProvisional");
1100
            serialNumber = dbConn.getCheckOutSerialNumber();
1101

    
1102
            // Execute the insert statement
1103
            String query = "update " + TYPE_SYSTEM_METADATA + 
1104
                " set provisional = ? where guid = ?";
1105
            PreparedStatement stmt = dbConn.prepareStatement(query);
1106
            
1107
            //data values
1108
            stmt.setBoolean(1, provisional);
1109
            //where clause
1110
            stmt.setString(2, guid);
1111
            logMetacat.debug("stmt: " + stmt.toString());
1112
            //execute
1113
            int rows = stmt.executeUpdate();
1114

    
1115
            stmt.close();
1116
        } catch (SQLException e) {
1117
            e.printStackTrace();
1118
            logMetacat.error("setProvisional: SQL error while creating a mapping to the system metadata identifier: " 
1119
                    + e.getMessage());
1120
        } finally {
1121
            // Return database connection to the pool
1122
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1123
        }
1124
    }
1125
    
1126
    private void insertSystemMetadataProvenance(String guid, String relationship, List<String> targetGuids)
1127
    {
1128
        DBConnection dbConn = null;
1129
        int serialNumber = -1;
1130
        
1131
        try {
1132
            // Get a database connection from the pool
1133
            dbConn = 
1134
                DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadataProvenance");
1135
            serialNumber = dbConn.getCheckOutSerialNumber();
1136

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

    
1182
            // remove existing values first
1183
            String delete = "delete from systemMetadataReplicationPolicy " + 
1184
            "where guid = ? and policy = ?";
1185
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1186
	        //data values
1187
	        stmt.setString(1, guid);
1188
	        stmt.setString(2, policy);
1189
	        //execute
1190
	        int deletedCount = stmt.executeUpdate();
1191
	        stmt.close();
1192
            
1193
            for (String memberNode: memberNodes) {
1194
	            // Execute the insert statement
1195
	            String insert = "insert into systemMetadataReplicationPolicy " + 
1196
	                "(guid, policy, member_node) " +
1197
	                "values (?, ?, ?)";
1198
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1199
	            
1200
	            //data values
1201
	            insertStatement.setString(1, guid);
1202
	            insertStatement.setString(2, policy);
1203
	            insertStatement.setString(3, memberNode);
1204
	            //execute
1205
	            int rows = insertStatement.executeUpdate();
1206
	            insertStatement.close();
1207
            }
1208
        } catch (SQLException e) {
1209
            logMetacat.error("SQL error while adding systemMetadataReplicationPolicy for: " + guid, e); 
1210
        } finally {
1211
            // Return database connection to the pool
1212
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1213
        }
1214
    }
1215
    
1216
    private void insertReplicationStatus(String guid, List<Replica> replicas) {
1217
        DBConnection dbConn = null;
1218
        int serialNumber = -1;
1219
        
1220
        try {
1221
            // Get a database connection from the pool
1222
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertReplicas");
1223
            serialNumber = dbConn.getCheckOutSerialNumber();
1224

    
1225
            // remove existing values first
1226
            String delete = "delete from systemMetadataReplicationStatus " + 
1227
            "where guid = ?";
1228
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1229
	        //data values
1230
	        stmt.setString(1, guid);
1231
	        //execute
1232
	        int deletedCount = stmt.executeUpdate();
1233
	        stmt.close();
1234
            
1235
            for (Replica replica: replicas) {
1236
	            // Execute the insert statement
1237
	            String insert = "insert into systemMetadataReplicationStatus " + 
1238
	                "(guid, member_node, status, date_verified) " +
1239
	                "values (?, ?, ?, ?)";
1240
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1241
	            
1242
	            //data values
1243
	            String memberNode = replica.getReplicaMemberNode().getValue();
1244
	            String status = replica.getReplicationStatus().toString();
1245
	            java.sql.Date sqlDate = new java.sql.Date(replica.getReplicaVerified().getTime());
1246
	            insertStatement.setString(1, guid);
1247
	            insertStatement.setString(2, memberNode);
1248
	            insertStatement.setString(3, status);
1249
	            insertStatement.setDate(4, sqlDate);
1250

    
1251
	            //execute
1252
	            int rows = insertStatement.executeUpdate();
1253
	            insertStatement.close();
1254
            }
1255
        } catch (SQLException e) {
1256
            logMetacat.error("SQL error while adding systemMetadataReplicationStatus for: " + guid, e); 
1257
        } finally {
1258
            // Return database connection to the pool
1259
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1260
        }
1261
    }
1262
    
1263
    /**
1264
     * Insert the system metadata fields into the db
1265
     * @param sm
1266
     * @throws McdbDocNotFoundException 
1267
     */
1268
    public void updateSystemMetadata(SystemMetadata sm) throws McdbDocNotFoundException {
1269
    	
1270
        Boolean replicationAllowed = false;
1271
		Integer numberReplicas = -1;
1272
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1273
    	if (replicationPolicy != null) {
1274
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1275
    		numberReplicas = replicationPolicy.getNumberReplicas();
1276
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1277
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1278
    	}
1279

    
1280
    	// the main systemMetadata fields
1281
		updateSystemMetadataFields(
1282
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1283
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1284
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1285
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm().name(), 
1286
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1287
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1288
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1289
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1290
                sm.getIdentifier().getValue(),
1291
                sm.getObjectFormat() == null ? null: sm.getObjectFormat().getFmtid().getValue(),
1292
                sm.getSize(),
1293
                replicationAllowed, 
1294
                numberReplicas);
1295
        
1296
        // add provenance information
1297
        String guid = sm.getIdentifier().getValue();
1298
        List<Identifier> idList = null;
1299
        List<String> targetGuids = null;
1300
        String relationship = null;
1301
        
1302
        relationship = "obsoletedBy";
1303
        targetGuids = new ArrayList<String>();
1304
        idList = sm.getObsoletedByList();
1305
        if (idList != null) {
1306
	        for (Identifier id: idList) {
1307
	        	targetGuids.add(id.getValue());
1308
	        }
1309
	        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
1310
        }
1311
        relationship = "obsoletes";
1312
        targetGuids = new ArrayList<String>();
1313
        idList = sm.getObsoleteList();
1314
        if (idList != null) {
1315
	        for (Identifier id: idList) {
1316
	        	targetGuids.add(id.getValue());
1317
	        }
1318
	        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
1319
        }
1320
        
1321
        relationship = "describes";
1322
        targetGuids = new ArrayList<String>();
1323
        idList = sm.getDescribeList();
1324
        if (idList != null) {
1325
	        for (Identifier id: idList) {
1326
	        	targetGuids.add(id.getValue());
1327
	        }
1328
	        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
1329
        }
1330
        
1331
        relationship = "describedBy";
1332
        targetGuids = new ArrayList<String>();
1333
        idList = sm.getDescribedByList();
1334
        if (idList != null) {
1335
	        for (Identifier id: idList) {
1336
	        	targetGuids.add(id.getValue());
1337
	        }
1338
	        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
1339
        }
1340
        
1341
        relationship = "derivedFrom";
1342
        targetGuids = new ArrayList<String>();
1343
        idList = sm.getDerivedFromList();
1344
        if (idList != null) {
1345
	        for (Identifier id: idList) {
1346
	        	targetGuids.add(id.getValue());
1347
	        }
1348
	        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
1349
        }
1350
                
1351
        // save replication policies
1352
        if (replicationPolicy != null) {
1353
		    List<String> nodes = null;
1354
		    String policy = null;
1355
		    
1356
		    nodes = new ArrayList<String>();
1357
		    policy = "blocked";
1358
		    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1359
		    	nodes.add(node.getValue());
1360
		    }
1361
		    this.insertReplicationPolicy(guid, policy, nodes);
1362
		    
1363
		    nodes = new ArrayList<String>();
1364
		    policy = "preferred";
1365
		    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1366
		    	nodes.add(node.getValue());
1367
		    }
1368
	        this.insertReplicationPolicy(guid, policy, nodes);
1369
        }
1370
        
1371
        // save replica information
1372
        this.insertReplicationStatus(guid, sm.getReplicaList());
1373
        
1374
        // save access policy
1375
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1376
        if (accessPolicy != null) {
1377
        	try {
1378
				this.insertAccessPolicy(guid, accessPolicy);
1379
			} catch (AccessException e) {
1380
				throw new McdbDocNotFoundException(e);
1381
			}
1382
        }
1383
    }
1384
    
1385
    /**
1386
     * Creates Metacat access rules and inserts them
1387
     * @param accessPolicy
1388
     * @throws McdbDocNotFoundException
1389
     * @throws AccessException
1390
     */
1391
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1392
    	
1393
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1394
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1395
        	List<Subject> subjects = accessRule.getSubjectList();
1396
        	List<Permission> permissions = accessRule.getPermissionList();
1397
        	for (Subject subject: subjects) {
1398
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1399
        		accessDAO.setPrincipalName(subject.getValue());
1400
    			accessDAO.setGuid(guid);
1401
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1402
    			accessDAO.setPermOrder(AccessControlInterface.DENYFIRST);
1403
    			for (Permission permission: permissions) {
1404
    				Long metacatPermission = new Long(convertPermission(permission));
1405
        			accessDAO.addPermission(metacatPermission);
1406
    			}
1407
    			accessDAOs.add(accessDAO);
1408
        	}
1409
        }
1410
        
1411
        // use GUID to update
1412
        XMLAccessAccess accessController  = new XMLAccessAccess(true);
1413
        accessController.replaceAccess(guid, accessDAOs);
1414
        
1415
        
1416
    }
1417
    
1418
    /**
1419
     * Lookup access policy from Metacat
1420
     * @param guid
1421
     * @return
1422
     * @throws McdbDocNotFoundException
1423
     * @throws AccessException
1424
     */
1425
    private AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1426
    	// use GUID to look up the access
1427
        XMLAccessAccess accessController  = new XMLAccessAccess(true);
1428
    	List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1429
    	AccessRule accessRule = new AccessRule();    	
1430
        for (XMLAccessDAO accessDAO: accessDAOs) {
1431
        	Permission permission = convertPermission(accessDAO.getPermission().intValue());
1432
        	accessRule.addPermission(permission);
1433
        	Subject subject = new Subject();
1434
        	subject.setValue(accessDAO.getPrincipalName());
1435
        	accessRule.addSubject(subject);
1436
        }
1437
        AccessPolicy accessPolicy = new AccessPolicy();
1438
        accessPolicy.addAllow(accessRule);
1439
        return accessPolicy;
1440
    }
1441
    
1442
    public int convertPermission(Permission permission) {
1443
    	if (permission.equals(Permission.READ)) {
1444
    		return AccessControlInterface.READ;
1445
    	}
1446
    	if (permission.equals(Permission.WRITE)) {
1447
    		return AccessControlInterface.WRITE;
1448
    	}
1449
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1450
    		return AccessControlInterface.CHMOD;
1451
    	}
1452
		return -1;
1453
    }
1454
    
1455
    public Permission convertPermission(int permission) {
1456
    	if (permission == AccessControlInterface.READ) {
1457
    		return Permission.READ;
1458
    	}
1459
    	if (permission == AccessControlInterface.WRITE) {
1460
    		return Permission.WRITE;
1461
    	}
1462
    	if (permission == AccessControlInterface.CHMOD) {
1463
    		return Permission.CHANGE_PERMISSION;
1464
    	}
1465
		return null;
1466
    }
1467
    
1468
    /**
1469
     * Lookup a localId given the GUID. If
1470
     * the identifier is not found, throw an exception.
1471
     * 
1472
     * @param guid the global identifier to look up
1473
     * @return String containing the corresponding LocalId
1474
     * @throws McdbDocNotFoundException if the identifier is not found
1475
     */
1476
    public String getLocalId(String guid) throws McdbDocNotFoundException {
1477
      
1478
      String db_guid = "";
1479
      String docid = "";
1480
      int rev = 0;
1481
      
1482
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1483
      
1484
      DBConnection dbConn = null;
1485
      int serialNumber = -1;
1486
      try {
1487
          // Get a database connection from the pool
1488
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1489
          serialNumber = dbConn.getCheckOutSerialNumber();
1490
          
1491
          // Execute the insert statement
1492
          PreparedStatement stmt = dbConn.prepareStatement(query);
1493
          stmt.setString(1, guid);
1494
          ResultSet rs = stmt.executeQuery();
1495
          if (rs.next()) {
1496
              db_guid = rs.getString(1);
1497
              docid = rs.getString(2);
1498
              rev = rs.getInt(3);
1499
              assert(db_guid.equals(guid));
1500
          } else {
1501
              throw new McdbDocNotFoundException("Document not found:" + guid);
1502
          }
1503
          stmt.close();
1504
      } catch (SQLException e) {
1505
          logMetacat.error("Error while looking up the local identifier: " 
1506
                  + e.getMessage());
1507
      } finally {
1508
          // Return database connection to the pool
1509
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1510
      }
1511
      return docid + "." + rev;
1512
    }
1513
    
1514
    /**
1515
     * query the systemmetadata table based on the given parameters
1516
     * @param startTime
1517
     * @param endTime
1518
     * @param objectFormat
1519
     * @param replicaStatus
1520
     * @param start
1521
     * @param count
1522
     * @return ObjectList
1523
     * @throws SQLException 
1524
     * @throws ServiceException 
1525
     * @throws PropertyNotFoundException 
1526
     */
1527
    public ObjectList querySystemMetadata(Date startTime, Date endTime, 
1528
            ObjectFormat objectFormat, boolean replicaStatus, int start, int count) throws SQLException, PropertyNotFoundException, ServiceException
1529
    {
1530
        ObjectList ol = new ObjectList();
1531
        int total = 0;
1532
        DBConnection dbConn = null;
1533
        int serialNumber = -1;
1534
        
1535
        try {
1536
            String sql = "select guid, date_uploaded, rights_holder, checksum, " +
1537
                "checksum_algorithm, origin_member_node, authoritive_member_node, " +
1538
                "date_modified, submitter, object_format, size from systemmetadata";
1539
            
1540
            boolean f1 = false;
1541
            boolean f2 = false;
1542
            boolean f3 = false;
1543
            
1544
            if (startTime != null) {
1545
                sql += " where systemmetadata.date_modified > ?";
1546
                f1 = true;
1547
            }
1548
            
1549
            if (endTime != null) {
1550
                if (!f1) {
1551
                    sql += " where systemmetadata.date_modified < ?";
1552
                }
1553
                else {
1554
                    sql += " and systemmetadata.date_modified < ?";
1555
                }
1556
                f2 = true;
1557
            }
1558
            
1559
            if (objectFormat != null) {
1560
                if (!f1 && !f2) {
1561
                    sql += " where object_format = ?";
1562
                }
1563
                else {
1564
                    sql += " and object_format = ?";
1565
                }
1566
                f3 = true;
1567
            }
1568
            
1569
            if (replicaStatus) {
1570
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.memberNodeId");
1571
                if (!f1 && !f2 && !f3) {
1572
                    sql += " where authoritive_member_node != '" + currentNodeId.trim() + "'";
1573
                }
1574
                else {
1575
                    sql += " and authoritive_member_node != '" + currentNodeId.trim() + "'";
1576
                }
1577
            }
1578
            
1579
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1580
            serialNumber = dbConn.getCheckOutSerialNumber();
1581
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1582
            
1583
            if (f1 && f2 && f3) {
1584
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1585
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1586
                stmt.setString(3, objectFormat.getFmtid().getValue());
1587
            }
1588
            else if (f1 && f2 && !f3) {
1589
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1590
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1591
            }
1592
            else if (f1 && !f2 && f3) {
1593
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1594
                stmt.setString(2, objectFormat.getFmtid().getValue());
1595
            }
1596
            else if (f1 && !f2 && !f3) {
1597
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1598
            }
1599
            else if (!f1 && f2 && f3) {
1600
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1601
                stmt.setString(2, objectFormat.getFmtid().getValue());
1602
            }
1603
            else if (!f1 && !f2 && f3) {
1604
                stmt.setString(1, objectFormat.getFmtid().getValue());
1605
            }
1606
            else if (!f1 && f2 && !f3) {
1607
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1608
            }
1609
            
1610
            //logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1611
            
1612
            ResultSet rs = stmt.executeQuery();
1613
            for (int i=0; i<start; i++) {
1614
                if (rs.next()) {
1615
                    total++;
1616
                } else {
1617
                    break;
1618
                }
1619
            }
1620
            
1621
            int countIndex = 0;
1622
                        
1623
            while (rs.next()) {
1624
                total++;
1625
                if (countIndex >= count) {
1626
                	// allow unlimited (negative number for count)
1627
                	if (count > 0) {
1628
                		break;
1629
                	}
1630
                }
1631
                                
1632
                String guid = rs.getString(1);
1633
                //logMetacat.debug("query found doc with guid " + guid);
1634
                //Timestamp dateUploaded = rs.getTimestamp(2);
1635
                //String rightsHolder = rs.getString(3);
1636
                String checksum = rs.getString(4);
1637
                String checksumAlgorithm = rs.getString(5);
1638
                //String originMemberNode = rs.getString(6);
1639
                //String authoritiveMemberNode = rs.getString(7);
1640
                Timestamp dateModified = rs.getTimestamp(8);
1641
                //String submitter = rs.getString(9);
1642
                String fmtidStr = rs.getString(10);
1643
                String sz = rs.getString(11);
1644
                long size = 0;
1645
                
1646
                if (sz != null && !sz.trim().equals("")) {
1647
                    size = new Long(rs.getString(11)).longValue();
1648
                }
1649
                
1650
                ObjectInfo oi = new ObjectInfo();
1651
                
1652
                Identifier id = new Identifier();
1653
                id.setValue(guid);
1654
                oi.setIdentifier(id);
1655
                
1656
                if (dateModified != null) {
1657
                	oi.setDateSysMetadataModified(new Date(dateModified.getTime()));
1658
                }
1659
                
1660
                Checksum cs = new Checksum();
1661
                cs.setValue(checksum);
1662
                try {
1663
                	cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1664
                    //cs.setAlgorithm(ChecksumAlgorithm.convert(checksumAlgorithm));
1665
                } catch (Exception e) {
1666
					logMetacat.warn("could not parse checksum algorithm", e);
1667
				}
1668
                oi.setChecksum(cs);
1669
                
1670
                try {
1671
	                oi.setObjectFormat(ObjectFormatCache.getInstance().getFormat(fmtidStr));
1672
                } catch (NotFound e) {
1673
                	logMetacat.warn("could not find object format: " + fmtidStr, e);
1674
				}
1675
                                
1676
                oi.setSize(size);
1677
                
1678
                ol.addObjectInfo(oi);
1679
                countIndex++;
1680
            }
1681
            
1682
            // expend the resultset to get the total count of possible rows
1683
            while (rs.next()) { 
1684
                total++;
1685
            }
1686
        }
1687
        
1688
        finally {
1689
            // Return database connection to the pool
1690
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1691
        }
1692
        
1693
        ol.setStart(start);
1694
        ol.setCount(ol.sizeObjectInfoList());
1695
        ol.setTotal(total);
1696
        
1697
        return ol;
1698
    }
1699
    
1700
    /**
1701
     * create a mapping in the identifier table
1702
     * @param guid
1703
     * @param localId
1704
     */
1705
    public void createMapping(String guid, String localId)
1706
    {        
1707
        
1708
        int serialNumber = -1;
1709
        DBConnection dbConn = null;
1710
        try {
1711

    
1712
            // Parse the localId into scope and rev parts
1713
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1714
            String docid = acc.getDocid();
1715
            int rev = 1;
1716
            if (acc.getRev() != null) {
1717
              rev = (new Integer(acc.getRev()).intValue());
1718
            }
1719

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

    
1724
            // Execute the insert statement
1725
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1726
            PreparedStatement stmt = dbConn.prepareStatement(query);
1727
            stmt.setString(1, guid);
1728
            stmt.setString(2, docid);
1729
            stmt.setInt(3, rev);
1730
            logMetacat.debug("mapping query: " + stmt.toString());
1731
            int rows = stmt.executeUpdate();
1732

    
1733
            stmt.close();
1734
        } catch (SQLException e) {
1735
            e.printStackTrace();
1736
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1737
                    + e.getMessage());
1738
        } catch (NumberFormatException e) {
1739
            e.printStackTrace();
1740
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1741
                    + e.getMessage());
1742
        } catch (AccessionNumberException e) {
1743
            e.printStackTrace();
1744
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1745
                    + e.getMessage());
1746
        } finally {
1747
            // Return database connection to the pool
1748
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1749
        }
1750
    }
1751
    
1752
    /**
1753
     * create the systemmetadata record
1754
     * @param guid
1755
     */
1756
    private void insertSystemMetadata(String guid, boolean provisional)
1757
    {        
1758
        
1759
        int serialNumber = -1;
1760
        DBConnection dbConn = null;
1761
        try {
1762

    
1763
            // Get a database connection from the pool
1764
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1765
            serialNumber = dbConn.getCheckOutSerialNumber();
1766

    
1767
            // Execute the insert statement
1768
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid, provisional) values (?, ?)";
1769
            PreparedStatement stmt = dbConn.prepareStatement(query);
1770
            stmt.setString(1, guid);
1771
            stmt.setBoolean(2, provisional);
1772
            logMetacat.debug("system metadata query: " + stmt.toString());
1773
            int rows = stmt.executeUpdate();
1774

    
1775
            stmt.close();
1776
        } catch (Exception e) {
1777
            e.printStackTrace();
1778
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1779
        } finally {
1780
            // Return database connection to the pool
1781
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1782
        }
1783
    }
1784
    
1785
    private void deleteSystemMetadata(String guid)
1786
    {        
1787
        
1788
        int serialNumber = -1;
1789
        DBConnection dbConn = null;
1790
        try {
1791

    
1792
            // Get a database connection from the pool
1793
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1794
            serialNumber = dbConn.getCheckOutSerialNumber();
1795

    
1796
            // Execute the statement
1797
            String query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1798
            PreparedStatement stmt = dbConn.prepareStatement(query);
1799
            stmt.setString(1, guid);
1800
            logMetacat.debug("delete system metadata: " + stmt.toString());
1801
            int rows = stmt.executeUpdate();
1802

    
1803
            stmt.close();
1804
        } catch (Exception e) {
1805
            e.printStackTrace();
1806
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1807
        } finally {
1808
            // Return database connection to the pool
1809
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1810
        }
1811
    }
1812
}
1813

    
(37-37/65)