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
        PreparedStatement stmt = null;
932
        try {
933
            // Get a database connection from the pool
934
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
935
            serialNumber = dbConn.getCheckOutSerialNumber();
936
            
937
            // Execute the insert statement
938
            stmt = dbConn.prepareStatement(query);
939
            stmt.setString(1, docid);
940
            stmt.setInt(2, rev);
941
            ResultSet rs = stmt.executeQuery();
942
            if (rs.next()) 
943
            {
944
                guid = rs.getString(1);
945
            } 
946
            else
947
            {
948
            	throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
949
            }
950
            if(rs != null) {
951
                rs.close();
952
            }
953
        } catch (SQLException e) {
954
            logMetacat.error("Error while looking up the guid: " 
955
                    + e.getMessage());
956
        } finally {
957
            try {
958
                if(stmt != null) {
959
                    stmt.close();
960
                }
961
            } catch (Exception e) {
962
                logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
963
            } finally {
964
                // Return database connection to the pool
965
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
966
            }
967
            
968
        }
969
        
970
        return guid;
971
    }
972
    
973
    /**
974
     * Get the pid of the head (current) version of objects match the specified sid.
975
     * 1. locate all candidate chain-ends for S1:
976
     *      determined by:  seriesId == S1 AND (obsoletedBy == null  OR obsoletedBy.seriesId != S1) // these are the type1 and type2 ends
977
     *      If obsoletedBy is missing, we generally consider it a type 2 end except:
978
     *      there is another object in the chain (has the same series id) that obsoletes the missing object. 
979
     * 2. if only 1 candidate chain-end, return it as the HEAD
980
     * 3. otherwise return the one in the chain with the latest dateUploaded value.
981
     * @param sid specified sid which should match.
982
     * @return the pid of the head version. The null will be returned if there is no pid found.
983
     * @throws SQLException 
984
     */
985
    public Identifier getHeadPID(Identifier sid) throws SQLException {
986
        Identifier pid = null;
987
        if(sid != null && sid.getValue() != null && !sid.getValue().trim().equals("")) {
988
            logMetacat.debug("getting pid of the head version for matching the sid: " + sid.getValue());
989
            String sql = "select guid from systemMetadata where series_id = ? order by date_uploaded DESC";
990
            DBConnection dbConn = null;
991
            int serialNumber = -1;
992
            PreparedStatement stmt = null;
993
            int endsCount = 0;
994
            boolean hasError = false;
995
            try {
996
                // Get a database connection from the pool
997
                dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getHeadPID");
998
                serialNumber = dbConn.getCheckOutSerialNumber();
999
                // Execute the insert statement
1000
                stmt = dbConn.prepareStatement(sql);
1001
                stmt.setString(1, sid.getValue());
1002
                ResultSet rs = stmt.executeQuery();
1003
                boolean hasNext = rs.next();
1004
                boolean first = true;
1005
                Identifier firstOne = new Identifier();//since the sql using the desc order, the first one has the latest upload date.
1006
                if (hasNext) 
1007
                {
1008
                    while(hasNext) {
1009
                        String guidStr = rs.getString(1);
1010
                        Identifier guid = new Identifier();
1011
                        guid.setValue(guidStr);
1012
                        if(first) {
1013
                            firstOne = guid;
1014
                            first =false;
1015
                        }
1016
                        SystemMetadata sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(guid);
1017
                        if(sysmeta.getObsoletedBy() == null) {
1018
                            //type 1 end
1019
                            logMetacat.debug(""+guidStr+" is a type 1 end for sid "+sid.getValue());
1020
                            pid = guid;
1021
                            endsCount++;
1022
                        } else {
1023
                            Identifier obsoletedBy = sysmeta.getObsoletedBy();
1024
                            SystemMetadata obsoletedBySysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletedBy);
1025
                            if(obsoletedBySysmeta != null) {
1026
                                Identifier sidInObsoletedBy = obsoletedBySysmeta.getSeriesId();
1027
                                if(sidInObsoletedBy == null|| !sidInObsoletedBy.equals(sid)) {
1028
                                    // type 2 end
1029
                                    logMetacat.debug(""+guidStr+" is a type 2 end for sid "+sid.getValue());
1030
                                    pid = guid;
1031
                                    endsCount++;
1032
                                }
1033
                            } else {
1034
                                //obsoletedBySysmeta doesn't exist; it means the object is missing
1035
                                //generally, we consider it we generally consider it a type 2 end except:
1036
                                 //there is another object in the chain (has the same series id) that obsoletes the missing object. 
1037
                                String sql2 = "select guid from systemMetadata where  obsoletes = ? and series_id = ?";
1038
                                PreparedStatement stmt2 = dbConn.prepareStatement(sql2);
1039
                                stmt2.setString(1, obsoletedBy.getValue());
1040
                                stmt2.setString(2, sid.getValue());
1041
                                ResultSet result = stmt2.executeQuery();
1042
                                boolean next = result.next();
1043
                                int count = 0;
1044
                                while(next) {
1045
                                    count++;
1046
                                    next = result.next();
1047
                                }
1048
                                if(count == 0) {
1049
                                    //the exception (another object in the chain (has the same series id) that obsoletes the missing object) doesn't exist
1050
                                    // it is a type 2 end
1051
                                    logMetacat.debug(""+guidStr+" is a type 2 end for sid "+sid.getValue());
1052
                                    pid = guid;
1053
                                    endsCount++;
1054
                                } else if (count ==1) {
1055
                                    // it is not end, do nothing;
1056
                                } else {
1057
                                    // something is wrong - there are more than one objects obsolete the missing object!
1058
                                    hasError = true;
1059
                                    break;
1060
                                }
1061
                            }
1062
                        }
1063
                        hasNext = rs.next();
1064
                    }
1065
                    if(endsCount == 1) {
1066
                        //it has one end and it is an ideal chain. We already assign the guid to the pid. So do nothing.
1067
                        logMetacat.info("It is an ideal for sid "+sid.getValue());
1068
                    }
1069
                    if(hasError || endsCount >1) {
1070
                        // 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)
1071
                        logMetacat.info("It is NOT an ideal for sid "+sid.getValue());
1072
                        pid = firstOne;
1073
                    }
1074
                } else {
1075
                    //it is not a sid or at least we don't have anything to match it.
1076
                    //do nothing, so null will be returned
1077
                }
1078
                if(rs != null) {
1079
                    rs.close();
1080
                }
1081
                
1082
            } catch (SQLException e) {
1083
                logMetacat.error("Error while get the head pid for the sid "+sid.getValue()+" : " 
1084
                        + e.getMessage());
1085
                throw e;
1086
            } finally {
1087
                try {
1088
                    if(stmt != null) {
1089
                        stmt.close();
1090
                    }
1091
                } catch (Exception e) {
1092
                    logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
1093
                } finally {
1094
                    // Return database connection to the pool
1095
                    DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1096
                }
1097
            }
1098
        }
