Project

General

Profile

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

    
25
package edu.ucsb.nceas.metacat;
26

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1156
	            // Execute the insert statement
1157
	            PreparedStatement stmt = dbConn.prepareStatement(query);
1158
	            stmt.setString(1, guid);
1159
	            ResultSet rs = stmt.executeQuery();
1160
	            if (rs.next()) {
1161
	                exists = true;
1162
	            }
1163

    
1164
	        } catch (SQLException e) {
1165
	            logMetacat.error("Error while looking up the system metadata: "
1166
	                    + e.getMessage());
1167
	            throw e;
1168
	        } finally {
1169
	            // Return database connection to the pool
1170
	            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1171
	        }
1172
		}
1173
		return exists;
1174
	}
1175
    
1176
    /**
1177
     * creates a system metadata mapping and adds additional fields from sysmeta
1178
     * to the table for quick searching.
1179
     * 
1180
     * @param guid the id to insert
1181
     * @param localId the systemMetadata object to get the local id for
1182
     * @throws McdbDocNotFoundException 
1183
     * @throws SQLException 
1184
     * @throws InvalidSystemMetadata 
1185
     */
1186
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta) 
1187
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1188
    	String guid = sysmeta.getIdentifier().getValue();
1189
    	
1190
    	 // Get a database connection from the pool
1191
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1192
        int serialNumber = dbConn.getCheckOutSerialNumber();
1193
        
1194
        try {
1195
        	// use a single transaction for it all
1196
        	dbConn.setAutoCommit(false);
1197
        	
1198
	    	// insert the record if needed
1199
        	if (!IdentifierManager.getInstance().systemMetadataPIDExists(guid)) {
1200
    	        insertSystemMetadata(guid, dbConn);
1201
			}
1202
	        // update with the values
1203
	        updateSystemMetadata(sysmeta, dbConn);
1204
	        
1205
	        // commit if we got here with no errors
1206
	        dbConn.commit();
1207
        } catch (Exception e) {
1208
            e.printStackTrace();
1209
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1210
            dbConn.rollback();
1211
            throw new SQLException("Can't save system metadata "+e.getMessage());
1212
        } finally {
1213
            // Return database connection to the pool
1214
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1215
        }
1216
        
1217
        
1218
    }
1219
        
1220
    
1221
    /**
1222
     * update a mapping
1223
     * @param guid
1224
     * @param localId
1225
     */
1226
    public void updateMapping(String guid, String localId)
1227
    {
1228
    	
1229
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1230
        int serialNumber = -1;
1231
        DBConnection dbConn = null;
1232
        try {
1233
            // Parse the localId into scope and rev parts
1234
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1235
            String docid = acc.getDocid();
1236
            int rev = 1;
1237
            if(acc.getRev() != null)
1238
            {
1239
              rev = (new Integer(acc.getRev()).intValue());
1240
            }
1241

    
1242
            // Get a database connection from the pool
1243
            dbConn = 
1244
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1245
            serialNumber = dbConn.getCheckOutSerialNumber();
1246

    
1247
            // Execute the update statement
1248
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1249
            PreparedStatement stmt = dbConn.prepareStatement(query);
1250
            stmt.setString(1, docid);
1251
            stmt.setInt(2, rev);
1252
            stmt.setString(3, guid);
1253
            int rows = stmt.executeUpdate();
1254

    
1255
            stmt.close();
1256
        } catch (SQLException e) {
1257
            e.printStackTrace();
1258
            logMetacat.error("SQL error while updating a mapping identifier: " 
1259
                    + e.getMessage());
1260
        } catch (NumberFormatException e) {
1261
            e.printStackTrace();
1262
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1263
                    + e.getMessage());
1264
        } catch (AccessionNumberException e) {
1265
            e.printStackTrace();
1266
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1267
                    + e.getMessage());
1268
        } finally {
1269
            // Return database connection to the pool
1270
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1271
        }
1272
        logMetacat.debug("done updating mapping");
1273
    }
1274
        
1275
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1276
        String checksum, String checksumAlgorithm, String originMemberNode, 
1277
        String authoritativeMemberNode, long modifiedDate, String submitter, 
1278
        String guid, String objectFormat, BigInteger size, boolean archived,
1279
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1280
        String obsoletedBy, BigInteger serialVersion, String seriesId, 
