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.io.File;
28
import java.math.BigInteger;
29
import java.sql.PreparedStatement;
30
import java.sql.ResultSet;
31
import java.sql.SQLException;
32
import java.sql.Timestamp;
33
import java.util.ArrayList;
34
import java.util.Date;
35
import java.util.HashMap;
36
import java.util.Hashtable;
37
import java.util.List;
38
import java.util.Vector;
39

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1288
	            // Execute the insert statement
1289
	            stmt = dbConn.prepareStatement(query);
1290
	            stmt.setString(1, guid);
1291
	            ResultSet rs = stmt.executeQuery();
1292
	            if (rs.next()) {
1293
	                exists = true;
1294
	            }
1295
	            if(rs != null) {
1296
	                rs.close();
1297
	            }
1298

    
1299
	        } catch (SQLException e) {
1300
	            logMetacat.error("Error while looking up the system metadata: "
1301
	                    + e.getMessage());
1302
	            throw e;
1303
	        } finally {
1304
	            try {
1305
	                if(stmt != null) {
1306
	                    stmt.close();
1307
	                }
1308
	            } catch (Exception e) {
1309
	                logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
1310
	            } finally {
1311
	                // Return database connection to the pool
1312
	                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1313
	            }
1314
	        }
1315
		}
1316
		return exists;
1317
	}
1318
    
1319
    /**
1320
     * creates a system metadata mapping and adds additional fields from sysmeta
1321
     * to the table for quick searching.
1322
     * 
1323
     * @param guid the id to insert
1324
     * @param localId the systemMetadata object to get the local id for
1325
     * @throws McdbDocNotFoundException 
1326
     * @throws SQLException 
1327
     * @throws InvalidSystemMetadata 
1328
     */
1329
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta) 
1330
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1331
    	String guid = sysmeta.getIdentifier().getValue();
1332
    	
1333
    	 // Get a database connection from the pool
1334
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1335
        int serialNumber = dbConn.getCheckOutSerialNumber();
1336
        
1337
        try {
1338
        	// use a single transaction for it all
1339
        	dbConn.setAutoCommit(false);
1340
        	
1341
	    	// insert the record if needed
1342
        	if (!IdentifierManager.getInstance().systemMetadataPIDExists(guid)) {
1343
    	        insertSystemMetadata(guid, dbConn);
1344
			}
1345
	        // update with the values
1346
	        updateSystemMetadata(sysmeta, dbConn);
1347
	        
1348
	        // commit if we got here with no errors
1349
	        dbConn.commit();
1350
        } catch (Exception e) {
1351
            e.printStackTrace();
1352
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1353
            dbConn.rollback();
1354
            throw new SQLException("Can't save system metadata "+e.getMessage());
1355
        } finally {
1356
            // Return database connection to the pool
1357
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1358
        }
1359
        
1360
        
1361
    }
1362
        
1363
    
1364
    /**
1365
     * update a mapping
1366
     * @param guid
1367
     * @param localId
1368
     */
1369
    public void updateMapping(String guid, String localId)
1370
    {
1371
    	
1372
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1373
        int serialNumber = -1;
1374
        DBConnection dbConn = null;
1375
        try {
1376
            // Parse the localId into scope and rev parts
1377
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1378
            String docid = acc.getDocid();
1379
            int rev = 1;
1380
            if(acc.getRev() != null)
1381
            {
1382
              rev = (new Integer(acc.getRev()).intValue());
1383
            }
1384

    
1385
            // Get a database connection from the pool
1386
            dbConn = 
1387
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1388
            serialNumber = dbConn.getCheckOutSerialNumber();
1389

    
1390
            // Execute the update statement
1391
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1392
            PreparedStatement stmt = dbConn.prepareStatement(query);
1393
            stmt.setString(1, docid);
1394
            stmt.setInt(2, rev);
1395
            stmt.setString(3, guid);
1396
            int rows = stmt.executeUpdate();
1397

    
1398
            stmt.close();
1399
        } catch (SQLException e) {
1400
            e.printStackTrace();
1401
            logMetacat.error("SQL error while updating a mapping identifier: " 
1402
                    + e.getMessage());
1403
        } catch (NumberFormatException e) {
1404
            e.printStackTrace();
1405
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1406
                    + e.getMessage());
1407
        } catch (AccessionNumberException e) {
1408
            e.printStackTrace();
1409
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1410
                    + e.getMessage());
1411
        } finally {
1412
            // Return database connection to the pool
1413
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1414
        }
1415
        logMetacat.debug("done updating mapping");
1416
    }
1417
        
1418
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1419
        String checksum, String checksumAlgorithm, String originMemberNode, 
1420
        String authoritativeMemberNode, long modifiedDate, String submitter, 
1421
        String guid, String objectFormat, BigInteger size, boolean archived,
1422
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1423
        String obsoletedBy, BigInteger serialVersion, String seriesId, 
