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.SystemMetadata;
56

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

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

    
89
    /**
90
     * A private constructor that initializes the class when getInstance() is
91
     * called.
92
     */
93
    private IdentifierManager() {}
94

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

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

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

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

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

    
291
                Identifier sysMetaId = new Identifier();
292
                sysMetaId.setValue(guid);
293
                sysMeta.setIdentifier(sysMetaId);
294
                sysMeta.setSerialVersion(serialVersion);
295
                sysMeta.setDateUploaded(dateUploaded);
296
                Subject rightsHolderSubject = new Subject();
297
                rightsHolderSubject.setValue(rightsHolder);
298
                sysMeta.setRightsHolder(rightsHolderSubject);
299
                Checksum checksumObject = new Checksum();
300
                checksumObject.setValue(checksum);
301
                checksumObject.setAlgorithm(checksumAlgorithm);
302
                sysMeta.setChecksum(checksumObject);
303
                if (originMemberNode != null) {
304
	                NodeReference omn = new NodeReference();
305
	                omn.setValue(originMemberNode);
306
	                sysMeta.setOriginMemberNode(omn);
307
                }
308
                if (authoritativeMemberNode != null) {
309
	                NodeReference amn = new NodeReference();
310
	                amn.setValue(authoritativeMemberNode);
311
	                sysMeta.setAuthoritativeMemberNode(amn);
312
                }
313
                sysMeta.setDateSysMetadataModified(dateModified);
314
                if (submitter != null) {
315
	                Subject submitterSubject = new Subject();
316
	                submitterSubject.setValue(submitter);
317
	                sysMeta.setSubmitter(submitterSubject);
318
                }
319
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
320
                fmtid.setValue(fmtidStr);
321
            	sysMeta.setFormatId(fmtid);
322
                sysMeta.setSize(size);
323
                if (obsoletes != null) {
324
	                Identifier obsoletesId = new Identifier();
325
	                obsoletesId.setValue(obsoletes);
326
	                sysMeta.setObsoletes(obsoletesId);
327
                }
328
                if (obsoletedBy != null) {
329
		            Identifier obsoletedById = new Identifier();
330
		            obsoletedById.setValue(obsoletedBy);
331
		            sysMeta.setObsoletedBy(obsoletedById);
332
                }
333
                sysMeta.setArchived(archived);
334
                stmt.close();
335
            } 
336
            else
337
            {
338
                stmt.close();
339
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
340
                throw new McdbDocNotFoundException("Could not find " + guid);
341
            }
342
            
343
        } 
344
        catch (SQLException e) 
345
        {
346
            e.printStackTrace();
347
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "  
348
                    + e.getMessage());
349
        } 
350
        finally 
351
        {
352
            // Return database connection to the pool
353
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
354
        }
355

    
356
        // populate the replication policy
357
        ReplicationPolicy replicationPolicy = new ReplicationPolicy();
358
        if ( numberOfReplicas != null  && numberOfReplicas.intValue() != -1 ) {
359
            replicationPolicy.setNumberReplicas(numberOfReplicas.intValue());
360
            
361
        }
362
        
363
        if ( replicationAllowed != null ) {
364
            replicationPolicy.setReplicationAllowed(replicationAllowed);
365
            
366
        }
367
        replicationPolicy.setBlockedMemberNodeList(getReplicationPolicy(guid, "blocked"));
368
        replicationPolicy.setPreferredMemberNodeList(getReplicationPolicy(guid, "preferred"));
369
		    sysMeta.setReplicationPolicy(replicationPolicy);
370
		
371
		    // look up replication status
372
		    sysMeta.setReplicaList(getReplicationStatus(guid));
373
		
374
		    // look up access policy
375
		    try {
376
		    	sysMeta.setAccessPolicy(getAccessPolicy(guid));
377
		    } catch (AccessException e) {
378
		    	throw new McdbDocNotFoundException(e);
379
		    }
380
        
381
        return sysMeta;
382
    }
383
    
384
    
385
    private List<NodeReference> getReplicationPolicy(String guid, String policy)
386
		throws McdbDocNotFoundException {
387
		
388
		List<NodeReference> nodes = new ArrayList<NodeReference>();
389
		String sql = "select guid, policy, member_node " +
390
			"from smReplicationPolicy where guid = ? and policy = ?";
391
	    DBConnection dbConn = null;
392
	    int serialNumber = -1;
393
	    try {
394
	        // Get a database connection from the pool
395
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicationPolicy");
396
	        serialNumber = dbConn.getCheckOutSerialNumber();
397
	
398
	        // Execute the statement
399
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
400
	        stmt.setString(1, guid);
401
	        stmt.setString(2, policy);
402
	        ResultSet rs = stmt.executeQuery();
403
	        while (rs.next()) 
404
	        {
405
	            String memberNode = rs.getString(3);
406
	            NodeReference node = new NodeReference();
407
	            node.setValue(memberNode);
408
	            nodes.add(node);
409
	        
410
	        } 
411
	        stmt.close();
412
	        
413
	    } catch (SQLException e) {
414
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
415
	    } 
416
	    finally {
417
	        // Return database connection to the pool
418
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
419
	    }
420
	    
421
	    return nodes;
422
	}
423
    
424
    private List<Replica> getReplicationStatus(String guid) throws McdbDocNotFoundException {
425
		
426
		List<Replica> replicas = new ArrayList<Replica>();
427
		String sql = "select guid, member_node, status, date_verified " +
428
			"from smReplicationStatus where guid = ?";
429
	    DBConnection dbConn = null;
430
	    int serialNumber = -1;
431
	    try {
432
	        // Get a database connection from the pool
433
	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicas");
434
	        serialNumber = dbConn.getCheckOutSerialNumber();
435
	
436
	        // Execute the statement
437
	        PreparedStatement stmt = dbConn.prepareStatement(sql);
438
	        stmt.setString(1, guid);
439
	        ResultSet rs = stmt.executeQuery();
440
	        while (rs.next()) 
441
	        {
442
	            String memberNode = rs.getString(2);
443
	            String status = rs.getString(3);
444
	            java.sql.Timestamp verified = rs.getTimestamp(4);
445
	            
446
	            Replica replica = new Replica();	            
447
	            NodeReference node = new NodeReference();
448
	            node.setValue(memberNode);
449
	            replica.setReplicaMemberNode(node);
450
	            replica.setReplicationStatus(ReplicationStatus.valueOf(status));
451
	            replica.setReplicaVerified(new Date(verified.getTime()));
452
	            replicas.add(replica);
453
	        } 
454
	        stmt.close();
455
	        
456
	    } catch (SQLException e) {
457
	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
458
	    } 
459
	    finally {
460
	        // Return database connection to the pool
461
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
462
	    }
463
	    
464
	    return replicas;
465
	}
466
    
467
    
468
    /**
469
     * return the newest rev for a given localId
470
     * @param localId
471
     * @return
472
     */
473
    public int getLatestRevForLocalId(String localId)
474
        throws McdbDocNotFoundException