1099
        return pid;
1100
    }
1101
    
1102
    /**
1103
     * Check if the specified sid object exists on the serial id field on the system metadata table
1104
     * @param sid
1105
     * @return true if it exists; false otherwise.
1106
     * @throws SQLException
1107
     */
1108
    public boolean systemMetadataSIDExists(Identifier sid) throws SQLException {
1109
        if (sid != null && sid.getValue() != null && !sid.getValue().trim().equals("")) {
1110
            return systemMetadataSIDExists(sid.getValue());
1111
        } else {
1112
            return false;
1113
        }
1114
    }
1115
    
1116
    /**
1117
     * Check if the specified sid exists on the serial id field on the system metadata table
1118
     * @param id
1119
     * @return true if it exists; false otherwise.
1120
     */
1121
    public boolean systemMetadataSIDExists(String sid) throws SQLException {
1122
        boolean exists = false;
1123
        logMetacat.debug("Check if the  sid: " + sid +" exists on the series_id field of the system metadata table.");
1124
        if(sid != null && !sid.trim().equals("")) {
1125
            String sql = "select guid from systemMetadata where series_id = ?";
1126
            DBConnection dbConn = null;
1127
            int serialNumber = -1;
1128
            PreparedStatement stmt = null;
1129
            try {
1130
                // Get a database connection from the pool
1131
                dbConn = DBConnectionPool.getDBConnection("IdentifierManager.serialIdExists");
1132
                serialNumber = dbConn.getCheckOutSerialNumber();
1133
                // Execute the insert statement
1134
                stmt = dbConn.prepareStatement(sql);
1135
                stmt.setString(1, sid);
1136
                ResultSet rs = stmt.executeQuery();
1137
                if (rs.next()) 
1138
                {
1139
                    exists = true;
1140
                } 
1141
                if(rs != null) {
1142
                    rs.close();
1143
                }
1144
            } catch (SQLException e) {
1145
                logMetacat.error("Error while checking if the sid "+sid+" exists on the series_id field of the system metadata table: " 
1146
                        + e.getMessage());
1147
                throw e;
1148
            } finally {
1149
                try {
1150
                    if(stmt != null) {
1151
                        stmt.close();
1152
                    }
1153
                } catch (Exception e) {
1154
                    logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
1155
                } finally {
1156
                    // Return database connection to the pool
1157
                    DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1158
                }
1159
            }
1160
        }
1161
        return exists;
1162
    }
1163
    
1164
    /**
1165
     * Determine if the specified identifier object exists or not.
1166
     * @param pid - the specified identifier
1167
     * @return true if it is exists.
1168
     * @throws SQLException
1169
     * @throws NullPointerException
1170
     */
1171
    public boolean systemMetadataPIDExists(Identifier pid) throws SQLException {
1172
        if (pid != null && pid.getValue() != null && !pid.getValue().trim().equals("")) {
1173
            return systemMetadataPIDExists(pid.getValue());
1174
        } else {
1175
            return false;
1176
        }
1177
    }
1178
    
1179
    public boolean systemMetadataPIDExists(String guid) throws SQLException {
1180
		logMetacat.debug("looking up system metadata for guid " + guid);
1181
		boolean exists = false;
1182
		String query = "select guid from systemmetadata where guid = ?";
1183
		DBConnection dbConn = null;
1184
		int serialNumber = -1;
1185
		PreparedStatement stmt = null;
1186
		if(guid != null && !guid.trim().equals("")) {
1187
		    try {
1188
	            // Get a database connection from the pool
1189
	            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
1190
	            serialNumber = dbConn.getCheckOutSerialNumber();
1191

    
1192
	            // Execute the insert statement
1193
	            stmt = dbConn.prepareStatement(query);
1194
	            stmt.setString(1, guid);
1195
	            ResultSet rs = stmt.executeQuery();
1196
	            if (rs.next()) {
1197
	                exists = true;
1198
	            }
1199
	            if(rs != null) {
1200
	                rs.close();
1201
	            }
1202

    
1203
	        } catch (SQLException e) {
1204
	            logMetacat.error("Error while looking up the system metadata: "
1205
	                    + e.getMessage());
1206
	            throw e;
1207
	        } finally {
1208
	            try {
1209
	                if(stmt != null) {
1210
	                    stmt.close();
1211
	                }
1212
	            } catch (Exception e) {
1213
	                logMetacat.warn("Couldn't close the prepared statement since "+e.getMessage());
1214
	            } finally {
1215
	                // Return database connection to the pool
1216
	                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1217
	            }
1218
	        }
1219
		}
1220
		return exists;
1221
	}
1222
    
1223
    /**
1224
     * creates a system metadata mapping and adds additional fields from sysmeta
1225
     * to the table for quick searching.
1226
     * 
1227
     * @param guid the id to insert
1228
     * @param localId the systemMetadata object to get the local id for
1229
     * @throws McdbDocNotFoundException 
1230
     * @throws SQLException 
1231
     * @throws InvalidSystemMetadata 
1232
     */
