Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2010 Regents of the University of California and the
4
 *             National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: jones $'
7
 *     '$Date: 2010-02-03 17:58:12 -0900 (Wed, 03 Feb 2010) $'
8
 * '$Revision: 5211 $'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 */
24

    
25
package edu.ucsb.nceas.metacat;
26

    
27
import java.math.BigInteger;
28
import java.sql.PreparedStatement;
29
import java.sql.ResultSet;
30
import java.sql.SQLException;
31
import java.sql.Timestamp;
32
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.Hashtable;
35
import java.util.List;
36
import java.util.Vector;
37

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

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

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

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

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

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

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

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

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

    
284

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

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

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

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

    
650
            // Execute the insert statement
651
            PreparedStatement stmt = dbConn.prepareStatement(sql);
652
            ResultSet rs = stmt.executeQuery();
653
            while (rs.next()) 
654
            {
655
                String localid = rs.getString(1);
656
                String rev = rs.getString(2);
657
                localid += "." + rev;
658
                logMetacat.debug("id to add SM for: " + localid);
659
                ids.add(localid);
660
            } 
661
            stmt.close();
662
        } 
663
        catch (SQLException e) 
664
        {
665
            logMetacat.error("Error while looking up the guid: " 
666
                    + e.getMessage());
667
        } 
668
        finally 
669
        {
670
            // Return database connection to the pool
671
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
672
        }
673
        
674
        return ids;
675
    }
676
    
677
    /**
678
     * return a listing of all local ids in the object store
679
     * @return a list of all local ids in metacat
680
     */
681
    public List<String> getAllLocalIds()
682
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
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
    /**
720
     * return a listing of all guids in the object store
721
     * @return a list of all GUIDs in metacat
722
     */
723
    public List<String> getAllGUIDs()