475
    {
476
        try
477
        {
478
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
479
            localId = acc.getDocid();
480
        }
481
        catch(Exception e)
482
        {
483
            //do nothing. just try the localId as it is
484
        }
485
        int rev = 0;
486
        String sql = "select rev from xml_documents where docid like ? ";
487
        DBConnection dbConn = null;
488
        int serialNumber = -1;
489
        try 
490
        {
491
            // Get a database connection from the pool
492
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLatestRevForLocalId");
493
            serialNumber = dbConn.getCheckOutSerialNumber();
494

    
495
            // Execute the insert statement
496
            PreparedStatement stmt = dbConn.prepareStatement(sql);
497
            stmt.setString(1, localId);
498
            ResultSet rs = stmt.executeQuery();
499
            if (rs.next()) 
500
            {
501
                rev = rs.getInt(1);
502
                stmt.close();
503
            } 
504
            else
505
            {
506
                stmt.close();
507
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
508
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
509
            }
510
        } 
511
        catch (SQLException e) 
512
        {
513
            logMetacat.error("Error while looking up the guid: " 
514
                    + e.getMessage());
515
        } 
516
        finally 
517
        {
518
            // Return database connection to the pool
519
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
520
        }
521
        return rev;
522
    }
523
    
524
    /**
525
     * return all local ids in the object store that do not have associated
526
     * system metadata
527
     */
528
    public List<String> getLocalIdsWithNoSystemMetadata(boolean includeRevisions, int serverLocation)
529
    {
530
        Vector<String> ids = new Vector<String>();
531
        String sql = "select docid, rev from xml_documents " +
532
        		"where docid not in " +
533
        		"(select docid from identifier where guid in (select guid from systemmetadata))";
534
        if (serverLocation > 0) {
535
        	sql = sql + " and server_location = ? ";
536
        }
537
        
538
        String revisionSql = "select docid, rev from xml_revisions " +
539
				"where docid not in " +
540
				"(select docid from identifier where guid in (select guid from systemmetadata))";
541
        if (serverLocation > 0) {
542
        	revisionSql = revisionSql + " and server_location = ? ";
543
        }
544
        
545
        if (includeRevisions) {
546
        	sql = sql + " UNION ALL " + revisionSql;
547
        }
548
        
549
        DBConnection dbConn = null;
550
        int serialNumber = -1;
551
        try 
552
        {
553
            // Get a database connection from the pool
554
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
555
            serialNumber = dbConn.getCheckOutSerialNumber();
556

    
557
            // Execute the insert statement
558
            PreparedStatement stmt = dbConn.prepareStatement(sql);
559
            // set params based on what we have in the query string
560
            if (serverLocation > 0) {
561
            	stmt.setInt(1, serverLocation);
562
            	if (includeRevisions) {
563
            		stmt.setInt(2, serverLocation);
564
            	}
565
            }
566
            ResultSet rs = stmt.executeQuery();
567
            while (rs.next()) 
568
            {
569
                String localid = rs.getString(1);
570
                String rev = rs.getString(2);
571
                localid += "." + rev;
572
                logMetacat.debug("id to add SM for: " + localid);
573
                ids.add(localid);
574
            } 
575
            stmt.close();
576
        } 
577
        catch (SQLException e) 
578
        {
579
            logMetacat.error("Error while looking up the guid: " 
580
                    + e.getMessage());
581
        } 
582
        finally 
583
        {
584
            // Return database connection to the pool
585
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
586
        }
587
        
588
        return ids;
589
    }
590
    
591
    /**
592
     * return a listing of all local ids in the object store
593
     * @return a list of all local ids in metacat
594
     */
595
    public List<String> getAllLocalIds()
596
    // seems to be an unnecessary and restrictive throw -rnahf 13-Sep-2011
597
    //    throws Exception
598
    {
599
        Vector<String> ids = new Vector<String>();
600
        String sql = "select docid from xml_documents";
601
        DBConnection dbConn = null;
602
        int serialNumber = -1;
603
        try 
604
        {
605
            // Get a database connection from the pool
606
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
607
            serialNumber = dbConn.getCheckOutSerialNumber();
608

    
609
            // Execute the insert statement
610
            PreparedStatement stmt = dbConn.prepareStatement(sql);
611
            ResultSet rs = stmt.executeQuery();
612
            while (rs.next()) 
613
            {
614
                String localid = rs.getString(1);
615
                ids.add(localid);
616
            } 
617
            stmt.close();
618
        } 
619
        catch (SQLException e) 
620
        {
621
            logMetacat.error("Error while looking up the guid: " 
622
                    + e.getMessage());
623
        } 
624
        finally 
625
        {
626
            // Return database connection to the pool
627
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
628
        }
629
        return ids;
630
    }
631
    
632
    
633
    /**
634
     * return a listing of all guids in the object store
635
     * @return a list of all GUIDs in metacat
636
     */
637
    public List<String> getAllSystemMetadataGUIDs()
638
    {
639
        Vector<String> guids = new Vector<String>();
640
        String sql = "select guid from systemmetadata";
641
        DBConnection dbConn = null;
642
        int serialNumber = -1;
643
        try 
644
        {
645
            // Get a database connection from the pool
646
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllGUIDs");
647
            serialNumber = dbConn.getCheckOutSerialNumber();
648

    
649
            // Execute the insert statement
650
            PreparedStatement stmt = dbConn.prepareStatement(sql);
651
            ResultSet rs = stmt.executeQuery();
652
            while (rs.next()) 
653
            {
654
                String guid = rs.getString(1);
655
                guids.add(guid);
656
            } 
657
            stmt.close();
658
        } 
659
        catch (SQLException e) 
660
        {
661
            logMetacat.error("Error while retrieving the guid: " 
662
                    + e.getMessage());
663
        } 
664
        finally 
665
        {
666
            // Return database connection to the pool
667
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
668
        }
669
        return guids;
670
    }
671
    
672
    
673
    
674
    /**
675
     * returns a list of system metadata-only guids since the given date
676
     * @return a list of system ids in metacat that do not correspond to objects
677
     * TODO: need to check which server they are on
678
     */
679
    public List<String> getUpdatedSystemMetadataIds(Date since)
680
       throws Exception
681
    {
682
        List<String> ids = new Vector<String>();
683
        String sql = 
684
        	"select guid from " + TYPE_SYSTEM_METADATA +
685
        	" where guid not in " +
686
        	" (select guid from " + TYPE_IDENTIFIER + ") " +
687
        	" and date_modified > ?";
688
        DBConnection dbConn = null;
689
        int serialNumber = -1;
690
        try 
691
        {
692
            // Get a database connection from the pool
693
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getUpdatedSystemMetadataIds");
694
            serialNumber = dbConn.getCheckOutSerialNumber();
695

    
696
            // Execute the insert statement
697
            PreparedStatement stmt = dbConn.prepareStatement(sql);
698
            stmt.setDate(1, new java.sql.Date(since.getTime()));
699
            ResultSet rs = stmt.executeQuery();
700
            while (rs.next()) 
701
            {
702
                String guid = rs.getString(1);
703
                ids.add(guid);
704
            } 
705
            stmt.close();
706
        } 
707
        catch (SQLException e) 
708
        {
709
            logMetacat.error("Error while looking up the updated guids: " 
710
                    + e.getMessage());
711
        } 
712
        finally 
713
        {
714
            // Return database connection to the pool
715
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
716
        }
717
        return ids;
718
    }
