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, file_name, media_type) " +
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
            if(serialVersion != null) {
1312
                stmt.setString(16, serialVersion.toString());
1313
            } else {
1314
                stmt.setString(16, null);
1315
            }
1316
            
1317
            stmt.setString(17, seriesId);
1318
            stmt.setString(18, fileName);
1319
            if (mediaType == null) {
1320
                stmt.setString(19, null);
1321
            } else {
1322
                stmt.setString(19, mediaType.getName());
1323
            }
1324
            //where clause
1325
            stmt.setString(20, guid);
1326
            logMetacat.debug("stmt: " + stmt.toString());
1327
            //execute
1328
            int rows = stmt.executeUpdate();
1329
            
1330
            //insert media type properties into another table
1331
            if(mediaType != null && mediaType.getPropertyList() != null) {
1332
                String sql2 = "insert into smmediatypeproperties " + 
1333
                        "(guid, name, value) " + "values (?, ?, ?)";
1334
                stmt2 = dbConn.prepareStatement(sql2);
1335
                for(MediaTypeProperty item : mediaType.getPropertyList()) {
1336
                    if(item != null) {
1337
                        String name = item.getName();
1338
                        String value = item.getValue();
1339
                        stmt2.setString(1, guid);
1340
                        stmt2.setString(2, name);
1341
                        stmt2.setString(3, value);
1342
                        logMetacat.debug("insert media type properties query: " + stmt2.toString());
1343
                        int row =stmt2.executeUpdate();
1344
                    }
1345
                    
1346
                }
1347
            }
1348
            dbConn.commit();
1349
            dbConn.setAutoCommit(true);
1350
        } catch (Exception e) {
1351
            dbConn.rollback();
1352
            dbConn.setAutoCommit(true);
1353
            e.printStackTrace();
1354
            throw new SQLException(e.getMessage());
1355
        } finally {
1356
            if(stmt != null) {
1357
                stmt.close();
1358
            }
1359
            if(stmt2 != null) {
1360
                stmt2.close();
1361
            }
1362
        }
1363
        
1364
               
1365
    }
1366
    
