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) {
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).getFmtid();
138
        	sysMeta.setFmtid(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.setFmtid(fmtid);
145
        }
146
        sysMeta.setSize(size);
147
        
148
        return sysMeta;
149
    }
150
    
151
    /**
152
     * return a hash of all of the info that is in the systemmetadata table
153
     * @param localId
154
     * @return
155
     */
156
    public Hashtable<String, String> getSystemMetadataInfo(String localId)
157
    throws McdbDocNotFoundException
158
    {
159
        try
160
        {
161
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
162
            localId = acc.getDocid();
163
        }
164
        catch(Exception e)
165
        {
166
            //do nothing. just try the localId as it is
167
        }
168
        Hashtable<String, String> h = new Hashtable<String, String>();
169
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
170
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size " +
171
          "from systemmetadata where docid = ?";
172
        DBConnection dbConn = null;
173
        int serialNumber = -1;
174
        try 
175
        {
176
            // Get a database connection from the pool
177
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getDocumentInfo");
178
            serialNumber = dbConn.getCheckOutSerialNumber();
179

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

    
257
            // Execute the statement
258
            PreparedStatement stmt = dbConn.prepareStatement(sql);
259
            stmt.setString(1, guid);
260
            ResultSet rs = stmt.executeQuery();
261
            if (rs.next()) 
262
            {
263
                Timestamp dateUploaded = rs.getTimestamp(2);
264
                String rightsHolder = rs.getString(3);
265
                String checksum = rs.getString(4);
266
                String checksumAlgorithm = rs.getString(5);
267
                String originMemberNode = rs.getString(6);
268
                String authoritativeMemberNode = rs.getString(7);
269
                Timestamp dateModified = rs.getTimestamp(8);
270
                String submitter = rs.getString(9);
271
                String fmtidStr = rs.getString(10);
272
                BigInteger size = new BigInteger(rs.getString(11));
273
                String obsoletes = rs.getString(12);
274
                String obsoletedBy = rs.getString(13);
275

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

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

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

    
571
            // Execute the insert statement
572
            PreparedStatement stmt = dbConn.prepareStatement(sql);
573
            ResultSet rs = stmt.executeQuery();
574
            if (rs.next()) 
575
            {
576
                rev = rs.getInt(1);
577
                stmt.close();
578
            } 
579
            else
580
            {
581
                stmt.close();
582
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
583
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
584
            }
585
        } 
586
        catch (SQLException e) 
587
        {
588
            logMetacat.error("Error while looking up the guid: " 
589
                    + e.getMessage());
590
        } 
591
        finally 
592
        {
593
            // Return database connection to the pool
594
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
595
        }
596
        return rev;
597
    }
598
    
599
    /**
600
     * return all local ids in the object store that do not have associated
601
     * system metadata
602
     */
603
    public List<String> getLocalIdsWithNoSystemMetadata()
604
    {
605
        Vector<String> ids = new Vector<String>();
606
        String sql = "select docid, rev from xml_documents " +
607
        		"where docid not in " +
608
        		"(select docid from identifier where guid in (select guid from systemmetadata)))";
609
        DBConnection dbConn = null;
610
        int serialNumber = -1;
611
        try 
612
        {
613
            // Get a database connection from the pool
614
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
615
            serialNumber = dbConn.getCheckOutSerialNumber();
616

    
617
            // Execute the insert statement
618
            PreparedStatement stmt = dbConn.prepareStatement(sql);
619
            ResultSet rs = stmt.executeQuery();
620
            while (rs.next()) 
621
            {
622
                String localid = rs.getString(1);
623
                String rev = rs.getString(2);
624
                localid += "." + rev;
625
                logMetacat.debug("id to add SM for: " + localid);
626
                ids.add(localid);
627
            } 
628
            stmt.close();
629
        } 
630
        catch (SQLException e) 
631
        {
632
            logMetacat.error("Error while looking up the guid: " 
633
                    + e.getMessage());
634
        } 
635
        finally 
636
        {
637
            // Return database connection to the pool
638
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
639
        }
640
        
641
        return ids;
642
    }
643
    
644
    /**
645
     * return a listing of all local ids in the object store
646
     * @return a list of all local ids in metacat
647
     */
648
    public List<String> getAllLocalIds()
649
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
650
    //    throws Exception
651
    {
652
        Vector<String> ids = new Vector<String>();
653
        String sql = "select docid from xml_documents";
654
        DBConnection dbConn = null;
655
        int serialNumber = -1;
656
        try 
657
        {
658
            // Get a database connection from the pool
659
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
660
            serialNumber = dbConn.getCheckOutSerialNumber();
661

    
662
            // Execute the insert statement
663
            PreparedStatement stmt = dbConn.prepareStatement(sql);
664
            ResultSet rs = stmt.executeQuery();
665
            while (rs.next()) 
666
            {
667
                String localid = rs.getString(1);
668
                ids.add(localid);
669
            } 
670
            stmt.close();
671
        } 
672
        catch (SQLException e) 
673
        {
674
            logMetacat.error("Error while looking up the guid: " 
675
                    + e.getMessage());
676
        } 
677
        finally 
678
        {
679
            // Return database connection to the pool
680
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
681
        }
682
        return ids;
683
    }
684
    
685
    
686
    /**
687
     * return a listing of all guids in the object store
688
     * @return a list of all GUIDs in metacat
689
     */
690
    public List<String> getAllGUIDs()
691
    {
692
        Vector<String> guids = new Vector<String>();
693
        String sql = "select guid from identifier";
694
        DBConnection dbConn = null;
695
        int serialNumber = -1;
696
        try 
697
        {
698
            // Get a database connection from the pool
699
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllGUIDs");
700
            serialNumber = dbConn.getCheckOutSerialNumber();
701

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

    
749
            // Execute the insert statement
750
            PreparedStatement stmt = dbConn.prepareStatement(sql);
751
            stmt.setDate(1, new java.sql.Date(since.getTime()));
752
            ResultSet rs = stmt.executeQuery();
753
            while (rs.next()) 
754
            {
755
                String guid = rs.getString(1);
756
                ids.add(guid);
757
            } 
758
            stmt.close();
759
        } 
760
        catch (SQLException e) 
761
        {
762
            logMetacat.error("Error while looking up the updated guids: " 
763
                    + e.getMessage());
764
        } 
765
        finally 
766
        {
767
            // Return database connection to the pool
768
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
769
        }
770
        return ids;
771
    }
772
    
773
    /**
774
     * returns a list of system metadata-only guids since the given date
775
     * @return a list of system ids in metacat that do not correspond to objects
776
     * TODO: need to check which server they are on
777
     */
778
    public Date getLastModifiedDate() throws Exception {
779
        Date maxDate = null;
780

    
781
        List<String> ids = new Vector<String>();
782
        String sql = 
783
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
784
        DBConnection dbConn = null;
785
        int serialNumber = -1;
786
        try 
787
        {
788
            // Get a database connection from the pool
789
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
790
            serialNumber = dbConn.getCheckOutSerialNumber();
791

    
792
            // Execute the insert statement
793
            PreparedStatement stmt = dbConn.prepareStatement(sql);
794
            ResultSet rs = stmt.executeQuery();
795
            if (rs.next()) {
796
            	maxDate = rs.getDate(1);
797
            } 
798
            stmt.close();
799
        } 
800
        catch (SQLException e) 
801
        {
802
            logMetacat.error("Error while looking up the latest update date: " 
803
                    + e.getMessage());
804
        } 
805
        finally 
806
        {
807
            // Return database connection to the pool
808
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
809
        }
810
        return maxDate;
811
    }
812

    
813
    
814
    /**
815
     * Determine if an identifier exists already, returning true if so.
816
     * 
817
     * @param guid the global identifier to look up
818
     * @return boolean true if the identifier exists
819
     */
820
    public boolean identifierExists(String guid)
821
    {
822
        boolean idExists = false;
823
        try {
824
            String id = getLocalId(guid);
825
            if (id != null) {
826
                idExists = true;
827
            }
828
        } catch (McdbDocNotFoundException e) {
829
        	// try system metadata only
830
        	try {
831
        		idExists = systemMetadataExists(guid);
832
            } catch (Exception e2) {
833
            	idExists = false;
834
            }
835
        }
836
        return idExists;
837
    }
838
    
839
    /**
840
     * 
841
     * @param guid
842
     * @param rev
843
     * @return
844
     */
845
    public String generateLocalId(String guid, int rev)
846
    {
847
        return generateLocalId(guid, rev, false);
848
    }
849

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

    
952
		DBConnection dbConn = null;
953
		int serialNumber = -1;
954
		try {
955
			// Get a database connection from the pool
956
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
957
			serialNumber = dbConn.getCheckOutSerialNumber();
958

    
959
			// Execute the insert statement
960
			PreparedStatement stmt = dbConn.prepareStatement(query);
961
			stmt.setString(1, guid);
962
			ResultSet rs = stmt.executeQuery();
963
			if (rs.next()) {
964
				exists = true;
965
			}
966

    
967
		} catch (SQLException e) {
968
			logMetacat.error("Error while looking up the system metadata: "
969
					+ e.getMessage());
970
		} finally {
971
			// Return database connection to the pool
972
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
973
		}
974

    
975
		return exists;
976
	}