719
    
720
    /**
721
     * returns a list of system metadata-only guids since the given date
722
     * @return a list of system ids in metacat that do not correspond to objects
723
     * TODO: need to check which server they are on
724
     */
725
    public Date getLastModifiedDate() throws Exception {
726
        Date maxDate = null;
727

    
728
        List<String> ids = new Vector<String>();
729
        String sql = 
730
        	"select max(date_modified) from " + TYPE_SYSTEM_METADATA;
731
        DBConnection dbConn = null;
732
        int serialNumber = -1;
733
        try 
734
        {
735
            // Get a database connection from the pool
736
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLastModifiedDate");
737
            serialNumber = dbConn.getCheckOutSerialNumber();
738

    
739
            // Execute the insert statement
740
            PreparedStatement stmt = dbConn.prepareStatement(sql);
741
            ResultSet rs = stmt.executeQuery();
742
            if (rs.next()) {
743
            	maxDate = rs.getDate(1);
744
            } 
745
            stmt.close();
746
        } 
747
        catch (SQLException e) 
748
        {
749
            logMetacat.error("Error while looking up the latest update date: " 
750
                    + e.getMessage());
751
        } 
752
        finally 
753
        {
754
            // Return database connection to the pool
755
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
756
        }
757
        return maxDate;
758
    }
759

    
760
    
761
    /**
762
     * Determine if an identifier exists already, returning true if so.
763
     * NOTE: looks in the identifier and system metadata table for a match
764
     * (in that order)
765
     * 
766
     * @param guid the global identifier to look up
767
     * @return boolean true if the identifier exists
768
     */
769
    public boolean identifierExists(String guid)
770
    {
771
        boolean idExists = false;
772
        try {
773
            String id = getLocalId(guid);
774
            if (id != null) {
775
                idExists = true;
776
            }
777
        } catch (McdbDocNotFoundException e) {
778
        	// try system metadata only
779
        	try {
780
        		idExists = systemMetadataExists(guid);
781
            } catch (Exception e2) {
782
            	idExists = false;
783
            }
784
        }
785
        return idExists;
786
    }
787
    
788
    /**
789
     * Determine if an identifier mapping exists already, 
790
     * returning true if so.
791
     * 
792
     * @param guid the global identifier to look up
793
     * @return boolean true if the identifier exists
794
     */
795
    public boolean mappingExists(String guid)
796
    {
797
        boolean idExists = false;
798
        try {
799
            String id = getLocalId(guid);
800
            if (id != null) {
801
                idExists = true;
802
            }
803
        } catch (McdbDocNotFoundException e) {
804
        	// nope!
805
        }
806
        return idExists;
807
    }
808
    
809
    /**
810
     * 
811
     * @param guid
812
     * @param rev
813
     * @return
814
     */
815
    public String generateLocalId(String guid, int rev)
816
    {
817
        return generateLocalId(guid, rev, false);
818
    }
819

    
820
    /**
821
     * Given a global identifier (guid), create a suitable local identifier that
822
     * follows Metacat's docid semantics and format (scope.id.rev), and create
823
     * a mapping between these two identifiers.  This effectively reserves both
824
     * the global and the local identifier, as they will now be present in the
825
     * identifier mapping table.  
826
     * 
827
     * REMOVED feature: If the incoming guid has the syntax of a
828
     * Metacat docid (scope.id.rev), then simply use it.
829
     * WHY: because "test.1.001" becomes "test.1.1" which is not correct for DataONE
830
     * identifier use (those revision numbers are just chartacters and should not be interpreted)
831
     * 
832
     * @param guid the global string identifier
833
     * @param rev the revision number to be used in the localId
834
     * @return String containing the localId to be used for Metacat operations
835
     */
836
    public String generateLocalId(String guid, int rev, boolean isSystemMetadata) 
837
    {
838
        String localId = "";
839
        boolean conformsToDocidFormat = false;
840
        
841
        // BRL -- do not allow Metacat-conforming IDs to be used:
842
        // test.1.001 becomes test.1.1 which is NOT correct for DataONE identifiers
843
        // Check if the guid passed in is already in docid (scope.id.rev) format
844
//        try {
845
//            AccessionNumber acc = new AccessionNumber(guid, "NONE");
846
//            if (new Integer(acc.getRev()).intValue() > 0) {
847
//                conformsToDocidFormat = true;
848
//            }
849
//        } catch (NumberFormatException e) {
850
//            // No action needed, simply detecting invalid AccessionNumbers
851
//        } catch (AccessionNumberException e) {
852
//            // No action needed, simply detecting invalid AccessionNumbers
853
//        } catch (SQLException e) {
854
//            // No action needed, simply detecting invalid AccessionNumbers
855
//        }
856
        
857
        if (conformsToDocidFormat) {
858
            // if it conforms, use it for both guid and localId
859
            localId = guid;
860
        } else {
861
            // if not, then generate a new unique localId
862
            localId = DocumentUtil.generateDocumentId(rev);
863
        }
864
        
865
        // Register this new pair in the identifier mapping table
866
        logMetacat.debug("creating mapping in generateLocalId");
867
        if(!isSystemMetadata)
868
        { //don't do this if we're generating for system metadata
869
            createMapping(guid, localId);
870
        }
871
        
872
        return localId;
873
    }
874
    
875
    /**
876
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
877
     * if the docid, rev is not found in the identifiers or systemmetadata tables
878
     *
879
     * @param docid the docid to look up
880
     * @param rev the revision of the docid to look up
881
     * @return String containing the mapped guid
882
     * @throws McdbDocNotFoundException if the docid, rev is not found
883
     */
884
    public String getGUID(String docid, int rev)
885
      throws McdbDocNotFoundException
886
    {
887
        logMetacat.debug("getting guid for " + docid);
888
        String query = "select guid from identifier where docid = ? and rev = ?";
889
        String guid = null;
890
        
891
        DBConnection dbConn = null;
892
        int serialNumber = -1;
893
        try {
894
            // Get a database connection from the pool
895
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
896
            serialNumber = dbConn.getCheckOutSerialNumber();
897
            
898
            // Execute the insert statement
899
            PreparedStatement stmt = dbConn.prepareStatement(query);
900
            stmt.setString(1, docid);
901
            stmt.setInt(2, rev);
902
            ResultSet rs = stmt.executeQuery();
903
            if (rs.next()) 
904
            {
905
                guid = rs.getString(1);
906
            } 
907
            else
908
            {
909
            	throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
910
            }
911
            
912
        } catch (SQLException e) {
913
            logMetacat.error("Error while looking up the guid: " 
914
                    + e.getMessage());
915
        } finally {
916
            // Return database connection to the pool
917
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
918
        }
919
        
920
        return guid;
921
    }
922
    