1424
        String fileName, MediaType mediaType, DBConnection dbConn) throws SQLException  {
1425
        PreparedStatement stmt = null;
1426
        PreparedStatement stmt2 = null;
1427
        try {
1428
            dbConn.setAutoCommit(false);
1429
            // Execute the insert statement
1430
            String query = "update " + TYPE_SYSTEM_METADATA + 
1431
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1432
                "origin_member_node, authoritive_member_node, date_modified, " +
1433
                "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1434
                "obsoletes, obsoleted_by, serial_version, series_id, file_name, media_type) " +
1435
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?) where guid = ?";
1436
            stmt = dbConn.prepareStatement(query);
1437
            
1438
            //data values
1439
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1440
            stmt.setString(2, rightsHolder);
1441
            stmt.setString(3, checksum);
1442
            stmt.setString(4, checksumAlgorithm);
1443
            stmt.setString(5, originMemberNode);
1444
            stmt.setString(6, authoritativeMemberNode);
1445
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1446
            stmt.setString(8, submitter);
1447
            stmt.setString(9, objectFormat);
1448
            stmt.setString(10, size.toString());
1449
            stmt.setBoolean(11, archived);
1450
            stmt.setBoolean(12, replicationAllowed);
1451
            stmt.setInt(13, numberReplicas);
1452
            stmt.setString(14, obsoletes);
1453
            stmt.setString(15, obsoletedBy);
1454
            if(serialVersion != null) {
1455
                stmt.setString(16, serialVersion.toString());
1456
            } else {
1457
                stmt.setString(16, null);
1458
            }
1459
            
1460
            stmt.setString(17, seriesId);
1461
            stmt.setString(18, fileName);
1462
            if (mediaType == null) {
1463
                stmt.setString(19, null);
1464
            } else {
1465
                stmt.setString(19, mediaType.getName());
1466
            }
1467
            //where clause
1468
            stmt.setString(20, guid);
1469
            logMetacat.debug("stmt: " + stmt.toString());
1470
            //execute
1471
            int rows = stmt.executeUpdate();
1472
            
1473
            //insert media type properties into another table
1474
            if(mediaType != null && mediaType.getPropertyList() != null) {
1475
                String sql2 = "insert into smmediatypeproperties " + 
1476
                        "(guid, name, value) " + "values (?, ?, ?)";
1477
                stmt2 = dbConn.prepareStatement(sql2);
1478
                for(MediaTypeProperty item : mediaType.getPropertyList()) {
1479
                    if(item != null) {
1480
                        String name = item.getName();
1481
                        String value = item.getValue();
1482
                        stmt2.setString(1, guid);
1483
                        stmt2.setString(2, name);
1484
                        stmt2.setString(3, value);
1485
                        logMetacat.debug("insert media type properties query: " + stmt2.toString());
1486
                        int row =stmt2.executeUpdate();
1487
                    }
1488
                    
1489
                }
1490
            }
1491
            dbConn.commit();
1492
            dbConn.setAutoCommit(true);
1493
        } catch (Exception e) {
1494
            dbConn.rollback();
1495
            dbConn.setAutoCommit(true);
1496
            e.printStackTrace();
1497
            throw new SQLException(e.getMessage());
1498
        } finally {
1499
            if(stmt != null) {
1500
                stmt.close();
1501
            }
1502
            if(stmt2 != null) {
1503
                stmt2.close();
1504
            }
1505
        }
1506
        
1507
               
1508
    }
1509
    
1510
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1511
    {
1512
           
1513
        // remove existing values first
1514
        String delete = "delete from smReplicationPolicy " + 
1515
        "where guid = ? and policy = ?";
1516
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1517
        //data values
1518
        stmt.setString(1, guid);
1519
        stmt.setString(2, policy);
1520
        //execute
1521
        int deletedCount = stmt.executeUpdate();
1522
        stmt.close();
1523
        
1524
        for (String memberNode: memberNodes) {
1525
            // Execute the insert statement
1526
            String insert = "insert into smReplicationPolicy " + 
1527
                "(guid, policy, member_node) " +
1528
                "values (?, ?, ?)";
1529
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1530
            
1531
            //data values
1532
            insertStatement.setString(1, guid);
1533
            insertStatement.setString(2, policy);
1534
            insertStatement.setString(3, memberNode);
1535
            
1536
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1537

    
1538
            //execute
1539
            int rows = insertStatement.executeUpdate();
1540
            insertStatement.close();
1541
        }
1542
        
1543
    }
1544
    
1545
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1546
       
1547
        // remove existing values first
1548
        String delete = "delete from smReplicationStatus " + 
1549
        "where guid = ?";
1550
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1551
        //data values
1552
        stmt.setString(1, guid);
1553
        //execute
1554
        int deletedCount = stmt.executeUpdate();
1555
        stmt.close();
1556
        
1557
        if (replicas != null) {
1558
            for (Replica replica: replicas) {
1559
	            // Execute the insert statement
1560
	            String insert = "insert into smReplicationStatus " + 
1561
	                "(guid, member_node, status, date_verified) " +
1562
	                "values (?, ?, ?, ?)";
1563
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1564
	            
1565
	            //data values
1566
	            String memberNode = replica.getReplicaMemberNode().getValue();
1567
	            String status = replica.getReplicationStatus().toString();
1568
	            java.sql.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1569
	            insertStatement.setString(1, guid);
1570
	            insertStatement.setString(2, memberNode);
1571
	            insertStatement.setString(3, status);
1572
	            insertStatement.setTimestamp(4, sqlDate);
1573

    
1574
	            logMetacat.debug("smReplicationStatus sql: " + insertStatement.toString());
1575
	            
1576
	            //execute
1577
	            int rows = insertStatement.executeUpdate();
1578
	            insertStatement.close();
1579
            }
1580
        }