977
    
978
    /**
979
     * creates a system metadata mapping and adds additional fields from sysmeta
980
     * to the table for quick searching.
981
     * 
982
     * @param guid the id to insert
983
     * @param localId the systemMetadata object to get the local id for
984
     * @throws McdbDocNotFoundException 
985
     */
986
    public void createSystemMetadata(SystemMetadata sysmeta) throws McdbDocNotFoundException
987
    {
988
    	String guid = sysmeta.getIdentifier().getValue();
989
    	// insert the record
990
        insertSystemMetadata(guid);
991
        // update with the values
992
        updateSystemMetadata(sysmeta);
993
    }
994
        
995
    
996
    /**
997
     * update a mapping
998
     * @param guid
999
     * @param localId
1000
     */
1001
    public void updateMapping(String guid, String localId)
1002
    {
1003
    	
1004
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1005
        int serialNumber = -1;
1006
        DBConnection dbConn = null;
1007
        try {
1008
            // Parse the localId into scope and rev parts
1009
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1010
            String docid = acc.getDocid();
1011
            int rev = 1;
1012
            if(acc.getRev() != null)
1013
            {
1014
              rev = (new Integer(acc.getRev()).intValue());
1015
            }
1016

    
1017
            // Get a database connection from the pool
1018
            dbConn = 
1019
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1020
            serialNumber = dbConn.getCheckOutSerialNumber();
1021

    
1022
            // Execute the update statement
1023
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid='" + guid + "'";
1024
            PreparedStatement stmt = dbConn.prepareStatement(query);
1025
            stmt.setString(1, docid);
1026
            stmt.setInt(2, rev);
1027
            int rows = stmt.executeUpdate();
1028

    
1029
            stmt.close();
1030
        } catch (SQLException e) {
1031
            e.printStackTrace();
1032
            logMetacat.error("SQL error while updating a mapping identifier: " 
1033
                    + e.getMessage());
1034
        } catch (NumberFormatException e) {
1035
            e.printStackTrace();
1036
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1037
                    + e.getMessage());
1038
        } catch (AccessionNumberException e) {
1039
            e.printStackTrace();
1040
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1041
                    + e.getMessage());