923
    public boolean systemMetadataExists(String guid) {
924
		logMetacat.debug("looking up system metadata for guid " + guid);
925
		boolean exists = false;
926
		String query = "select guid from systemmetadata where guid = ?";
927

    
928
		DBConnection dbConn = null;
929
		int serialNumber = -1;
930
		try {
931
			// Get a database connection from the pool
932
			dbConn = DBConnectionPool.getDBConnection("IdentifierManager.systemMetadataExisits");
933
			serialNumber = dbConn.getCheckOutSerialNumber();
934

    
935
			// Execute the insert statement
936
			PreparedStatement stmt = dbConn.prepareStatement(query);
937
			stmt.setString(1, guid);
938
			ResultSet rs = stmt.executeQuery();
939
			if (rs.next()) {
940
				exists = true;
941
			}
942

    
943
		} catch (SQLException e) {
944
			logMetacat.error("Error while looking up the system metadata: "
945
					+ e.getMessage());
946
		} finally {
947
			// Return database connection to the pool
948
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
949
		}
950

    
951
		return exists;
952
	}
953
    
954
    /**
955
     * creates a system metadata mapping and adds additional fields from sysmeta
956
     * to the table for quick searching.
957
     * 
958
     * @param guid the id to insert
959
     * @param localId the systemMetadata object to get the local id for
960
     * @throws McdbDocNotFoundException 
961
     * @throws SQLException 
962
     * @throws InvalidSystemMetadata 
963
     */
964
    public void insertOrUpdateSystemMetadata(SystemMetadata sysmeta) 
965
        throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata {
966
    	String guid = sysmeta.getIdentifier().getValue();
967
    	
968
    	 // Get a database connection from the pool
969
        DBConnection dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
970
        int serialNumber = dbConn.getCheckOutSerialNumber();
971
        
972
        try {
973
        	// use a single transaction for it all
974
        	dbConn.setAutoCommit(false);
975
        	
976
	    	// insert the record if needed
977
        	if (!IdentifierManager.getInstance().systemMetadataExists(guid)) {
978
    	        insertSystemMetadata(guid, dbConn);
979
			}
980
	        // update with the values
981
	        updateSystemMetadata(sysmeta, dbConn);
982
	        
983
	        // commit if we got here with no errors
984
	        dbConn.commit();
985
        } catch (Exception e) {
986
            e.printStackTrace();
987
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
988
            dbConn.rollback();
989
        } finally {
990
            // Return database connection to the pool
991
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
992
        }
993
        
994
        
995
    }
996
        
997
    
998
    /**
999
     * update a mapping
1000
     * @param guid
1001
     * @param localId
1002
     */
1003
    public void updateMapping(String guid, String localId)
1004
    {
1005
    	
1006
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
1007
        int serialNumber = -1;
1008
        DBConnection dbConn = null;
1009
        try {
1010
            // Parse the localId into scope and rev parts
1011
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1012
            String docid = acc.getDocid();
1013
            int rev = 1;
1014
            if(acc.getRev() != null)
1015
            {
1016
              rev = (new Integer(acc.getRev()).intValue());
1017
            }
1018

    
1019
            // Get a database connection from the pool
1020
            dbConn = 
1021
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
1022
            serialNumber = dbConn.getCheckOutSerialNumber();
1023

    
1024
            // Execute the update statement
1025
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid = ?";
1026
            PreparedStatement stmt = dbConn.prepareStatement(query);
1027
            stmt.setString(1, docid);
1028
            stmt.setInt(2, rev);
1029
            stmt.setString(3, guid);
1030
            int rows = stmt.executeUpdate();
1031

    
1032
            stmt.close();
1033
        } catch (SQLException e) {
1034
            e.printStackTrace();
1035
            logMetacat.error("SQL error while updating a mapping identifier: " 
1036
                    + e.getMessage());
1037
        } catch (NumberFormatException e) {
1038
            e.printStackTrace();
1039
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
1040
                    + e.getMessage());
1041
        } catch (AccessionNumberException e) {
1042
            e.printStackTrace();
1043
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
1044
                    + e.getMessage());
1045
        } finally {
1046
            // Return database connection to the pool
1047
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1048
        }
1049
        logMetacat.debug("done updating mapping");
1050
    }
1051
        
1052
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
1053
        String checksum, String checksumAlgorithm, String originMemberNode, 
1054
        String authoritativeMemberNode, long modifiedDate, String submitter, 
1055
        String guid, String objectFormat, BigInteger size, boolean archived,
1056
        boolean replicationAllowed, int numberReplicas, String obsoletes,
1057
        String obsoletedBy, BigInteger serialVersion, String seriesId, DBConnection dbConn) throws SQLException  {
1058
  
1059
        // Execute the insert statement
1060
        String query = "update " + TYPE_SYSTEM_METADATA + 
1061
            " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1062
            "origin_member_node, authoritive_member_node, date_modified, " +
1063
            "submitter, object_format, size, archived, replication_allowed, number_replicas, " +
1064
            "obsoletes, obsoleted_by, serial_version, series_id) " +
1065
            "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1066
        PreparedStatement stmt = dbConn.prepareStatement(query);
1067
        
1068
        //data values
1069
        stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
1070
        stmt.setString(2, rightsHolder);
1071
        stmt.setString(3, checksum);
1072
        stmt.setString(4, checksumAlgorithm);
1073
        stmt.setString(5, originMemberNode);
1074
        stmt.setString(6, authoritativeMemberNode);
1075
        stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
1076
        stmt.setString(8, submitter);
1077
        stmt.setString(9, objectFormat);
1078
        stmt.setString(10, size.toString());
1079
        stmt.setBoolean(11, archived);
1080
        stmt.setBoolean(12, replicationAllowed);
1081
        stmt.setInt(13, numberReplicas);
1082
        stmt.setString(14, obsoletes);
1083
        stmt.setString(15, obsoletedBy);
1084
        stmt.setString(16, serialVersion.toString());
1085
        stmt.setString(17, seriesId);
1086

    
1087

    
1088
        //where clause
1089
        stmt.setString(18, guid);
1090
        logMetacat.debug("stmt: " + stmt.toString());
1091
        //execute
1092
        int rows = stmt.executeUpdate();
1093

    
1094
        stmt.close();
1095
               
1096
    }
1097
    
1098
    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes, DBConnection dbConn) throws SQLException
1099
    {
1100
           
1101
        // remove existing values first
1102
        String delete = "delete from smReplicationPolicy " + 
1103
        "where guid = ? and policy = ?";
1104
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1105
        //data values
1106
        stmt.setString(1, guid);
1107
        stmt.setString(2, policy);
1108
        //execute
1109
        int deletedCount = stmt.executeUpdate();
1110
        stmt.close();
1111
        
1112
        for (String memberNode: memberNodes) {
1113
            // Execute the insert statement
1114
            String insert = "insert into smReplicationPolicy " + 
1115
                "(guid, policy, member_node) " +
1116
                "values (?, ?, ?)";
1117
            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1118
            
1119
            //data values
1120
            insertStatement.setString(1, guid);
1121
            insertStatement.setString(2, policy);
1122
            insertStatement.setString(3, memberNode);
1123
            
1124
            logMetacat.debug("smReplicationPolicy sql: " + insertStatement.toString());
1125

    
1126
            //execute
1127
            int rows = insertStatement.executeUpdate();
1128
            insertStatement.close();
1129
        }
1130
        
1131
    }
