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.util.DocumentUtil;
66

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1101
            // remove existing values first
1102
            String delete = "delete from systemMetadataProvenance " + 
1103
            "where guid = ? and relationship = ?";
1104
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1105
	        //data values
1106
	        stmt.setString(1, guid);
1107
	        stmt.setString(2, relationship);
1108
	        //execute
1109
	        int deletedCount = stmt.executeUpdate();
1110
	        stmt.close();
1111
            
1112
            for (String targetGuid: targetGuids) {
1113
	            // Execute the insert statement
1114
	            String insert = "insert into systemMetadataProvenance " + 
1115
	                "(guid, relationship, target_guid) " +
1116
	                "values (?, ?, ?)";
1117
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1118
	            
1119
	            //data values
1120
	            insertStatement.setString(1, guid);
1121
	            insertStatement.setString(2, relationship);
1122
	            insertStatement.setString(3, targetGuid);
1123
	            //execute
1124
	            int rows = insertStatement.executeUpdate();
1125
	            insertStatement.close();
1126
            }
1127
        } catch (SQLException e) {
1128
            logMetacat.error("SQL error while adding systemMetadataProvenance for: " + guid, e); 
1129
        } finally {
1130
            // Return database connection to the pool
1131
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1132
        }
1133
    }
1134
    
1135
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
1136
    {
1137
        DBConnection dbConn = null;
1138
        int serialNumber = -1;
1139
        
1140
        try {
1141
            // Get a database connection from the pool
1142
            dbConn = 
1143
                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
1144
            serialNumber = dbConn.getCheckOutSerialNumber();
1145

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

    
1189
            // remove existing values first
1190
            String delete = "delete from systemMetadataReplicationStatus " + 
1191
            "where guid = ?";
1192
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1193
	        //data values
1194
	        stmt.setString(1, guid);
1195
	        //execute
1196
	        int deletedCount = stmt.executeUpdate();
1197
	        stmt.close();
1198
            
1199
            for (Replica replica: replicas) {
1200
	            // Execute the insert statement
1201
	            String insert = "insert into systemMetadataReplicationStatus " + 
1202
	                "(guid, member_node, status, date_verified) " +
1203
	                "values (?, ?, ?, ?)";
1204
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1205
	            
1206
	            //data values
1207
	            String memberNode = replica.getReplicaMemberNode().getValue();
1208
	            String status = replica.getReplicationStatus().toString();
1209
	            java.sql.Date sqlDate = new java.sql.Date(replica.getReplicaVerified().getTime());
1210
	            insertStatement.setString(1, guid);
1211
	            insertStatement.setString(2, memberNode);
1212
	            insertStatement.setString(3, status);
1213
	            insertStatement.setDate(4, sqlDate);
1214

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

    
1634
                } catch (NotFound nfe) {
1635
                  oi.setObjectFormat(ObjectFormatCache.getInstance().getFormat("application/octet-stream"));
1636
	
1637
                }
1638
                                
1639
                oi.setSize(size);
1640
                
1641
                ol.addObjectInfo(oi);
1642
                countIndex++;
1643
            }
1644
            
1645
            while(rs.next())
1646
            { //expend the resultset to get the total count of possible rows
1647
                total++;
1648
            }
1649
        }
1650
        catch(Exception e)
1651
        {
1652
           e.printStackTrace();
1653
           logMetacat.error("Error querying system metadata: " + e.getMessage());
1654
        }
1655
        finally 
1656
        {
1657
            // Return database connection to the pool
1658
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1659
        }
1660
        
1661
        ol.setStart(start);
1662
        ol.setCount(ol.sizeObjectInfoList());
1663
        ol.setTotal(total);
1664
        
1665
        return ol;
1666
    }
1667
    
1668
    /**
1669
     * create a mapping in the identifier table
1670
     * @param guid
1671
     * @param localId
1672
     */
1673
    public void createMapping(String guid, String localId)
1674
    {        
1675
        
1676
        int serialNumber = -1;
1677
        DBConnection dbConn = null;
1678
        try {
1679

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

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

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

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

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

    
1735
            // Execute the insert statement
1736
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid, provisional) values (?, ?)";
1737
            PreparedStatement stmt = dbConn.prepareStatement(query);
1738
            stmt.setString(1, guid);
1739
            stmt.setBoolean(2, provisional);
1740
            logMetacat.debug("system metadata query: " + stmt.toString());
1741
            int rows = stmt.executeUpdate();
1742

    
1743
            stmt.close();
1744
        } catch (Exception e) {
1745
            e.printStackTrace();
1746
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1747
        } finally {
1748
            // Return database connection to the pool
1749
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1750
        }
1751
    }
1752
    
1753
    private void deleteSystemMetadata(String guid)
1754
    {        
1755
        
1756
        int serialNumber = -1;
1757
        DBConnection dbConn = null;
1758
        try {
1759

    
1760
            // Get a database connection from the pool
1761
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1762
            serialNumber = dbConn.getCheckOutSerialNumber();
1763

    
1764
            // Execute the statement
1765
            String query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1766
            PreparedStatement stmt = dbConn.prepareStatement(query);
1767
            stmt.setString(1, guid);
1768
            logMetacat.debug("delete system metadata: " + stmt.toString());
1769
            int rows = stmt.executeUpdate();
1770

    
1771
            stmt.close();
1772
        } catch (Exception e) {
1773
            e.printStackTrace();
1774
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1775
        } finally {
1776
            // Return database connection to the pool
1777
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1778
        }
1779
    }
1780
}
1781

    
(37-37/65)