1042
        } finally {
1043
            // Return database connection to the pool
1044
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1045
        }
1046
        logMetacat.debug("done updating mapping");
1047
    }
1048
        
1049
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1050
            String checksum, String checksumAlgorithm, String originMemberNode,
1051
            String authoritativeMemberNode, long modifiedDate, String submitter, 
1052
            String guid, String objectFormat, BigInteger size, boolean replicationAllowed,
1053
            int numberReplicas, String obsoletes, String obsoletedBy)
1054
    {
1055
        DBConnection dbConn = null;
1056
        int serialNumber = -1;
1057
        
1058
        try {
1059
            // Get a database connection from the pool
1060
            dbConn = 
1061
                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1062
            serialNumber = dbConn.getCheckOutSerialNumber();
1063

    
1064
            // Execute the insert statement
1065
            String query = "update " + TYPE_SYSTEM_METADATA + 
1066
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1067
                "origin_member_node, authoritive_member_node, date_modified, " +
1068
                "submitter, object_format, size, replication_allowed, number_replicas, obsoletes, obsoleted_by) " +
1069
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1070
            PreparedStatement stmt = dbConn.prepareStatement(query);
1071
            
1072
            //data values
1073
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1074
            stmt.setString(2, rightsHolder);
1075
            stmt.setString(3, checksum);
1076
            stmt.setString(4, checksumAlgorithm);
1077
            stmt.setString(5, originMemberNode);
1078
            stmt.setString(6, authoritativeMemberNode);
1079
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1080
            stmt.setString(8, submitter);
1081
            stmt.setString(9, objectFormat);
1082
            stmt.setString(10, size.toString());
1083
            stmt.setBoolean(11, replicationAllowed);
1084
            stmt.setInt(12, numberReplicas);
1085
            stmt.setString(13, obsoletes);
1086
            stmt.setString(14, obsoletedBy);
1087

    
1088
            //where clause
1089
            stmt.setString(15, guid);
1090
            logMetacat.debug("stmt: " + stmt.toString());
1091
            //execute
1092
            int rows = stmt.executeUpdate();
1093

    
1094
            stmt.close();
1095
        } catch (SQLException e) {
1096
            e.printStackTrace();
1097
            logMetacat.error("insertAdditionalSystemMetadataFields: SQL error while creating a mapping to the system metadata identifier: " 
1098
                    + e.getMessage());
1099
        } catch (NumberFormatException e) {
1100
            e.printStackTrace();
1101
            logMetacat.error("insertAdditionalSystemMetadataFields: NumberFormat error while creating a mapping to the system metadata identifier: " 
1102
                    + e.getMessage());
1103
        } finally {
1104
            // Return database connection to the pool
1105
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1106
        }
1107
    }