1581
       
1582
    }
1583
    
1584
    /**
1585
     * Insert the system metadata fields into the db
1586
     * @param sm
1587
     * @throws McdbDocNotFoundException 
1588
     * @throws SQLException 
1589
     * @throws InvalidSystemMetadata 
1590
     * @throws AccessException 
1591
     */
1592
    public void updateSystemMetadata(SystemMetadata sm, DBConnection dbConn) 
1593
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata, AccessException {
1594
    	
1595
      Boolean replicationAllowed = false;
1596
		  Integer numberReplicas = -1;
1597
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1598
    	if (replicationPolicy != null) {
1599
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1600
    		numberReplicas = replicationPolicy.getNumberReplicas();
1601
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1602
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1603
    	}
1604
    	
1605
    	// the main systemMetadata fields
1606
		  updateSystemMetadataFields(
1607
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1608
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1609
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1610
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1611
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1612
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1613
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1614
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1615
		    sm.getIdentifier().getValue(),
1616
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1617
		    sm.getSize(),
1618
		    sm.getArchived() == null ? false: sm.getArchived(),
1619
		    replicationAllowed, 
1620
		    numberReplicas,
1621
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1622
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1623
		    sm.getSerialVersion(),
1624
		    sm.getSeriesId() == null ? null: sm.getSeriesId().getValue(),
1625
		    sm.getFileName() == null ? null: sm.getFileName(),
1626
		    sm.getMediaType() == null ? null: sm.getMediaType(),
1627
		    dbConn
1628
        );
1629
        
1630
        String guid = sm.getIdentifier().getValue();
1631
        
1632
        // save replication policies
1633
        if (replicationPolicy != null) {
1634
		    List<String> nodes = null;
1635
		    String policy = null;
1636
		    
1637
		    // check for null 
1638
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1639
			    nodes = new ArrayList<String>();
1640
			    policy = "blocked";
1641
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1642
			    	nodes.add(node.getValue());
1643
			    }
1644
			    this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1645
		    }
1646
		    
1647
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1648
			    nodes = new ArrayList<String>();
1649
			    policy = "preferred";
1650
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1651
			    	nodes.add(node.getValue());
1652
			    }
1653
		        this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1654
		    }
1655
        }
1656
        
1657
        // save replica information
1658
        this.insertReplicationStatus(guid, sm.getReplicaList(), dbConn);
1659
        
1660
        // save access policy
1661
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1662
        if (accessPolicy != null) {
1663
			this.insertAccessPolicy(guid, accessPolicy);
1664
        }
1665
    }
1666
    
1667
    /**
1668
     * Creates Metacat access rules and inserts them
1669
     * @param accessPolicy
1670
     * @throws McdbDocNotFoundException
1671
     * @throws AccessException
1672
     */
1673
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1674
    	
1675
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1676
        XMLAccessAccess accessController  = new XMLAccessAccess();
1677
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1678
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1679
        if (existingAccess != null && existingAccess.size() > 0) {
1680
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1681
        }
1682
        
1683
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1684
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1685
        	List<Subject> subjects = accessRule.getSubjectList();
1686
        	List<Permission> permissions = accessRule.getPermissionList();
1687
        	for (Subject subject: subjects) {
1688
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1689
        		accessDAO.setPrincipalName(subject.getValue());
1690
    			accessDAO.setGuid(guid);
1691
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1692
				accessDAO.setPermOrder(existingPermOrder);
1693
    			if (permissions != null) {
1694
	    			for (Permission permission: permissions) {
1695
	    				Long metacatPermission = new Long(convertPermission(permission));
1696
	        			accessDAO.addPermission(metacatPermission);
1697
	    			}
1698
    			}
1699
    			accessDAOs.add(accessDAO);
1700
        	}
1701
        }
1702
        
1703
        
1704
        // remove all existing allow records
1705
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1706
        // add the ones we can for this guid
1707
        accessController.insertAccess(guid, accessDAOs);
1708
        
1709
        
1710
    }
1711
    
1712
    /**
1713
     * Lookup access policy from Metacat
1714
     * @param guid
1715
     * @return
1716
     * @throws McdbDocNotFoundException
1717
     * @throws AccessException
1718
     */
1719
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1720
        AccessPolicy accessPolicy = new AccessPolicy();
1721

    
1722
    	// use GUID to look up the access
1723
        XMLAccessAccess accessController  = new XMLAccessAccess();
1724
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1725
        
1726
        for (XMLAccessDAO accessDAO: accessDAOs) {
1727
        	// only add allow rule
1728
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1729
	        	AccessRule accessRule = new AccessRule();    	
1730
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1731
	        	// cannot include if we have no permissions
1732
	        	if (permissions == null || permissions.isEmpty()) {
1733
	        		logMetacat.warn("skipping empty access rule permissions for " + guid);
1734
	        		continue;
1735
	        	}
1736
	        	accessRule.setPermissionList(permissions);
1737
	        	Subject subject = new Subject();
1738
	        	subject.setValue(accessDAO.getPrincipalName());
1739
	        	accessRule.addSubject(subject);
1740
	            accessPolicy.addAllow(accessRule);
1741
        	}
1742
        }
1743
        return accessPolicy;
1744
    }
1745
    