1132
    
1133
    private void insertReplicationStatus(String guid, List<Replica> replicas, DBConnection dbConn) throws SQLException {
1134
       
1135
        // remove existing values first
1136
        String delete = "delete from smReplicationStatus " + 
1137
        "where guid = ?";
1138
        PreparedStatement stmt = dbConn.prepareStatement(delete);
1139
        //data values
1140
        stmt.setString(1, guid);
1141
        //execute
1142
        int deletedCount = stmt.executeUpdate();
1143
        stmt.close();
1144
        
1145
        if (replicas != null) {
1146
            for (Replica replica: replicas) {
1147
	            // Execute the insert statement
1148
	            String insert = "insert into smReplicationStatus " + 
1149
	                "(guid, member_node, status, date_verified) " +
1150
	                "values (?, ?, ?, ?)";
1151
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
1152
	            
1153
	            //data values
1154
	            String memberNode = replica.getReplicaMemberNode().getValue();
1155
	            String status = replica.getReplicationStatus().toString();
1156
	            java.sql.Timestamp sqlDate = new java.sql.Timestamp(replica.getReplicaVerified().getTime());
1157
	            insertStatement.setString(1, guid);
1158
	            insertStatement.setString(2, memberNode);
1159
	            insertStatement.setString(3, status);
1160
	            insertStatement.setTimestamp(4, sqlDate);
1161

    
1162
	            logMetacat.debug("smReplicationStatus sql: " + insertStatement.toString());
1163
	            
1164
	            //execute
1165
	            int rows = insertStatement.executeUpdate();
1166
	            insertStatement.close();
1167
            }
1168
        }
1169
       
1170
    }
1171
    
1172
    /**
1173
     * Insert the system metadata fields into the db
1174
     * @param sm
1175
     * @throws McdbDocNotFoundException 
1176
     * @throws SQLException 
1177
     * @throws InvalidSystemMetadata 
1178
     * @throws AccessException 
1179
     */
1180
    public void updateSystemMetadata(SystemMetadata sm, DBConnection dbConn) 
1181
      throws McdbDocNotFoundException, SQLException, InvalidSystemMetadata, AccessException {
1182
    	
1183
      Boolean replicationAllowed = false;
1184
		  Integer numberReplicas = -1;
1185
    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
1186
    	if (replicationPolicy != null) {
1187
    		replicationAllowed = replicationPolicy.getReplicationAllowed();
1188
    		numberReplicas = replicationPolicy.getNumberReplicas();
1189
    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
1190
    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
1191
    	}
1192
    	
1193
    	// the main systemMetadata fields
1194
		  updateSystemMetadataFields(
1195
				sm.getDateUploaded() == null ? null: sm.getDateUploaded().getTime(),
1196
				sm.getRightsHolder() == null ? null: sm.getRightsHolder().getValue(), 
1197
				sm.getChecksum() == null ? null: sm.getChecksum().getValue(), 
1198
				sm.getChecksum() == null ? null: sm.getChecksum().getAlgorithm(), 
1199
				sm.getOriginMemberNode() == null ? null: sm.getOriginMemberNode().getValue(),
1200
				sm.getAuthoritativeMemberNode() == null ? null: sm.getAuthoritativeMemberNode().getValue(), 
1201
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1202
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1203
		    sm.getIdentifier().getValue(),
1204
		    sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1205
		    sm.getSize(),
1206
		    sm.getArchived() == null ? false: sm.getArchived(),
1207
		    replicationAllowed, 
1208
		    numberReplicas,
1209
		    sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1210
		    sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1211
		    sm.getSerialVersion(),
1212
		    sm.getSeriesId() == null ? null: sm.getSeriesId().getValue(),
1213
		    dbConn
1214
        );
1215
        
1216
        String guid = sm.getIdentifier().getValue();
1217
        
1218
        // save replication policies
1219
        if (replicationPolicy != null) {
1220
		    List<String> nodes = null;
1221
		    String policy = null;
1222
		    
1223
		    // check for null 
1224
		    if (replicationPolicy.getBlockedMemberNodeList() != null) {
1225
			    nodes = new ArrayList<String>();
1226
			    policy = "blocked";
1227
			    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
1228
			    	nodes.add(node.getValue());
1229
			    }
1230
			    this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1231
		    }
1232
		    
1233
		    if (replicationPolicy.getPreferredMemberNodeList() != null) {
1234
			    nodes = new ArrayList<String>();
1235
			    policy = "preferred";
1236
			    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
1237
			    	nodes.add(node.getValue());
1238
			    }
1239
		        this.insertReplicationPolicy(guid, policy, nodes, dbConn);
1240
		    }
1241
        }
1242
        
1243
        // save replica information
1244
        this.insertReplicationStatus(guid, sm.getReplicaList(), dbConn);
1245
        
1246
        // save access policy
1247
        AccessPolicy accessPolicy = sm.getAccessPolicy();
1248
        if (accessPolicy != null) {
1249
			this.insertAccessPolicy(guid, accessPolicy);
1250
        }
1251
    }
1252
    
1253
    /**
1254
     * Creates Metacat access rules and inserts them
1255
     * @param accessPolicy
1256
     * @throws McdbDocNotFoundException
1257
     * @throws AccessException
1258
     */
1259
    private void insertAccessPolicy(String guid, AccessPolicy accessPolicy) throws McdbDocNotFoundException, AccessException {
1260
    	
1261
    	// check for the existing permOrder so that we remain compatible with it (DataONE does not care)
1262
        XMLAccessAccess accessController  = new XMLAccessAccess();
1263
		String existingPermOrder = AccessControlInterface.ALLOWFIRST;
1264
        Vector<XMLAccessDAO> existingAccess = accessController.getXMLAccessForDoc(guid);
1265
        if (existingAccess != null && existingAccess.size() > 0) {
1266
        	existingPermOrder = existingAccess.get(0).getPermOrder();
1267
        }
1268
        
1269
    	List<XMLAccessDAO> accessDAOs = new ArrayList<XMLAccessDAO>();
1270
        for (AccessRule accessRule: accessPolicy.getAllowList()) {
1271
        	List<Subject> subjects = accessRule.getSubjectList();
1272
        	List<Permission> permissions = accessRule.getPermissionList();
1273
        	for (Subject subject: subjects) {
1274
    			XMLAccessDAO accessDAO = new XMLAccessDAO();
1275
        		accessDAO.setPrincipalName(subject.getValue());
1276
    			accessDAO.setGuid(guid);
1277
    			accessDAO.setPermType(AccessControlInterface.ALLOW);
1278
				accessDAO.setPermOrder(existingPermOrder);
1279
    			if (permissions != null) {
1280
	    			for (Permission permission: permissions) {
1281
	    				Long metacatPermission = new Long(convertPermission(permission));
1282
	        			accessDAO.addPermission(metacatPermission);
1283
	    			}
1284
    			}
1285
    			accessDAOs.add(accessDAO);
1286
        	}
1287
        }
1288
        
1289
        
1290
        // remove all existing allow records
1291
        accessController.deleteXMLAccessForDoc(guid, AccessControlInterface.ALLOW);
1292
        // add the ones we can for this guid
1293
        accessController.insertAccess(guid, accessDAOs);
1294
        
1295
        
1296
    }