1108
    
1109
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
1110
    {
1111
        DBConnection dbConn = null;
1112
        int serialNumber = -1;
1113
        
1114
        try {
1115
            // Get a database connection from the pool
1116
            dbConn = 
1117
                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
1118
            serialNumber = dbConn.getCheckOutSerialNumber();
1119

    
1120
            // remove existing values first
1121
            String delete = "delete from systemMetadataReplicationPolicy " + 
1122
            "where guid = ? and policy = ?";
1123
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1124
	        //data values
1125
	        stmt.setString(1, guid);
1126
	        stmt.setString(2, policy);
1127
	        //execute
1128
	        int deletedCount = stmt.executeUpdate();
1129
	        stmt.close();
1130
            
1131
            for (String memberNode: memberNodes) {
1132
	            // Execute the insert statement
1133
	            String insert = "insert into systemMetadataReplicationPolicy " + 
1134
	                "(guid, policy, member_node) " +
1135
	                "values (?, ?, ?)";
1136
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1137
	            
1138
	            //data values
1139
	            insertStatement.setString(1, guid);
1140
	            insertStatement.setString(2, policy);
1141
	            insertStatement.setString(3, memberNode);
1142
	            //execute
1143
	            int rows = insertStatement.executeUpdate();
1144
	            insertStatement.close();
1145
            }
1146
        } catch (SQLException e) {
1147
            logMetacat.error("SQL error while adding systemMetadataReplicationPolicy for: " + guid, e); 
1148
        } finally {
1149
            // Return database connection to the pool
1150
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1151
        }
1152
    }
1153
    
1154
    private void insertReplicationStatus(String guid, List<Replica> replicas) {
1155
        DBConnection dbConn = null;
1156
        int serialNumber = -1;
1157
        
1158
        try {
1159
            // Get a database connection from the pool
1160
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertReplicas");
1161
            serialNumber = dbConn.getCheckOutSerialNumber();
1162

    
1163
            // remove existing values first
1164
            String delete = "delete from systemMetadataReplicationStatus " + 
1165
            "where guid = ?";
1166
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
1167
	        //data values
1168
	        stmt.setString(1, guid);
1169
	        //execute
1170
	        int deletedCount = stmt.executeUpdate();
1171
	        stmt.close();
1172
            
1173
	        if (replicas != null) {
1174
	            for (Replica replica: replicas) {
1175
		            // Execute the insert statement
1176
		            String insert = "insert into systemMetadataReplicationStatus " + 
1177
		                "(guid, member_node, status, date_verified) " +
1178
		                "values (?, ?, ?, ?)";
1179
		            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1180
		            
1181
		            //data values
1182
		            String memberNode = replica.getReplicaMemberNode().getValue();
1183
		            String status = replica.getReplicationStatus().toString();
1184
		            java.sql.Date sqlDate = new java.sql.Date(replica.getReplicaVerified().getTime());
1185
		            insertStatement.setString(1, guid);
1186
		            insertStatement.setString(2, memberNode);
1187
		            insertStatement.setString(3, status);
1188
		            insertStatement.setDate(4, sqlDate);
1189
	
1190
		            //execute
1191
		            int rows = insertStatement.executeUpdate();
1192
		            insertStatement.close();
1193
	            }
1194
	        }
1195
        } catch (SQLException e) {
1196
            logMetacat.error("SQL error while adding systemMetadataReplicationStatus for: " + guid, e); 
1197
        } finally {
1198
            // Return database connection to the pool
1199
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1200
        }
1201
    }