1233
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta) 
1234
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
1235
    	String guid = sysmeta.getIdentifier().getValue();
1236
    	
1237
    	 // Get a database connection from the pool
1238
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1239
        int serialNumber = dbConn.getCheckOutSerialNumber();
1240
        
1241
        try {
1242
        	// use a single transaction for it all
1243
        	dbConn.setAutoCommit(false);
1244
        	
1245
	    	// insert the record if needed
1246
        	if (!IdentifierManager.getInstance().systemMetadataPIDExists(guid)) {
1247
    	        insertSystemMetadata(guid, dbConn);
1248
			}
1249
	        // update with the values
1250
	        updateSystemMetadata(sysmeta, dbConn);
1251
	        
1252
	        // commit if we got here with no errors
1253
	        dbConn.commit();
1254
        } catch (Exception e) {
1255
            e.printStackTrace();
1256
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1257
            dbConn.rollback();
1258
            throw new SQLException("Can't save system metadata "+e.getMessage());
1259
        } finally {
1260
            // Return database connection to the pool
1261
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1262
        }
1263
        
1264
        
1265
    }
1266
        
1267
    
1268
    /**
1269
     * update a mapping
1270
     * @param guid
1271
     * @param localId
1272
     */
1273
    public void updateMapping(String guid, String localId)
1274
    {
1275
    	
1276
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1277
        int serialNumber = -1;
1278
        DBConnection dbConn = null;
1279
        try {
1280
            // Parse the localId into scope and rev parts
1281
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1282
            String docid = acc.getDocid();
1283
            int rev = 1;
1284
            if(acc.getRev() != null)
1285
            {
1286
              rev = (new Integer(acc.getRev()).intValue());
1287
            }
1288

    
1289
            // Get a database connection from the pool
1290
            dbConn = 
1291
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1292
            serialNumber = dbConn.getCheckOutSerialNumber();
1293

    
1294
            // Execute the update statement
1295
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1296
            PreparedStatement stmt = dbConn.prepareStatement(query);
1297
            stmt.setString(1, docid);
1298
            stmt.setInt(2, rev);
1299
            stmt.setString(3, guid);
1300
            int rows = stmt.executeUpdate();
1301

    
1302
            stmt.close();
1303
        } catch (SQLException e) {
1304
            e.printStackTrace();
1305
            logMetacat.error("SQL error while updating a mapping identifier: " 
1306
                    + e.getMessage());
1307
        } catch (NumberFormatException e) {
1308
            e.printStackTrace();
1309
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1310
                    + e.getMessage());
1311
        } catch (AccessionNumberException e) {
1312
            e.printStackTrace();
1313
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1314
                    + e.getMessage());
1315
        } finally {
1316
            // Return database connection to the pool
1317
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1318
        }
1319
        logMetacat.debug("done updating mapping");
1320
    }
1321
        
1322
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1323
        String checksum, String checksumAlgorithm, String originMemberNode, 
1324
        String authoritativeMemberNode, long modifiedDate, String submitter, 
1325
        String guid, String objectFormat, BigInteger size, boolean archived,
1326
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1327
        String obsoletedBy, BigInteger serialVersion, String seriesId, 
1328
        String fileName, MediaType mediaType, DBConnection dbConn) throws SQLException  {
1329
        PreparedStatement stmt = null;
1330
        PreparedStatement stmt2 = null;
1331
        try {
1332
            dbConn.setAutoCommit(false);
1333
            // Execute the insert statement
1334
            String query = "update " + TYPE_SYSTEM_METADATA + 
1335
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1336
                "origin_member_node, authoritive_member_node, date_modified, " +
1337
                "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1338
                "obsoletes, obsoleted_by, serial_version, series_id, file_name, media_type) " +
1339
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?) where guid = ?";
1340
            stmt = dbConn.prepareStatement(query);
1341
            
1342
            //data values
1343
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1344
            stmt.setString(2, rightsHolder);
1345
            stmt.setString(3, checksum);
1346
            stmt.setString(4, checksumAlgorithm);
1347
            stmt.setString(5, originMemberNode);
1348
            stmt.setString(6, authoritativeMemberNode);
1349
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1350
            stmt.setString(8, submitter);
1351
            stmt.setString(9, objectFormat);
1352
            stmt.setString(10, size.toString());
1353
            stmt.setBoolean(11, archived);
1354
            stmt.setBoolean(12, replicationAllowed);
1355
            stmt.setInt(13, numberReplicas);
1356
            stmt.setString(14, obsoletes);
1357
            stmt.setString(15, obsoletedBy);
1358
            if(serialVersion != null) {
1359
                stmt.setString(16, serialVersion.toString());
1360
            } else {
1361
                stmt.setString(16, null);
1362
            }
1363
            
1364
            stmt.setString(17, seriesId);
1365
            stmt.setString(18, fileName);
1366
            if (mediaType == null) {
1367
                stmt.setString(19, null);
1368
            } else {
1369
                stmt.setString(19, mediaType.getName());
1370
            }
1371
            //where clause
1372
            stmt.setString(20, guid);
1373
            logMetacat.debug("stmt: " + stmt.toString());
1374
            //execute
1375
            int rows = stmt.executeUpdate();
1376
            
1377
            //insert media type properties into another table
1378
            if(mediaType != null && mediaType.getPropertyList() != null) {
1379
                String sql2 = "insert into smmediatypeproperties " + 
1380
                        "(guid, name, value) " + "values (?, ?, ?)";
1381
                stmt2 = dbConn.prepareStatement(sql2);
1382
                for(MediaTypeProperty item : mediaType.getPropertyList()) {
1383
                    if(item != null) {
1384
                        String name = item.getName();
1385
                        String value = item.getValue();
1386
                        stmt2.setString(1, guid);
1387
                        stmt2.setString(2, name);
1388
                        stmt2.setString(3, value);
1389
                        logMetacat.debug("insert media type properties query: " + stmt2.toString());
1390
                        int row =stmt2.executeUpdate();
1391
                    }
1392
                    
1393
                }
1394
            }
1395
            dbConn.commit();
1396
            dbConn.setAutoCommit(true);
1397
        } catch (Exception e) {
1398
            dbConn.rollback();
1399
            dbConn.setAutoCommit(true);
1400
            e.printStackTrace();
1401
            throw new SQLException(e.getMessage());
1402
        } finally {
1403
            if(stmt != null) {
1404
                stmt.close();
1405
            }
1406
            if(stmt2 != null) {
1407
                stmt2.close();
1408
            }
1409
        }