1297
    
1298
    /**
1299
     * Lookup access policy from Metacat
1300
     * @param guid
1301
     * @return
1302
     * @throws McdbDocNotFoundException
1303
     * @throws AccessException
1304
     */
1305
    public AccessPolicy getAccessPolicy(String guid) throws McdbDocNotFoundException, AccessException {
1306
        AccessPolicy accessPolicy = new AccessPolicy();
1307

    
1308
    	// use GUID to look up the access
1309
        XMLAccessAccess accessController  = new XMLAccessAccess();
1310
        List<XMLAccessDAO> accessDAOs = accessController.getXMLAccessForDoc(guid);
1311
        
1312
        for (XMLAccessDAO accessDAO: accessDAOs) {
1313
        	// only add allow rule
1314
        	if (accessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
1315
	        	AccessRule accessRule = new AccessRule();    	
1316
	        	List <Permission> permissions = convertPermission(accessDAO.getPermission().intValue());
1317
	        	// cannot include if we have no permissions
1318
	        	if (permissions == null || permissions.isEmpty()) {
1319
	        		logMetacat.warn("skipping empty access rule permissions for " + guid);
1320
	        		continue;
1321
	        	}
1322
	        	accessRule.setPermissionList(permissions);
1323
	        	Subject subject = new Subject();
1324
	        	subject.setValue(accessDAO.getPrincipalName());
1325
	        	accessRule.addSubject(subject);
1326
	            accessPolicy.addAllow(accessRule);
1327
        	}
1328
        }
1329
        return accessPolicy;
1330
    }
1331
    
1332
    public int convertPermission(Permission permission) {
1333
    	if (permission.equals(Permission.READ)) {
1334
    		return AccessControlInterface.READ;
1335
    	}
1336
    	if (permission.equals(Permission.WRITE)) {
1337
    		return AccessControlInterface.WRITE;
1338
    	}
1339
    	if (permission.equals(Permission.CHANGE_PERMISSION)) {
1340
    		return AccessControlInterface.CHMOD;
1341
    	}
1342
		return -1;
1343
    }
1344
    
1345
    public List<Permission> convertPermission(int permission) {
1346
    	
1347
    	List<Permission> permissions = new ArrayList<Permission>();
1348
    	if (permission == AccessControlInterface.ALL) {
1349
    		permissions.add(Permission.READ);
1350
    		permissions.add(Permission.WRITE);
1351
    		permissions.add(Permission.CHANGE_PERMISSION);
1352
    		return permissions;
1353
    	}
1354
    	
1355
    	if ((permission & AccessControlInterface.CHMOD) == AccessControlInterface.CHMOD) {
1356
    		permissions.add(Permission.CHANGE_PERMISSION);
1357
    	}
1358
    	if ((permission & AccessControlInterface.READ) == AccessControlInterface.READ) {
1359
    		permissions.add(Permission.READ);
1360
    	}
1361
    	if ((permission & AccessControlInterface.WRITE) == AccessControlInterface.WRITE) {
1362
    		permissions.add(Permission.WRITE);
1363
    	}
1364
    	
1365
		return permissions;
1366
    }
1367
    
1368
    /**
1369
     * Lookup a localId given the GUID. If
1370
     * the identifier is not found, throw an exception.
1371
     * 
1372
     * @param guid the global identifier to look up
1373
     * @return String containing the corresponding LocalId
1374
     * @throws McdbDocNotFoundException if the identifier is not found
1375
     */
1376
    public String getLocalId(String guid) throws McdbDocNotFoundException {
1377
      
1378
      String db_guid = "";
1379
      String docid = "";
1380
      int rev = 0;
1381
      
1382
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
1383
      
1384
      DBConnection dbConn = null;
1385
      int serialNumber = -1;
1386
      try {
1387
          // Get a database connection from the pool
1388
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
1389
          serialNumber = dbConn.getCheckOutSerialNumber();
1390
          
1391
          // Execute the insert statement
1392
          PreparedStatement stmt = dbConn.prepareStatement(query);
1393
          stmt.setString(1, guid);
1394
          ResultSet rs = stmt.executeQuery();
1395
          if (rs.next()) {
1396
              db_guid = rs.getString(1);
1397
              docid = rs.getString(2);
1398
              rev = rs.getInt(3);
1399
              assert(db_guid.equals(guid));
1400
          } else {
1401
              throw new McdbDocNotFoundException("Document not found:" + guid);
1402
          }
1403
          stmt.close();
1404
      } catch (SQLException e) {
1405
          logMetacat.error("Error while looking up the local identifier: " 
1406
                  + e.getMessage());
1407
      } finally {
1408
          // Return database connection to the pool
1409
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1410
      }
1411
      return docid + "." + rev;
1412
    }
1413
    
1414
    /**
1415
     * query the systemmetadata table based on the given parameters
1416
     * @param startTime
1417
     * @param endTime
1418
     * @param objectFormat
1419
     * @param replicaStatus
1420
     * @param start
1421
     * @param count
1422
     * @return ObjectList
1423
     * @throws SQLException 
1424
     * @throws ServiceException 
1425
     * @throws PropertyNotFoundException 
1426
     */
1427
    public ObjectList querySystemMetadata(Date startTime, Date endTime,
1428
        ObjectFormatIdentifier objectFormatId, boolean replicaStatus,
1429
        int start, int count) 