1202
    
1203
    /**
1204
     * Insert the system metadata fields into the db
1205
     * @param sm
1206
     * @throws McdbDocNotFoundException 
1207
     */
1208
    public void updateSystemMetadata(SystemMetadata sm) throws McdbDocNotFoundException {
1209
    	
1210
        Boolean replicationAllowed = false;
1211
		Integer numberReplicas = -1;
1212
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1213
    	if (replicationPolicy != null) {
1214
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1215
    		numberReplicas = replicationPolicy.getNumberReplicas();
1216
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1217
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1218
    	}
1219

    
1220
    	// the main systemMetadata fields
1221
		updateSystemMetadataFields(
1222
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1223
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1224
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1225
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1226
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1227
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1228
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1229
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1230
        sm.getIdentifier().getValue(),
1231
        sm.getFmtid() == null ? null: sm.getFmtid().getValue(),
1232
        sm.getSize(),
1233
        replicationAllowed, 
1234
        numberReplicas,
1235
        sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1236
        sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue());
1237
        
1238
        String guid = sm.getIdentifier().getValue();
1239
        
1240
        // save replication policies
1241
        if (replicationPolicy != null) {
1242
		    List<String> nodes = null;
1243
		    String policy = null;
1244
		    
1245
		    // check for null 
1246
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1247
			    nodes = new ArrayList<String>();
1248
			    policy = "blocked";
1249
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1250
			    	nodes.add(node.getValue());
1251
			    }
1252
			    this.insertReplicationPolicy(guid, policy, nodes);
1253
		    }
1254
		    
1255
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1256
			    nodes = new ArrayList<String>();
1257
			    policy = "preferred";
1258
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1259
			    	nodes.add(node.getValue());
1260
			    }
1261
		        this.insertReplicationPolicy(guid, policy, nodes);
1262
		    }
1263
        }
1264
        
1265
        // save replica information
1266
        this.insertReplicationStatus(guid, sm.getReplicaList());
1267
        
1268
        // save access policy
1269
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1270
        if (accessPolicy != null) {
1271
        	try {
1272
				this.insertAccessPolicy(guid, accessPolicy);
1273
			} catch (AccessException e) {
1274
				throw new McdbDocNotFoundException(e);
1275
			}
1276
        }
1277
    }
1278
    
1279
    /**
1280
     * Creates Metacat access rules and inserts them
1281
     * @param accessPolicy
1282
     * @throws McdbDocNotFoundException
1283
     * @throws AccessException
1284
     */
1285
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1286
    	
1287
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1288
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1289
        	List<Subject> subjects = accessRule.getSubjectList();
1290
        	List<Permission> permissions = accessRule.getPermissionList();
1291
        	for (Subject subject: subjects) {
1292
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1293
        		accessDAO.setPrincipalName(subject.getValue());
1294
    			accessDAO.setGuid(guid);
1295
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1296
    			accessDAO.setPermOrder(AccessControlInterface.DENYFIRST);
1297
    			for (Permission permission: permissions) {
1298
    				Long metacatPermission = new Long(convertPermission(permission));
1299
        			accessDAO.addPermission(metacatPermission);
1300
    			}
1301
    			accessDAOs.add(accessDAO);
1302
        	}
1303
        }
1304
        
1305
        // use GUID to update
1306
        XMLAccessAccess accessController  = new XMLAccessAccess(true);
1307
        accessController.replaceAccess(guid, accessDAOs);
1308
        
1309
        
1310
    }
1311
    
1312
    /**
1313
     * Lookup access policy from Metacat
1314
     * @param guid
1315
     * @return
1316
     * @throws McdbDocNotFoundException
1317
     * @throws AccessException
1318
     */
1319
    private AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1320
        AccessPolicy accessPolicy = new AccessPolicy();