1410
        
1411
               
1412
    }
1413
    
1414
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1415
    {
1416
           
1417
        // remove existing values first
1418
        String delete = "delete from smReplicationPolicy " + 
1419
        "where guid = ? and policy = ?";
1420
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1421
        //data values
1422
        stmt.setString(1, guid);
1423
        stmt.setString(2, policy);
1424
        //execute
1425
        int deletedCount = stmt.executeUpdate();
1426
        stmt.close();
1427
        
1428
        for (String memberNode: memberNodes) {
1429
            // Execute the insert statement
1430
            String insert = "insert into smReplicationPolicy " + 
1431
                "(guid, policy, member_node) " +
1432
                "values (?, ?, ?)";
1433
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1434
            
1435
            //data values
1436
            insertStatement.setString(1, guid);
1437
            insertStatement.setString(2, policy);
1438
            insertStatement.setString(3, memberNode);
1439
            
1440
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1441

    
1442
            //execute
1443
            int rows = insertStatement.executeUpdate();
1444
            insertStatement.close();
1445
        }
1446
        
1447
    }
1448
    
1449
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1450
       
1451
        // remove existing values first
1452
        String delete = "delete from smReplicationStatus " + 
1453
        "where guid = ?";
1454
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1455
        //data values
1456
        stmt.setString(1, guid);
1457
        //execute
1458
        int deletedCount = stmt.executeUpdate();
1459
        stmt.close();
1460
        
1461
        if (replicas != null) {
1462
            for (Replica replica: replicas) {
1463
	            // Execute the insert statement
1464
	            String insert = "insert into smReplicationStatus " + 
1465
	                "(guid, member_node, status, date_verified) " +
1466
	                "values (?, ?, ?, ?)";
1467
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1468
	            
1469
	            //data values
1470
	            String memberNode = replica.getReplicaMemberNode().getValue();
1471
	            String status = replica.getReplicationStatus().toString();
1472
	            java.sql.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1473
	            insertStatement.setString(1, guid);
1474
	            insertStatement.setString(2, memberNode);
1475
	            insertStatement.setString(3, status);
1476
	            insertStatement.setTimestamp(4, sqlDate);
1477

    
1478
	            logMetacat.debug("smReplicationStatus sql: " + insertStatement.toString());
1479
	            
1480
	            //execute
1481
	            int rows = insertStatement.executeUpdate();
1482
	            insertStatement.close();
1483
            }
1484
        }
1485
       
1486
    }
1487
    
1488
    /**
1489
     * Insert the system metadata fields into the db
1490
     * @param sm
1491
     * @throws McdbDocNotFoundException 
1492
     * @throws SQLException 
1493
     * @throws InvalidSystemMetadata 
1494
     * @throws AccessException 
1495
     */
1496
    public void updateSystemMetadata(SystemMetadata sm, DBConnection dbConn) 
1497
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata, AccessException {
1498
    	
1499
      Boolean replicationAllowed = false;
1500
		  Integer numberReplicas = -1;
1501
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1502
    	if (replicationPolicy != null) {
1503
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1504
    		numberReplicas = replicationPolicy.getNumberReplicas();
1505
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1506
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1507
    	}
1508
    	
1509
    	// the main systemMetadata fields
1510
		  updateSystemMetadataFields(
1511
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1512
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1513
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1514
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1515
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1516
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1517
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1518
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1519
		    sm.getIdentifier().getValue(),
1520
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1521
		    sm.getSize(),
1522
		    sm.getArchived() == null ? false: sm.getArchived(),
1523
		    replicationAllowed, 
1524
		    numberReplicas,
1525
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1526
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1527
		    sm.getSerialVersion(),
1528
		    sm.getSeriesId() == null ? null: sm.getSeriesId().getValue(),
1529
		    sm.getFileName() == null ? null: sm.getFileName(),
1530
		    sm.getMediaType() == null ? null: sm.getMediaType(),
1531
		    dbConn
1532
        );
1533
        
1534
        String guid = sm.getIdentifier().getValue();
1535
        
1536
        // save replication policies
1537
        if (replicationPolicy != null) {
1538
		    List<String> nodes = null;
1539
		    String policy = null;
1540
		    
1541
		    // check for null 
1542
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1543
			    nodes = new ArrayList<String>();
1544
			    policy = "blocked";
1545
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1546
			    	nodes.add(node.getValue());
1547
			    }
1548
			    this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1549
		    }
1550
		    
1551
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1552
			    nodes = new ArrayList<String>();
1553
			    policy = "preferred";
1554
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1555
			    	nodes.add(node.getValue());
1556
			    }
1557
		        this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1558
		    }
1559
        }
1560
        
1561
        // save replica information
1562
        this.insertReplicationStatus(guid, sm.getReplicaList(), dbConn);
1563
        
1564
        // save access policy
1565
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1566
        if (accessPolicy != null) {
1567
			this.insertAccessPolicy(guid, accessPolicy);
1568
        }
1569
    }
1570
    
1571
    /**
1572
     * Creates Metacat access rules and inserts them
1573
     * @param accessPolicy
1574
     * @throws McdbDocNotFoundException
1575
     * @throws AccessException
1576
     */
1577
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1578
    	
1579
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1580
        XMLAccessAccess accessController  = new XMLAccessAccess();
1581
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1582
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1583
        if (existingAccess != null && existingAccess.size() > 0) {
1584
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1585
        }
1586
        
1587
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1588
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1589
        	List<Subject> subjects = accessRule.getSubjectList();
