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.HashMap;
35
import java.util.Hashtable;
36
import java.util.List;
37
import java.util.Vector;
38

    
39
import org.apache.log4j.Logger;
40
import org.dataone.client.v2.formats.ObjectFormatCache;
41
import org.dataone.service.exceptions.BaseException;
42
import org.dataone.service.exceptions.InvalidSystemMetadata;
43
import org.dataone.service.types.v1.AccessPolicy;
44
import org.dataone.service.types.v1.AccessRule;
45
import org.dataone.service.types.v1.Checksum;
46
import org.dataone.service.types.v1.Identifier;
47
import org.dataone.service.types.v1.NodeReference;
48
import org.dataone.service.types.v1.ObjectFormatIdentifier;
49
import org.dataone.service.types.v1.ObjectInfo;
50
import org.dataone.service.types.v1.ObjectList;
51
import org.dataone.service.types.v1.Permission;
52
import org.dataone.service.types.v1.Replica;
53
import org.dataone.service.types.v1.ReplicationPolicy;
54
import org.dataone.service.types.v1.ReplicationStatus;
55
import org.dataone.service.types.v1.Subject;
56
import org.dataone.service.types.v2.MediaType;
57
import org.dataone.service.types.v2.MediaTypeProperty;
58
import org.dataone.service.types.v2.SystemMetadata;
59

    
60
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessAccess;
61
import edu.ucsb.nceas.metacat.database.DBConnection;
62
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
63
import edu.ucsb.nceas.metacat.database.DatabaseService;
64
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
65
import edu.ucsb.nceas.metacat.properties.PropertyService;
66
import edu.ucsb.nceas.metacat.shared.AccessException;
67
import edu.ucsb.nceas.metacat.shared.ServiceException;
68
import edu.ucsb.nceas.metacat.util.DocumentUtil;
69
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
70
import edu.ucsb.nceas.utilities.access.AccessControlInterface;
71
import edu.ucsb.nceas.utilities.access.XMLAccessDAO;
72

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

    
93
    /**
94
     * A private constructor that initializes the class when getInstance() is
95
     * called.
96
     */
97
    private IdentifierManager() {}
98

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

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

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

    
266
        try 
267
        {
268
            // Get a database connection from the pool
269
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadata");
270
            serialNumber = dbConn.getCheckOutSerialNumber();
271

    
272
            // Execute the statement
273
            PreparedStatement stmt = dbConn.prepareStatement(sql);
274
            stmt.setString(1, guid);
275
            ResultSet rs = stmt.executeQuery();
276
            if (rs.next()) 
277
            {
278
                Timestamp dateUploaded = rs.getTimestamp(2);
279
                String rightsHolder = rs.getString(3);
280
                String checksum = rs.getString(4);
281
                String checksumAlgorithm = rs.getString(5);
282
                String originMemberNode = rs.getString(6);
283
                String authoritativeMemberNode = rs.getString(7);
284
                Timestamp dateModified = rs.getTimestamp(8);
285
                String submitter = rs.getString(9);
286
                String fmtidStr = rs.getString(10);
287
                BigInteger size = new BigInteger(rs.getString(11));
288
                replicationAllowed = new Boolean(rs.getBoolean(12));
289
                numberOfReplicas = new BigInteger(rs.getString(13));
290
                String obsoletes = rs.getString(14);
291
                String obsoletedBy = rs.getString(15);
292
                serialVersion = new BigInteger(rs.getString(16));
293
                archived = new Boolean(rs.getBoolean(17));
294
                String series_id = rs.getString(18);
295
                String file_name = rs.getString(19);
296
                String media_type = rs.getString(20);
297

    
298
                Identifier sysMetaId = new Identifier();
299
                sysMetaId.setValue(guid);
300
                sysMeta.setIdentifier(sysMetaId);
301
                sysMeta.setSerialVersion(serialVersion);
302
                sysMeta.setDateUploaded(dateUploaded);
303
                Subject rightsHolderSubject = new Subject();
304
                rightsHolderSubject.setValue(rightsHolder);
305
                sysMeta.setRightsHolder(rightsHolderSubject);
306
                Checksum checksumObject = new Checksum();
307
                checksumObject.setValue(checksum);
308
                checksumObject.setAlgorithm(checksumAlgorithm);
309
                sysMeta.setChecksum(checksumObject);
310
                if (originMemberNode != null) {
311
	                NodeReference omn = new NodeReference();
312
	                omn.setValue(originMemberNode);
313
	                sysMeta.setOriginMemberNode(omn);
314
                }
315
                if (authoritativeMemberNode != null) {
316
	                NodeReference amn = new NodeReference();
317
	                amn.setValue(authoritativeMemberNode);
318
	                sysMeta.setAuthoritativeMemberNode(amn);
319
                }
320
                sysMeta.setDateSysMetadataModified(dateModified);
321
                if (submitter != null) {
322
	                Subject submitterSubject = new Subject();
323
	                submitterSubject.setValue(submitter);
324
	                sysMeta.setSubmitter(submitterSubject);
325
                }
326
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
327
                fmtid.setValue(fmtidStr);
328
            	sysMeta.setFormatId(fmtid);
329
                sysMeta.setSize(size);
330
                if (obsoletes != null) {
331
	                Identifier obsoletesId = new Identifier();
332
	                obsoletesId.setValue(obsoletes);
333
	                sysMeta.setObsoletes(obsoletesId);
334
                }
335
                if (obsoletedBy != null) {
336
		            Identifier obsoletedById = new Identifier();
337
		            obsoletedById.setValue(obsoletedBy);
338
		            sysMeta.setObsoletedBy(obsoletedById);
339
                }
340
                sysMeta.setArchived(archived);
341
                if(series_id != null) {
342
                    Identifier seriesId = new Identifier();
343
                    seriesId.setValue(series_id);
344
                    sysMeta.setSeriesId(seriesId);
345
                }
346
                if(file_name != null ) {
347
                    sysMeta.setFileName(file_name);
348
                }
349
                
350
                if(media_type != null ) {
351
                    MediaType mediaType = new MediaType();
352
                    mediaType.setName(media_type);
353
                    // get media type properties from another table.
354
                    String mediaTypePropertyQuery = "select name, value from smmediatypeproperties where guid = ?";
355
                    PreparedStatement stmt2 = dbConn.prepareStatement(mediaTypePropertyQuery);
356
                    stmt2.setString(1, guid);
357
                    ResultSet rs2 = stmt2.executeQuery();
358
                    while (rs2.next()) {
359
                        String name = rs2.getString(1);
360
                        String value = rs2.getString(2);
361
                        MediaTypeProperty property = new MediaTypeProperty();
362
                        property.setName(name);
363
                        property.setValue(value);
364
                        mediaType.addProperty(property);
365
                    }
366
                    sysMeta.setMediaType(mediaType);
367
                    rs2.close();
368
                    stmt2.close();
369
                }
370
                stmt.close();
371
            } 
372
            else
373
            {
374
                stmt.close();
375
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
376
                throw new McdbDocNotFoundException("Could not find " + guid);
377
            }
378
            
379
        } 
380
        catch (SQLException e) 
381
        {
382
            e.printStackTrace();
383
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "  
384
                    + e.getMessage());
385
        } 
386
        finally 
387
        {
388
            // Return database connection to the pool
389
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
390
        }
391

    
392
        // populate the replication policy
393
        ReplicationPolicy replicationPolicy = new ReplicationPolicy();
394
        if ( numberOfReplicas != null  && numberOfReplicas.intValue() != -1 ) {
395
            replicationPolicy.setNumberReplicas(numberOfReplicas.intValue());
396
            
397
        }
398
        
399
        if ( replicationAllowed != null ) {
400
            replicationPolicy.setReplicationAllowed(replicationAllowed);
401
            
402
        }
403
        replicationPolicy.setBlockedMemberNodeList(getReplicationPolicy(guid, "blocked"));
404
        replicationPolicy.setPreferredMemberNodeList(getReplicationPolicy(guid, "preferred"));
405
		    sysMeta.setReplicationPolicy(replicationPolicy);
406
		
407
		    // look up replication status
408
		    sysMeta.setReplicaList(getReplicationStatus(guid));
409
		
410
		    // look up access policy
411
		    try {
412
		    	sysMeta.setAccessPolicy(getAccessPolicy(guid));
413
		    } catch (AccessException e) {
414
		    	throw new McdbDocNotFoundException(e);
415
		    }
416
        
417
        return sysMeta;
418
    }
419
    
420
    
421
    private List<NodeReference> getReplicationPolicy(String guid, String policy)
422
		throws McdbDocNotFoundException {
423
		
424
		List<NodeReference> nodes = new ArrayList<NodeReference>();
425
		String sql = "select guid, policy, member_node " +
426
			"from smReplicationPolicy where guid = ? and policy = ? order by policy_id ASC";
427
	    DBConnection dbConn = null;
428
	    int serialNumber = -1;
429
	    try {
430
	        // Get a database connection from the pool
431
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicationPolicy");
432
	        serialNumber = dbConn.getCheckOutSerialNumber();
433
	
434
	        // Execute the statement
435
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
436
	        stmt.setString(1, guid);
437
	        stmt.setString(2, policy);
438
	        ResultSet rs = stmt.executeQuery();
439
	        while (rs.next()) 
440
	        {
441
	            String memberNode = rs.getString(3);
442
	            NodeReference node = new NodeReference();
443
	            node.setValue(memberNode);
444
	            nodes.add(node);
445
	        
446
	        } 
447
	        stmt.close();
448
	        
449
	    } catch (SQLException e) {
450
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
451
	    } 
452
	    finally {
453
	        // Return database connection to the pool
454
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
455
	    }
456
	    
457
	    return nodes;
458
	}