1746
    public int convertPermission(Permission permission) {
1747
    	if (permission.equals(Permission.READ)) {
1748
    		return AccessControlInterface.READ;
1749
    	}
1750
    	if (permission.equals(Permission.WRITE)) {
1751
    		return AccessControlInterface.WRITE;
1752
    	}
1753
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1754
    		// implies all permission, rather than just CHMOD
1755
    		return AccessControlInterface.ALL;
1756
    	}
1757
		return -1;
1758
    }
1759
    
1760
    public List<Permission> convertPermission(int permission) {
1761
    	
1762
    	List<Permission> permissions = new ArrayList<Permission>();
1763
    	if (permission == AccessControlInterface.ALL) {
1764
    		permissions.add(Permission.READ);
1765
    		permissions.add(Permission.WRITE);
1766
    		permissions.add(Permission.CHANGE_PERMISSION);
1767
    		return permissions;
1768
    	}
1769
    	
1770
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1771
    		permissions.add(Permission.CHANGE_PERMISSION);
1772
    	}
1773
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1774
    		permissions.add(Permission.READ);
1775
    	}
1776
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1777
    		permissions.add(Permission.WRITE);
1778
    	}
1779
    	
1780
		return permissions;
1781
    }
1782
    
1783
    /**
1784
     * Lookup a localId given the GUID. If
1785
     * the identifier is not found, throw an exception.
1786
     * 
1787
     * @param guid the global identifier to look up
1788
     * @return String containing the corresponding LocalId
1789
     * @throws McdbDocNotFoundException if the identifier is not found
1790
     */
1791
    public String getLocalId(String guid) throws McdbDocNotFoundException, SQLException {
1792
      
1793
      String db_guid = "";
1794
      String docid = "";
1795
      int rev = 0;
1796
      
1797
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1798
      
1799
      DBConnection dbConn = null;
1800
      int serialNumber = -1;
1801
      try {
1802
          // Get a database connection from the pool
1803
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1804
          serialNumber = dbConn.getCheckOutSerialNumber();
1805
          
1806
          // Execute the insert statement
1807
          PreparedStatement stmt = dbConn.prepareStatement(query);
1808
          stmt.setString(1, guid);
1809
          ResultSet rs = stmt.executeQuery();
1810
          if (rs.next()) {
1811
              db_guid = rs.getString(1);
1812
              docid = rs.getString(2);
1813
              rev = rs.getInt(3);
1814
              assert(db_guid.equals(guid));
1815
          } else {
1816
              throw new McdbDocNotFoundException("Document not found:" + guid);
1817
          }
1818
          stmt.close();
1819
      } catch (SQLException e) {
1820
          logMetacat.error("Error while looking up the local identifier: " 
1821
                  + e.getMessage());
1822
          throw e;
1823
      } finally {
1824
          // Return database connection to the pool
1825
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1826
      }
1827
      return docid + "." + rev;
1828
    }
1829
    
1830
    /**
1831
     * query the systemmetadata table based on the given parameters
1832
     * @param startTime
1833
     * @param endTime
1834
     * @param objectFormat
1835
     * @param nodeId
1836
     * @param start
1837
     * @param count
1838
     * @return ObjectList
1839
     * @throws SQLException 
1840
     * @throws ServiceException 
1841
     * @throws PropertyNotFoundException 
1842
     */
1843
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1844
        ObjectFormatIdentifier objectFormatId, NodeReference nodeId,
1845
        int start, int count, Identifier identifier, boolean isSID) 
