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()
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
        DBConnection dbConn = null;
634
        int serialNumber = -1;
635
        try 
636
        {
637
            // Get a database connection from the pool
638
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
639
            serialNumber = dbConn.getCheckOutSerialNumber();
640

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1652
            // Get a database connection from the pool
1653
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1654
            serialNumber = dbConn.getCheckOutSerialNumber();
1655

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

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

    
1695
            // Get a database connection from the pool
1696
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1697
            serialNumber = dbConn.getCheckOutSerialNumber();
1698

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

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

    
1726
            // Get a database connection from the pool
1727
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1728
            serialNumber = dbConn.getCheckOutSerialNumber();
1729

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

    
(37-37/65)