1281
        String fileName, MediaType mediaType, DBConnection dbConn) throws SQLException  {
1282
        PreparedStatement stmt = null;
1283
        PreparedStatement stmt2 = null;
1284
        try {
1285
            dbConn.setAutoCommit(false);
1286
            // Execute the insert statement
1287
            String query = "update " + TYPE_SYSTEM_METADATA + 
1288
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1289
                "origin_member_node, authoritive_member_node, date_modified, " +
1290
                "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1291
                "obsoletes, obsoleted_by, serial_version, series_id) " +
1292
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?) where guid = ?";
1293
            stmt = dbConn.prepareStatement(query);
1294
            
1295
            //data values
1296
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1297
            stmt.setString(2, rightsHolder);
1298
            stmt.setString(3, checksum);
1299
            stmt.setString(4, checksumAlgorithm);
1300
            stmt.setString(5, originMemberNode);
1301
            stmt.setString(6, authoritativeMemberNode);
1302
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1303
            stmt.setString(8, submitter);
1304
            stmt.setString(9, objectFormat);
1305
            stmt.setString(10, size.toString());
1306
            stmt.setBoolean(11, archived);
1307
            stmt.setBoolean(12, replicationAllowed);
1308
            stmt.setInt(13, numberReplicas);
1309
            stmt.setString(14, obsoletes);
1310
            stmt.setString(15, obsoletedBy);
1311
            stmt.setString(16, serialVersion.toString());
1312
            stmt.setString(17, seriesId);
1313
            stmt.setString(18, fileName);
1314
            if (mediaType == null) {
1315
                stmt.setString(19, null);
1316
            } else {
1317
                stmt.setString(19, mediaType.getName());
1318
            }
1319
            //where clause
1320
            stmt.setString(20, guid);
1321
            logMetacat.debug("stmt: " + stmt.toString());
1322
            //execute
1323
            int rows = stmt.executeUpdate();
1324
            
1325
            //insert media type properties into another table
1326
            if(mediaType != null && mediaType.getPropertyList() != null) {
1327
                String sql2 = "insert into smmediatypeproperties " + 
1328
                        "(guid, name, value) " + "values (?, ?, ?)";
1329
                stmt2 = dbConn.prepareStatement(sql2);
1330
                for(MediaTypeProperty item : mediaType.getPropertyList()) {
1331
                    if(item != null) {
1332
                        String name = item.getName();
1333
                        String value = item.getValue();
1334
                        stmt2.setString(1, guid);
1335
                        stmt2.setString(2, name);
1336
                        stmt2.setString(3, value);
1337
                        logMetacat.debug("insert media type properties query: " + stmt2.toString());
1338
                        int row =stmt2.executeUpdate();
1339
                    }
1340
                    
1341
                }
1342
            }
1343
            dbConn.commit();
1344
            dbConn.setAutoCommit(true);
1345
        } catch (Exception e) {
1346
            dbConn.rollback();
1347
            dbConn.setAutoCommit(true);
1348
            throw new SQLException(e.getMessage());
1349
        } finally {
1350
            if(stmt != null) {
1351
                stmt.close();
1352
            }
1353
            if(stmt2 != null) {
1354
                stmt2.close();
1355
            }
1356
        }
1357
        
1358
               
1359
    }
1360
    
1361
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1362
    {
1363
           
1364
        // remove existing values first
1365
        String delete = "delete from smReplicationPolicy " + 
1366
        "where guid = ? and policy = ?";
1367
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1368
        //data values
1369
        stmt.setString(1, guid);
1370
        stmt.setString(2, policy);
1371
        //execute
1372
        int deletedCount = stmt.executeUpdate();
1373
        stmt.close();
1374
        
1375
        for (String memberNode: memberNodes) {
1376
            // Execute the insert statement
1377
            String insert = "insert into smReplicationPolicy " + 
1378
                "(guid, policy, member_node) " +
1379
                "values (?, ?, ?)";
1380
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1381
            
1382
            //data values
1383
            insertStatement.setString(1, guid);
1384
            insertStatement.setString(2, policy);
1385
            insertStatement.setString(3, memberNode);
1386
            
1387
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1388

    
1389
            //execute
1390
            int rows = insertStatement.executeUpdate();
1391
            insertStatement.close();
1392
        }
1393
        
1394
    }
1395
    
1396
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1397
       
1398
        // remove existing values first
1399
        String delete = "delete from smReplicationStatus " + 
1400
        "where guid = ?";
1401
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1402
        //data values
1403
        stmt.setString(1, guid);
1404
        //execute
1405
        int deletedCount = stmt.executeUpdate();
1406
        stmt.close();
1407
        