1590
        	List<Permission> permissions = accessRule.getPermissionList();
1591
        	for (Subject subject: subjects) {
1592
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1593
        		accessDAO.setPrincipalName(subject.getValue());
1594
    			accessDAO.setGuid(guid);
1595
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1596
				accessDAO.setPermOrder(existingPermOrder);
1597
    			if (permissions != null) {
1598
	    			for (Permission permission: permissions) {
1599
	    				Long metacatPermission = new Long(convertPermission(permission));
1600
	        			accessDAO.addPermission(metacatPermission);
1601
	    			}
1602
    			}
1603
    			accessDAOs.add(accessDAO);
1604
        	}
1605
        }
1606
        
1607
        
1608
        // remove all existing allow records
1609
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1610
        // add the ones we can for this guid
1611
        accessController.insertAccess(guid, accessDAOs);
1612
        
1613
        
1614
    }
1615
    
1616
    /**
1617
     * Lookup access policy from Metacat
1618
     * @param guid
1619
     * @return
1620
     * @throws McdbDocNotFoundException
1621
     * @throws AccessException
1622
     */
1623
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1624
        AccessPolicy accessPolicy = new AccessPolicy();
1625

    
1626
    	// use GUID to look up the access
1627
        XMLAccessAccess accessController  = new XMLAccessAccess();
1628
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1629
        
1630
        for (XMLAccessDAO accessDAO: accessDAOs) {
1631
        	// only add allow rule
1632
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1633
	        	AccessRule accessRule = new AccessRule();    	
1634
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1635
	        	// cannot include if we have no permissions
1636
	        	if (permissions == null || permissions.isEmpty()) {
1637
	        		logMetacat.warn("skipping empty access rule permissions for " + guid);
1638
	        		continue;
1639
	        	}
1640
	        	accessRule.setPermissionList(permissions);
1641
	        	Subject subject = new Subject();
1642
	        	subject.setValue(accessDAO.getPrincipalName());
1643
	        	accessRule.addSubject(subject);
1644
	            accessPolicy.addAllow(accessRule);
1645
        	}
1646
        }
1647
        return accessPolicy;
1648
    }
1649
    
1650
    public int convertPermission(Permission permission) {
1651
    	if (permission.equals(Permission.READ)) {
1652
    		return AccessControlInterface.READ;
1653
    	}
1654
    	if (permission.equals(Permission.WRITE)) {
1655
    		return AccessControlInterface.WRITE;
1656
    	}
1657
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1658
    		return AccessControlInterface.CHMOD;
1659
    	}
1660
		return -1;
1661
    }
1662
    
1663
    public List<Permission> convertPermission(int permission) {
1664
    	
1665
    	List<Permission> permissions = new ArrayList<Permission>();
1666
    	if (permission == AccessControlInterface.ALL) {
1667
    		permissions.add(Permission.READ);
1668
    		permissions.add(Permission.WRITE);
1669
    		permissions.add(Permission.CHANGE_PERMISSION);
1670
    		return permissions;
1671
    	}
1672
    	
1673
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1674
    		permissions.add(Permission.CHANGE_PERMISSION);
1675
    	}
1676
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1677
    		permissions.add(Permission.READ);
1678
    	}
1679
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1680
    		permissions.add(Permission.WRITE);
1681
    	}
1682
    	
1683
		return permissions;
1684
    }
1685
    
1686
    /**
1687
     * Lookup a localId given the GUID. If
1688
     * the identifier is not found, throw an exception.
1689
     * 
1690
     * @param guid the global identifier to look up
1691
     * @return String containing the corresponding LocalId
1692
     * @throws McdbDocNotFoundException if the identifier is not found
1693
     */
1694
    public String getLocalId(String guid) throws McdbDocNotFoundException, SQLException {
1695
      
1696
      String db_guid = "";
1697
      String docid = "";
1698
      int rev = 0;
1699
      
1700
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1701
      
1702
      DBConnection dbConn = null;
1703
      int serialNumber = -1;
1704
      try {
1705
          // Get a database connection from the pool
1706
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1707
          serialNumber = dbConn.getCheckOutSerialNumber();
1708
          
1709
          // Execute the insert statement
1710
          PreparedStatement stmt = dbConn.prepareStatement(query);
1711
          stmt.setString(1, guid);
1712
          ResultSet rs = stmt.executeQuery();
1713
          if (rs.next()) {
1714
              db_guid = rs.getString(1);
1715
              docid = rs.getString(2);
1716
              rev = rs.getInt(3);
1717
              assert(db_guid.equals(guid));
1718
          } else {
1719
              throw new McdbDocNotFoundException("Document not found:" + guid);
1720
          }
1721
          stmt.close();
1722
      } catch (SQLException e) {
1723
          logMetacat.error("Error while looking up the local identifier: " 
1724
                  + e.getMessage());
1725
          throw e;
1726
      } finally {
1727
          // Return database connection to the pool
1728
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1729
      }
1730
      return docid + "." + rev;
1731
    }
1732
    
1733
    /**
1734
     * query the systemmetadata table based on the given parameters
1735
     * @param startTime
1736
     * @param endTime
1737
     * @param objectFormat
1738
     * @param nodeId
1739
     * @param start
1740
     * @param count
1741
     * @return ObjectList
1742
     * @throws SQLException 
1743
     * @throws ServiceException 
1744
     * @throws PropertyNotFoundException 
1745
     */
1746
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1747
        ObjectFormatIdentifier objectFormatId, NodeReference nodeId,
1748
        int start, int count, Identifier identifier, boolean isSID) 