459
    
460
    private List<Replica> getReplicationStatus(String guid) throws McdbDocNotFoundException {
461
		
462
		List<Replica> replicas = new ArrayList<Replica>();
463
		String sql = "select guid, member_node, status, date_verified " +
464
			"from smReplicationStatus where guid = ?";
465
	    DBConnection dbConn = null;
466
	    int serialNumber = -1;
467
	    try {
468
	        // Get a database connection from the pool
469
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicas");
470
	        serialNumber = dbConn.getCheckOutSerialNumber();
471
	
472
	        // Execute the statement
473
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
474
	        stmt.setString(1, guid);
475
	        ResultSet rs = stmt.executeQuery();
476
	        while (rs.next()) 
477
	        {
478
	            String memberNode = rs.getString(2);
479
	            String status = rs.getString(3);
480
	            java.sql.Timestamp verified = rs.getTimestamp(4);
481
	            
482
	            Replica replica = new Replica();	            
483
	            NodeReference node = new NodeReference();
484
	            node.setValue(memberNode);
485
	            replica.setReplicaMemberNode(node);
486
	            replica.setReplicationStatus(ReplicationStatus.valueOf(status));
487
	            replica.setReplicaVerified(new Date(verified.getTime()));
488
	            replicas.add(replica);
489
	        } 
490
	        stmt.close();
491
	        
492
	    } catch (SQLException e) {
493
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
494
	    } 
495
	    finally {
496
	        // Return database connection to the pool
497
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
498
	    }
499
	    
500
	    return replicas;
501
	}
502
    
503
    
504
    /**
505
     * return the newest rev for a given localId
506
     * @param localId
507
     * @return
508
     */
509
    public int getLatestRevForLocalId(String localId)
510
        throws McdbDocNotFoundException
511
    {
512
        try
513
        {
514
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
515
            localId = acc.getDocid();
516
        }
517
        catch(Exception e)
518
        {
519
            //do nothing. just try the localId as it is
520
        }
521
        int rev = 0;
522
        String sql = "select rev from xml_documents where docid like ? ";
523
        DBConnection dbConn = null;
524
        int serialNumber = -1;
525
        try 
526
        {
527
            // Get a database connection from the pool
528
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLatestRevForLocalId");
529
            serialNumber = dbConn.getCheckOutSerialNumber();
530

    
531
            // Execute the insert statement
532
            PreparedStatement stmt = dbConn.prepareStatement(sql);
533
            stmt.setString(1, localId);
534
            ResultSet rs = stmt.executeQuery();
535
            if (rs.next()) 
536
            {
537
                rev = rs.getInt(1);
538
                stmt.close();
539
            } 
540
            else
541
            {
542
                stmt.close();
543
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
544
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
545
            }
546
        } 
547
        catch (SQLException e) 
548
        {
549
            logMetacat.error("Error while looking up the guid: " 
550
                    + e.getMessage());
551
        } 
552
        finally 
553
        {
554
            // Return database connection to the pool
555
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
556
        }
557
        return rev;
558
    }
559
    
560
    /**
561
     * return all local ids in the object store that do not have associated
562
     * system metadata
563
     */
564
    public List<String> getLocalIdsWithNoSystemMetadata(boolean includeRevisions, int serverLocation)
565
    {
566
        Vector<String> ids = new Vector<String>();
567
        String sql = "select docid, rev from xml_documents " +
568
        		"where docid not in " +
569
        		"(select docid from identifier where guid in (select guid from systemmetadata))";
570
        if (serverLocation > 0) {
571
        	sql = sql + " and server_location = ? ";
572
        }
573
        
574
        String revisionSql = "select docid, rev from xml_revisions " +
575
				"where docid not in " +
576
				"(select docid from identifier where guid in (select guid from systemmetadata))";
577
        if (serverLocation > 0) {
578
        	revisionSql = revisionSql + " and server_location = ? ";
579
        }
580
        
581
        if (includeRevisions) {
582
        	sql = sql + " UNION ALL " + revisionSql;
583
        }
584
        
585
        DBConnection dbConn = null;
586
        int serialNumber = -1;
587
        try 
588
        {
589
            // Get a database connection from the pool
590
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
591
            serialNumber = dbConn.getCheckOutSerialNumber();
592

    
593
            // Execute the insert statement
594
            PreparedStatement stmt = dbConn.prepareStatement(sql);
595
            // set params based on what we have in the query string
596
            if (serverLocation > 0) {
597
            	stmt.setInt(1, serverLocation);
598
            	if (includeRevisions) {
599
            		stmt.setInt(2, serverLocation);
600
            	}
601
            }
602
            ResultSet rs = stmt.executeQuery();
603
            while (rs.next()) 
604
            {
605
                String localid = rs.getString(1);
606
                String rev = rs.getString(2);
607
                localid += "." + rev;
608
                logMetacat.debug("id to add SM for: " + localid);
609
                ids.add(localid);
610
            } 
611
            stmt.close();
612
        } 
613
        catch (SQLException e) 
614
        {
615
            logMetacat.error("Error while looking up the guid: " 
616
                    + e.getMessage());
617
        } 
618
        finally 
619
        {
620
            // Return database connection to the pool
621
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
622
        }
623
        
624
        return ids;
625
    }
626
    
627
    /**
628
     * return a listing of all local ids in the object store
629
     * @return a list of all local ids in metacat
630
     */
631
    public List<String> getAllLocalIds()
632
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
633
    //    throws Exception
634
    {
635
        Vector<String> ids = new Vector<String>();
636
        String sql = "select docid from xml_documents";
637
        DBConnection dbConn = null;
638
        int serialNumber = -1;
639
        try 
640
        {
641
            // Get a database connection from the pool
642
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
643
            serialNumber = dbConn.getCheckOutSerialNumber();
644

    
645
            // Execute the insert statement
646
            PreparedStatement stmt = dbConn.prepareStatement(sql);
647
            ResultSet rs = stmt.executeQuery();
648
            while (rs.next()) 
649
            {
650
                String localid = rs.getString(1);
651
                ids.add(localid);
652
            } 
653
            stmt.close();
654
        } 
655
        catch (SQLException e) 
656
        {
657
            logMetacat.error("Error while looking up the guid: " 
658
                    + e.getMessage());
659
        } 
660
        finally 
661
        {
662
            // Return database connection to the pool
663
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
664
        }
665
        return ids;
666
    }
667
    
668
    
669
    /**
670
     * return a listing of all guids in the object store
671
     * @return a list of all GUIDs in metacat
672
     */
673
    public List<String> getAllSystemMetadataGUIDs()
674
    {
675
        Vector<String> guids = new Vector<String>();
676
        String sql = "select guid from systemmetadata";
677
        DBConnection dbConn = null;
678
        int serialNumber = -1;
679
        try 
680
        {
681
            // Get a database connection from the pool
682
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllGUIDs");
683
            serialNumber = dbConn.getCheckOutSerialNumber();
684

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

    
732
            // Execute the insert statement
733
            PreparedStatement stmt = dbConn.prepareStatement(sql);
734
            stmt.setDate(1, new java.sql.Date(since.getTime()));
735
            ResultSet rs = stmt.executeQuery();
736
            while (rs.next()) 
737
            {
738
                String guid = rs.getString(1);
739
                ids.add(guid);
740
            } 
741
            stmt.close();
742
        } 
743
        catch (SQLException e) 
744
        {
745
            logMetacat.error("Error while looking up the updated guids: " 
746
                    + e.getMessage());
747
        } 
748
        finally 
749
        {
750
            // Return database connection to the pool
751
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
752
        }
753
        return ids;
754
    }
755
    
756
    /**
757
     * returns a list of system metadata-only guids since the given date
758
     * @return a list of system ids in metacat that do not correspond to objects
759
     * TODO: need to check which server they are on
760
     */
761
    public Date getLastModifiedDate() throws Exception {
762
        Date maxDate = null;
763

    
764
        List<String> ids = new Vector<String>();
765
        String sql = 
766
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
767
        DBConnection dbConn = null;
768
        int serialNumber = -1;
769
        try 
770
        {
771
            // Get a database connection from the pool
772
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
773
            serialNumber = dbConn.getCheckOutSerialNumber();
774

    
775
            // Execute the insert statement
776
            PreparedStatement stmt = dbConn.prepareStatement(sql);
777
            ResultSet rs = stmt.executeQuery();
778
            if (rs.next()) {
779
            	maxDate = rs.getDate(1);
780
            } 
781
            stmt.close();
782
        } 
783
        catch (SQLException e) 
784
        {
785
            logMetacat.error("Error while looking up the latest update date: " 
786
                    + e.getMessage());
787
        } 
788
        finally 
789
        {
790
            // Return database connection to the pool
791
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
792
        }
793
        return maxDate;
794
    }
795

    
796
    