1408
        if (replicas != null) {
1409
            for (Replica replica: replicas) {
1410
	            // Execute the insert statement
1411
	            String insert = "insert into smReplicationStatus " + 
1412
	                "(guid, member_node, status, date_verified) " +
1413
	                "values (?, ?, ?, ?)";
1414
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1415
	            
1416
	            //data values
1417
	            String memberNode = replica.getReplicaMemberNode().getValue();
1418
	            String status = replica.getReplicationStatus().toString();
1419
	            java.sql.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1420
	            insertStatement.setString(1, guid);
1421
	            insertStatement.setString(2, memberNode);
1422
	            insertStatement.setString(3, status);
1423
	            insertStatement.setTimestamp(4, sqlDate);
1424

    
1425
	            logMetacat.debug("smReplicationStatus sql: " + insertStatement.toString());
1426
	            
1427
	            //execute
1428
	            int rows = insertStatement.executeUpdate();
1429
	            insertStatement.close();
1430
            }
1431
        }
1432
       
1433
    }
1434
    
1435
    /**
1436
     * Insert the system metadata fields into the db
1437
     * @param sm
1438
     * @throws McdbDocNotFoundException 
1439
     * @throws SQLException 
1440
     * @throws InvalidSystemMetadata 
1441
     * @throws AccessException 
1442
     */
1443
    public void updateSystemMetadata(SystemMetadata sm, DBConnection dbConn) 
1444
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata, AccessException {
1445
    	
1446
      Boolean replicationAllowed = false;
1447
		  Integer numberReplicas = -1;
1448
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1449
    	if (replicationPolicy != null) {
1450
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1451
    		numberReplicas = replicationPolicy.getNumberReplicas();
1452
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1453
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1454
    	}
1455
    	
1456
    	// the main systemMetadata fields
1457
		  updateSystemMetadataFields(
1458
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1459
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1460
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1461
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1462
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1463
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1464
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1465
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1466
		    sm.getIdentifier().getValue(),
1467
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1468
		    sm.getSize(),
1469
		    sm.getArchived() == null ? false: sm.getArchived(),
1470
		    replicationAllowed, 
1471
		    numberReplicas,
1472
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1473
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1474
		    sm.getSerialVersion(),
1475
		    sm.getSeriesId() == null ? null: sm.getSeriesId().getValue(),
1476
		    sm.getFileName() == null ? null: sm.getFileName(),
1477
		    sm.getMediaType() == null ? null: sm.getMediaType(),
1478
		    dbConn
1479
        );
1480
        
1481
        String guid = sm.getIdentifier().getValue();
1482
        
1483
        // save replication policies
1484
        if (replicationPolicy != null) {
1485
		    List<String> nodes = null;
1486
		    String policy = null;
1487
		    
1488
		    // check for null 
1489
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1490
			    nodes = new ArrayList<String>();
1491
			    policy = "blocked";
1492
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1493
			    	nodes.add(node.getValue());
1494
			    }
1495
			    this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1496
		    }
1497
		    
1498
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1499
			    nodes = new ArrayList<String>();
1500
			    policy = "preferred";
1501
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1502
			    	nodes.add(node.getValue());
1503
			    }
1504
		        this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1505
		    }
1506
        }
1507
        
1508
        // save replica information
1509
        this.insertReplicationStatus(guid, sm.getReplicaList(), dbConn);
1510
        
1511
        // save access policy
1512
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1513
        if (accessPolicy != null) {
1514
			this.insertAccessPolicy(guid, accessPolicy);
1515
        }
1516
    }
1517
    
1518
    /**
1519
     * Creates Metacat access rules and inserts them
1520
     * @param accessPolicy
1521
     * @throws McdbDocNotFoundException
1522
     * @throws AccessException
1523
     */
1524
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1525
    	
1526
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1527
        XMLAccessAccess accessController  = new XMLAccessAccess();
1528
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1529
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1530
        if (existingAccess != null && existingAccess.size() > 0) {
1531
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1532
        }
1533
        
1534
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1535
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1536
        	List<Subject> subjects = accessRule.getSubjectList();
1537
        	List<Permission> permissions = accessRule.getPermissionList();
1538
        	for (Subject subject: subjects) {
1539
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1540
        		accessDAO.setPrincipalName(subject.getValue());
1541
    			accessDAO.setGuid(guid);
1542
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1543
				accessDAO.setPermOrder(existingPermOrder);
1544
    			if (permissions != null) {
1545
	    			for (Permission permission: permissions) {
1546
	    				Long metacatPermission = new Long(convertPermission(permission));
1547
	        			accessDAO.addPermission(metacatPermission);
1548
	    			}
1549
    			}
1550
    			accessDAOs.add(accessDAO);
1551
        	}