1846
        throws SQLException, PropertyNotFoundException, ServiceException {
1847
        ObjectList ol = new ObjectList();
1848
        DBConnection dbConn = null;
1849
        int serialNumber = -1;
1850
        PreparedStatement countStmt=null;
1851
        ResultSet totalResult=null;
1852
        PreparedStatement fieldStmt = null;
1853
        ResultSet rs= null;
1854

    
1855
        try {
1856
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1857
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1858
                    + "date_modified, submitter, object_format, size from systemmetadata";
1859
            
1860
            // handle special case quickly
1861
            String countSql = "select count(guid) from systemmetadata";
1862
            
1863
            // the clause
1864
            String whereClauseSql = "";
1865
            
1866

    
1867
            boolean f1 = false;
1868
            boolean f2 = false;
1869
            boolean f3 = false;
1870
            boolean f4 = false;
1871

    
1872

    
1873
            if (startTime != null) {
1874
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1875
                f1 = true;
1876
            }
1877

    
1878
            if (endTime != null) {
1879
                if (!f1) {
1880
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1881
                } else {
1882
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1883
                }
1884
                f2 = true;
1885
            }
1886

    
1887
            if (objectFormatId != null) {
1888
                if (!f1 && !f2) {
1889
                    whereClauseSql += " where object_format = ?";
1890
                } else {
1891
                    whereClauseSql += " and object_format = ?";
1892
                }
1893
                f3 = true;
1894
            }
1895
            
1896
            if(identifier != null && identifier.getValue() != null && !identifier.getValue().equals("")) {
1897
                if (!f1 && !f2 && !f3 ) {
1898
                    if(isSID) {
1899
                        whereClauseSql += " where series_id = ?";
1900
                    } else {
1901
                        whereClauseSql += " where guid = ?";
1902
                    }
1903
                    
1904
                } else {
1905
                    if(isSID) {
1906
                        whereClauseSql += " and series_id = ?";
1907
                    } else {
1908
                        whereClauseSql += " and guid = ?";
1909
                    }
1910
                }
1911
                f4 = true;
1912
            }
1913

    
1914
            /*if (!replicaStatus) {
1915
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1916
                if (!f1 && !f2 && !f3 && !f4) {
1917
                    whereClauseSql += " where authoritive_member_node = '" +
1918
                        currentNodeId.trim() + "'";
1919
                } else {
1920
                    whereClauseSql += " and authoritive_member_node = '" +
1921
                        currentNodeId.trim() + "'";
1922
                }
1923
            }*/
1924
            
1925
            if (nodeId != null && nodeId.getValue() != null && !nodeId.getValue().trim().equals("")) {
1926
                if (!f1 && !f2 && !f3 && !f4) {
1927
                    whereClauseSql += " where authoritive_member_node = '" +
1928
                        nodeId.getValue().trim() + "'";
1929
                } else {
1930
                    whereClauseSql += " and authoritive_member_node = '" +
1931
                        nodeId.getValue().trim() + "'";
1932
                }
1933
            }
1934
           
1935
            
1936
            // connection
1937
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1938
            serialNumber = dbConn.getCheckOutSerialNumber();
1939

    
1940
            // the field query
1941
            String orderBySql = " order by guid ";
1942
            String fieldQuery = fieldSql + whereClauseSql + orderBySql;
1943
            String finalQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldQuery, start, count);
1944
            fieldStmt = dbConn.prepareStatement(finalQuery);
1945
            
1946
            // construct the count query and statment
1947
            String countQuery = countSql + whereClauseSql;
1948
            countStmt = dbConn.prepareStatement(countQuery);
1949

    
1950
            if (f1 && f2 && f3 && f4) {
1951
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1952
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1953
                fieldStmt.setString(3, objectFormatId.getValue());
1954
                fieldStmt.setString(4, identifier.getValue());
1955
                // count
1956
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1957
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1958
                countStmt.setString(3, objectFormatId.getValue());
1959
                countStmt.setString(4, identifier.getValue());
1960
            } if (f1 && f2 && f3 && !f4) {
1961
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1962
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1963
                fieldStmt.setString(3, objectFormatId.getValue());
1964
                // count
1965
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1966
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1967
                countStmt.setString(3, objectFormatId.getValue());
1968
            } else if (f1 && f2 && !f3 && f4) {
1969
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1970
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1971
                fieldStmt.setString(3, identifier.getValue());
1972
                // count
1973
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1974
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1975
                countStmt.setString(3, identifier.getValue());
1976
            } else if (f1 && f2 && !f3 && !f4) {
1977
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1978
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1979
                // count
1980
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1981
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1982
            } else if (f1 && !f2 && f3 && f4) {
1983
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1984
                fieldStmt.setString(2, objectFormatId.getValue());
1985
                fieldStmt.setString(3, identifier.getValue());
1986
                // count
1987
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1988
                countStmt.setString(2, objectFormatId.getValue());
1989
                countStmt.setString(3, identifier.getValue());
1990
            } else if (f1 && !f2 && f3 && !f4) {
1991
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1992
                fieldStmt.setString(2, objectFormatId.getValue());
1993
                // count
1994
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1995
                countStmt.setString(2, objectFormatId.getValue());
1996
            } else if (f1 && !f2 && !f3 && f4) {
1997
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1998
                fieldStmt.setString(2, identifier.getValue());
1999
                // count
2000
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
2001
                countStmt.setString(2, identifier.getValue());
2002
            } else if (f1 && !f2 && !f3 && !f4) {
2003
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
2004
                // count
2005
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
2006
            } else if (!f1 && f2 && f3 && f4) {
2007
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2008
                fieldStmt.setString(2, objectFormatId.getValue());
2009
                fieldStmt.setString(3, identifier.getValue());
2010
                // count
2011
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2012
                countStmt.setString(2, objectFormatId.getValue());
2013
                countStmt.setString(3, identifier.getValue());
2014
            } else if (!f1 && f2 && f3 && !f4) {
2015
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2016
                fieldStmt.setString(2, objectFormatId.getValue());
2017
                // count
2018
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2019
                countStmt.setString(2, objectFormatId.getValue());
2020
            } else if (!f1 && !f2 && f3 && f4) {
2021
                fieldStmt.setString(1, objectFormatId.getValue());
2022
                fieldStmt.setString(2, identifier.getValue());
2023
                // count
2024
                countStmt.setString(1, objectFormatId.getValue());
2025
                countStmt.setString(2, identifier.getValue());
2026
            } else if (!f1 && !f2 && f3 && !f4) {
2027
                fieldStmt.setString(1, objectFormatId.getValue());
2028
                // count
2029
                countStmt.setString(1, objectFormatId.getValue());
2030
            } else if (!f1 && f2 && !f3 && f4) {
2031
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2032
                fieldStmt.setString(2, identifier.getValue());
2033
                // count
2034
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2035
                countStmt.setString(2, identifier.getValue());
2036
            } else if (!f1 && f2 && !f3 && !f4) {
2037
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2038
                // count
2039
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
2040
            } else if (!f1 && !f2 && !f3 && f4) {
2041
                fieldStmt.setString(1, identifier.getValue());
2042
                // count
2043
                countStmt.setString(1, identifier.getValue());
2044
            } else if (!f1 && !f2 && !f3 && !f4) {
2045
                //do nothing
2046
            }
2047

    
2048
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
2049
            
2050
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
2051
            
2052
            // get the total object count no matter what
2053
            int total = 0;
2054
            totalResult = countStmt.executeQuery();
2055
            if (totalResult.next()) {
2056
            	total = totalResult.getInt(1);
2057
            }
2058
            
2059
            logMetacat.debug("list objects total: " + total);
2060

    
2061
        	// set the totals
2062
        	ol.setStart(start);
2063
            ol.setCount(count);
2064
            
2065
            // retrieve the actual records if requested
2066
            if (count != 0) {
2067
            	
2068
                rs = fieldStmt.executeQuery();
2069
	            while (rs.next()) {                
2070
	                
2071
	                String guid = rs.getString(1);
2072
	                logMetacat.debug("query found object with guid " + guid);
2073
	                // Timestamp dateUploaded = rs.getTimestamp(2);
2074
	                // String rightsHolder = rs.getString(3);
2075
	                String checksum = rs.getString(4);
2076
	                String checksumAlgorithm = rs.getString(5);
2077
	                // String originMemberNode = rs.getString(6);
2078
	                // String authoritiveMemberNode = rs.getString(7);
2079
	                Timestamp dateModified = rs.getTimestamp(8);
2080
	                // String submitter = rs.getString(9);
2081
	                String fmtidStr = rs.getString(10);
2082
	                String sz = rs.getString(11);
2083
	                BigInteger size = new BigInteger("0");
2084
	
2085
	                if (sz != null && !sz.trim().equals("")) {
2086
	                    size = new BigInteger(rs.getString(11));
2087
	                }
2088
	
2089
	                ObjectInfo oi = new ObjectInfo();
2090
	
2091
	                Identifier id = new Identifier();
2092
	                id.setValue(guid);
2093
	                oi.setIdentifier(id);
2094
	
2095
	                if (dateModified != null) {
2096
	                    oi.setDateSysMetadataModified(dateModified);
2097
	                }
2098
	
2099
	                Checksum cs = new Checksum();
2100
	                cs.setValue(checksum);
2101
	                try {
2102
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
2103
	                    cs.setAlgorithm(checksumAlgorithm);
2104
	                } catch (Exception e) {
2105
	                    logMetacat.error("could not parse checksum algorithm", e);
2106
	                    continue;
2107
	                }
2108
	                oi.setChecksum(cs);
2109
	
2110
	                // set the format type
2111
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
2112
	                fmtid.setValue(fmtidStr);
2113
	                oi.setFormatId(fmtid);
2114
	
2115
	                oi.setSize(size);
2116
	                
2117
	                ol.addObjectInfo(oi);                    
2118

    
2119
	            }
2120
	            
2121
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
2122
	            // set the actual count retrieved
2123
	            ol.setCount(ol.sizeObjectInfoList());
2124
	            
2125
	
2126
	        }
2127
            ol.setTotal(total);
2128
        } finally {
2129
            // Return database connection to the pool
2130
            try {
2131
                if(totalResult !=null ){
2132
                    totalResult.close();
2133
                }
2134
                if(countStmt!=null ) {
2135
                    countStmt.close();
2136
                }
2137
                if(rs != null) {
2138
                    rs.close();
2139
                }
2140
                if(fieldStmt != null) {
2141
                    fieldStmt.close();
2142
                }
2143
                
2144
            } catch (SQLException sql) {
2145
                
2146
            }
2147
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2148
            
2149
        }