797
    /**
798
     * Determine if an identifier exists already, returning true if so.
799
     * NOTE: looks in the identifier and system metadata table for a match
800
     * (in that order)
801
     * 
802
     * @param guid the global identifier to look up
803
     * @return boolean true if the identifier exists
804
     */
805
    public boolean identifierExists(String guid) throws SQLException
806
    {
807
        boolean idExists = false;
808
        try {
809
            String id = getLocalId(guid);
810
            if (id != null) {
811
                idExists = true;
812
            }
813
        } catch (McdbDocNotFoundException e) {
814
        	// try system metadata only
815
        	    //this will check if the guid field on the system metadata table has the id
816
        		idExists = systemMetadataPIDExists(guid);
817
        		if(!idExists) {
818
        		    //if the guid field of the system metadata table doesn't have the id,
819
        		    //we will check if the serial_id field of the system metadata table has it
820
        		    idExists=systemMetadataSIDExists(guid);
821
        		}
822
            
823
        }
824
        return idExists;
825
    }
826
    
827
    /**
828
     * Determine if an identifier mapping exists already, 
829
     * returning true if so.
830
     * 
831
     * @param guid the global identifier to look up
832
     * @return boolean true if the identifier exists
833
     */
834
    public boolean mappingExists(String guid) throws SQLException
835
    {
836
        boolean idExists = false;
837
        try {
838
            String id = getLocalId(guid);
839
            if (id != null) {
840
                idExists = true;
841
            }
842
        } catch (McdbDocNotFoundException e) {
843
        	// nope!
844
        }
845
        return idExists;
846
    }
847
    
848
    /**
849
     * 
850
     * @param guid
851
     * @param rev
852
     * @return
853
     */
854
    public String generateLocalId(String guid, int rev)
855
    {
856
        return generateLocalId(guid, rev, false);
857
    }
858

    
859
    /**
860
     * Given a global identifier (guid), create a suitable local identifier that
861
     * follows Metacat's docid semantics and format (scope.id.rev), and create
862
     * a mapping between these two identifiers.  This effectively reserves both
863
     * the global and the local identifier, as they will now be present in the
864
     * identifier mapping table.  
865
     * 
866
     * REMOVED feature: If the incoming guid has the syntax of a
867
     * Metacat docid (scope.id.rev), then simply use it.
868
     * WHY: because "test.1.001" becomes "test.1.1" which is not correct for DataONE
869
     * identifier use (those revision numbers are just chartacters and should not be interpreted)
870
     * 
871
     * @param guid the global string identifier
872
     * @param rev the revision number to be used in the localId
873
     * @return String containing the localId to be used for Metacat operations
874
     */
875
    public String generateLocalId(String guid, int rev, boolean isSystemMetadata) 
876
    {
877
        String localId = "";
878
        boolean conformsToDocidFormat = false;
879
        
880
        // BRL -- do not allow Metacat-conforming IDs to be used:
881
        // test.1.001 becomes test.1.1 which is NOT correct for DataONE identifiers
882
        // Check if the guid passed in is already in docid (scope.id.rev) format
883
//        try {
884
//            AccessionNumber acc = new AccessionNumber(guid, "NONE");
885
//            if (new Integer(acc.getRev()).intValue() > 0) {
886
//                conformsToDocidFormat = true;
887
//            }
888
//        } catch (NumberFormatException e) {
889
//            // No action needed, simply detecting invalid AccessionNumbers
890
//        } catch (AccessionNumberException e) {
891
//            // No action needed, simply detecting invalid AccessionNumbers
892
//        } catch (SQLException e) {
893
//            // No action needed, simply detecting invalid AccessionNumbers
894
//        }
895
        
896
        if (conformsToDocidFormat) {
897
            // if it conforms, use it for both guid and localId
898
            localId = guid;
899
        } else {
900
            // if not, then generate a new unique localId
901
            localId = DocumentUtil.generateDocumentId(rev);
902
        }
903
        
904
        // Register this new pair in the identifier mapping table
905
        logMetacat.debug("creating mapping in generateLocalId");
906
        if(!isSystemMetadata)
907
        { //don't do this if we're generating for system metadata
908
            createMapping(guid, localId);
909
        }
910
        
911
        return localId;
912
    }
913
    
914
    /**
915
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
916
     * if the docid, rev is not found in the identifiers or systemmetadata tables
917
     *
918
     * @param docid the docid to look up
919
     * @param rev the revision of the docid to look up
920
     * @return String containing the mapped guid
921
     * @throws McdbDocNotFoundException if the docid, rev is not found
922
     */
923
    public String getGUID(String docid, int rev)
924
      throws McdbDocNotFoundException
925
    {
926
        logMetacat.debug("getting guid for " + docid);
927
        String query = "select guid from identifier where docid = ? and rev = ?";
928
        String guid = null;
929
        
930
        DBConnection dbConn = null;
931
        int serialNumber = -1;
932
        PreparedStatement stmt = null;
933
        try {
934
            // Get a database connection from the pool
935
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
936
            serialNumber = dbConn.getCheckOutSerialNumber();
937
            
938
            // Execute the insert statement
939
            stmt = dbConn.prepareStatement(query);
940
            stmt.setString(1, docid);
941
            stmt.setInt(2, rev);
942
            ResultSet rs = stmt.executeQuery();
943
            if (rs.next()) 
944
            {
945
                guid = rs.getString(1);
946
            } 
947
            else
948
            {
949
            	throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
950
            }
951
            if(rs != null) {
952
                rs.close();
953
            }
954
        } catch (SQLException e) {
955
            logMetacat.error("Error while looking up the guid: " 
956
                    + e.getMessage());
957
        } finally {
958
            try {
959
                if(stmt != null) {
960
                    stmt.close();
961
                }
962
            } catch (Exception e) {
963
                logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
964
            } finally {
965
                // Return database connection to the pool
966
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
967
            }
968
            
969
        }
970
        
971
        return guid;
972
    }
973
    
974
    /**
975
     * Get the pid of the head (current) version of objects match the specified sid.
976
     * 1. locate all candidate chain-ends for S1:
977
     *      determined by:  seriesId == S1 AND (obsoletedBy == null  OR obsoletedBy.seriesId != S1) // these are the type1 and type2 ends
978
     *      If obsoletedBy is missing, we generally consider it a type 2 end except:
979
     *      there is another object in the chain (has the same series id) that obsoletes the missing object. 
980
     * 2. if only 1 candidate chain-end, return it as the HEAD
981
     * 3. otherwise return the one in the chain with the latest dateUploaded value.
982
     * @param sid specified sid which should match.
983
     * @return the pid of the head version. The null will be returned if there is no pid found.
984
     * @throws SQLException 
985
     */