1321

    
1322
    	// use GUID to look up the access
1323
        XMLAccessAccess accessController  = new XMLAccessAccess(true);
1324
    	List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1325
        for (XMLAccessDAO accessDAO: accessDAOs) {
1326
        	AccessRule accessRule = new AccessRule();    	
1327
        	Permission permission = convertPermission(accessDAO.getPermission().intValue());
1328
        	accessRule.addPermission(permission);
1329
        	Subject subject = new Subject();
1330
        	subject.setValue(accessDAO.getPrincipalName());
1331
        	accessRule.addSubject(subject);
1332
            accessPolicy.addAllow(accessRule);
1333
        }
1334
        return accessPolicy;
1335
    }
1336
    
1337
    public int convertPermission(Permission permission) {
1338
    	if (permission.equals(Permission.READ)) {
1339
    		return AccessControlInterface.READ;
1340
    	}
1341
    	if (permission.equals(Permission.WRITE)) {
1342
    		return AccessControlInterface.WRITE;
1343
    	}
1344
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1345
    		return AccessControlInterface.CHMOD;
1346
    	}
1347
		return -1;
1348
    }
1349
    
1350
    public Permission convertPermission(int permission) {
1351
    	if (permission == AccessControlInterface.READ) {
1352
    		return Permission.READ;
1353
    	}
1354
    	if (permission == AccessControlInterface.WRITE) {
1355
    		return Permission.WRITE;
1356
    	}
1357
    	if (permission == AccessControlInterface.CHMOD) {
1358
    		return Permission.CHANGE_PERMISSION;
1359
    	}
1360
		return null;
1361
    }
1362
    
1363
    /**
1364
     * Lookup a localId given the GUID. If
1365
     * the identifier is not found, throw an exception.
1366
     * 
1367
     * @param guid the global identifier to look up
1368
     * @return String containing the corresponding LocalId
1369
     * @throws McdbDocNotFoundException if the identifier is not found
1370
     */
1371
    public String getLocalId(String guid) throws McdbDocNotFoundException {
1372
      
1373
      String db_guid = "";
1374
      String docid = "";
1375
      int rev = 0;
1376
      
1377
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1378
      
1379
      DBConnection dbConn = null;
1380
      int serialNumber = -1;
1381
      try {
1382
          // Get a database connection from the pool
1383
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1384
          serialNumber = dbConn.getCheckOutSerialNumber();
1385
          
1386
          // Execute the insert statement
1387
          PreparedStatement stmt = dbConn.prepareStatement(query);
1388
          stmt.setString(1, guid);
1389
          ResultSet rs = stmt.executeQuery();
1390
          if (rs.next()) {
1391
              db_guid = rs.getString(1);
1392
              docid = rs.getString(2);
1393
              rev = rs.getInt(3);
1394
              assert(db_guid.equals(guid));
1395
          } else {
1396
              throw new McdbDocNotFoundException("Document not found:" + guid);
1397
          }
1398
          stmt.close();
1399
      } catch (SQLException e) {
1400
          logMetacat.error("Error while looking up the local identifier: " 
1401
                  + e.getMessage());
1402
      } finally {
1403
          // Return database connection to the pool
1404
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1405
      }
1406
      return docid + "." + rev;
1407
    }
1408
    
1409
    /**
1410
     * query the systemmetadata table based on the given parameters
1411
     * @param startTime
1412
     * @param endTime
1413
     * @param objectFormat
1414
     * @param replicaStatus
1415
     * @param start
1416
     * @param count
1417
     * @return ObjectList
1418
     * @throws SQLException 
1419
     * @throws ServiceException 
1420
     * @throws PropertyNotFoundException 
1421
     */
1422
    public ObjectList querySystemMetadata(Date startTime, Date endTime, 
1423
            ObjectFormatIdentifier objectFormatId, boolean replicaStatus, int start, int count) throws SQLException, PropertyNotFoundException, ServiceException