1430
        throws SQLException, PropertyNotFoundException, ServiceException {
1431
        ObjectList ol = new ObjectList();
1432
        DBConnection dbConn = null;
1433
        int serialNumber = -1;
1434

    
1435
        try {
1436
            String fieldSql = "select guid, date_uploaded, rights_holder, checksum, "
1437
                    + "checksum_algorithm, origin_member_node, authoritive_member_node, "
1438
                    + "date_modified, submitter, object_format, size from systemmetadata";
1439
            
1440
            // handle special case quickly
1441
            String countSql = "select count(guid) from systemmetadata";
1442
            
1443
            // the clause
1444
            String whereClauseSql = "";
1445

    
1446
            boolean f1 = false;
1447
            boolean f2 = false;
1448
            boolean f3 = false;
1449

    
1450
            if (startTime != null) {
1451
                whereClauseSql += " where systemmetadata.date_modified >= ?";
1452
                f1 = true;
1453
            }
1454

    
1455
            if (endTime != null) {
1456
                if (!f1) {
1457
                    whereClauseSql += " where systemmetadata.date_modified < ?";
1458
                } else {
1459
                    whereClauseSql += " and systemmetadata.date_modified < ?";
1460
                }
1461
                f2 = true;
1462
            }
1463

    
1464
            if (objectFormatId != null) {
1465
                if (!f1 && !f2) {
1466
                    whereClauseSql += " where object_format = ?";
1467
                } else {
1468
                    whereClauseSql += " and object_format = ?";
1469
                }
1470
                f3 = true;
1471
            }
1472

    
1473
            if (!replicaStatus) {
1474
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.nodeId");
1475
                if (!f1 && !f2 && !f3) {
1476
                    whereClauseSql += " where authoritive_member_node = '" +
1477
                        currentNodeId.trim() + "'";
1478
                } else {
1479
                    whereClauseSql += " and authoritive_member_node = '" +
1480
                        currentNodeId.trim() + "'";
1481
                }
1482
            }
1483
            
1484
            // connection
1485
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1486
            serialNumber = dbConn.getCheckOutSerialNumber();
1487

    
1488
            // the field query
1489
            String orderBySql = " order by guid ";
1490
            String fieldQuery = fieldSql + whereClauseSql + orderBySql;
1491
            String finalQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldQuery, start, count);
1492
            PreparedStatement fieldStmt = dbConn.prepareStatement(finalQuery);
1493
            
1494
            // construct the count query and statment
1495
            String countQuery = countSql + whereClauseSql;
1496
            PreparedStatement countStmt = dbConn.prepareStatement(countQuery);
1497

    
1498
            if (f1 && f2 && f3) {
1499
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1500
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1501
                fieldStmt.setString(3, objectFormatId.getValue());
1502
                // count
1503
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1504
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1505
                countStmt.setString(3, objectFormatId.getValue());
1506
            } else if (f1 && f2 && !f3) {
1507
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1508
                fieldStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1509
                // count
1510
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1511
                countStmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1512
            } else if (f1 && !f2 && f3) {
1513
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1514
                fieldStmt.setString(2, objectFormatId.getValue());
1515
                // count
1516
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1517
                countStmt.setString(2, objectFormatId.getValue());
1518
            } else if (f1 && !f2 && !f3) {
1519
                fieldStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1520
                // count
1521
                countStmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1522
            } else if (!f1 && f2 && f3) {
1523
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1524
                fieldStmt.setString(2, objectFormatId.getValue());
1525
                // count
1526
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1527
                countStmt.setString(2, objectFormatId.getValue());
1528
            } else if (!f1 && !f2 && f3) {
1529
                fieldStmt.setString(1, objectFormatId.getValue());
1530
                // count
1531
                countStmt.setString(1, objectFormatId.getValue());
1532
            } else if (!f1 && f2 && !f3) {
1533
                fieldStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1534
                // count
1535
                countStmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1536
            }
1537

    
1538
            logMetacat.debug("list objects fieldStmt: " + fieldStmt.toString());
1539
            
1540
            logMetacat.debug("list objects countStmt: " + countStmt.toString());
1541
            
1542
            // get the total object count no matter what
1543
            int total = 0;
1544
            ResultSet totalResult = countStmt.executeQuery();
1545
            if (totalResult.next()) {
1546
            	total = totalResult.getInt(1);
1547
            }
1548
            
1549
            logMetacat.debug("list objects total: " + total);
1550

    
1551
        	// set the totals
1552
        	ol.setStart(start);
1553
            ol.setCount(count);
1554
            ol.setTotal(total);
1555
            
1556
            // retrieve the actual records if requested
1557
            if (count != 0) {
1558
            	
1559
                ResultSet rs = fieldStmt.executeQuery();
1560
	            while (rs.next()) {                
1561
	                
1562
	                String guid = rs.getString(1);
1563
	                logMetacat.debug("query found object with guid " + guid);
1564
	                // Timestamp dateUploaded = rs.getTimestamp(2);
1565
	                // String rightsHolder = rs.getString(3);
1566
	                String checksum = rs.getString(4);
1567
	                String checksumAlgorithm = rs.getString(5);
1568
	                // String originMemberNode = rs.getString(6);
1569
	                // String authoritiveMemberNode = rs.getString(7);
1570
	                Timestamp dateModified = rs.getTimestamp(8);
1571
	                // String submitter = rs.getString(9);
1572
	                String fmtidStr = rs.getString(10);
1573
	                String sz = rs.getString(11);
1574
	                BigInteger size = new BigInteger("0");
1575
	
1576
	                if (sz != null && !sz.trim().equals("")) {
1577
	                    size = new BigInteger(rs.getString(11));
1578
	                }
1579
	
1580
	                ObjectInfo oi = new ObjectInfo();
1581
	
1582
	                Identifier id = new Identifier();
1583
	                id.setValue(guid);
1584
	                oi.setIdentifier(id);
1585
	
1586
	                if (dateModified != null) {
1587
	                    oi.setDateSysMetadataModified(dateModified);
1588
	                }
1589
	
1590
	                Checksum cs = new Checksum();
1591
	                cs.setValue(checksum);
1592
	                try {
1593
	                    // cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1594
	                    cs.setAlgorithm(checksumAlgorithm);
1595
	                } catch (Exception e) {
1596
	                    logMetacat.error("could not parse checksum algorithm", e);
1597
	                    continue;
1598
	                }
1599
	                oi.setChecksum(cs);
1600
	
1601
	                // set the format type
1602
	                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1603
	                fmtid.setValue(fmtidStr);
1604
	                oi.setFormatId(fmtid);
1605
	
1606
	                oi.setSize(size);
1607
	
1608
	                ol.addObjectInfo(oi);                    
1609

    
1610
	            }
1611
	            
1612
	            logMetacat.debug("list objects count: " + ol.sizeObjectInfoList());
1613

    
1614
	            // set the actual count retrieved
1615
	            ol.setCount(ol.sizeObjectInfoList());
1616
	
1617
	        }
1618
            
1619
        }
1620

    
1621
        finally {
1622
            // Return database connection to the pool
1623
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1624
        }
1625

    
1626
        return ol;
1627
    }
1628
    
1629
    /**
1630
     * create a mapping in the identifier table
1631
     * @param guid
1632
     * @param localId
1633
     */
1634
    public void createMapping(String guid, String localId)
1635
    {        
1636
        
1637
        int serialNumber = -1;
1638
        DBConnection dbConn = null;
1639
        try {
1640

    
1641
            // Parse the localId into scope and rev parts
1642
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1643
            String docid = acc.getDocid();
1644
            int rev = 1;
1645
            if (acc.getRev() != null) {
1646
              rev = (new Integer(acc.getRev()).intValue());
1647
            }
1648

    
1649
            // Get a database connection from the pool
1650
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1651
            serialNumber = dbConn.getCheckOutSerialNumber();
1652

    
1653
            // Execute the insert statement
1654
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1655
            PreparedStatement stmt = dbConn.prepareStatement(query);
1656
            stmt.setString(1, guid);
1657
            stmt.setString(2, docid);
1658
            stmt.setInt(3, rev);
1659
            logMetacat.debug("mapping query: " + stmt.toString());
1660
            int rows = stmt.executeUpdate();
1661

    
1662
            stmt.close();
1663
        } catch (SQLException e) {
1664
            e.printStackTrace();
1665
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1666
                    + e.getMessage());
1667
        } catch (NumberFormatException e) {
1668
            e.printStackTrace();
1669
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1670
                    + e.getMessage());