986
    public Identifier getHeadPID(Identifier sid) throws SQLException {
987
        Identifier pid = null;
988
        if(sid != null && sid.getValue() != null && !sid.getValue().trim().equals("")) {
989
            logMetacat.debug("getting pid of the head version for matching the sid: " + sid.getValue());
990
            String sql = "select guid, obsoleted_by, obsoletes from systemMetadata where series_id = ? order by date_uploaded DESC";
991
            DBConnection dbConn = null;
992
            int serialNumber = -1;
993
            PreparedStatement stmt = null;
994
            PreparedStatement stmt2 = null;
995
            ResultSet rs = null;
996
            ResultSet result = null;
997
            int endsCount = 0;
998
            boolean hasError = false;
999
            HashMap<String, String> obsoletesIdGuidMap = new HashMap<String, String>();//the key is an obsoletes id, the value is an guid
1000
            try {
1001
                // Get a database connection from the pool
1002
                dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getHeadPID");
1003
                serialNumber = dbConn.getCheckOutSerialNumber();
1004
                // Execute the insert statement
1005
                stmt = dbConn.prepareStatement(sql);
1006
                stmt.setString(1, sid.getValue());
1007
                rs = stmt.executeQuery();
1008
                boolean hasNext = rs.next();
1009
                boolean first = true;
1010
                Identifier firstOne = new Identifier();//since the sql using the desc order, the first one has the latest upload date.
1011
                if (hasNext) 
1012
                {
1013
                    while(hasNext) {
1014
                        String guidStr = rs.getString(1);
1015
                        String obsoletedByStr = rs.getString(2);
1016
                        String obsoletesStr = rs.getString(3);
1017
                        Identifier guid = new Identifier();
1018
                        guid.setValue(guidStr);
1019
                        if(obsoletesStr != null && !obsoletesStr.trim().equals("")) {
1020
                            if(obsoletesIdGuidMap.containsKey(obsoletesStr) && !guidStr.equals(obsoletesIdGuidMap.get(obsoletesStr))) {
1021
                                logMetacat.error("Both id "+guidStr+" and id "+obsoletesIdGuidMap.get(obsoletesStr)+" obsoletes the id"+obsoletesStr+
1022
                                        ". It is illegal. So the head pid maybe is wrong.");
1023
                                hasError = true;
1024
                            } 
1025
                            obsoletesIdGuidMap.put(obsoletesStr, guidStr);
1026
                        }
1027
                        if(first) {
1028
                            firstOne = guid;
1029
                            first =false;
1030
                        }
1031
                        //SystemMetadata sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(guid);
1032
                        //if(sysmeta.getObsoletedBy() == null) {
1033
                        if(obsoletedByStr == null || obsoletedByStr.trim().equals("")) {
1034
                            //type 1 end
1035
                            logMetacat.debug(""+guidStr+" is a type 1 end for sid "+sid.getValue());
1036
                            pid = guid;
1037
                            endsCount++;
1038
                        } else {
1039
                            //Identifier obsoletedBy = sysmeta.getObsoletedBy();
1040
                            Identifier obsoletedBy = new Identifier();
1041
                            obsoletedBy.setValue(obsoletedByStr);
1042
                            //SystemMetadata obsoletedBySysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletedBy);
1043
                            String sql2 = "select series_id, guid from systemMetadata where guid = ? ";
1044
                            stmt2 = dbConn.prepareStatement(sql2);
1045
                            stmt2.setString(1, obsoletedByStr);
1046
                            result = stmt2.executeQuery();
1047
                            boolean next = result.next();
1048
                            //if(obsoletedBySysmeta != null) {
1049
                            if(next) {
1050
                                logMetacat.debug("The object "+obsoletedBy+" which obsoletes "+guidStr+" does have a system metadata on the table.");
1051
                                //Identifier sidInObsoletedBy = obsoletedBySysmeta.getSeriesId();
1052
                                String sidInObsoletedBy = result.getString(1);
1053
                                if(sidInObsoletedBy == null|| !sidInObsoletedBy.equals(sid.getValue())) {
1054
                                    // type 2 end
1055
                                    logMetacat.debug(""+guidStr+" is a type 2 end for sid "+sid.getValue()+ "since it is obsoleted by the object "+sidInObsoletedBy+
1056
                                            " which has a different sid or no sids");
1057
                                    pid = guid;
1058
                                    endsCount++;
1059
                                }
1060
                            } else {
1061
                                logMetacat.debug("The object "+obsoletedBy+" which obsoletes "+guidStr+" is missing on the host.");
1062
                                //obsoletedBySysmeta doesn't exist; it means the object is missing
1063
                                //generally, we consider it we generally consider it a type 2 end except:
1064
                                 //there is another object in the chain (has the same series id) that obsoletes the missing object. 
1065
                                /*String sql2 = "select guid from systemMetadata where  obsoletes = ? and series_id = ?";
1066
                                PreparedStatement stmt2 = dbConn.prepareStatement(sql2);
1067
                                stmt2.setString(1, obsoletedBy.getValue());
1068
                                stmt2.setString(2, sid.getValue());
1069
                                ResultSet result = stmt2.executeQuery();
1070
                                boolean next = result.next();
1071
                                int count = 0;
1072
                                while(next) {
1073
                                    count++;
1074
                                    next = result.next();
1075
                                }
1076
                                if(count == 0) {
1077
                                    //the exception (another object in the chain (has the same series id) that obsoletes the missing object) doesn't exist
1078
                                    // it is a type 2 end
1079
                                    logMetacat.debug(""+guidStr+" is a type 2 end for sid "+sid.getValue());
1080
                                    pid = guid;
1081
                                    endsCount++;
1082
                                } else if (count ==1) {
1083
                                    // it is not end, do nothing;
1084
                                } else {
1085
                                    // something is wrong - there are more than one objects obsolete the missing object!
1086
                                    hasError = true;
1087
                                    break;
1088
                                }*/
1089
                                if(obsoletesIdGuidMap != null && obsoletesIdGuidMap.containsKey(obsoletedByStr)) {
1090
                                   //This is the exception - another object in the chain (has the same series id) that obsoletes the missing object
1091
                                    //The obsoletesIdGuidMap maintains the relationship (with the same  series id)
1092
                                    logMetacat.debug("Though the object "+obsoletedBy+" which obsoletes "+guidStr+" is missing."+
1093
                                            " However, there is another object "+obsoletesIdGuidMap.get(obsoletedByStr)+" in the chain obsoleting it. So it is not an end.");
1094
                                  
1095
                                } else {
1096
                                    //the exception (another object in the chain (has the same series id) that obsoletes the missing object) doesn't exist
1097
                                    // it is a type 2 end
1098
                                    logMetacat.debug(""+guidStr+" is a type 2 end for sid "+sid.getValue());
1099
                                    pid = guid;
1100
                                    endsCount++;
1101
                                }
1102
                            }
1103
                        }
1104
                        hasNext = rs.next();
1105
                    }
1106
                    if(endsCount == 1) {
1107
                        //it has one end and it is an ideal chain. We already assign the guid to the pid. So do nothing.
1108
                        logMetacat.info("It is an ideal for sid "+sid.getValue());
1109
                    }
1110
                    if(hasError || endsCount >1) {
1111
                        // it is not an ideal chain, use the one with latest upload date(the first one in the result set since we have the desc order)
1112
                        logMetacat.info("It is NOT an ideal for sid "+sid.getValue());
1113
                        pid = firstOne;
1114
                    }
1115
                } else {
1116
                    //it is not a sid or at least we don't have anything to match it.
1117
                    //do nothing, so null will be returned
1118
                }
1119
                
1120
                
1121
            } catch (SQLException e) {
1122
                logMetacat.error("Error while get the head pid for the sid "+sid.getValue()+" : " 
1123
                        + e.getMessage());
1124
                throw e;
1125
            } finally {
1126
                try {
1127
                    if(rs != null) {
1128
                        rs.close();
1129
                    }
1130
                    if(result != null) {
1131
                        result.close();
1132
                    }
1133
                    if(stmt != null) {
1134
                        stmt.close();
1135
                    }
1136
                    if(stmt2 != null) {
1137
                        stmt2.close();
1138
                    }
1139
                } catch (Exception e) {
1140
                    logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
1141
                } finally {
1142
                    // Return database connection to the pool
1143
                    DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1144
                }
1145
            }
1146
        }
1147
        return pid;
1148
    }
1149
    
1150
    /**
1151
     * Check if the specified sid object exists on the serial id field on the system metadata table
1152
     * @param sid
1153
     * @return true if it exists; false otherwise.
1154
     * @throws SQLException
1155
     */
1156
    public boolean systemMetadataSIDExists(Identifier sid) throws SQLException {
1157
        if (sid != null && sid.getValue() != null && !sid.getValue().trim().equals("")) {
1158
            return systemMetadataSIDExists(sid.getValue());
1159
        } else {
1160
            return false;
1161
        }
1162
    }
1163
    
1164
    /**
1165
     * Check if the specified sid exists on the serial id field on the system metadata table
1166
     * @param id
1167
     * @return true if it exists; false otherwise.
1168
     */
1169
    public boolean systemMetadataSIDExists(String sid) throws SQLException {
1170
        boolean exists = false;
1171
        logMetacat.debug("Check if the  sid: " + sid +" exists on the series_id field of the system metadata table.");
1172
        if(sid != null && !sid.trim().equals("")) {
1173
            String sql = "select guid from systemMetadata where series_id = ?";
1174
            DBConnection dbConn = null;
1175
            int serialNumber = -1;
1176
            PreparedStatement stmt = null;
1177
            try {
1178
                // Get a database connection from the pool
1179
                dbConn = DBConnectionPool.getDBConnection("IdentifierManager.serialIdExists");
1180
                serialNumber = dbConn.getCheckOutSerialNumber();
1181
                // Execute the insert statement
1182
                stmt = dbConn.prepareStatement(sql);
1183
                stmt.setString(1, sid);
1184
                ResultSet rs = stmt.executeQuery();
1185
                if (rs.next()) 
1186
                {
1187
                    exists = true;
1188
                } 
1189
                if(rs != null) {
1190
                    rs.close();
1191
                }
1192
            } catch (SQLException e) {
1193
                logMetacat.error("Error while checking if the sid "+sid+" exists on the series_id field of the system metadata table: " 
1194
                        + e.getMessage());
1195
                throw e;
1196
            } finally {
1197
                try {
1198
                    if(stmt != null) {
1199
                        stmt.close();
1200
                    }
1201
                } catch (Exception e) {
1202
                    logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
1203
                } finally {
1204
                    // Return database connection to the pool
1205
                    DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1206
                }
1207
            }
1208
        }
1209
        return exists;
1210
    }
1211
    
1212
    /**
1213
     * Determine if the specified identifier object exists or not.
1214
     * @param pid - the specified identifier
1215
     * @return true if it is exists.
1216
     * @throws SQLException
1217
     * @throws NullPointerException
1218
     */
1219
    public boolean systemMetadataPIDExists(Identifier pid) throws SQLException {
1220
        if (pid != null && pid.getValue() != null && !pid.getValue().trim().equals("")) {
1221
            return systemMetadataPIDExists(pid.getValue());
1222
        } else {
1223
            return false;
1224
        }
1225
    }
1226
    