1749
        throws SQLException, PropertyNotFoundException, ServiceException {
1750
        ObjectList ol = new ObjectList();
1751
        DBConnection dbConn = null;
1752
        int serialNumber = -1;
1753
        PreparedStatement countStmt=null;
1754
        ResultSet totalResult=null;
1755
        PreparedStatement fieldStmt = null;
1756
        ResultSet rs= null;
1757

    
1758
        try {
1759
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1760
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1761
                    + "date_modified, submitter, object_format, size from systemmetadata";
1762
            
1763
            // handle special case quickly
1764
            String countSql = "select count(guid) from systemmetadata";
1765
            
1766
            // the clause
1767
            String whereClauseSql = "";
1768
            
1769

    
1770
            boolean f1 = false;
1771
            boolean f2 = false;
1772
            boolean f3 = false;
1773
            boolean f4 = false;
1774

    
1775

    
1776
            if (startTime != null) {
1777
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1778
                f1 = true;
1779
            }
1780

    
1781
            if (endTime != null) {
1782
                if (!f1) {
1783
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1784
                } else {
1785
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1786
                }
1787
                f2 = true;
1788
            }
1789

    
1790
            if (objectFormatId != null) {
1791
                if (!f1 && !f2) {
1792
                    whereClauseSql += " where object_format = ?";
1793
                } else {
1794
                    whereClauseSql += " and object_format = ?";
1795
                }
1796
                f3 = true;
1797
            }
1798
            
1799
            if(identifier != null && identifier.getValue() != null && !identifier.getValue().equals("")) {
1800
                if (!f1 && !f2 && !f3 ) {
1801
                    if(isSID) {
1802
                        whereClauseSql += " where series_id = ?";
1803
                    } else {
1804
                        whereClauseSql += " where guid = ?";
1805
                    }
1806
                    
1807
                } else {
1808
                    if(isSID) {
1809
                        whereClauseSql += " and series_id = ?";
1810
                    } else {
1811
                        whereClauseSql += " and guid = ?";
1812
                    }
1813
                }
1814
                f4 = true;
1815
            }
1816

    
1817
            /*if (!replicaStatus) {
1818
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1819
                if (!f1 && !f2 && !f3 && !f4) {
1820
                    whereClauseSql += " where authoritive_member_node = '" +
1821
                        currentNodeId.trim() + "'";
1822
                } else {
1823
                    whereClauseSql += " and authoritive_member_node = '" +
1824
                        currentNodeId.trim() + "'";
1825
                }
1826
            }*/
1827
            
1828
            if (nodeId != null && nodeId.getValue() != null && !nodeId.getValue().trim().equals("")) {
1829
                if (!f1 && !f2 && !f3 && !f4) {
1830
                    whereClauseSql += " where authoritive_member_node = '" +
1831
                        nodeId.getValue().trim() + "'";
1832
                } else {
1833
                    whereClauseSql += " and authoritive_member_node = '" +
1834
                        nodeId.getValue().trim() + "'";
1835
                }
1836
            }
1837
           
1838
            
1839
            // connection
1840
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1841
            serialNumber = dbConn.getCheckOutSerialNumber();
1842

    
1843
            // the field query
1844
            String orderBySql = " order by guid ";
1845
            String fieldQuery = fieldSql + whereClauseSql + orderBySql;
1846
            String finalQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldQuery, start, count);
1847
            fieldStmt = dbConn.prepareStatement(finalQuery);
1848
            
1849
            // construct the count query and statment
1850
            String countQuery = countSql + whereClauseSql;
1851
            countStmt = dbConn.prepareStatement(countQuery);
1852

    
1853
            if (f1 && f2 && f3 && f4) {
1854
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1855
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1856
                fieldStmt.setString(3, objectFormatId.getValue());
1857
                fieldStmt.setString(4, identifier.getValue());
1858
                // count
1859
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1860
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1861
                countStmt.setString(3, objectFormatId.getValue());
1862
                countStmt.setString(4, identifier.getValue());
1863
            } if (f1 && f2 && f3 && !f4) {
1864
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1865
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1866
                fieldStmt.setString(3, objectFormatId.getValue());
1867
                // count
1868
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1869
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1870
                countStmt.setString(3, objectFormatId.getValue());
1871
            } else if (f1 && f2 && !f3 && f4) {
1872
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1873
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1874
                fieldStmt.setString(3, identifier.getValue());
1875
                // count
1876
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1877
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1878
                countStmt.setString(3, identifier.getValue());
1879
            } else if (f1 && f2 && !f3 && !f4) {
1880
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1881
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1882
                // count
1883
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1884
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1885
            } else if (f1 && !f2 && f3 && f4) {
1886
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1887
                fieldStmt.setString(2, objectFormatId.getValue());
1888
                fieldStmt.setString(3, identifier.getValue());
1889
                // count
1890
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1891
                countStmt.setString(2, objectFormatId.getValue());
1892
                countStmt.setString(3, identifier.getValue());
1893
            } else if (f1 && !f2 && f3 && !f4) {
1894
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1895
                fieldStmt.setString(2, objectFormatId.getValue());
1896
                // count
1897
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1898
                countStmt.setString(2, objectFormatId.getValue());
1899
            } else if (f1 && !f2 && !f3 && f4) {
1900
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1901
                fieldStmt.setString(2, identifier.getValue());
1902
                // count
1903
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1904
                countStmt.setString(2, identifier.getValue());
1905
            } else if (f1 && !f2 && !f3 && !f4) {
1906
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1907
                // count
1908
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1909
            } else if (!f1 && f2 && f3 && f4) {
1910
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1911
                fieldStmt.setString(2, objectFormatId.getValue());
1912
                fieldStmt.setString(3, identifier.getValue());
1913
                // count
1914
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1915
                countStmt.setString(2, objectFormatId.getValue());
1916
                countStmt.setString(3, identifier.getValue());
1917
            } else if (!f1 && f2 && f3 && !f4) {
1918
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1919
                fieldStmt.setString(2, objectFormatId.getValue());
1920
                // count
1921
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1922
                countStmt.setString(2, objectFormatId.getValue());
1923
            } else if (!f1 && !f2 && f3 && f4) {
1924
                fieldStmt.setString(1, objectFormatId.getValue());
1925
                fieldStmt.setString(2, identifier.getValue());
1926
                // count
1927
                countStmt.setString(1, objectFormatId.getValue());
1928
                countStmt.setString(2, identifier.getValue());
1929
            } else if (!f1 && !f2 && f3 && !f4) {
1930
                fieldStmt.setString(1, objectFormatId.getValue());
1931
                // count
1932
                countStmt.setString(1, objectFormatId.getValue());
1933
            } else if (!f1 && f2 && !f3 && f4) {
1934
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1935
                fieldStmt.setString(2, identifier.getValue());
1936
                // count
1937
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1938
                countStmt.setString(2, identifier.getValue());
1939
            } else if (!f1 && f2 && !f3 && !f4) {
1940
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1941
                // count
1942
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1943
            } else if (!f1 && !f2 && !f3 && f4) {
1944
                fieldStmt.setString(1, identifier.getValue());
1945
                // count
1946
                countStmt.setString(1, identifier.getValue());
1947
            } else if (!f1 && !f2 && !f3 && !f4) {
1948
                //do nothing
1949
            }
1950

    
1951
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
1952
            
1953
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
1954
            
1955
            // get the total object count no matter what
1956
            int total = 0;
1957
            totalResult = countStmt.executeQuery();
1958
            if (totalResult.next()) {
1959
            	total = totalResult.getInt(1);
1960
            }
1961
            
1962
            logMetacat.debug("list objects total: " + total);
1963

    
1964
        	// set the totals
1965
        	ol.setStart(start);
1966
            ol.setCount(count);
1967
            
1968
            // retrieve the actual records if requested
1969
            if (count != 0) {
1970
            	
1971
                rs = fieldStmt.executeQuery();
1972
	            while (rs.next()) {                
1973
	                
1974
	                String guid = rs.getString(1);
1975
	                logMetacat.debug("query found object with guid " + guid);
1976
	                // Timestamp dateUploaded = rs.getTimestamp(2);
1977
	                // String rightsHolder = rs.getString(3);
1978
	                String checksum = rs.getString(4);
1979
	                String checksumAlgorithm = rs.getString(5);
1980
	                // String originMemberNode = rs.getString(6);
1981
	                // String authoritiveMemberNode = rs.getString(7);
1982
	                Timestamp dateModified = rs.getTimestamp(8);
1983
	                // String submitter = rs.getString(9);
1984
	                String fmtidStr = rs.getString(10);
1985
	                String sz = rs.getString(11);
1986
	                BigInteger size = new BigInteger("0");
1987
	
1988
	                if (sz != null && !sz.trim().equals("")) {
1989
	                    size = new BigInteger(rs.getString(11));
1990
	                }
1991
	
1992
	                ObjectInfo oi = new ObjectInfo();
1993
	
1994
	                Identifier id = new Identifier();
1995
	                id.setValue(guid);
1996
	                oi.setIdentifier(id);
1997
	
1998
	                if (dateModified != null) {
1999
	                    oi.setDateSysMetadataModified(dateModified);
2000
	                }
2001
	
2002
	                Checksum cs = new Checksum();
2003
	                cs.setValue(checksum);
2004
	                try {
2005
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
2006
	                    cs.setAlgorithm(checksumAlgorithm);
2007
	                } catch (Exception e) {
2008
	                    logMetacat.error("could not parse checksum algorithm", e);
2009
	                    continue;
2010
	                }
2011
	                oi.setChecksum(cs);
2012
	
2013
	                // set the format type
2014
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
2015
	                fmtid.setValue(fmtidStr);
2016
	                oi.setFormatId(fmtid);
2017
	
2018
	                oi.setSize(size);
2019
	                
2020
	                ol.addObjectInfo(oi);                    
2021

    
2022
	            }
2023
	            
2024
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
2025
	            // set the actual count retrieved
2026
	            ol.setCount(ol.sizeObjectInfoList());
2027
	            
2028
	
2029
	        }
2030
            ol.setTotal(total);
2031
        } finally {
2032
            // Return database connection to the pool
2033
            try {
2034
                if(totalResult !=null ){
2035
                    totalResult.close();
2036
                }
2037
                if(countStmt!=null ) {
2038
                    countStmt.close();
2039
                }
2040
                if(rs != null) {
2041
                    rs.close();
2042
                }
2043
                if(fieldStmt != null) {
2044
                    fieldStmt.close();
2045
                }
2046
                
2047
            } catch (SQLException sql) {
2048
                
2049
            }
2050
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2051
            
2052
        }