1671
        } catch (AccessionNumberException e) {
1672
            e.printStackTrace();
1673
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1674
                    + e.getMessage());
1675
        } finally {
1676
            // Return database connection to the pool
1677
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1678
        }
1679
    }
1680
    
1681
    /**
1682
     * remove a mapping in the identifier table
1683
     * @param guid
1684
     * @param localId
1685
     */
1686
    public void removeMapping(String guid, String localId)
1687
    {        
1688
        
1689
        int serialNumber = -1;
1690
        DBConnection dbConn = null;
1691
        try {
1692

    
1693
            // Parse the localId into scope and rev parts
1694
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1695
            String docid = acc.getDocid();
1696
            int rev = 1;
1697
            if (acc.getRev() != null) {
1698
              rev = (new Integer(acc.getRev()).intValue());
1699
            }
1700

    
1701
            // Get a database connection from the pool
1702
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.removeMapping");
1703
            serialNumber = dbConn.getCheckOutSerialNumber();
1704

    
1705
            // Execute the insert statement
1706
            String query = "DELETE FROM " + TYPE_IDENTIFIER + " WHERE guid = ? AND docid = ? AND rev = ?";
1707
            PreparedStatement stmt = dbConn.prepareStatement(query);
1708
            stmt.setString(1, guid);
1709
            stmt.setString(2, docid);
1710
            stmt.setInt(3, rev);
1711
            logMetacat.debug("remove mapping query: " + stmt.toString());
1712
            int rows = stmt.executeUpdate();
1713

    
1714
            stmt.close();
1715
        } catch (SQLException e) {
1716
            e.printStackTrace();
1717
            logMetacat.error("removeMapping: SQL error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1718
                    + e.getMessage());
1719
        } catch (NumberFormatException e) {
1720
            e.printStackTrace();
1721
            logMetacat.error("removeMapping: NumberFormat error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1722
                    + e.getMessage());
1723
        } catch (AccessionNumberException e) {
1724
            e.printStackTrace();
1725
            logMetacat.error("removeMapping: AccessionNumber error while removing a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1726
                    + e.getMessage());
1727
        } finally {
1728
            // Return database connection to the pool
1729
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1730
        }
1731
    }
1732
    
1733
    /**
1734
     * create the systemmetadata record
1735
     * @param guid
1736
     * @param dbConn 
1737
     * @throws SQLException 
1738
     */
1739
    private void insertSystemMetadata(String guid, DBConnection dbConn) throws SQLException
1740
    {        
1741

    
1742
        // Execute the insert statement
1743
        String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1744
        PreparedStatement stmt = dbConn.prepareStatement(query);
1745
        stmt.setString(1, guid);
1746
        logMetacat.debug("system metadata query: " + stmt.toString());
1747
        int rows = stmt.executeUpdate();
1748

    
1749
        stmt.close();
1750
        
1751
    }
1752
    
1753
    public void deleteSystemMetadata(String guid)
1754
    {        
1755
        
1756
        int serialNumber = -1;
1757
        DBConnection dbConn = null;
1758
        String query = null;
1759
        PreparedStatement stmt = null;
1760
        int rows = 0;
1761
        try {
1762

    
1763
            // Get a database connection from the pool
1764
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.deleteSystemMetadata");
1765
            serialNumber = dbConn.getCheckOutSerialNumber();
1766

    
1767
            // remove main system metadata entry
1768
            query = "delete from " + TYPE_SYSTEM_METADATA + " where guid = ? ";
1769
            stmt = dbConn.prepareStatement(query);
1770
            stmt.setString(1, guid);
1771
            logMetacat.debug("delete system metadata: " + stmt.toString());
1772
            rows = stmt.executeUpdate();
1773
            stmt.close();
1774
            
1775
            // remove the smReplicationPolicy
1776
            query = "delete from smReplicationPolicy " + 
1777
            "where guid = ?";
1778
            stmt = dbConn.prepareStatement(query);
1779
            stmt.setString(1, guid);
1780
            logMetacat.debug("delete smReplicationPolicy: " + stmt.toString());
1781
            rows = stmt.executeUpdate();
1782
            stmt.close();
1783
            
1784
            // remove the smReplicationStatus
1785
            query = "delete from smReplicationStatus " + 
1786
            "where guid = ?";
1787
            stmt = dbConn.prepareStatement(query);
1788
            stmt.setString(1, guid);
1789
            logMetacat.debug("delete smReplicationStatus: " + stmt.toString());
1790
            rows = stmt.executeUpdate();
1791
            stmt.close();
1792
            
1793
            // TODO: remove the access?
1794
            // Metacat keeps "deleted" documents so we should not remove access rules.
1795
            
1796
        } catch (Exception e) {
1797
            e.printStackTrace();
1798
            logMetacat.error("Error while deleting " + TYPE_SYSTEM_METADATA + " record: " + guid, e );
1799
            try {
1800
				dbConn.rollback();
1801
			} catch (SQLException sqle) {
1802
	            logMetacat.error("Error while rolling back delete for record: " + guid, sqle );
1803
			}
1804
        } finally {
1805
            // Return database connection to the pool
1806
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1807
        }
1808
    }
1809
    
1810
    public void updateAuthoritativeMemberNodeId(String existingMemberNodeId, String newMemberNodeId)
1811
    {
1812
        DBConnection dbConn = null;
1813
        int serialNumber = -1;
1814
        
1815
        try {
1816
            // Get a database connection from the pool
1817
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.updateAuthoritativeMemberNodeId");
1818
            serialNumber = dbConn.getCheckOutSerialNumber();
1819

    
1820
            // Execute the insert statement
1821
            String query = "update " + TYPE_SYSTEM_METADATA + 
1822
                " set authoritive_member_node = ? " +
1823
                " where authoritive_member_node = ?";
1824
            PreparedStatement stmt = dbConn.prepareStatement(query);
1825
            
1826
            //data values
1827
            stmt.setString(1, newMemberNodeId);
1828
            stmt.setString(2, existingMemberNodeId);
1829

    
1830
            logMetacat.debug("stmt: " + stmt.toString());
1831
            //execute
1832
            int rows = stmt.executeUpdate();
1833

    
1834
            stmt.close();
1835
        } catch (SQLException e) {
1836
            e.printStackTrace();
1837
            logMetacat.error("updateSystemMetadataFields: SQL error while updating system metadata: " 
1838
                    + e.getMessage());
1839
        } catch (NumberFormatException e) {
1840
            e.printStackTrace();
1841
            logMetacat.error("updateSystemMetadataFields: NumberFormat error while updating system metadata: " 
1842
                    + e.getMessage());
1843
        } finally {
1844
            // Return database connection to the pool
1845
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1846
        }
1847
    }
1848
}
1849

    
(36-36/63)