1227
    public boolean systemMetadataPIDExists(String guid) throws SQLException {
1228
		logMetacat.debug("looking up system metadata for guid " + guid);
1229
		boolean exists = false;
1230
		String query = "select guid from systemmetadata where guid = ?";
1231
		DBConnection dbConn = null;
1232
		int serialNumber = -1;
1233
		PreparedStatement stmt = null;
1234
		if(guid != null && !guid.trim().equals("")) {
1235
		    try {
1236
	            // Get a database connection from the pool
1237
	            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
1238
	            serialNumber = dbConn.getCheckOutSerialNumber();
1239

    
1240
	            // Execute the insert statement
1241
	            stmt = dbConn.prepareStatement(query);
1242
	            stmt.setString(1, guid);
1243
	            ResultSet rs = stmt.executeQuery();
1244
	            if (rs.next()) {
1245
	                exists = true;
1246
	            }
1247
	            if(rs != null) {
1248
	                rs.close();
1249
	            }
1250

    
1251
	        } catch (SQLException e) {
1252
	            logMetacat.error("Error while looking up the system metadata: "
1253
	                    + e.getMessage());
1254
	            throw e;
1255
	        } finally {
1256
	            try {
1257
	                if(stmt != null) {
1258
	                    stmt.close();
1259
	                }
1260
	            } catch (Exception e) {
1261
	                logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
1262
	            } finally {
1263
	                // Return database connection to the pool
1264
	                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1265
	            }
1266
	        }
1267
		}
1268
		return exists;
1269
	}
1270
    
1271
    /**
1272
     * creates a system metadata mapping and adds additional fields from sysmeta
1273
     * to the table for quick searching.
1274
     * 
1275
     * @param guid the id to insert
1276
     * @param localId the systemMetadata object to get the local id for
1277
     * @throws McdbDocNotFoundException 
1278
     * @throws SQLException 
1279
     * @throws InvalidSystemMetadata 
1280
     */
1281
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta) 
1282
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1283
    	String guid = sysmeta.getIdentifier().getValue();
1284
    	
1285
    	 // Get a database connection from the pool
1286
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1287
        int serialNumber = dbConn.getCheckOutSerialNumber();
1288
        
1289
        try {
1290
        	// use a single transaction for it all
1291
        	dbConn.setAutoCommit(false);
1292
        	
1293
	    	// insert the record if needed
1294
        	if (!IdentifierManager.getInstance().systemMetadataPIDExists(guid)) {
1295
    	        insertSystemMetadata(guid, dbConn);
1296
			}
1297
	        // update with the values
1298
	        updateSystemMetadata(sysmeta, dbConn);
1299
	        
1300
	        // commit if we got here with no errors
1301
	        dbConn.commit();
1302
        } catch (Exception e) {
1303
            e.printStackTrace();
1304
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1305
            dbConn.rollback();
1306
            throw new SQLException("Can't save system metadata "+e.getMessage());
1307
        } finally {
1308
            // Return database connection to the pool
1309
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1310
        }
1311
        
1312
        
1313
    }
1314
        
1315
    
1316
    /**
1317
     * update a mapping
1318
     * @param guid
1319
     * @param localId
1320
     */
1321
    public void updateMapping(String guid, String localId)
1322
    {
1323
    	
1324
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1325
        int serialNumber = -1;
1326
        DBConnection dbConn = null;
1327
        try {
1328
            // Parse the localId into scope and rev parts
1329
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1330
            String docid = acc.getDocid();
1331
            int rev = 1;
1332
            if(acc.getRev() != null)
1333
            {
1334
              rev = (new Integer(acc.getRev()).intValue());
1335
            }
1336

    
1337
            // Get a database connection from the pool
1338
            dbConn = 
1339
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1340
            serialNumber = dbConn.getCheckOutSerialNumber();
1341

    
1342
            // Execute the update statement
1343
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1344
            PreparedStatement stmt = dbConn.prepareStatement(query);
1345
            stmt.setString(1, docid);
1346
            stmt.setInt(2, rev);
1347
            stmt.setString(3, guid);
1348
            int rows = stmt.executeUpdate();
1349

    
1350
            stmt.close();
1351
        } catch (SQLException e) {
1352
            e.printStackTrace();
1353
            logMetacat.error("SQL error while updating a mapping identifier: " 
1354
                    + e.getMessage());
1355
        } catch (NumberFormatException e) {
1356
            e.printStackTrace();
1357
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1358
                    + e.getMessage());
1359
        } catch (AccessionNumberException e) {
1360
            e.printStackTrace();
1361
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1362
                    + e.getMessage());
1363
        } finally {
1364
            // Return database connection to the pool
1365
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1366
        }
1367
        logMetacat.debug("done updating mapping");
1368
    }
1369
        
1370
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1371
        String checksum, String checksumAlgorithm, String originMemberNode, 
1372
        String authoritativeMemberNode, long modifiedDate, String submitter, 
1373
        String guid, String objectFormat, BigInteger size, boolean archived,
1374
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1375
        String obsoletedBy, BigInteger serialVersion, String seriesId, 
1376
        String fileName, MediaType mediaType, DBConnection dbConn) throws SQLException  {
1377
        PreparedStatement stmt = null;
1378
        PreparedStatement stmt2 = null;
1379
        try {
1380
            dbConn.setAutoCommit(false);
1381
            // Execute the insert statement
1382
            String query = "update " + TYPE_SYSTEM_METADATA + 
1383
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1384
                "origin_member_node, authoritive_member_node, date_modified, " +
1385
                "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1386
                "obsoletes, obsoleted_by, serial_version, series_id, file_name, media_type) " +
1387
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?) where guid = ?";
1388
            stmt = dbConn.prepareStatement(query);
1389
            
1390
            //data values
1391
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1392
            stmt.setString(2, rightsHolder);
1393
            stmt.setString(3, checksum);
1394
            stmt.setString(4, checksumAlgorithm);
1395
            stmt.setString(5, originMemberNode);
1396
            stmt.setString(6, authoritativeMemberNode);
1397
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1398
            stmt.setString(8, submitter);
1399
            stmt.setString(9, objectFormat);
1400
            stmt.setString(10, size.toString());
1401
            stmt.setBoolean(11, archived);
1402
            stmt.setBoolean(12, replicationAllowed);
1403
            stmt.setInt(13, numberReplicas);
1404
            stmt.setString(14, obsoletes);
1405
            stmt.setString(15, obsoletedBy);
1406
            if(serialVersion != null) {
1407
                stmt.setString(16, serialVersion.toString());
1408
            } else {
1409
                stmt.setString(16, null);
1410
            }
1411
            
1412
            stmt.setString(17, seriesId);
1413
            stmt.setString(18, fileName);
1414
            if (mediaType == null) {
1415
                stmt.setString(19, null);
1416
            } else {
1417
                stmt.setString(19, mediaType.getName());
1418
            }
1419
            //where clause
1420
            stmt.setString(20, guid);
1421
            logMetacat.debug("stmt: " + stmt.toString());
1422
            //execute
1423
            int rows = stmt.executeUpdate();
1424
            
1425
            //insert media type properties into another table
1426
            if(mediaType != null && mediaType.getPropertyList() != null) {
1427
                String sql2 = "insert into smmediatypeproperties " + 
1428
                        "(guid, name, value) " + "values (?, ?, ?)";
1429
                stmt2 = dbConn.prepareStatement(sql2);
1430
                for(MediaTypeProperty item : mediaType.getPropertyList()) {
1431
                    if(item != null) {
1432
                        String name = item.getName();
1433
                        String value = item.getValue();
1434
                        stmt2.setString(1, guid);
1435
                        stmt2.setString(2, name);
1436
                        stmt2.setString(3, value);
1437
                        logMetacat.debug("insert media type properties query: " + stmt2.toString());
1438
                        int row =stmt2.executeUpdate();
1439
                    }
1440
                    
1441
                }
1442
            }
1443
            dbConn.commit();
1444
            dbConn.setAutoCommit(true);
1445
        } catch (Exception e) {
1446
            dbConn.rollback();
1447
            dbConn.setAutoCommit(true);
1448
            e.printStackTrace();
1449
            throw new SQLException(e.getMessage());
1450
        } finally {
1451
            if(stmt != null) {
1452
                stmt.close();
1453
            }
1454
            if(stmt2 != null) {
1455
                stmt2.close();
1456
            }
1457
        }
1458
        
1459
               
1460
    }
1461
    
1462
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1463
    {
1464
           
1465
        // remove existing values first
1466
        String delete = "delete from smReplicationPolicy " + 
1467
        "where guid = ? and policy = ?";
1468
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1469
        //data values
1470
        stmt.setString(1, guid);
1471
        stmt.setString(2, policy);
1472
        //execute
1473
        int deletedCount = stmt.executeUpdate();
1474
        stmt.close();
1475
        
1476
        for (String memberNode: memberNodes) {
1477
            // Execute the insert statement
1478
            String insert = "insert into smReplicationPolicy " + 
1479
                "(guid, policy, member_node) " +
1480
                "values (?, ?, ?)";
1481
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1482
            
1483
            //data values
1484
            insertStatement.setString(1, guid);
1485
            insertStatement.setString(2, policy);
1486
            insertStatement.setString(3, memberNode);
1487
            
1488
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1489

    
1490
            //execute
1491
            int rows = insertStatement.executeUpdate();
1492
            insertStatement.close();
1493
        }
1494
        
1495
    }
1496
    
1497
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1498
       
1499
        // remove existing values first
1500
        String delete = "delete from smReplicationStatus " + 
1501
        "where guid = ?";
1502
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1503
        //data values
1504
        stmt.setString(1, guid);
1505
        //execute
1506
        int deletedCount = stmt.executeUpdate();
1507
        stmt.close();
1508
        