1552
        }
1553
        
1554
        
1555
        // remove all existing allow records
1556
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1557
        // add the ones we can for this guid
1558
        accessController.insertAccess(guid, accessDAOs);
1559
        
1560
        
1561
    }
1562
    
1563
    /**
1564
     * Lookup access policy from Metacat
1565
     * @param guid
1566
     * @return
1567
     * @throws McdbDocNotFoundException
1568
     * @throws AccessException
1569
     */
1570
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1571
        AccessPolicy accessPolicy = new AccessPolicy();
1572

    
1573
    	// use GUID to look up the access
1574
        XMLAccessAccess accessController  = new XMLAccessAccess();
1575
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1576
        
1577
        for (XMLAccessDAO accessDAO: accessDAOs) {
1578
        	// only add allow rule
1579
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1580
	        	AccessRule accessRule = new AccessRule();    	
1581
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1582
	        	// cannot include if we have no permissions
1583
	        	if (permissions == null || permissions.isEmpty()) {
1584
	        		logMetacat.warn("skipping empty access rule permissions for " + guid);
1585
	        		continue;
1586
	        	}
1587
	        	accessRule.setPermissionList(permissions);
1588
	        	Subject subject = new Subject();
1589
	        	subject.setValue(accessDAO.getPrincipalName());
1590
	        	accessRule.addSubject(subject);
1591
	            accessPolicy.addAllow(accessRule);
1592
        	}
1593
        }
1594
        return accessPolicy;
1595
    }
1596
    
1597
    public int convertPermission(Permission permission) {
1598
    	if (permission.equals(Permission.READ)) {
1599
    		return AccessControlInterface.READ;
1600
    	}
1601
    	if (permission.equals(Permission.WRITE)) {
1602
    		return AccessControlInterface.WRITE;
1603
    	}
1604
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1605
    		return AccessControlInterface.CHMOD;
1606
    	}
1607
		return -1;
1608
    }
1609
    
1610
    public List<Permission> convertPermission(int permission) {
1611
    	
1612
    	List<Permission> permissions = new ArrayList<Permission>();
1613
    	if (permission == AccessControlInterface.ALL) {
1614
    		permissions.add(Permission.READ);
1615
    		permissions.add(Permission.WRITE);
1616
    		permissions.add(Permission.CHANGE_PERMISSION);
1617
    		return permissions;
1618
    	}
1619
    	
1620
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1621
    		permissions.add(Permission.CHANGE_PERMISSION);
1622
    	}
1623
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1624
    		permissions.add(Permission.READ);
1625
    	}
1626
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1627
    		permissions.add(Permission.WRITE);
1628
    	}
1629
    	
1630
		return permissions;
1631
    }
1632
    
1633
    /**
1634
     * Lookup a localId given the GUID. If
1635
     * the identifier is not found, throw an exception.
1636
     * 
1637
     * @param guid the global identifier to look up
1638
     * @return String containing the corresponding LocalId
1639
     * @throws McdbDocNotFoundException if the identifier is not found
1640
     */
1641
    public String getLocalId(String guid) throws McdbDocNotFoundException, SQLException {
1642
      
1643
      String db_guid = "";
1644
      String docid = "";
1645
      int rev = 0;
1646
      
1647
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1648
      
1649
      DBConnection dbConn = null;
1650
      int serialNumber = -1;
1651
      try {
1652
          // Get a database connection from the pool
1653
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1654
          serialNumber = dbConn.getCheckOutSerialNumber();
1655
          
1656
          // Execute the insert statement
1657
          PreparedStatement stmt = dbConn.prepareStatement(query);
1658
          stmt.setString(1, guid);
1659
          ResultSet rs = stmt.executeQuery();
1660
          if (rs.next()) {
1661
              db_guid = rs.getString(1);
1662
              docid = rs.getString(2);
1663
              rev = rs.getInt(3);
1664
              assert(db_guid.equals(guid));
1665
          } else {
1666
              throw new McdbDocNotFoundException("Document not found:" + guid);
1667
          }
1668
          stmt.close();
1669
      } catch (SQLException e) {
1670
          logMetacat.error("Error while looking up the local identifier: " 
1671
                  + e.getMessage());
1672
          throw e;
1673
      } finally {
1674
          // Return database connection to the pool
1675
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1676
      }
1677
      return docid + "." + rev;
1678
    }