2150
        if(ol != null) {
2151
            logMetacat.debug("list objects start(before returning): " + ol.getStart());
2152
            logMetacat.debug("list objects count: " + ol.getCount());
2153
            logMetacat.debug("list objects total: " + ol.getTotal());
2154
        }
2155
        return ol;
2156
    }
2157
    
2158
    /**
2159
     * create a mapping in the identifier table
2160
     * @param guid
2161
     * @param localId
2162
     */
2163
    public void createMapping(String guid, String localId)
2164
    {        
2165
        
2166
        int serialNumber = -1;
2167
        DBConnection dbConn = null;
2168
        try {
2169

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

    
2178
            // Get a database connection from the pool
2179
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
2180
            serialNumber = dbConn.getCheckOutSerialNumber();
2181

    
2182
            // Execute the insert statement
2183
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
2184
            PreparedStatement stmt = dbConn.prepareStatement(query);
2185
            stmt.setString(1, guid);
2186
            stmt.setString(2, docid);
2187
            stmt.setInt(3, rev);
2188
            logMetacat.debug("mapping query: " + stmt.toString());
2189
            int rows = stmt.executeUpdate();
2190

    
2191
            stmt.close();
2192
        } catch (SQLException e) {
2193
            e.printStackTrace();
2194
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2195
                    + e.getMessage());
2196
        } catch (NumberFormatException e) {
2197
            e.printStackTrace();
2198
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2199
                    + e.getMessage());
2200
        } catch (AccessionNumberException e) {
2201
            e.printStackTrace();
2202
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2203
                    + e.getMessage());
2204
        } finally {
2205
            // Return database connection to the pool
2206
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2207
        }
2208
    }
2209
    