1509
        if (replicas != null) {
1510
            for (Replica replica: replicas) {
1511
	            // Execute the insert statement
1512
	            String insert = "insert into smReplicationStatus " + 
1513
	                "(guid, member_node, status, date_verified) " +
1514
	                "values (?, ?, ?, ?)";
1515
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1516
	            
1517
	            //data values
1518
	            String memberNode = replica.getReplicaMemberNode().getValue();
1519
	            String status = replica.getReplicationStatus().toString();
1520
	            java.sql.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1521
	            insertStatement.setString(1, guid);
1522
	            insertStatement.setString(2, memberNode);
1523
	            insertStatement.setString(3, status);
1524
	            insertStatement.setTimestamp(4, sqlDate);
1525

    
1526
	            logMetacat.debug("smReplicationStatus sql: " + insertStatement.toString());
1527
	            
1528
	            //execute
1529
	            int rows = insertStatement.executeUpdate();
1530
	            insertStatement.close();
1531
            }
1532
        }
1533
       
1534
    }
1535
    
1536
    /**
1537
     * Insert the system metadata fields into the db
1538
     * @param sm
1539
     * @throws McdbDocNotFoundException 
1540
     * @throws SQLException 
1541
     * @throws InvalidSystemMetadata 
1542
     * @throws AccessException 
1543
     */
1544
    public void updateSystemMetadata(SystemMetadata sm, DBConnection dbConn) 
1545
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata, AccessException {
1546
    	
1547
      Boolean replicationAllowed = false;
1548
		  Integer numberReplicas = -1;
1549
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1550
    	if (replicationPolicy != null) {
1551
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1552
    		numberReplicas = replicationPolicy.getNumberReplicas();
1553
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1554
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1555
    	}
1556
    	
1557
    	// the main systemMetadata fields
1558
		  updateSystemMetadataFields(
1559
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1560
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1561
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1562
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1563
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1564
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1565
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1566
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1567
		    sm.getIdentifier().getValue(),
1568
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1569
		    sm.getSize(),
1570
		    sm.getArchived() == null ? false: sm.getArchived(),
1571
		    replicationAllowed, 
1572
		    numberReplicas,
1573
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1574
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1575
		    sm.getSerialVersion(),
1576
		    sm.getSeriesId() == null ? null: sm.getSeriesId().getValue(),
1577
		    sm.getFileName() == null ? null: sm.getFileName(),
1578
		    sm.getMediaType() == null ? null: sm.getMediaType(),
1579
		    dbConn
1580
        );
1581
        
1582
        String guid = sm.getIdentifier().getValue();
1583
        
1584
        // save replication policies
1585
        if (replicationPolicy != null) {
1586
		    List<String> nodes = null;
1587
		    String policy = null;
1588
		    
1589
		    // check for null 
1590
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1591
			    nodes = new ArrayList<String>();
1592
			    policy = "blocked";
1593
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1594
			    	nodes.add(node.getValue());
1595
			    }
1596
			    this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1597
		    }
1598
		    
1599
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1600
			    nodes = new ArrayList<String>();
1601
			    policy = "preferred";
1602
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1603
			    	nodes.add(node.getValue());
1604
			    }
1605
		        this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1606
		    }
1607
        }
1608
        
1609
        // save replica information
1610
        this.insertReplicationStatus(guid, sm.getReplicaList(), dbConn);
1611
        
1612
        // save access policy
1613
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1614
        if (accessPolicy != null) {
1615
			this.insertAccessPolicy(guid, accessPolicy);
1616
        }
1617
    }
1618
    
1619
    /**
1620
     * Creates Metacat access rules and inserts them
1621
     * @param accessPolicy
1622
     * @throws McdbDocNotFoundException
1623
     * @throws AccessException
1624
     */
1625
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1626
    	
1627
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1628
        XMLAccessAccess accessController  = new XMLAccessAccess();
1629
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1630
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1631
        if (existingAccess != null && existingAccess.size() > 0) {
1632
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1633
        }
1634
        
1635
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1636
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1637
        	List<Subject> subjects = accessRule.getSubjectList();
1638
        	List<Permission> permissions = accessRule.getPermissionList();
1639
        	for (Subject subject: subjects) {
1640
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1641
        		accessDAO.setPrincipalName(subject.getValue());
1642
    			accessDAO.setGuid(guid);
1643
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1644
				accessDAO.setPermOrder(existingPermOrder);
1645
    			if (permissions != null) {
1646
	    			for (Permission permission: permissions) {
1647
	    				Long metacatPermission = new Long(convertPermission(permission));
1648
	        			accessDAO.addPermission(metacatPermission);
1649
	    			}
1650
    			}
1651
    			accessDAOs.add(accessDAO);
1652
        	}
1653
        }
1654
        
1655
        
1656
        // remove all existing allow records
1657
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1658
        // add the ones we can for this guid
1659
        accessController.insertAccess(guid, accessDAOs);
1660
        
1661
        
1662
    }
1663
    
1664
    /**
1665
     * Lookup access policy from Metacat
1666
     * @param guid
1667
     * @return
1668
     * @throws McdbDocNotFoundException
1669
     * @throws AccessException
1670
     */
1671
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1672
        AccessPolicy accessPolicy = new AccessPolicy();
1673

    
1674
    	// use GUID to look up the access
1675
        XMLAccessAccess accessController  = new XMLAccessAccess();
1676
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1677
        
1678
        for (XMLAccessDAO accessDAO: accessDAOs) {
1679
        	// only add allow rule
1680
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1681
	        	AccessRule accessRule = new AccessRule();    	
1682
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1683
	        	// cannot include if we have no permissions
1684
	        	if (permissions == null || permissions.isEmpty()) {
1685
	        		logMetacat.warn("skipping empty access rule permissions for " + guid);
1686
	        		continue;
1687
	        	}
1688
	        	accessRule.setPermissionList(permissions);
1689
	        	Subject subject = new Subject();
1690
	        	subject.setValue(accessDAO.getPrincipalName());
1691
	        	accessRule.addSubject(subject);
1692
	            accessPolicy.addAllow(accessRule);
1693
        	}
1694
        }
1695
        return accessPolicy;
1696
    }
1697
    
1698
    public int convertPermission(Permission permission) {
1699
    	if (permission.equals(Permission.READ)) {
1700
    		return AccessControlInterface.READ;
1701
    	}
1702
    	if (permission.equals(Permission.WRITE)) {
1703
    		return AccessControlInterface.WRITE;
1704
    	}
1705
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1706
    		return AccessControlInterface.CHMOD;
1707
    	}
1708
		return -1;
1709
    }
1710
    
1711
    public List<Permission> convertPermission(int permission) {
1712
    	
1713
    	List<Permission> permissions = new ArrayList<Permission>();
1714
    	if (permission == AccessControlInterface.ALL) {
1715
    		permissions.add(Permission.READ);
1716
    		permissions.add(Permission.WRITE);
1717
    		permissions.add(Permission.CHANGE_PERMISSION);
1718
    		return permissions;
1719
    	}
1720
    	
1721
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1722
    		permissions.add(Permission.CHANGE_PERMISSION);
1723
    	}
1724
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1725
    		permissions.add(Permission.READ);
1726
    	}
1727
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1728
    		permissions.add(Permission.WRITE);
1729
    	}
1730
    	
1731
		return permissions;
1732
    }
1733
    
1734
    /**
1735
     * Lookup a localId given the GUID. If
1736
     * the identifier is not found, throw an exception.
1737
     * 
1738
     * @param guid the global identifier to look up
1739
     * @return String containing the corresponding LocalId
1740
     * @throws McdbDocNotFoundException if the identifier is not found
1741
     */
1742
    public String getLocalId(String guid) throws McdbDocNotFoundException, SQLException {
1743
      
1744
      String db_guid = "";
1745
      String docid = "";
1746
      int rev = 0;
1747
      
1748
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1749
      
1750
      DBConnection dbConn = null;
1751
      int serialNumber = -1;
1752
      try {
1753
          // Get a database connection from the pool
1754
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1755
          serialNumber = dbConn.getCheckOutSerialNumber();
1756
          
1757
          // Execute the insert statement
1758
          PreparedStatement stmt = dbConn.prepareStatement(query);
1759
          stmt.setString(1, guid);
1760
          ResultSet rs = stmt.executeQuery();
1761
          if (rs.next()) {
1762
              db_guid = rs.getString(1);
1763
              docid = rs.getString(2);
1764
              rev = rs.getInt(3);
1765
              assert(db_guid.equals(guid));
1766
          } else {
1767
              throw new McdbDocNotFoundException("Document not found:" + guid);
1768
          }
1769
          stmt.close();
1770
      } catch (SQLException e) {
1771
          logMetacat.error("Error while looking up the local identifier: " 
1772
                  + e.getMessage());
1773
          throw e;
1774
      } finally {
1775
          // Return database connection to the pool
1776
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1777
      }
1778
      return docid + "." + rev;
1779
    }
1780
    
1781
    /**
1782
     * query the systemmetadata table based on the given parameters
1783
     * @param startTime
1784
     * @param endTime
1785
     * @param objectFormat
1786
     * @param nodeId
1787
     * @param start
1788
     * @param count
1789
     * @return ObjectList
1790
     * @throws SQLException 
1791
     * @throws ServiceException 
1792
     * @throws PropertyNotFoundException 
1793
     */
1794
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1795
        ObjectFormatIdentifier objectFormatId, NodeReference nodeId,