1424
    {
1425
        ObjectList ol = new ObjectList();
1426
        int total = 0;
1427
        DBConnection dbConn = null;
1428
        int serialNumber = -1;
1429
        
1430
        try {
1431
            String sql = "select guid, date_uploaded, rights_holder, checksum, " +
1432
                "checksum_algorithm, origin_member_node, authoritive_member_node, " +
1433
                "date_modified, submitter, object_format, size from systemmetadata";
1434
            
1435
            boolean f1 = false;
1436
            boolean f2 = false;
1437
            boolean f3 = false;
1438
            
1439
            if (startTime != null) {
1440
                sql += " where systemmetadata.date_modified > ?";
1441
                f1 = true;
1442
            }
1443
            
1444
            if (endTime != null) {
1445
                if (!f1) {
1446
                    sql += " where systemmetadata.date_modified < ?";
1447
                }
1448
                else {
1449
                    sql += " and systemmetadata.date_modified < ?";
1450
                }
1451
                f2 = true;
1452
            }
1453
            
1454
            if (objectFormatId != null) {
1455
                if (!f1 && !f2) {
1456
                    sql += " where object_format = ?";
1457
                }
1458
                else {
1459
                    sql += " and object_format = ?";
1460
                }
1461
                f3 = true;
1462
            }
1463
            
1464
            if (replicaStatus) {
1465
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.memberNodeId");
1466
                if (!f1 && !f2 && !f3) {
1467
                    sql += " where authoritive_member_node != '" + currentNodeId.trim() + "'";
1468
                }
1469
                else {
1470
                    sql += " and authoritive_member_node != '" + currentNodeId.trim() + "'";
1471
                }
1472
            }
1473
            
1474
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1475
            serialNumber = dbConn.getCheckOutSerialNumber();
1476
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1477
            
1478
            if (f1 && f2 && f3) {
1479
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1480
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1481
                stmt.setString(3, objectFormatId.getValue());
1482
            }
1483
            else if (f1 && f2 && !f3) {
1484
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1485
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1486
            }
1487
            else if (f1 && !f2 && f3) {
1488
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1489
                stmt.setString(2, objectFormatId.getValue());
1490
            }
1491
            else if (f1 && !f2 && !f3) {
1492
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1493
            }
1494
            else if (!f1 && f2 && f3) {
1495
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1496
                stmt.setString(2, objectFormatId.getValue());
1497
            }
1498
            else if (!f1 && !f2 && f3) {
1499
                stmt.setString(1, objectFormatId.getValue());
1500
            }
1501
            else if (!f1 && f2 && !f3) {
1502
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1503
            }
1504
            
1505
            //logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1506
            
1507
            ResultSet rs = stmt.executeQuery();
1508
            for (int i=0; i<start; i++) {
1509
                if (rs.next()) {
1510
                    total++;
1511
                } else {
1512
                    break;
1513
                }
1514
            }
1515
            
1516
            int countIndex = 0;
1517
                        
1518
            while (rs.next()) {
1519
                total++;
1520
                if (countIndex >= count) {
1521
                	// allow unlimited (negative number for count)
1522
                	if (count > 0) {
1523
                		break;
1524
                	}
1525
                }
1526
                                
1527
                String guid = rs.getString(1);
1528
                //logMetacat.debug("query found doc with guid " + guid);
1529
                //Timestamp dateUploaded = rs.getTimestamp(2);
1530
                //String rightsHolder = rs.getString(3);
1531
                String checksum = rs.getString(4);
1532
                String checksumAlgorithm = rs.getString(5);
1533
                //String originMemberNode = rs.getString(6);
1534
                //String authoritiveMemberNode = rs.getString(7);
1535
                Timestamp dateModified = rs.getTimestamp(8);
1536
                //String submitter = rs.getString(9);
1537
                String fmtidStr = rs.getString(10);
1538
                String sz = rs.getString(11);
1539
                BigInteger size = new BigInteger("0");
1540
                
1541
                if (sz != null && !sz.trim().equals("")) {
1542
                    size = new BigInteger(rs.getString(11));
1543
                }
1544
                
1545
                ObjectInfo oi = new ObjectInfo();
1546
                
1547
                Identifier id = new Identifier();
1548
                id.setValue(guid);
1549
                oi.setIdentifier(id);
1550
                
1551
                if (dateModified != null) {
1552
                	oi.setDateSysMetadataModified(new Date(dateModified.getTime()));
1553
                }
1554
                
1555
                Checksum cs = new Checksum();
1556
                cs.setValue(checksum);
1557
                try {
1558
                	//cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1559
                    cs.setAlgorithm(checksumAlgorithm);
1560
                } catch (Exception e) {
1561
					logMetacat.warn("could not parse checksum algorithm", e);
1562
				}
1563
                oi.setChecksum(cs);
1564
                
1565
                try {
1566
	                oi.setFmtid(ObjectFormatCache.getInstance().getFormat(fmtidStr).getFmtid());
1567
                } catch (NotFound e) {
1568
                	logMetacat.warn("could not find object format: " + fmtidStr, e);
1569

    
1570
				}
1571
                                
1572
                oi.setSize(size);
1573
                
1574
                ol.addObjectInfo(oi);
1575
                countIndex++;
1576
            }
1577
            
1578
            // expend the resultset to get the total count of possible rows
1579
            while (rs.next()) { 
1580
                total++;
1581
            }
1582
        }
1583
        
1584
        finally {
1585
            // Return database connection to the pool
1586
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1587
        }
1588
        
1589
        ol.setStart(start);
1590
        ol.setCount(ol.sizeObjectInfoList());
1591
        ol.setTotal(total);
1592
        
1593
        return ol;
1594
    }