2210
    /**
2211
     * remove a mapping in the identifier table
2212
     * @param guid
2213
     * @param localId
2214
     */
2215
    public void removeMapping(String guid, String localId)
2216
    {        
2217
        
2218
        int serialNumber = -1;
2219
        DBConnection dbConn = null;
2220
        try {
2221

    
2222
            // Parse the localId into scope and rev parts
2223
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
2224
            String docid = acc.getDocid();
2225
            int rev = 1;
2226
            if (acc.getRev() != null) {
2227
              rev = (new Integer(acc.getRev()).intValue());
2228
            }
2229

    
2230
            // Get a database connection from the pool
2231
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
2232
            serialNumber = dbConn.getCheckOutSerialNumber();
2233

    
2234
            // Execute the insert statement
2235
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
2236
            PreparedStatement stmt = dbConn.prepareStatement(query);
2237
            stmt.setString(1, guid);
2238
            stmt.setString(2, docid);
2239
            stmt.setInt(3, rev);
2240
            logMetacat.debug("remove mapping query: " + stmt.toString());
2241
            int rows = stmt.executeUpdate();
2242

    
2243
            stmt.close();
2244
        } catch (SQLException e) {
2245
            e.printStackTrace();
2246
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2247
                    + e.getMessage());
2248
        } catch (NumberFormatException e) {
2249
            e.printStackTrace();
2250
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2251
                    + e.getMessage());
2252
        } catch (AccessionNumberException e) {
2253
            e.printStackTrace();
2254
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2255
                    + e.getMessage());
2256
        } finally {
2257
            // Return database connection to the pool
2258
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2259
        }
2260
    }
2261
    
2262
    /**
2263
     * create the systemmetadata record
2264
     * @param guid
2265
     * @param dbConn 
2266
     * @throws SQLException 
2267
     */
2268
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
2269
    {        
2270

    
2271
        // Execute the insert statement
2272
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
2273
        PreparedStatement stmt = dbConn.prepareStatement(query);
2274
        stmt.setString(1, guid);
2275
        logMetacat.debug("system metadata query: " + stmt.toString());
2276
        int rows = stmt.executeUpdate();
2277

    
2278
        stmt.close();
2279
        
2280
    }
2281
    
2282
    public boolean deleteSystemMetadata(String guid)
2283
    {        
2284
        boolean success = false;
2285
        int serialNumber = -1;
2286
        DBConnection dbConn = null;
2287
        String query = null;
2288
        PreparedStatement stmt = null;
2289
        int rows = 0;
2290
        try {
2291

    
2292
        	 // Get a database connection from the pool
2293
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
2294
            serialNumber = dbConn.getCheckOutSerialNumber();
2295
            dbConn.setAutoCommit(false);
2296
        	
2297
            // remove the smReplicationPolicy
2298
            query = "delete from smReplicationPolicy " + 
2299
            "where guid = ?";
2300
            stmt = dbConn.prepareStatement(query);
2301
            stmt.setString(1, guid);
2302
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
2303
            rows = stmt.executeUpdate();
2304
            stmt.close();
2305
            
2306
            // remove the smReplicationStatus
2307
            query = "delete from smReplicationStatus " + 
2308
            "where guid = ?";
2309
            stmt = dbConn.prepareStatement(query);
2310
            stmt.setString(1, guid);
2311
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
2312
            rows = stmt.executeUpdate();
2313
            stmt.close();
2314
            
2315
            // remove the smmediatypeproperties
2316
            query = "delete from smMediaTypeProperties " + 
2317
                    "where guid = ?";
2318
            stmt = dbConn.prepareStatement(query);
2319
            stmt.setString(1, guid);
2320
            logMetacat.debug("delete smMediaTypeProperties: " + stmt.toString());
2321
            rows = stmt.executeUpdate();
2322
            stmt.close();
2323
            
2324
            // remove the xml_access
2325
            query = "delete from xml_access " + 
2326
                    "where guid = ?";
2327
            stmt = dbConn.prepareStatement(query);
2328
            stmt.setString(1, guid);
2329
            logMetacat.debug("delete xml_access: " + stmt.toString());
2330
            rows = stmt.executeUpdate();
2331
            stmt.close();
2332
            
2333
            // remove main system metadata entry
2334
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
2335
            stmt = dbConn.prepareStatement(query);
2336
            stmt.setString(1, guid);
2337
            logMetacat.debug("delete system metadata: " + stmt.toString());
2338
            rows = stmt.executeUpdate();
2339
            stmt.close();
2340
            
2341
            dbConn.commit();
2342
            dbConn.setAutoCommit(true);
2343
            success = true;
2344
            // TODO: remove the access?
2345
            // Metacat keeps "deleted" documents so we should not remove access rules.
2346
            
2347
        } catch (Exception e) {
2348
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
2349
            try {
2350
				dbConn.rollback();
2351
			} catch (SQLException sqle) {
2352
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
2353
			}
2354
        } finally {
2355
            // Return database connection to the pool
2356
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2357
        }
2358
        return success;
2359
    }
2360
    