1796
        int start, int count, Identifier identifier, boolean isSID) 
1797
        throws SQLException, PropertyNotFoundException, ServiceException {
1798
        ObjectList ol = new ObjectList();
1799
        DBConnection dbConn = null;
1800
        int serialNumber = -1;
1801
        PreparedStatement countStmt=null;
1802
        ResultSet totalResult=null;
1803
        PreparedStatement fieldStmt = null;
1804
        ResultSet rs= null;
1805

    
1806
        try {
1807
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1808
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1809
                    + "date_modified, submitter, object_format, size from systemmetadata";
1810
            
1811
            // handle special case quickly
1812
            String countSql = "select count(guid) from systemmetadata";
1813
            
1814
            // the clause
1815
            String whereClauseSql = "";
1816
            
1817

    
1818
            boolean f1 = false;
1819
            boolean f2 = false;
1820
            boolean f3 = false;
1821
            boolean f4 = false;
1822

    
1823

    
1824
            if (startTime != null) {
1825
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1826
                f1 = true;
1827
            }
1828

    
1829
            if (endTime != null) {
1830
                if (!f1) {
1831
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1832
                } else {
1833
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1834
                }
1835
                f2 = true;
1836
            }
1837

    
1838
            if (objectFormatId != null) {
1839
                if (!f1 && !f2) {
1840
                    whereClauseSql += " where object_format = ?";
1841
                } else {
1842
                    whereClauseSql += " and object_format = ?";
1843
                }
1844
                f3 = true;
1845
            }
1846
            
1847
            if(identifier != null && identifier.getValue() != null && !identifier.getValue().equals("")) {
1848
                if (!f1 && !f2 && !f3 ) {
1849
                    if(isSID) {
1850
                        whereClauseSql += " where series_id = ?";
1851
                    } else {
1852
                        whereClauseSql += " where guid = ?";
1853
                    }
1854
                    
1855
                } else {
1856
                    if(isSID) {
1857
                        whereClauseSql += " and series_id = ?";
1858
                    } else {
1859
                        whereClauseSql += " and guid = ?";
1860
                    }
1861
                }
1862
                f4 = true;
1863
            }
1864

    
1865
            /*if (!replicaStatus) {
1866
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1867
                if (!f1 && !f2 && !f3 && !f4) {
1868
                    whereClauseSql += " where authoritive_member_node = '" +
1869
                        currentNodeId.trim() + "'";
1870
                } else {
1871
                    whereClauseSql += " and authoritive_member_node = '" +
1872
                        currentNodeId.trim() + "'";
1873
                }
1874
            }*/
1875
            
1876
            if (nodeId != null && nodeId.getValue() != null && !nodeId.getValue().trim().equals("")) {
1877
                if (!f1 && !f2 && !f3 && !f4) {
1878
                    whereClauseSql += " where authoritive_member_node = '" +
1879
                        nodeId.getValue().trim() + "'";
1880
                } else {
1881
                    whereClauseSql += " and authoritive_member_node = '" +
1882
                        nodeId.getValue().trim() + "'";
1883
                }
1884
            }
1885
           
1886
            
1887
            // connection
1888
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1889
            serialNumber = dbConn.getCheckOutSerialNumber();
1890

    
1891
            // the field query
1892
            String orderBySql = " order by guid ";
1893
            String fieldQuery = fieldSql + whereClauseSql + orderBySql;
1894
            String finalQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldQuery, start, count);
1895
            fieldStmt = dbConn.prepareStatement(finalQuery);
1896
            
1897
            // construct the count query and statment
1898
            String countQuery = countSql + whereClauseSql;
1899
            countStmt = dbConn.prepareStatement(countQuery);
1900

    
1901
            if (f1 && f2 && f3 && f4) {
1902
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1903
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1904
                fieldStmt.setString(3, objectFormatId.getValue());
1905
                fieldStmt.setString(4, identifier.getValue());
1906
                // count
1907
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1908
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1909
                countStmt.setString(3, objectFormatId.getValue());
1910
                countStmt.setString(4, identifier.getValue());
1911
            } if (f1 && f2 && f3 && !f4) {
1912
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1913
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1914
                fieldStmt.setString(3, objectFormatId.getValue());
1915
                // count
1916
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1917
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1918
                countStmt.setString(3, objectFormatId.getValue());
1919
            } else if (f1 && f2 && !f3 && f4) {
1920
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1921
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1922
                fieldStmt.setString(3, identifier.getValue());
1923
                // count
1924
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1925
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1926
                countStmt.setString(3, identifier.getValue());
1927
            } else if (f1 && f2 && !f3 && !f4) {
1928
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1929
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1930
                // count
1931
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1932
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1933
            } else if (f1 && !f2 && f3 && f4) {
1934
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1935
                fieldStmt.setString(2, objectFormatId.getValue());
1936
                fieldStmt.setString(3, identifier.getValue());
1937
                // count
1938
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1939
                countStmt.setString(2, objectFormatId.getValue());
1940
                countStmt.setString(3, identifier.getValue());
1941
            } else if (f1 && !f2 && f3 && !f4) {
1942
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1943
                fieldStmt.setString(2, objectFormatId.getValue());
1944
                // count
1945
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1946
                countStmt.setString(2, objectFormatId.getValue());
1947
            } else if (f1 && !f2 && !f3 && f4) {
1948
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1949
                fieldStmt.setString(2, identifier.getValue());
1950
                // count
1951
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1952
                countStmt.setString(2, identifier.getValue());
1953
            } else if (f1 && !f2 && !f3 && !f4) {
1954
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1955
                // count
1956
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1957
            } else if (!f1 && f2 && f3 && f4) {
1958
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1959
                fieldStmt.setString(2, objectFormatId.getValue());
1960
                fieldStmt.setString(3, identifier.getValue());
1961
                // count
1962
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1963
                countStmt.setString(2, objectFormatId.getValue());
1964
                countStmt.setString(3, identifier.getValue());
1965
            } else if (!f1 && f2 && f3 && !f4) {
1966
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1967
                fieldStmt.setString(2, objectFormatId.getValue());
1968
                // count
1969
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1970
                countStmt.setString(2, objectFormatId.getValue());
1971
            } else if (!f1 && !f2 && f3 && f4) {
1972
                fieldStmt.setString(1, objectFormatId.getValue());
1973
                fieldStmt.setString(2, identifier.getValue());
1974
                // count
1975
                countStmt.setString(1, objectFormatId.getValue());
1976
                countStmt.setString(2, identifier.getValue());
1977
            } else if (!f1 && !f2 && f3 && !f4) {
1978
                fieldStmt.setString(1, objectFormatId.getValue());
1979
                // count
1980
                countStmt.setString(1, objectFormatId.getValue());
1981
            } else if (!f1 && f2 && !f3 && f4) {
1982
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1983
                fieldStmt.setString(2, identifier.getValue());
1984
                // count
1985
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1986
                countStmt.setString(2, identifier.getValue());
1987
            } else if (!f1 && f2 && !f3 && !f4) {
1988
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1989
                // count
1990
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1991
            } else if (!f1 && !f2 && !f3 && f4) {
1992
                fieldStmt.setString(1, identifier.getValue());
1993
                // count
1994
                countStmt.setString(1, identifier.getValue());
1995
            } else if (!f1 && !f2 && !f3 && !f4) {
1996
                //do nothing
1997
            }
1998

    
1999
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
2000
            
2001
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
2002
            
2003
            // get the total object count no matter what
2004
            int total = 0;
2005
            totalResult = countStmt.executeQuery();
2006
            if (totalResult.next()) {
2007
            	total = totalResult.getInt(1);
2008
            }
2009
            
2010
            logMetacat.debug("list objects total: " + total);
2011

    
2012
        	// set the totals
2013
        	ol.setStart(start);
2014
            ol.setCount(count);
2015
            
2016
            // retrieve the actual records if requested
2017
            if (count != 0) {
2018
            	
2019
                rs = fieldStmt.executeQuery();
2020
	            while (rs.next()) {                
2021
	                
2022
	                String guid = rs.getString(1);
2023
	                logMetacat.debug("query found object with guid " + guid);
2024
	                // Timestamp dateUploaded = rs.getTimestamp(2);
2025
	                // String rightsHolder = rs.getString(3);
2026
	                String checksum = rs.getString(4);
2027
	                String checksumAlgorithm = rs.getString(5);
2028
	                // String originMemberNode = rs.getString(6);
2029
	                // String authoritiveMemberNode = rs.getString(7);
2030
	                Timestamp dateModified = rs.getTimestamp(8);
2031
	                // String submitter = rs.getString(9);
2032
	                String fmtidStr = rs.getString(10);
2033
	                String sz = rs.getString(11);
2034
	                BigInteger size = new BigInteger("0");
2035
	
2036
	                if (sz != null && !sz.trim().equals("")) {
2037
	                    size = new BigInteger(rs.getString(11));
2038
	                }
2039
	
2040
	                ObjectInfo oi = new ObjectInfo();
2041
	
2042
	                Identifier id = new Identifier();
2043
	                id.setValue(guid);
2044
	                oi.setIdentifier(id);
2045
	
2046
	                if (dateModified != null) {
2047
	                    oi.setDateSysMetadataModified(dateModified);
2048
	                }
2049
	
2050
	                Checksum cs = new Checksum();
2051
	                cs.setValue(checksum);
2052
	                try {
2053
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
2054
	                    cs.setAlgorithm(checksumAlgorithm);
2055
	                } catch (Exception e) {
2056
	                    logMetacat.error("could not parse checksum algorithm", e);
2057
	                    continue;
2058
	                }
2059
	                oi.setChecksum(cs);
2060
	
2061
	                // set the format type
2062
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
2063
	                fmtid.setValue(fmtidStr);
2064
	                oi.setFormatId(fmtid);
2065
	
2066
	                oi.setSize(size);
2067
	                
2068
	                ol.addObjectInfo(oi);                    
2069

    
2070
	            }
2071
	            
2072
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
2073
	            // set the actual count retrieved
2074
	            ol.setCount(ol.sizeObjectInfoList());
2075
	            
2076
	
2077
	        }
2078
            ol.setTotal(total);
2079
        } finally {
2080
            // Return database connection to the pool
2081
            try {
2082
                if(totalResult !=null ){
2083
                    totalResult.close();
2084
                }
2085
                if(countStmt!=null ) {
2086
                    countStmt.close();
2087
                }
2088
                if(rs != null) {
2089
                    rs.close();
2090
                }
2091
                if(fieldStmt != null) {
2092
                    fieldStmt.close();
2093
                }
2094
                
2095
            } catch (SQLException sql) {
2096
                
2097
            }
2098
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2099
            
2100
        }