2053
        if(ol != null) {
2054
            logMetacat.debug("list objects start(before returning): " + ol.getStart());
2055
            logMetacat.debug("list objects count: " + ol.getCount());
2056
            logMetacat.debug("list objects total: " + ol.getTotal());
2057
        }
2058
        return ol;
2059
    }
2060
    
2061
    /**
2062
     * create a mapping in the identifier table
2063
     * @param guid
2064
     * @param localId
2065
     */
2066
    public void createMapping(String guid, String localId)
2067
    {        
2068
        
2069
        int serialNumber = -1;
2070
        DBConnection dbConn = null;
2071
        try {
2072

    
2073
            // Parse the localId into scope and rev parts
2074
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
2075
            String docid = acc.getDocid();
2076
            int rev = 1;
2077
            if (acc.getRev() != null) {
2078
              rev = (new Integer(acc.getRev()).intValue());
2079
            }
2080

    
2081
            // Get a database connection from the pool
2082
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
2083
            serialNumber = dbConn.getCheckOutSerialNumber();
2084

    
2085
            // Execute the insert statement
2086
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
2087
            PreparedStatement stmt = dbConn.prepareStatement(query);
2088
            stmt.setString(1, guid);
2089
            stmt.setString(2, docid);
2090
            stmt.setInt(3, rev);
2091
            logMetacat.debug("mapping query: " + stmt.toString());
2092
            int rows = stmt.executeUpdate();
2093

    
2094
            stmt.close();
2095
        } catch (SQLException e) {
2096
            e.printStackTrace();
2097
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2098
                    + e.getMessage());
2099
        } catch (NumberFormatException e) {
2100
            e.printStackTrace();
2101
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2102
                    + e.getMessage());