1595
    
1596
    /**
1597
     * create a mapping in the identifier table
1598
     * @param guid
1599
     * @param localId
1600
     */
1601
    public void createMapping(String guid, String localId)
1602
    {        
1603
        
1604
        int serialNumber = -1;
1605
        DBConnection dbConn = null;
1606
        try {
1607

    
1608
            // Parse the localId into scope and rev parts
1609
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1610
            String docid = acc.getDocid();
1611
            int rev = 1;
1612
            if (acc.getRev() != null) {
1613
              rev = (new Integer(acc.getRev()).intValue());
1614
            }
1615

    
1616
            // Get a database connection from the pool
1617
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1618
            serialNumber = dbConn.getCheckOutSerialNumber();
1619

    
1620
            // Execute the insert statement
1621
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1622
            PreparedStatement stmt = dbConn.prepareStatement(query);
1623
            stmt.setString(1, guid);
1624
            stmt.setString(2, docid);
1625
            stmt.setInt(3, rev);
1626
            logMetacat.debug("mapping query: " + stmt.toString());
1627
            int rows = stmt.executeUpdate();
1628

    
1629
            stmt.close();
1630
        } catch (SQLException e) {
1631
            e.printStackTrace();
1632
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1633
                    + e.getMessage());
1634
        } catch (NumberFormatException e) {
1635
            e.printStackTrace();
1636
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1637
                    + e.getMessage());
1638
        } catch (AccessionNumberException e) {
1639
            e.printStackTrace();
1640
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1641
                    + e.getMessage());
1642
        } finally {
1643
            // Return database connection to the pool
1644
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1645
        }
1646
    }
1647
    
1648
    /**
1649
     * create the systemmetadata record
1650
     * @param guid
1651
     */
1652
    private void insertSystemMetadata(String guid)
1653
    {        
1654
        
1655
        int serialNumber = -1;
1656
        DBConnection dbConn = null;
1657
        try {
1658

    
1659
            // Get a database connection from the pool
1660
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1661
            serialNumber = dbConn.getCheckOutSerialNumber();
1662

    
1663
            // Execute the insert statement
1664
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1665
            PreparedStatement stmt = dbConn.prepareStatement(query);
1666
            stmt.setString(1, guid);
1667
            logMetacat.debug("system metadata query: " + stmt.toString());
1668
            int rows = stmt.executeUpdate();
1669

    
1670
            stmt.close();
1671
        } catch (Exception e) {
1672
            e.printStackTrace();
1673
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1674
        } finally {
1675
            // Return database connection to the pool
1676
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1677
        }
1678
    }
1679
    
1680
    private void deleteSystemMetadata(String guid)
1681
    {        
1682
        
1683
        int serialNumber = -1;
1684
        DBConnection dbConn = null;
1685
        try {
1686

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

    
1691
            // Execute the statement
1692
            String query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1693
            PreparedStatement stmt = dbConn.prepareStatement(query);
1694
            stmt.setString(1, guid);
1695
            logMetacat.debug("delete system metadata: " + stmt.toString());
1696
            int rows = stmt.executeUpdate();
1697

    
1698
            stmt.close();
1699
        } catch (Exception e) {
1700
            e.printStackTrace();
1701
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1702
        } finally {
1703
            // Return database connection to the pool
1704
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1705
        }
1706
    }
1707
}
1708

    
(37-37/65)