2101
        if(ol != null) {
2102
            logMetacat.debug("list objects start(before returning): " + ol.getStart());
2103
            logMetacat.debug("list objects count: " + ol.getCount());
2104
            logMetacat.debug("list objects total: " + ol.getTotal());
2105
        }
2106
        return ol;
2107
    }
2108
    
2109
    /**
2110
     * create a mapping in the identifier table
2111
     * @param guid
2112
     * @param localId
2113
     */
2114
    public void createMapping(String guid, String localId)
2115
    {        
2116
        
2117
        int serialNumber = -1;
2118
        DBConnection dbConn = null;
2119
        try {
2120

    
2121
            // Parse the localId into scope and rev parts
2122
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
2123
            String docid = acc.getDocid();
2124
            int rev = 1;
2125
            if (acc.getRev() != null) {
2126
              rev = (new Integer(acc.getRev()).intValue());
2127
            }
2128

    
2129
            // Get a database connection from the pool
2130
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
2131
            serialNumber = dbConn.getCheckOutSerialNumber();
2132

    
2133
            // Execute the insert statement
2134
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
2135
            PreparedStatement stmt = dbConn.prepareStatement(query);
2136
            stmt.setString(1, guid);
2137
            stmt.setString(2, docid);
2138
            stmt.setInt(3, rev);
2139
            logMetacat.debug("mapping query: " + stmt.toString());
2140
            int rows = stmt.executeUpdate();
2141

    
2142
            stmt.close();
2143
        } catch (SQLException e) {
2144
            e.printStackTrace();
2145
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2146
                    + e.getMessage());
2147
        } catch (NumberFormatException e) {
2148
            e.printStackTrace();
2149
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2150
                    + e.getMessage());
2151
        } catch (AccessionNumberException e) {
2152
            e.printStackTrace();
2153
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2154
                    + e.getMessage());
2155
        } finally {
2156
            // Return database connection to the pool
2157
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2158
        }
2159
    }
2160
    
2161
    /**
2162
     * remove a mapping in the identifier table
2163
     * @param guid
2164
     * @param localId
2165
     */
2166
    public void removeMapping(String guid, String localId)
2167
    {        
2168
        
2169
        int serialNumber = -1;
2170
        DBConnection dbConn = null;
2171
        try {
2172

    
2173
            // Parse the localId into scope and rev parts
2174
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
2175
            String docid = acc.getDocid();
2176
            int rev = 1;
2177
            if (acc.getRev() != null) {
2178
              rev = (new Integer(acc.getRev()).intValue());
2179
            }
2180

    
2181
            // Get a database connection from the pool
2182
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
2183
            serialNumber = dbConn.getCheckOutSerialNumber();
2184

    
2185
            // Execute the insert statement
2186
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
2187
            PreparedStatement stmt = dbConn.prepareStatement(query);
2188
            stmt.setString(1, guid);
2189
            stmt.setString(2, docid);
2190
            stmt.setInt(3, rev);
2191
            logMetacat.debug("remove mapping query: " + stmt.toString());
2192
            int rows = stmt.executeUpdate();
2193

    
2194
            stmt.close();
2195
        } catch (SQLException e) {
2196
            e.printStackTrace();
2197
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2198
                    + e.getMessage());
2199
        } catch (NumberFormatException e) {
2200
            e.printStackTrace();
2201
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2202
                    + e.getMessage());
2203
        } catch (AccessionNumberException e) {
2204
            e.printStackTrace();
2205
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2206
                    + e.getMessage());
2207
        } finally {
2208
            // Return database connection to the pool
2209
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2210
        }
2211
    }
2212
    
2213
    /**
2214
     * create the systemmetadata record
2215
     * @param guid
2216
     * @param dbConn 
2217
     * @throws SQLException 
2218
     */
2219
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
2220
    {        
2221

    
2222
        // Execute the insert statement
2223
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
2224
        PreparedStatement stmt = dbConn.prepareStatement(query);
2225
        stmt.setString(1, guid);
2226
        logMetacat.debug("system metadata query: " + stmt.toString());
2227
        int rows = stmt.executeUpdate();
2228

    
2229
        stmt.close();
2230
        
2231
    }
2232
    
2233
    public boolean deleteSystemMetadata(String guid)
2234
    {        
2235
        boolean success = false;
2236
        int serialNumber = -1;
2237
        DBConnection dbConn = null;
2238
        String query = null;
2239
        PreparedStatement stmt = null;
2240
        int rows = 0;
2241
        try {
2242

    
2243
        	 // Get a database connection from the pool
2244
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
2245
            serialNumber = dbConn.getCheckOutSerialNumber();
2246
            dbConn.setAutoCommit(false);
2247
        	
2248
            // remove the smReplicationPolicy
2249
            query = "delete from smReplicationPolicy " + 
2250
            "where guid = ?";
2251
            stmt = dbConn.prepareStatement(query);
2252
            stmt.setString(1, guid);
2253
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
2254
            rows = stmt.executeUpdate();
2255
            stmt.close();
2256
            
2257
            // remove the smReplicationStatus
2258
            query = "delete from smReplicationStatus " + 
2259
            "where guid = ?";
2260
            stmt = dbConn.prepareStatement(query);
2261
            stmt.setString(1, guid);
2262
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
2263
            rows = stmt.executeUpdate();
2264
            stmt.close();
2265
            
2266
            // remove the smmediatypeproperties
2267
            query = "delete from smmediatypeproperties " + 
2268
                    "where guid = ?";
2269
            stmt = dbConn.prepareStatement(query);
2270
            stmt.setString(1, guid);
2271
            logMetacat.debug("delete smmediatypeproperties: " + stmt.toString());
2272
            rows = stmt.executeUpdate();
2273
            stmt.close();
2274
            
2275
            // remove main system metadata entry
2276
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
2277
            stmt = dbConn.prepareStatement(query);
2278
            stmt.setString(1, guid);
2279
            logMetacat.debug("delete system metadata: " + stmt.toString());
2280
            rows = stmt.executeUpdate();
2281
            stmt.close();
2282
            
2283
            dbConn.commit();
2284
            dbConn.setAutoCommit(true);
2285
            success = true;
2286
            // TODO: remove the access?
2287
            // Metacat keeps "deleted" documents so we should not remove access rules.
2288
            
2289
        } catch (Exception e) {
2290
            e.printStackTrace();
2291
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
2292
            try {
2293
				dbConn.rollback();
2294
			} catch (SQLException sqle) {
2295
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
2296
			}
2297
        } finally {
2298
            // Return database connection to the pool
2299
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2300
        }
2301
        return success;
2302
    }
2303
    
2304
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
2305
    {
2306
        DBConnection dbConn = null;
2307
        int serialNumber = -1;
2308
        
2309
        try {
2310
            // Get a database connection from the pool
2311
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
2312
            serialNumber = dbConn.getCheckOutSerialNumber();
2313

    
2314
            // Execute the insert statement
2315
            String query = "update " + TYPE_SYSTEM_METADATA + 
2316
                " set authoritive_member_node = ? " +
2317
                " where authoritive_member_node = ?";
2318
            PreparedStatement stmt = dbConn.prepareStatement(query);
2319
            
2320
            //data values
2321
            stmt.setString(1, newMemberNodeId);
2322
            stmt.setString(2, existingMemberNodeId);
2323

    
2324
            logMetacat.debug("stmt: " + stmt.toString());
2325
            //execute
2326
            int rows = stmt.executeUpdate();
2327

    
2328
            stmt.close();
2329
        } catch (SQLException e) {
2330
            e.printStackTrace();
2331
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
2332
                    + e.getMessage());
2333
        } catch (NumberFormatException e) {
2334
            e.printStackTrace();
2335
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
2336
                    + e.getMessage());
2337
        } finally {
2338
            // Return database connection to the pool
2339
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2340
        }
2341
    }
2342
}
2343

    
(36-36/64)