1367
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1368
    {
1369
           
1370
        // remove existing values first
1371
        String delete = "delete from smReplicationPolicy " + 
1372
        "where guid = ? and policy = ?";
1373
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1374
        //data values
1375
        stmt.setString(1, guid);
1376
        stmt.setString(2, policy);
1377
        //execute
1378
        int deletedCount = stmt.executeUpdate();
1379
        stmt.close();
1380
        
1381
        for (String memberNode: memberNodes) {
1382
            // Execute the insert statement
1383
            String insert = "insert into smReplicationPolicy " + 
1384
                "(guid, policy, member_node) " +
1385
                "values (?, ?, ?)";
1386
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1387
            
1388
            //data values
1389
            insertStatement.setString(1, guid);
1390
            insertStatement.setString(2, policy);
1391
            insertStatement.setString(3, memberNode);
1392
            
1393
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1394

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

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

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

    
1711
        try {
1712
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1713
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1714
                    + "date_modified, submitter, object_format, size from systemmetadata";
1715
            
1716
            // handle special case quickly
1717
            String countSql = "select count(guid) from systemmetadata";
1718
            
1719
            // the clause
1720
            String whereClauseSql = "";
1721
            
1722

    
1723
            boolean f1 = false;
1724
            boolean f2 = false;
1725
            boolean f3 = false;
1726
            boolean f4 = false;
1727

    
1728

    
1729
            if (startTime != null) {
1730
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1731
                f1 = true;
1732
            }
1733

    
1734
            if (endTime != null) {
1735
                if (!f1) {
1736
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1737
                } else {
1738
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1739
                }
1740
                f2 = true;
1741
            }
1742

    
1743
            if (objectFormatId != null) {
1744
                if (!f1 && !f2) {
1745
                    whereClauseSql += " where object_format = ?";
1746
                } else {
1747
                    whereClauseSql += " and object_format = ?";
1748
                }
1749
                f3 = true;
1750
            }
1751
            
1752
            if(identifier != null && identifier.getValue() != null && !identifier.getValue().equals("")) {
1753
                if (!f1 && !f2 && !f3 ) {
1754
                    if(isSID) {
1755
                        whereClauseSql += " where series_id = ?";
1756
                    } else {
1757
                        whereClauseSql += " where guid = ?";
1758
                    }
1759
                    
1760
                } else {
1761
                    if(isSID) {
1762
                        whereClauseSql += " and series_id = ?";
1763
                    } else {
1764
                        whereClauseSql += " and guid = ?";
1765
                    }
1766
                }
1767
                f4 = true;
1768
            }
1769

    
1770
            /*if (!replicaStatus) {
1771
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1772
                if (!f1 && !f2 && !f3 && !f4) {
1773
                    whereClauseSql += " where authoritive_member_node = '" +
1774
                        currentNodeId.trim() + "'";
1775
                } else {
1776
                    whereClauseSql += " and authoritive_member_node = '" +
1777
                        currentNodeId.trim() + "'";
1778
                }
1779
            }*/
1780
            
1781
            if (nodeId != null && nodeId.getValue() != null && !nodeId.getValue().trim().equals("")) {
1782
                if (!f1 && !f2 && !f3 && !f4) {
1783
                    whereClauseSql += " where authoritive_member_node = '" +
1784
                        nodeId.getValue().trim() + "'";
1785
                } else {
1786
                    whereClauseSql += " and authoritive_member_node = '" +
1787
                        nodeId.getValue().trim() + "'";
1788
                }
1789
            }
1790
           
1791
            
1792
            // connection
1793
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1794
            serialNumber = dbConn.getCheckOutSerialNumber();
1795

    
1796
            // the field query
1797
            String orderBySql = " order by guid ";
1798
            String fieldQuery = fieldSql + whereClauseSql + orderBySql;
1799
            String finalQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldQuery, start, count);
1800
            fieldStmt = dbConn.prepareStatement(finalQuery);
1801
            
1802
            // construct the count query and statment
1803
            String countQuery = countSql + whereClauseSql;
1804
            countStmt = dbConn.prepareStatement(countQuery);
1805

    
1806
            if (f1 && f2 && f3 && f4) {
1807
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1808
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1809
                fieldStmt.setString(3, objectFormatId.getValue());
1810
                fieldStmt.setString(4, identifier.getValue());
1811
                // count
1812
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1813
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1814
                countStmt.setString(3, objectFormatId.getValue());
1815
                countStmt.setString(4, identifier.getValue());
1816
            } if (f1 && f2 && f3 && !f4) {
1817
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1818
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1819
                fieldStmt.setString(3, objectFormatId.getValue());
1820
                // count
1821
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1822
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1823
                countStmt.setString(3, objectFormatId.getValue());
1824
            } else if (f1 && f2 && !f3 && f4) {
1825
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1826
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1827
                fieldStmt.setString(3, identifier.getValue());
1828
                // count
1829
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1830
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1831
                countStmt.setString(3, identifier.getValue());
1832
            } else if (f1 && f2 && !f3 && !f4) {
1833
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1834
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1835
                // count
1836
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1837
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1838
            } else if (f1 && !f2 && f3 && f4) {
1839
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1840
                fieldStmt.setString(2, objectFormatId.getValue());
1841
                fieldStmt.setString(3, identifier.getValue());
1842
                // count
1843
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1844
                countStmt.setString(2, objectFormatId.getValue());
1845
                countStmt.setString(3, identifier.getValue());
1846
            } else if (f1 && !f2 && f3 && !f4) {
1847
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1848
                fieldStmt.setString(2, objectFormatId.getValue());
1849
                // count
1850
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1851
                countStmt.setString(2, objectFormatId.getValue());
1852
            } else if (f1 && !f2 && !f3 && f4) {
1853
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1854
                fieldStmt.setString(2, identifier.getValue());
1855
                // count
1856
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1857
                countStmt.setString(2, identifier.getValue());
1858
            } else if (f1 && !f2 && !f3 && !f4) {
1859
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1860
                // count
1861
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1862
            } else if (!f1 && f2 && f3 && f4) {
1863
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1864
                fieldStmt.setString(2, objectFormatId.getValue());
1865
                fieldStmt.setString(3, identifier.getValue());
1866
                // count
1867
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1868
                countStmt.setString(2, objectFormatId.getValue());
1869
                countStmt.setString(3, identifier.getValue());
1870
            } else if (!f1 && f2 && f3 && !f4) {
1871
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1872
                fieldStmt.setString(2, objectFormatId.getValue());
1873
                // count
1874
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1875
                countStmt.setString(2, objectFormatId.getValue());
1876
            } else if (!f1 && !f2 && f3 && f4) {
1877
                fieldStmt.setString(1, objectFormatId.getValue());
1878
                fieldStmt.setString(2, identifier.getValue());
1879
                // count
1880
                countStmt.setString(1, objectFormatId.getValue());
1881
                countStmt.setString(2, identifier.getValue());
1882
            } else if (!f1 && !f2 && f3 && !f4) {
1883
                fieldStmt.setString(1, objectFormatId.getValue());
1884
                // count
1885
                countStmt.setString(1, objectFormatId.getValue());
1886
            } else if (!f1 && f2 && !f3 && f4) {
1887
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1888
                fieldStmt.setString(2, identifier.getValue());
1889
                // count
1890
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1891
                countStmt.setString(2, identifier.getValue());
1892
            } else if (!f1 && f2 && !f3 && !f4) {
1893
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1894
                // count
1895
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1896
            } else if (!f1 && !f2 && !f3 && f4) {
1897
                fieldStmt.setString(1, identifier.getValue());
1898
                // count
1899
                countStmt.setString(1, identifier.getValue());
1900
            } else if (!f1 && !f2 && !f3 && !f4) {
1901
                //do nothing
1902
            }
1903

    
1904
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
1905
            
1906
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
1907
            
1908
            // get the total object count no matter what
1909
            int total = 0;
1910
            totalResult = countStmt.executeQuery();
1911
            if (totalResult.next()) {
1912
            	total = totalResult.getInt(1);
1913
            }
1914
            
1915
            logMetacat.debug("list objects total: " + total);
1916

    
1917
        	// set the totals
1918
        	ol.setStart(start);
1919
            ol.setCount(count);
1920
            
1921
            // retrieve the actual records if requested
1922
            if (count != 0) {
1923
            	
1924
                rs = fieldStmt.executeQuery();
1925
	            while (rs.next()) {                
1926
	                
1927
	                String guid = rs.getString(1);
1928
	                logMetacat.debug("query found object with guid " + guid);
1929
	                // Timestamp dateUploaded = rs.getTimestamp(2);
1930
	                // String rightsHolder = rs.getString(3);
1931
	                String checksum = rs.getString(4);
1932
	                String checksumAlgorithm = rs.getString(5);
1933
	                // String originMemberNode = rs.getString(6);
1934
	                // String authoritiveMemberNode = rs.getString(7);
1935
	                Timestamp dateModified = rs.getTimestamp(8);
1936
	                // String submitter = rs.getString(9);
1937
	                String fmtidStr = rs.getString(10);
1938
	                String sz = rs.getString(11);
1939
	                BigInteger size = new BigInteger("0");
1940
	
1941
	                if (sz != null && !sz.trim().equals("")) {
1942
	                    size = new BigInteger(rs.getString(11));
1943
	                }
1944
	
1945
	                ObjectInfo oi = new ObjectInfo();
1946
	
1947
	                Identifier id = new Identifier();
1948
	                id.setValue(guid);
1949
	                oi.setIdentifier(id);
1950
	
1951
	                if (dateModified != null) {
1952
	                    oi.setDateSysMetadataModified(dateModified);
1953
	                }
1954
	
1955
	                Checksum cs = new Checksum();
1956
	                cs.setValue(checksum);
1957
	                try {
1958
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1959
	                    cs.setAlgorithm(checksumAlgorithm);
1960
	                } catch (Exception e) {
1961
	                    logMetacat.error("could not parse checksum algorithm", e);
1962
	                    continue;
1963
	                }
1964
	                oi.setChecksum(cs);
1965
	
1966
	                // set the format type
1967
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1968
	                fmtid.setValue(fmtidStr);
1969
	                oi.setFormatId(fmtid);
1970
	
1971
	                oi.setSize(size);
1972
	                
1973
	                ol.addObjectInfo(oi);                    
1974

    
1975
	            }
1976
	            
1977
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
1978
	            // set the actual count retrieved
1979
	            ol.setCount(ol.sizeObjectInfoList());
1980
	            
1981
	
1982
	        }
1983
            ol.setTotal(total);
1984
        } finally {
1985
            // Return database connection to the pool
1986
            try {
1987
                if(totalResult !=null ){
1988
                    totalResult.close();
1989
                }
1990
                if(countStmt!=null ) {
1991
                    countStmt.close();
1992
                }
1993
                if(rs != null) {
1994
                    rs.close();
1995
                }
1996
                if(fieldStmt != null) {
1997
                    fieldStmt.close();
1998
                }
1999
                
2000
            } catch (SQLException sql) {
2001
                
2002
            }
2003
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2004
            
2005
        }
2006
        if(ol != null) {
2007
            logMetacat.debug("list objects start(before returning): " + ol.getStart());
2008
            logMetacat.debug("list objects count: " + ol.getCount());
2009
            logMetacat.debug("list objects total: " + ol.getTotal());
2010
        }
2011
        return ol;
2012
    }