1679
    
1680
    /**
1681
     * query the systemmetadata table based on the given parameters
1682
     * @param startTime
1683
     * @param endTime
1684
     * @param objectFormat
1685
     * @param replicaStatus
1686
     * @param start
1687
     * @param count
1688
     * @return ObjectList
1689
     * @throws SQLException 
1690
     * @throws ServiceException 
1691
     * @throws PropertyNotFoundException 
1692
     */
1693
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1694
        ObjectFormatIdentifier objectFormatId, boolean replicaStatus,
1695
        int start, int count, Identifier identifier, boolean isSID) 
1696
        throws SQLException, PropertyNotFoundException, ServiceException {
1697
        ObjectList ol = new ObjectList();
1698
        DBConnection dbConn = null;
1699
        int serialNumber = -1;
1700

    
1701
        try {
1702
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1703
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1704
                    + "date_modified, submitter, object_format, size from systemmetadata";
1705
            
1706
            // handle special case quickly
1707
            String countSql = "select count(guid) from systemmetadata";
1708
            
1709
            // the clause
1710
            String whereClauseSql = "";
1711

    
1712
            boolean f1 = false;
1713
            boolean f2 = false;
1714
            boolean f3 = false;
1715
            boolean f4 = false;
1716

    
1717

    
1718
            if (startTime != null) {
1719
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1720
                f1 = true;
1721
            }
1722

    
1723
            if (endTime != null) {
1724
                if (!f1) {
1725
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1726
                } else {
1727
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1728
                }
1729
                f2 = true;
1730
            }
1731

    
1732
            if (objectFormatId != null) {
1733
                if (!f1 && !f2) {
1734
                    whereClauseSql += " where object_format = ?";
1735
                } else {
1736
                    whereClauseSql += " and object_format = ?";
1737
                }
1738
                f3 = true;
1739
            }
1740
            
1741
            if(identifier != null && identifier.getValue() != null && !identifier.getValue().equals("")) {
1742
                if (!f1 && !f2 && !f3 ) {
1743
                    if(isSID) {
1744
                        whereClauseSql += " where series_id = ?";
1745
                    } else {
1746
                        whereClauseSql += " where guid = ?";
1747
                    }
1748
                    
1749
                } else {
1750
                    if(isSID) {
1751
                        whereClauseSql += " and series_id = ?";
1752
                    } else {
1753
                        whereClauseSql += " and guid = ?";
1754
                    }
1755
                }
1756
                f4 = true;
1757
            }
1758

    
1759
            if (!replicaStatus) {
1760
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1761
                if (!f1 && !f2 && !f3 && !f4) {
1762
                    whereClauseSql += " where authoritive_member_node = '" +
1763
                        currentNodeId.trim() + "'";
1764
                } else {
1765
                    whereClauseSql += " and authoritive_member_node = '" +
1766
                        currentNodeId.trim() + "'";
1767
                }
1768
            }
1769
            
1770
           
1771
            
1772
            // connection
1773
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1774
            serialNumber = dbConn.getCheckOutSerialNumber();
1775

    
1776
            // the field query
1777
            String orderBySql = " order by guid ";
1778
            String fieldQuery = fieldSql + whereClauseSql + orderBySql;
1779
            String finalQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldQuery, start, count);
1780
            PreparedStatement fieldStmt = dbConn.prepareStatement(finalQuery);
1781
            
1782
            // construct the count query and statment
1783
            String countQuery = countSql + whereClauseSql;
1784
            PreparedStatement countStmt = dbConn.prepareStatement(countQuery);
1785

    
1786
            if (f1 && f2 && f3 && f4) {
1787
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1788
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1789
                fieldStmt.setString(3, objectFormatId.getValue());
1790
                fieldStmt.setString(4, identifier.getValue());
1791
                // count
1792
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1793
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1794
                countStmt.setString(3, objectFormatId.getValue());
1795
                countStmt.setString(4, identifier.getValue());
1796
            } if (f1 && f2 && f3 && !f4) {
1797
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1798
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1799
                fieldStmt.setString(3, objectFormatId.getValue());
1800
                // count
1801
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1802
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1803
                countStmt.setString(3, objectFormatId.getValue());
1804
            } else if (f1 && f2 && !f3 && f4) {
1805
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1806
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1807
                fieldStmt.setString(3, identifier.getValue());
1808
                // count
1809
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1810
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1811
                countStmt.setString(3, identifier.getValue());
1812
            } else if (f1 && f2 && !f3 && !f4) {
1813
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1814
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1815
                // count
1816
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1817
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1818
            } else if (f1 && !f2 && f3 && f4) {
1819
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1820
                fieldStmt.setString(2, objectFormatId.getValue());
1821
                fieldStmt.setString(3, identifier.getValue());
1822
                // count
1823
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1824
                countStmt.setString(2, objectFormatId.getValue());
1825
                countStmt.setString(3, identifier.getValue());
1826
            } else if (f1 && !f2 && f3 && !f4) {
1827
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1828
                fieldStmt.setString(2, objectFormatId.getValue());
1829
                // count
1830
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1831
                countStmt.setString(2, objectFormatId.getValue());
1832
            } else if (f1 && !f2 && !f3 && f4) {
1833
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1834
                fieldStmt.setString(2, identifier.getValue());
1835
                // count
1836
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1837
                countStmt.setString(2, identifier.getValue());
1838
            } else if (f1 && !f2 && !f3 && !f4) {
1839
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1840
                // count
1841
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1842
            } else if (!f1 && f2 && f3 && f4) {
1843
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1844
                fieldStmt.setString(2, objectFormatId.getValue());
1845
                fieldStmt.setString(3, identifier.getValue());
1846
                // count
1847
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1848
                countStmt.setString(2, objectFormatId.getValue());
1849
                countStmt.setString(3, identifier.getValue());
1850
            } else if (!f1 && f2 && f3 && !f4) {
1851
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1852
                fieldStmt.setString(2, objectFormatId.getValue());
1853
                // count
1854
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1855
                countStmt.setString(2, objectFormatId.getValue());
1856
            } else if (!f1 && !f2 && f3 && f4) {
1857
                fieldStmt.setString(1, objectFormatId.getValue());
1858
                fieldStmt.setString(2, identifier.getValue());
1859
                // count
1860
                countStmt.setString(1, objectFormatId.getValue());
1861
                countStmt.setString(2, identifier.getValue());
1862
            } else if (!f1 && !f2 && f3 && !f4) {
1863
                fieldStmt.setString(1, objectFormatId.getValue());
1864
                // count
1865
                countStmt.setString(1, objectFormatId.getValue());
1866
            } else if (!f1 && f2 && !f3 && f4) {
1867
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1868
                fieldStmt.setString(2, identifier.getValue());
1869
                // count
1870
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1871
                countStmt.setString(2, identifier.getValue());
1872
            } else if (!f1 && f2 && !f3 && !f4) {
1873
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1874
                // count
1875
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1876
            } else if (!f1 && !f2 && !f3 && f4) {
1877
                fieldStmt.setString(1, identifier.getValue());
1878
                // count
1879
                countStmt.setString(1, identifier.getValue());
1880
            } else if (!f1 && !f2 && !f3 && !f4) {
1881
                //do nothing
1882
            }
1883

    
1884
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
1885
            
1886
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
1887
            
1888
            // get the total object count no matter what
1889
            int total = 0;
1890
            ResultSet totalResult = countStmt.executeQuery();
1891
            if (totalResult.next()) {
1892
            	total = totalResult.getInt(1);
1893
            }
1894
            
1895
            logMetacat.debug("list objects total: " + total);
1896

    
1897
        	// set the totals
1898
        	ol.setStart(start);
1899
            ol.setCount(count);
1900
            ol.setTotal(total);
1901
            
1902
            // retrieve the actual records if requested
1903
            if (count != 0) {
1904
            	
1905
                ResultSet rs = fieldStmt.executeQuery();
1906
	            while (rs.next()) {                
1907
	                
1908
	                String guid = rs.getString(1);
1909
	                logMetacat.debug("query found object with guid " + guid);
1910
	                // Timestamp dateUploaded = rs.getTimestamp(2);
1911
	                // String rightsHolder = rs.getString(3);
1912
	                String checksum = rs.getString(4);
1913
	                String checksumAlgorithm = rs.getString(5);
1914
	                // String originMemberNode = rs.getString(6);
1915
	                // String authoritiveMemberNode = rs.getString(7);
1916
	                Timestamp dateModified = rs.getTimestamp(8);
1917
	                // String submitter = rs.getString(9);
1918
	                String fmtidStr = rs.getString(10);
1919
	                String sz = rs.getString(11);
1920
	                BigInteger size = new BigInteger("0");
1921
	
1922
	                if (sz != null && !sz.trim().equals("")) {
1923
	                    size = new BigInteger(rs.getString(11));
1924
	                }
1925
	
1926
	                ObjectInfo oi = new ObjectInfo();
1927
	
1928
	                Identifier id = new Identifier();
1929
	                id.setValue(guid);
1930
	                oi.setIdentifier(id);
1931
	
1932
	                if (dateModified != null) {
1933
	                    oi.setDateSysMetadataModified(dateModified);
1934
	                }
1935
	
1936
	                Checksum cs = new Checksum();
1937
	                cs.setValue(checksum);
1938
	                try {
1939
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1940
	                    cs.setAlgorithm(checksumAlgorithm);
1941
	                } catch (Exception e) {
1942
	                    logMetacat.error("could not parse checksum algorithm", e);
1943
	                    continue;
1944
	                }
1945
	                oi.setChecksum(cs);
1946
	
1947
	                // set the format type
1948
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1949
	                fmtid.setValue(fmtidStr);
1950
	                oi.setFormatId(fmtid);
1951
	
1952
	                oi.setSize(size);
1953
	
1954
	                ol.addObjectInfo(oi);                    
1955

    
1956
	            }
1957
	            
1958
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
1959

    
1960
	            // set the actual count retrieved
1961
	            ol.setCount(ol.sizeObjectInfoList());
1962
	
1963
	        }
1964
            
1965
        }