2103
        } catch (AccessionNumberException e) {
2104
            e.printStackTrace();
2105
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2106
                    + e.getMessage());
2107
        } finally {
2108
            // Return database connection to the pool
2109
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2110
        }
2111
    }
2112
    
2113
    /**
2114
     * remove a mapping in the identifier table
2115
     * @param guid
2116
     * @param localId
2117
     */
2118
    public void removeMapping(String guid, String localId)
2119
    {        
2120
        
2121
        int serialNumber = -1;
2122
        DBConnection dbConn = null;
2123
        try {
2124

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

    
2133
            // Get a database connection from the pool
2134
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
2135
            serialNumber = dbConn.getCheckOutSerialNumber();
2136

    
2137
            // Execute the insert statement
2138
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
2139
            PreparedStatement stmt = dbConn.prepareStatement(query);
2140
            stmt.setString(1, guid);
2141
            stmt.setString(2, docid);
2142
            stmt.setInt(3, rev);
2143
            logMetacat.debug("remove mapping query: " + stmt.toString());
2144
            int rows = stmt.executeUpdate();
2145

    
2146
            stmt.close();
2147
        } catch (SQLException e) {
2148
            e.printStackTrace();
2149
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2150
                    + e.getMessage());
2151
        } catch (NumberFormatException e) {
2152
            e.printStackTrace();
2153
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2154
                    + e.getMessage());
2155
        } catch (AccessionNumberException e) {
2156
            e.printStackTrace();
2157
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
2158
                    + e.getMessage());
2159
        } finally {
2160
            // Return database connection to the pool
2161
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2162
        }
2163
    }
2164
    
2165
    /**
2166
     * create the systemmetadata record
2167
     * @param guid
2168
     * @param dbConn 
2169
     * @throws SQLException 
2170
     */
2171
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
2172
    {        
2173

    
2174
        // Execute the insert statement
2175
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
2176
        PreparedStatement stmt = dbConn.prepareStatement(query);
2177
        stmt.setString(1, guid);
2178
        logMetacat.debug("system metadata query: " + stmt.toString());
2179
        int rows = stmt.executeUpdate();
2180

    
2181
        stmt.close();
2182
        
2183
    }
2184
    
2185
    public boolean deleteSystemMetadata(String guid)
2186
    {        
2187
        boolean success = false;
2188
        int serialNumber = -1;
2189
        DBConnection dbConn = null;
2190
        String query = null;
2191
        PreparedStatement stmt = null;
2192
        int rows = 0;
2193
        try {
2194

    
2195
        	 // Get a database connection from the pool
2196
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
2197
            serialNumber = dbConn.getCheckOutSerialNumber();
2198
            dbConn.setAutoCommit(false);
2199
        	
2200
            // remove the smReplicationPolicy
2201
            query = "delete from smReplicationPolicy " + 
2202
            "where guid = ?";
2203
            stmt = dbConn.prepareStatement(query);
2204
            stmt.setString(1, guid);
2205
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
2206
            rows = stmt.executeUpdate();
2207
            stmt.close();
2208
            
2209
            // remove the smReplicationStatus
2210
            query = "delete from smReplicationStatus " + 
2211
            "where guid = ?";
2212
            stmt = dbConn.prepareStatement(query);
2213
            stmt.setString(1, guid);
2214
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
2215
            rows = stmt.executeUpdate();
2216
            stmt.close();
2217
            
2218
            // remove the smmediatypeproperties
2219
            query = "delete from smmediatypeproperties " + 
2220
                    "where guid = ?";
2221
            stmt = dbConn.prepareStatement(query);
2222
            stmt.setString(1, guid);
2223
            logMetacat.debug("delete smmediatypeproperties: " + stmt.toString());
2224
            rows = stmt.executeUpdate();
2225
            stmt.close();
2226
            
2227
            // remove main system metadata entry
2228
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
2229
            stmt = dbConn.prepareStatement(query);
2230
            stmt.setString(1, guid);
2231
            logMetacat.debug("delete system metadata: " + stmt.toString());
2232
            rows = stmt.executeUpdate();
2233
            stmt.close();
2234
            
2235
            dbConn.commit();
2236
            dbConn.setAutoCommit(true);
2237
            success = true;
2238
            // TODO: remove the access?
2239
            // Metacat keeps "deleted" documents so we should not remove access rules.
2240
            
2241
        } catch (Exception e) {
2242
            e.printStackTrace();
2243
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
2244
            try {
2245
				dbConn.rollback();
2246
			} catch (SQLException sqle) {
2247
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
2248
			}
2249
        } finally {
2250
            // Return database connection to the pool
2251
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2252
        }
2253
        return success;
2254
    }
2255
    
2256
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
2257
    {
2258
        DBConnection dbConn = null;
2259
        int serialNumber = -1;
2260
        
2261
        try {
2262
            // Get a database connection from the pool
2263
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
2264
            serialNumber = dbConn.getCheckOutSerialNumber();
2265

    
2266
            // Execute the insert statement
2267
            String query = "update " + TYPE_SYSTEM_METADATA + 
2268
                " set authoritive_member_node = ? " +
2269
                " where authoritive_member_node = ?";
2270
            PreparedStatement stmt = dbConn.prepareStatement(query);
2271
            
2272
            //data values
2273
            stmt.setString(1, newMemberNodeId);
2274
            stmt.setString(2, existingMemberNodeId);
2275

    
2276
            logMetacat.debug("stmt: " + stmt.toString());
2277
            //execute
2278
            int rows = stmt.executeUpdate();
2279

    
2280
            stmt.close();
2281
        } catch (SQLException e) {
2282
            e.printStackTrace();
2283
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
2284
                    + e.getMessage());
2285
        } catch (NumberFormatException e) {
2286
            e.printStackTrace();
2287
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
2288
                    + e.getMessage());
2289
        } finally {
2290
            // Return database connection to the pool
2291
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2292
        }
2293
    }
2294
}
2295

    
(36-36/63)