2013
    
2014
    /**
2015
     * create a mapping in the identifier table
2016
     * @param guid
2017
     * @param localId
2018
     */
2019
    public void createMapping(String guid, String localId)
2020
    {        
2021
        
2022
        int serialNumber = -1;
2023
        DBConnection dbConn = null;
2024
        try {
2025

    
2026
            // Parse the localId into scope and rev parts
2027
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
2028
            String docid = acc.getDocid();
2029
            int rev = 1;
2030
            if (acc.getRev() != null) {
2031
              rev = (new Integer(acc.getRev()).intValue());
2032
            }
2033

    
2034
            // Get a database connection from the pool
2035
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
2036
            serialNumber = dbConn.getCheckOutSerialNumber();
2037

    
2038
            // Execute the insert statement
2039
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
2040
            PreparedStatement stmt = dbConn.prepareStatement(query);
2041
            stmt.setString(1, guid);
2042
            stmt.setString(2, docid);
2043
            stmt.setInt(3, rev);
2044
            logMetacat.debug("mapping query: " + stmt.toString());
2045
            int rows = stmt.executeUpdate();
2046

    
2047
            stmt.close();
2048
        } catch (SQLException e) {
2049
            e.printStackTrace();
2050
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2051
                    + e.getMessage());
2052
        } catch (NumberFormatException e) {
2053
            e.printStackTrace();
2054
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2055
                    + e.getMessage());