1966

    
1967
        finally {
1968
            // Return database connection to the pool
1969
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1970
        }
1971

    
1972
        return ol;
1973
    }
1974
    
1975
    /**
1976
     * create a mapping in the identifier table
1977
     * @param guid
1978
     * @param localId
1979
     */
1980
    public void createMapping(String guid, String localId)
1981
    {        
1982
        
1983
        int serialNumber = -1;
1984
        DBConnection dbConn = null;
1985
        try {
1986

    
1987
            // Parse the localId into scope and rev parts
1988
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1989
            String docid = acc.getDocid();
1990
            int rev = 1;
1991
            if (acc.getRev() != null) {
1992
              rev = (new Integer(acc.getRev()).intValue());
1993
            }
1994

    
1995
            // Get a database connection from the pool
1996
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1997
            serialNumber = dbConn.getCheckOutSerialNumber();
1998

    
1999
            // Execute the insert statement
2000
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
2001
            PreparedStatement stmt = dbConn.prepareStatement(query);
2002
            stmt.setString(1, guid);
2003
            stmt.setString(2, docid);
2004
            stmt.setInt(3, rev);
2005
            logMetacat.debug("mapping query: " + stmt.toString());
2006
            int rows = stmt.executeUpdate();
2007

    
2008
            stmt.close();
2009
        } catch (SQLException e) {
2010
            e.printStackTrace();
2011
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2012
                    + e.getMessage());
2013
        } catch (NumberFormatException e) {
2014
            e.printStackTrace();
2015
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2016
                    + e.getMessage());