2361
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
2362
    {
2363
        DBConnection dbConn = null;
2364
        int serialNumber = -1;
2365
        
2366
        try {
2367
            // Get a database connection from the pool
2368
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
2369
            serialNumber = dbConn.getCheckOutSerialNumber();
2370

    
2371
            // Execute the insert statement
2372
            String query = "update " + TYPE_SYSTEM_METADATA + 
2373
                " set authoritive_member_node = ? " +
2374
                " where authoritive_member_node = ?";
2375
            PreparedStatement stmt = dbConn.prepareStatement(query);
2376
            
2377
            //data values
2378
            stmt.setString(1, newMemberNodeId);
2379
            stmt.setString(2, existingMemberNodeId);
2380

    
2381
            logMetacat.debug("stmt: " + stmt.toString());
2382
            //execute
2383
            int rows = stmt.executeUpdate();
2384

    
2385
            stmt.close();
2386
        } catch (SQLException e) {
2387
            e.printStackTrace();
2388
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
2389
                    + e.getMessage());
2390
        } catch (NumberFormatException e) {
2391
            e.printStackTrace();
2392
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
2393
                    + e.getMessage());
2394
        } finally {
2395
            // Return database connection to the pool
2396
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2397
        }
2398
    }
2399
    
2400
    /**
2401
     * Determine if the object file exist for the given localId.
2402
     * @param localId
2403
     * @param isScienceMetadata
2404
     * @return
2405
     * @throws PropertyNotFoundException
2406
     */
2407
    public boolean objectFileExists(String localId, boolean isScienceMetadata) throws PropertyNotFoundException {
2408
        boolean exist =false;
2409
        if (localId != null) {
2410
            String documentPath = getObjectFilePath(localId, isScienceMetadata);
2411
            if(documentPath != null) {
2412
                File file = new File(documentPath);
2413
                exist = file.exists();
2414
            }
2415
        } 
2416
        logMetacat.debug("IdentifierManager.ObjectFileExist - Does the object file for the local id "+localId+" which is science metadata "+isScienceMetadata+" exist in the Metacast file system? The answer is "+exist);
2417
        return exist;   
2418
    }
2419
    
2420
    /**
2421
     *Get the the file path for the given object local id
2422
     * @param localId
2423
     * @param isScienceMetadata
2424
     * @return
2425
     * @throws PropertyNotFoundException
2426
     */
2427
    public String getObjectFilePath(String localId, boolean isScienceMetadata) throws PropertyNotFoundException {
2428
        String documentPath = null;
2429
        if (localId != null) {      
2430
            String documentDir = null;
2431
            // get the correct location on disk
2432
            if (isScienceMetadata) {
2433
                documentDir = PropertyService.getProperty("application.documentfilepath");
2434
            } else {
2435
                documentDir = PropertyService.getProperty("application.datafilepath");
2436
            }
2437
            documentPath = documentDir + FileUtil.getFS() + localId;
2438
        } 
2439
        logMetacat.debug("IdentifierManager.getObjectFilePath - the file path for the object with localId "+localId+" which is scienceMetacat "+isScienceMetadata+", is "+documentPath+". If the value is null, this means we can't find it.");
2440
        return documentPath;   
2441
    }
2442
    
2443
    /**
2444
     * IF the given localId exists on the xml_revisions table
2445
     * @param localId
2446
     * @return
2447
     * @throws SQLException
2448
     */
2449
    public boolean existsInXmlLRevisionTable(String docid, int rev) throws SQLException{
2450
        boolean exist =false;
2451
        DBConnection conn = null;
2452
        int serialNumber = -1;
2453
        PreparedStatement pstmt = null;
2454
        ResultSet rs = null;
2455
        logMetacat.info("IdentifierManager.existsInXmlLRevisionTable - the docid is "+docid +" and rev is "+rev);
2456
        try {
2457
            //check out DBConnection
2458
            conn = DBConnectionPool.getDBConnection("IdentifierManager.existsInXmlLRevisionTable");
2459
            serialNumber = conn.getCheckOutSerialNumber();
2460
            // Check if the document exists in xml_revisions table.
2461
            //this only archives a document from xml_documents to xml_revisions (also archive the xml_nodes table as well)
2462
            logMetacat.debug("IdentifierManager.existsInXmlLRevisionTable - check if the document "+docid+"."+rev+ " exists in the xml_revision table");
2463
            pstmt = conn.prepareStatement("SELECT rev, docid FROM xml_revisions WHERE docid = ? AND rev = ?");
2464
            pstmt.setString(1, docid);
2465
            pstmt.setInt(2, rev);
2466
            logMetacat.debug("IdentifierManager.existsInXmlLRevisionTable - executing SQL: " + pstmt.toString());
2467
            pstmt.execute();
2468
            rs = pstmt.getResultSet();
2469
            if(rs.next()){
2470
                exist = true;
2471
            }
2472
            conn.increaseUsageCount(1);
2473
        } catch (Exception e) {
2474
            throw new SQLException(e.getMessage());
2475
        } finally {
2476
            // Return database connection to the pool
2477
            DBConnectionPool.returnDBConnection(conn, serialNumber);
2478
            if(rs != null) {
2479
                rs.close();
2480
            }
2481
            if(pstmt != null) {
2482
                pstmt.close();
2483
            }
2484
        }
2485
        logMetacat.info("IdentifierManager.existsInXmlLRevisionTable - Does the docid "+docid+"."+rev+ " exist in the xml_revision table? - "+exist);
2486
        return exist;
2487
    }
2488
}
2489

    
(36-36/64)