2056
        } catch (AccessionNumberException e) {
2057
            e.printStackTrace();
2058
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2059
                    + e.getMessage());
2060
        } finally {
2061
            // Return database connection to the pool
2062
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2063
        }
2064
    }
2065
    
2066
    /**
2067
     * remove a mapping in the identifier table
2068
     * @param guid
2069
     * @param localId
2070
     */
2071
    public void removeMapping(String guid, String localId)
2072
    {        
2073
        
2074
        int serialNumber = -1;
2075
        DBConnection dbConn = null;
2076
        try {
2077

    
2078
            // Parse the localId into scope and rev parts
2079
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
2080
            String docid = acc.getDocid();
2081
            int rev = 1;
2082
            if (acc.getRev() != null) {
2083
              rev = (new Integer(acc.getRev()).intValue());
2084
            }
2085

    
2086
            // Get a database connection from the pool
2087
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
2088
            serialNumber = dbConn.getCheckOutSerialNumber();
2089

    
2090
            // Execute the insert statement
2091
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
2092
            PreparedStatement stmt = dbConn.prepareStatement(query);
2093
            stmt.setString(1, guid);
2094
            stmt.setString(2, docid);
2095
            stmt.setInt(3, rev);
2096
            logMetacat.debug("remove mapping query: " + stmt.toString());
2097
            int rows = stmt.executeUpdate();
2098

    
2099
            stmt.close();
2100
        } catch (SQLException e) {
2101
            e.printStackTrace();
2102
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2103
                    + e.getMessage());
2104
        } catch (NumberFormatException e) {
2105
            e.printStackTrace();
2106
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2107
                    + e.getMessage());
2108
        } catch (AccessionNumberException e) {
2109
            e.printStackTrace();
2110
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2111
                    + e.getMessage());
2112
        } finally {
2113
            // Return database connection to the pool
2114
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2115
        }
2116
    }
2117
    
2118
    /**
2119
     * create the systemmetadata record
2120
     * @param guid
2121
     * @param dbConn 
2122
     * @throws SQLException 
2123
     */