2017
        } catch (AccessionNumberException e) {
2018
            e.printStackTrace();
2019
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2020
                    + e.getMessage());
2021
        } finally {
2022
            // Return database connection to the pool
2023
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2024
        }
2025
    }
2026
    
2027
    /**
2028
     * remove a mapping in the identifier table
2029
     * @param guid
2030
     * @param localId
2031
     */
2032
    public void removeMapping(String guid, String localId)
2033
    {        
2034
        
2035
        int serialNumber = -1;
2036
        DBConnection dbConn = null;
2037
        try {
2038

    
2039
            // Parse the localId into scope and rev parts
2040
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
2041
            String docid = acc.getDocid();
2042
            int rev = 1;
2043
            if (acc.getRev() != null) {
2044
              rev = (new Integer(acc.getRev()).intValue());
2045
            }
2046

    
2047
            // Get a database connection from the pool
2048
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
2049
            serialNumber = dbConn.getCheckOutSerialNumber();
2050

    
2051
            // Execute the insert statement
2052
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
2053
            PreparedStatement stmt = dbConn.prepareStatement(query);
2054
            stmt.setString(1, guid);
2055
            stmt.setString(2, docid);
2056
            stmt.setInt(3, rev);
2057
            logMetacat.debug("remove mapping query: " + stmt.toString());
2058
            int rows = stmt.executeUpdate();
2059

    
2060
            stmt.close();
2061
        } catch (SQLException e) {
2062
            e.printStackTrace();
2063
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2064
                    + e.getMessage());
2065
        } catch (NumberFormatException e) {
2066
            e.printStackTrace();
2067
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2068
                    + e.getMessage());
2069
        } catch (AccessionNumberException e) {
2070
            e.printStackTrace();
2071
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2072
                    + e.getMessage());