724
    {
725
        Vector<String> guids = new Vector<String>();
726
        String sql = "select guid from identifier";
727
        DBConnection dbConn = null;
728
        int serialNumber = -1;
729
        try 
730
        {
731
            // Get a database connection from the pool
732
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllGUIDs");
733
            serialNumber = dbConn.getCheckOutSerialNumber();
734

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

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

    
814
        List<String> ids = new Vector<String>();
815
        String sql = 
816
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
817
        DBConnection dbConn = null;
818
        int serialNumber = -1;
819
        try 
820
        {
821
            // Get a database connection from the pool
822
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
823
            serialNumber = dbConn.getCheckOutSerialNumber();
824

    
825
            // Execute the insert statement
826
            PreparedStatement stmt = dbConn.prepareStatement(sql);
827
            ResultSet rs = stmt.executeQuery();
828
            if (rs.next()) {
829
            	maxDate = rs.getDate(1);
830
            } 
831
            stmt.close();
832
        } 
833
        catch (SQLException e) 
834
        {
835
            logMetacat.error("Error while looking up the latest update date: " 
836
                    + e.getMessage());
837
        } 
838
        finally 
839
        {
840
            // Return database connection to the pool
841
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
842
        }
843
        return maxDate;
844
    }
845

    
846
    
847
    /**
848
     * Determine if an identifier exists already, returning true if so.
849
     * 
850
     * @param guid the global identifier to look up
851
     * @return boolean true if the identifier exists
852
     */
853
    public boolean identifierExists(String guid)
854
    {
855
        boolean idExists = false;
856
        try {
857
            String id = getLocalId(guid);
858
            if (id != null) {
859
                idExists = true;
860
            }
861
        } catch (McdbDocNotFoundException e) {
862
        	// try system metadata only
863
        	try {
864
        		idExists = systemMetadataExists(guid);
865
            } catch (Exception e2) {
866
            	idExists = false;
867
            }
868
        }
869
        return idExists;
870
    }
871
    
872
    /**
873
     * 
874
     * @param guid
875
     * @param rev
876
     * @return
877
     */
878
    public String generateLocalId(String guid, int rev)
879
    {
880
        return generateLocalId(guid, rev, false);
881
    }
882

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

    
985
		DBConnection dbConn = null;
986
		int serialNumber = -1;
987
		try {
988
			// Get a database connection from the pool
989
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
990
			serialNumber = dbConn.getCheckOutSerialNumber();
991

    
992
			// Execute the insert statement
993
			PreparedStatement stmt = dbConn.prepareStatement(query);
994
			stmt.setString(1, guid);
995
			ResultSet rs = stmt.executeQuery();
996
			if (rs.next()) {
997
				exists = true;
998
			}
999

    
1000
		} catch (SQLException e) {
1001
			logMetacat.error("Error while looking up the system metadata: "
1002
					+ e.getMessage());
1003
		} finally {
1004
			// Return database connection to the pool
1005
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1006
		}
1007

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

    
1050
            // Get a database connection from the pool
1051
            dbConn = 
1052
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1053
            serialNumber = dbConn.getCheckOutSerialNumber();
1054

    
1055
            // Execute the update statement
1056
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1057
            PreparedStatement stmt = dbConn.prepareStatement(query);
1058
            stmt.setString(1, docid);
1059
            stmt.setInt(2, rev);
1060
            stmt.setString(3, guid);
1061
            int rows = stmt.executeUpdate();
1062

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

    
1098
            // Execute the insert statement
1099
            String query = "update " + TYPE_SYSTEM_METADATA + 
1100
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1101
                "origin_member_node, authoritive_member_node, date_modified, " +
1102
                "submitter, object_format, size, replication_allowed, number_replicas, " +
1103
                "obsoletes, obsoleted_by, serial_version) " +
1104
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1105
            PreparedStatement stmt = dbConn.prepareStatement(query);
1106
            
1107
            //data values
1108
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1109
            stmt.setString(2, rightsHolder);
1110
            stmt.setString(3, checksum);
1111
            stmt.setString(4, checksumAlgorithm);
1112
            stmt.setString(5, originMemberNode);
1113
            stmt.setString(6, authoritativeMemberNode);
1114
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1115
            stmt.setString(8, submitter);
1116
            stmt.setString(9, objectFormat);
1117
            stmt.setString(10, size.toString());
1118
            stmt.setBoolean(11, replicationAllowed);
1119
            stmt.setInt(12, numberReplicas);
1120
            stmt.setString(13, obsoletes);
1121
            stmt.setString(14, obsoletedBy);
1122
            stmt.setString(15, serialVersion.toString());
1123

    
1124
            //where clause
1125
            stmt.setString(16, guid);
1126
            logMetacat.debug("stmt: " + stmt.toString());
1127
            //execute
1128
            int rows = stmt.executeUpdate();
1129

    
1130
            stmt.close();
1131
        } catch (SQLException e) {
1132
            e.printStackTrace();
1133
            logMetacat.error("insertAdditionalSystemMetadataFields: SQL error while creating a mapping to the system metadata identifier: " 
1134
                    + e.getMessage());
1135
        } catch (NumberFormatException e) {
1136
            e.printStackTrace();
1137
            logMetacat.error("insertAdditionalSystemMetadataFields: NumberFormat error while creating a mapping to the system metadata identifier: " 
1138
                    + e.getMessage());
1139
        } finally {
1140
            // Return database connection to the pool
1141
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1142
        }
1143
    }
1144
    
1145
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
1146
    {
1147
        DBConnection dbConn = null;
1148
        int serialNumber = -1;
1149
        
1150
        try {
1151
            // Get a database connection from the pool
1152
            dbConn = 
1153
                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
1154
            serialNumber = dbConn.getCheckOutSerialNumber();
1155

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

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

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

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

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

    
1661
            // Get a database connection from the pool
1662
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1663
            serialNumber = dbConn.getCheckOutSerialNumber();
1664

    
1665
            // Execute the insert statement
1666
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1667
            PreparedStatement stmt = dbConn.prepareStatement(query);
1668
            stmt.setString(1, guid);
1669
            stmt.setString(2, docid);
1670
            stmt.setInt(3, rev);
1671
            logMetacat.debug("mapping query: " + stmt.toString());
1672
            int rows = stmt.executeUpdate();
1673

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

    
1704
            // Get a database connection from the pool
1705
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1706
            serialNumber = dbConn.getCheckOutSerialNumber();
1707

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

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

    
1735
            // Get a database connection from the pool
1736
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1737
            serialNumber = dbConn.getCheckOutSerialNumber();
1738

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

    
(37-37/65)