2124
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
2125
    {        
2126

    
2127
        // Execute the insert statement
2128
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
2129
        PreparedStatement stmt = dbConn.prepareStatement(query);
2130
        stmt.setString(1, guid);
2131
        logMetacat.debug("system metadata query: " + stmt.toString());
2132
        int rows = stmt.executeUpdate();
2133

    
2134
        stmt.close();
2135
        
2136
    }
2137
    
2138
    public boolean deleteSystemMetadata(String guid)
2139
    {        
2140
        boolean success = false;
2141
        int serialNumber = -1;
2142
        DBConnection dbConn = null;
2143
        String query = null;
2144
        PreparedStatement stmt = null;
2145
        int rows = 0;
2146
        try {
2147

    
2148
        	 // Get a database connection from the pool
2149
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
2150
            serialNumber = dbConn.getCheckOutSerialNumber();
2151
            dbConn.setAutoCommit(false);
2152
        	
2153
            // remove the smReplicationPolicy
2154
            query = "delete from smReplicationPolicy " + 
2155
            "where guid = ?";
2156
            stmt = dbConn.prepareStatement(query);
2157
            stmt.setString(1, guid);
2158
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
2159
            rows = stmt.executeUpdate();
2160
            stmt.close();
2161
            
2162
            // remove the smReplicationStatus
2163
            query = "delete from smReplicationStatus " + 
2164
            "where guid = ?";
2165
            stmt = dbConn.prepareStatement(query);
2166
            stmt.setString(1, guid);
2167
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
2168
            rows = stmt.executeUpdate();
2169
            stmt.close();
2170
            
2171
            // remove the smmediatypeproperties
2172
            query = "delete from smmediatypeproperties " + 
2173
                    "where guid = ?";
2174
            stmt = dbConn.prepareStatement(query);
2175
            stmt.setString(1, guid);
2176
            logMetacat.debug("delete smmediatypeproperties: " + stmt.toString());
2177
            rows = stmt.executeUpdate();
2178
            stmt.close();
2179
            
2180
            // remove main system metadata entry
2181
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
2182
            stmt = dbConn.prepareStatement(query);
2183
            stmt.setString(1, guid);
2184
            logMetacat.debug("delete system metadata: " + stmt.toString());
2185
            rows = stmt.executeUpdate();
2186
            stmt.close();
2187
            
2188
            dbConn.commit();
2189
            dbConn.setAutoCommit(true);
2190
            success = true;
2191
            // TODO: remove the access?
2192
            // Metacat keeps "deleted" documents so we should not remove access rules.
2193
            
2194
        } catch (Exception e) {
2195
            e.printStackTrace();
2196
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
2197
            try {
2198
				dbConn.rollback();
2199
			} catch (SQLException sqle) {
2200
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
2201
			}
2202
        } finally {
2203
            // Return database connection to the pool
2204
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2205
        }
2206
        return success;
2207
    }
2208
    
2209
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
2210
    {
2211
        DBConnection dbConn = null;
2212
        int serialNumber = -1;
2213
        
2214
        try {
2215
            // Get a database connection from the pool
2216
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
2217
            serialNumber = dbConn.getCheckOutSerialNumber();
2218

    
2219
            // Execute the insert statement
2220
            String query = "update " + TYPE_SYSTEM_METADATA + 
2221
                " set authoritive_member_node = ? " +
2222
                " where authoritive_member_node = ?";
2223
            PreparedStatement stmt = dbConn.prepareStatement(query);
2224
            
2225
            //data values
2226
            stmt.setString(1, newMemberNodeId);
2227
            stmt.setString(2, existingMemberNodeId);
2228

    
2229
            logMetacat.debug("stmt: " + stmt.toString());
2230
            //execute
2231
            int rows = stmt.executeUpdate();
2232

    
2233
            stmt.close();
2234
        } catch (SQLException e) {
2235
            e.printStackTrace();
2236
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
2237
                    + e.getMessage());
2238
        } catch (NumberFormatException e) {
2239
            e.printStackTrace();
2240
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
2241
                    + e.getMessage());
2242
        } finally {
2243
            // Return database connection to the pool
2244
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2245
        }
2246
    }
2247
}
2248

    
(36-36/63)