2073
        } finally {
2074
            // Return database connection to the pool
2075
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2076
        }
2077
    }
2078
    
2079
    /**
2080
     * create the systemmetadata record
2081
     * @param guid
2082
     * @param dbConn 
2083
     * @throws SQLException 
2084
     */
2085
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
2086
    {        
2087

    
2088
        // Execute the insert statement
2089
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
2090
        PreparedStatement stmt = dbConn.prepareStatement(query);
2091
        stmt.setString(1, guid);
2092
        logMetacat.debug("system metadata query: " + stmt.toString());
2093
        int rows = stmt.executeUpdate();
2094

    
2095
        stmt.close();
2096
        
2097
    }
2098
    
2099
    public boolean deleteSystemMetadata(String guid)
2100
    {        
2101
        boolean success = false;
2102
        int serialNumber = -1;
2103
        DBConnection dbConn = null;
2104
        String query = null;
2105
        PreparedStatement stmt = null;
2106
        int rows = 0;
2107
        try {
2108

    
2109
        	 // Get a database connection from the pool
2110
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
2111
            serialNumber = dbConn.getCheckOutSerialNumber();
2112
            dbConn.setAutoCommit(false);
2113
        	
2114
            // remove the smReplicationPolicy
2115
            query = "delete from smReplicationPolicy " + 
2116
            "where guid = ?";
2117
            stmt = dbConn.prepareStatement(query);
2118
            stmt.setString(1, guid);
2119
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
2120
            rows = stmt.executeUpdate();
2121
            stmt.close();
2122
            
2123
            // remove the smReplicationStatus
2124
            query = "delete from smReplicationStatus " + 
2125
            "where guid = ?";
2126
            stmt = dbConn.prepareStatement(query);
2127
            stmt.setString(1, guid);
2128
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
2129
            rows = stmt.executeUpdate();
2130
            stmt.close();
2131
            
2132
            // remove the smmediatypeproperties
2133
            query = "delete from smmediatypeproperties " + 
2134
                    "where guid = ?";
2135
            stmt = dbConn.prepareStatement(query);
2136
            stmt.setString(1, guid);
2137
            logMetacat.debug("delete smmediatypeproperties: " + stmt.toString());
2138
            rows = stmt.executeUpdate();
2139
            stmt.close();
2140
            
2141
            // remove main system metadata entry
2142
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
2143
            stmt = dbConn.prepareStatement(query);
2144
            stmt.setString(1, guid);
2145
            logMetacat.debug("delete system metadata: " + stmt.toString());
2146
            rows = stmt.executeUpdate();
2147
            stmt.close();
2148
            
2149
            dbConn.commit();
2150
            dbConn.setAutoCommit(true);
2151
            success = true;
2152
            // TODO: remove the access?
2153
            // Metacat keeps "deleted" documents so we should not remove access rules.
2154
            
2155
        } catch (Exception e) {
2156
            e.printStackTrace();
2157
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
2158
            try {
2159
				dbConn.rollback();
2160
			} catch (SQLException sqle) {
2161
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
2162
			}
2163
        } finally {
2164
            // Return database connection to the pool
2165
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2166
        }
2167
        return success;
2168
    }
2169
    
2170
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
2171
    {
2172
        DBConnection dbConn = null;
2173
        int serialNumber = -1;
2174
        
2175
        try {
2176
            // Get a database connection from the pool
2177
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
2178
            serialNumber = dbConn.getCheckOutSerialNumber();
2179

    
2180
            // Execute the insert statement
2181
            String query = "update " + TYPE_SYSTEM_METADATA + 
2182
                " set authoritive_member_node = ? " +
2183
                " where authoritive_member_node = ?";
2184
            PreparedStatement stmt = dbConn.prepareStatement(query);
2185
            
2186
            //data values
2187
            stmt.setString(1, newMemberNodeId);
2188
            stmt.setString(2, existingMemberNodeId);
2189

    
2190
            logMetacat.debug("stmt: " + stmt.toString());
2191
            //execute
2192
            int rows = stmt.executeUpdate();
2193

    
2194
            stmt.close();
2195
        } catch (SQLException e) {
2196
            e.printStackTrace();
2197
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
2198
                    + e.getMessage());
2199
        } catch (NumberFormatException e) {
2200
            e.printStackTrace();
2201
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
2202
                    + e.getMessage());
2203
        } finally {
2204
            // Return database connection to the pool
2205
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2206
        }
2207
    }
2208
}
2209

    
(36-36/63)