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.util.*;
28

    
29
import java.sql.PreparedStatement;
30
import java.sql.ResultSet;
31
import java.sql.SQLException;
32
import java.sql.Timestamp;
33

    
34
import org.apache.log4j.Logger;
35
import org.dataone.service.types.Checksum;
36
import org.dataone.service.types.ChecksumAlgorithm;
37
import org.dataone.service.types.NodeReference;
38
import org.dataone.service.types.ObjectFormat;
39
import org.dataone.service.types.ObjectInfo;
40
import org.dataone.service.types.ObjectList;
41
import org.dataone.service.types.Subject;
42
import org.dataone.service.types.SystemMetadata;
43
import org.dataone.service.types.Identifier;
44

    
45
import edu.ucsb.nceas.metacat.database.DBConnection;
46
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
47
import edu.ucsb.nceas.metacat.properties.PropertyService;
48
import edu.ucsb.nceas.metacat.util.DocumentUtil;
49

    
50
/**
51
 * Manage the relationship between Metacat local identifiers (LocalIDs) that are
52
 * codified as the (docid, rev) pair with globally unique string identifiers
53
 * (GUIDs) that are opaque strings.  This class provides methods to manage these
54
 * identifiers, and to search for and look up LocalIDs based on their GUID and
55
 * vice versa. IdentifierManager is a singleton.
56
 * 
57
 * @author Matthew Jones
58
 */
59
public class IdentifierManager {
60
    
61
    public static final String TYPE_SYSTEM_METADATA = "systemmetadata";
62
    public static final String TYPE_IDENTIFIER = "identifier";
63
  
64
    /**
65
     * The single instance of the manager that is always returned.
66
     */
67
    private static IdentifierManager self = null;
68
    private Logger logMetacat = Logger.getLogger(IdentifierManager.class);
69

    
70
    /**
71
     * A private constructor that initializes the class when getInstance() is
72
     * called.
73
     */
74
    private IdentifierManager() {}
75

    
76
    /**
77
     * Return the single instance of the manager after initializing it if it
78
     * wasn't previously initialized.
79
     * 
80
     * @return the single IdentifierManager instance
81
     */
82
    public static IdentifierManager getInstance()
83
    {
84
        if (self == null) {
85
            self = new IdentifierManager();
86
        }
87
        return self;
88
    }
89
    
90
    public SystemMetadata asSystemMetadata(Date dateUploaded, String rightsHolder,
91
            String checksum, String checksumAlgorithm, String originMemberNode,
92
            String authoritativeMemberNode, Date dateModified, String submitter, 
93
            String guid, String objectFormat, long size) {
94
        SystemMetadata sysMeta = new SystemMetadata();
95

    
96
        Identifier sysMetaId = new Identifier();
97
        sysMetaId.setValue(guid);
98
        sysMeta.setIdentifier(sysMetaId);
99
        sysMeta.setDateUploaded(dateUploaded);
100
        Subject rightsHolderSubject = new Subject();
101
        rightsHolderSubject.setValue(rightsHolder);
102
        sysMeta.setRightsHolder(rightsHolderSubject);
103
        Checksum checksumObject = new Checksum();
104
        checksumObject.setValue(checksum);
105
        checksumObject.setAlgorithm(ChecksumAlgorithm.convert(checksumAlgorithm));
106
        sysMeta.setChecksum(checksumObject);
107
        NodeReference omn = new NodeReference();
108
        omn.setValue(originMemberNode);
109
        sysMeta.setOriginMemberNode(omn);
110
        NodeReference amn = new NodeReference();
111
        amn.setValue(authoritativeMemberNode);
112
        sysMeta.setAuthoritativeMemberNode(amn);
113
        sysMeta.setDateSysMetadataModified(dateModified);
114
        Subject submitterSubject = new Subject();
115
        submitterSubject.setValue(submitter);
116
        sysMeta.setSubmitter(submitterSubject);
117
        sysMeta.setObjectFormat(ObjectFormat.convert(objectFormat));
118
        sysMeta.setSize(size);
119
        
120
        return sysMeta;
121
    }
122
    
123
    /**
124
     * return a hash of all of the info that is in the systemmetadata table
125
     * @param localId
126
     * @return
127
     */
128
    public Hashtable<String, String> getSystemMetadataInfo(String localId)
129
    throws McdbDocNotFoundException
130
    {
131
        try
132
        {
133
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
134
            localId = acc.getDocid();
135
        }
136
        catch(Exception e)
137
        {
138
            //do nothing. just try the localId as it is
139
        }
140
        Hashtable<String, String> h = new Hashtable<String, String>();
141
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
142
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size " +
143
          "from systemmetadata where docid = ?";
144
        DBConnection dbConn = null;
145
        int serialNumber = -1;
146
        try 
147
        {
148
            // Get a database connection from the pool
149
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getDocumentInfo");
150
            serialNumber = dbConn.getCheckOutSerialNumber();
151

    
152
            // Execute the insert statement
153
            PreparedStatement stmt = dbConn.prepareStatement(sql);
154
            stmt.setString(1, localId);
155
            ResultSet rs = stmt.executeQuery();
156
            if (rs.next()) 
157
            {
158
                String guid = rs.getString(1);
159
                Timestamp dateUploaded = rs.getTimestamp(2);
160
                String rightsHolder = rs.getString(3);
161
                String checksum = rs.getString(4);
162
                String checksumAlgorithm = rs.getString(5);
163
                String originMemberNode = rs.getString(6);
164
                String authoritativeMemberNode = rs.getString(7);
165
                Timestamp dateModified = rs.getTimestamp(8);
166
                String submitter = rs.getString(9);
167
                String objectFormat = rs.getString(10);
168
                long size = new Long(rs.getString(11)).longValue();
169
                
170
                h.put("guid", guid);
171
                h.put("date_uploaded", new Long(dateUploaded.getTime()).toString());
172
                h.put("rights_holder", rightsHolder);
173
                h.put("checksum", checksum);
174
                h.put("checksum_algorithm", checksumAlgorithm);
175
                h.put("origin_member_node", originMemberNode);
176
                h.put("authoritative_member_node", authoritativeMemberNode);
177
                h.put("date_modified", new Long(dateModified.getTime()).toString());
178
                h.put("submitter", submitter);
179
                h.put("object_format", objectFormat);
180
                h.put("size", new Long(size).toString());
181
                
182
                stmt.close();
183
            } 
184
            else
185
            {
186
                stmt.close();
187
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
188
                throw new McdbDocNotFoundException("2Could not find document " + localId);
189
            }
190
            
191
        } 
192
        catch (SQLException e) 
193
        {
194
            e.printStackTrace();
195
            logMetacat.error("Error while getting system metadata info for localid " + localId + " : "  
196
                    + e.getMessage());
197
        } 
198
        finally 
199
        {
200
            // Return database connection to the pool
201
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
202
        }
203
        return h;
204
    }
205
    
206
    /**
207
     * return a hash of all of the info that is in the systemmetadata table
208
     * @param guid
209
     * @return
210
     */
211
    public SystemMetadata getSystemMetadata(String guid)
212
    	throws McdbDocNotFoundException
213
    {
214
        
215
        SystemMetadata sysMeta = new SystemMetadata();
216
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
217
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size " +
218
          "from systemmetadata where guid = ?";
219
        DBConnection dbConn = null;
220
        int serialNumber = -1;
221
        try 
222
        {
223
            // Get a database connection from the pool
224
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadata");
225
            serialNumber = dbConn.getCheckOutSerialNumber();
226

    
227
            // Execute the statement
228
            PreparedStatement stmt = dbConn.prepareStatement(sql);
229
            stmt.setString(1, guid);
230
            ResultSet rs = stmt.executeQuery();
231
            if (rs.next()) 
232
            {
233
                Timestamp dateUploaded = rs.getTimestamp(2);
234
                String rightsHolder = rs.getString(3);
235
                String checksum = rs.getString(4);
236
                String checksumAlgorithm = rs.getString(5);
237
                String originMemberNode = rs.getString(6);
238
                String authoritativeMemberNode = rs.getString(7);
239
                Timestamp dateModified = rs.getTimestamp(8);
240
                String submitter = rs.getString(9);
241
                String objectFormat = rs.getString(10);
242
                long size = new Long(rs.getString(11)).longValue();
243
                
244
                Identifier sysMetaId = new Identifier();
245
                sysMetaId.setValue(guid);
246
                sysMeta.setIdentifier(sysMetaId);
247
                sysMeta.setDateUploaded(dateUploaded);
248
                Subject rightsHolderSubject = new Subject();
249
                rightsHolderSubject.setValue(rightsHolder);
250
                sysMeta.setRightsHolder(rightsHolderSubject);
251
                Checksum checksumObject = new Checksum();
252
                checksumObject.setValue(checksum);
253
                checksumObject.setAlgorithm(ChecksumAlgorithm.convert(checksumAlgorithm));
254
                sysMeta.setChecksum(checksumObject);
255
                NodeReference omn = new NodeReference();
256
                omn.setValue(originMemberNode);
257
                sysMeta.setOriginMemberNode(omn);
258
                NodeReference amn = new NodeReference();
259
                amn.setValue(authoritativeMemberNode);
260
                sysMeta.setAuthoritativeMemberNode(amn);
261
                sysMeta.setDateSysMetadataModified(dateModified);
262
                Subject submitterSubject = new Subject();
263
                submitterSubject.setValue(submitter);
264
                sysMeta.setSubmitter(submitterSubject);
265
                sysMeta.setObjectFormat(ObjectFormat.convert(objectFormat));
266
                sysMeta.setSize(size);
267
                
268
                stmt.close();
269
            } 
270
            else
271
            {
272
                stmt.close();
273
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
274
                throw new McdbDocNotFoundException("Could not find " + guid);
275
            }
276
            
277
        } 
278
        catch (SQLException e) 
279
        {
280
            e.printStackTrace();
281
            logMetacat.error("Error while getting system metadata for guid " + guid + " : "  
282
                    + e.getMessage());
283
        } 
284
        finally 
285
        {
286
            // Return database connection to the pool
287
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
288
        }
289
        
290
        // look up provenance information
291
        sysMeta.setObsoleteList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "obsoletes"));
292
        sysMeta.setObsoletedByList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "obsoletedBy"));
293
        sysMeta.setDescribeList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "describes"));
294
        sysMeta.setDescribedByList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "describedBy"));
295
        sysMeta.setDerivedFromList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "derivedFrom"));
296
        
297
        return sysMeta;
298
    }
299
    
300
    private List<Identifier> getSystemMetadataProvenance(String guid, String relationship)
301
    	throws McdbDocNotFoundException {
302
    	
303
    	List<Identifier> identifiers = new ArrayList<Identifier>();
304
    	String sql = "select guid, relationship, target_guid " +
305
    		"from systemMetadataProvenance where guid = ? and relationship = ?";
306
    DBConnection dbConn = null;
307
    int serialNumber = -1;
308
    try 
309
    {
310
        // Get a database connection from the pool
311
        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadataProvenance");
312
        serialNumber = dbConn.getCheckOutSerialNumber();
313

    
314
        // Execute the statement
315
        PreparedStatement stmt = dbConn.prepareStatement(sql);
316
        stmt.setString(1, guid);
317
        stmt.setString(2, relationship);
318
        ResultSet rs = stmt.executeQuery();
319
        while (rs.next()) 
320
        {
321
            String targetGuid = rs.getString(3);
322
            Identifier id = new Identifier();
323
            id.setValue(targetGuid);
324
            identifiers.add(id);
325
        
326
        } 
327
        stmt.close();
328
        
329
    } 
330
    catch (SQLException e) 
331
    {
332
        logMetacat.error("Error while getting system metadata provenance for guid " + guid, e);
333
    } 
334
    finally 
335
    {
336
        // Return database connection to the pool
337
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
338
    }
339
    
340
    return identifiers;
341
}
342
    
343
    /**
344
     * return information on the document with localId.  These are the fields
345
     * from the xml_documents table.  They can be used to contstruct metadata 
346
     * about the object that is stored.
347
     * @param localId
348
     * @return
349
     * @throws McdbDocNotFoundException
350
     */
351
    public Hashtable<String, Object> getDocumentInfo(String localId)
352
        throws McdbDocNotFoundException
353
    {
354
        try
355
        {
356
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
357
            localId = acc.getDocid();
358
        }
359
        catch(Exception e)
360
        {
361
            //do nothing. just try the localId as it is
362
        }
363
        Hashtable<String, Object> h = new Hashtable<String, Object>();
364
        String sql = "select docname, doctype, user_owner, user_updated, " +
365
            "server_location, rev, date_created, date_updated from " + 
366
            "xml_documents where docid like '" + localId + "'";
367
        DBConnection dbConn = null;
368
        int serialNumber = -1;
369
        try 
370
        {
371
            // Get a database connection from the pool
372
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getDocumentInfo");
373
            serialNumber = dbConn.getCheckOutSerialNumber();
374

    
375
            // Execute the insert statement
376
            PreparedStatement stmt = dbConn.prepareStatement(sql);
377
            ResultSet rs = stmt.executeQuery();
378
            if (rs.next()) 
379
            {
380
                String docname = rs.getString(1);
381
                String doctype = rs.getString(2);
382
                String user_owner = rs.getString(3);
383
                String user_updated = rs.getString(4);
384
                String server_location = rs.getString(5);
385
                int rev = rs.getInt(6);
386
                String date_created = rs.getString(7);
387
                String date_updated = rs.getString(8);
388
                h.put("docid", localId);
389
                h.put("docname", docname);
390
                h.put("doctype", doctype);
391
                h.put("user_owner", user_owner);
392
                h.put("user_updated", user_updated);
393
                h.put("server_location", server_location);
394
                h.put("rev", new Integer(rev).toString());
395
                h.put("date_created", date_created);
396
                h.put("date_updated", date_updated);
397
                
398
                stmt.close();
399
            } 
400
            else
401
            {
402
                stmt.close();
403
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
404
                throw new McdbDocNotFoundException("2Could not find document " + localId);
405
            }
406
            
407
            String sql2 = "select principal_name, permission, perm_type, perm_order from xml_access " +
408
            "where docid like '" + localId + "'";
409
            logMetacat.debug("executing sql: " + sql2);
410
            PreparedStatement stmt2 = dbConn.prepareStatement(sql2);
411
            rs = stmt2.executeQuery();
412
            Vector accessVector = new Vector();
413
            while(rs.next())
414
            {
415
                Hashtable accessHash = new Hashtable();
416
                String principal_name = rs.getString(1);
417
                String permission = rs.getString(2);
418
                String permissionType = rs.getString(3);
419
                String permissionOrder = rs.getString(4);
420
                accessHash.put("principal_name", principal_name);
421
                accessHash.put("permission", permission);
422
                accessHash.put("permission_type", permissionType);
423
                accessHash.put("permission_order", permissionOrder);
424
                logMetacat.debug("accessHash: " + accessHash.toString());
425
                accessVector.add(accessHash);
426
            }
427
            h.put("access", accessVector);
428
        } 
429
        catch (SQLException e) 
430
        {
431
            e.printStackTrace();
432
            logMetacat.error("Error while getting document info for localid " + localId + " : "  
433
                    + e.getMessage());
434
        } 
435
        finally 
436
        {
437
            // Return database connection to the pool
438
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
439
        }
440
        return h;
441
    }
442
    
443
    /**
444
     * return the newest rev for a given localId
445
     * @param localId
446
     * @return
447
     */
448
    public int getLatestRevForLocalId(String localId)
449
        throws McdbDocNotFoundException
450
    {
451
        try
452
        {
453
            AccessionNumber acc = new AccessionNumber(localId, "NONE");
454
            localId = acc.getDocid();
455
        }
456
        catch(Exception e)
457
        {
458
            //do nothing. just try the localId as it is
459
        }
460
        int rev = 0;
461
        String sql = "select rev from xml_documents where docid like '" + localId + "'";
462
        DBConnection dbConn = null;
463
        int serialNumber = -1;
464
        try 
465
        {
466
            // Get a database connection from the pool
467
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLatestRevForLocalId");
468
            serialNumber = dbConn.getCheckOutSerialNumber();
469

    
470
            // Execute the insert statement
471
            PreparedStatement stmt = dbConn.prepareStatement(sql);
472
            ResultSet rs = stmt.executeQuery();
473
            if (rs.next()) 
474
            {
475
                rev = rs.getInt(1);
476
                stmt.close();
477
            } 
478
            else
479
            {
480
                stmt.close();
481
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
482
                throw new McdbDocNotFoundException("While trying to get the latest rev, could not find document " + localId);
483
            }
484
        } 
485
        catch (SQLException e) 
486
        {
487
            logMetacat.error("Error while looking up the guid: " 
488
                    + e.getMessage());
489
        } 
490
        finally 
491
        {
492
            // Return database connection to the pool
493
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
494
        }
495
        return rev;
496
    }
497
    
498
    /**
499
     * return all local ids in the object store that do not have associated
500
     * system metadata
501
     */
502
    public List<String> getLocalIdsWithNoSystemMetadata()
503
    {
504
        Vector<String> ids = new Vector<String>();
505
        String sql = "select docid, rev from xml_documents " +
506
        		"where docid not in " +
507
        		"(select docid from identifier where guid in (select guid from systemmetadata)))";
508
        DBConnection dbConn = null;
509
        int serialNumber = -1;
510
        try 
511
        {
512
            // Get a database connection from the pool
513
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getLocalIdsWithNoSystemMetadata");
514
            serialNumber = dbConn.getCheckOutSerialNumber();
515

    
516
            // Execute the insert statement
517
            PreparedStatement stmt = dbConn.prepareStatement(sql);
518
            ResultSet rs = stmt.executeQuery();
519
            while (rs.next()) 
520
            {
521
                String localid = rs.getString(1);
522
                String rev = rs.getString(2);
523
                localid += "." + rev;
524
                logMetacat.debug("id to add SM for: " + localid);
525
                ids.add(localid);
526
            } 
527
            stmt.close();
528
        } 
529
        catch (SQLException e) 
530
        {
531
            logMetacat.error("Error while looking up the guid: " 
532
                    + e.getMessage());
533
        } 
534
        finally 
535
        {
536
            // Return database connection to the pool
537
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
538
        }
539
        
540
        return ids;
541
    }
542
    
543
    /**
544
     * return a listing of all local ids in the object store
545
     * @return a list of all local ids in metacat
546
     */
547
    public List<String> getAllLocalIds()
548
       throws Exception
549
    {
550
        Vector<String> ids = new Vector<String>();
551
        String sql = "select docid from xml_documents";
552
        DBConnection dbConn = null;
553
        int serialNumber = -1;
554
        try 
555
        {
556
            // Get a database connection from the pool
557
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getAllLocalIds");
558
            serialNumber = dbConn.getCheckOutSerialNumber();
559

    
560
            // Execute the insert statement
561
            PreparedStatement stmt = dbConn.prepareStatement(sql);
562
            ResultSet rs = stmt.executeQuery();
563
            while (rs.next()) 
564
            {
565
                String localid = rs.getString(1);
566
                ids.add(localid);
567
            } 
568
            stmt.close();
569
        } 
570
        catch (SQLException e) 
571
        {
572
            logMetacat.error("Error while looking up the guid: " 
573
                    + e.getMessage());
574
        } 
575
        finally 
576
        {
577
            // Return database connection to the pool
578
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
579
        }
580
        return ids;
581
    }
582
    
583

    
584
    
585
    /**
586
     * Determine if an identifier exists already, returning true if so.
587
     * 
588
     * @param guid the global identifier to look up
589
     * @return boolean true if the identifier exists
590
     */
591
    public boolean identifierExists(String guid)
592
    {
593
        boolean idExists = false;
594
        try {
595
            String id = getLocalId(guid);
596
            if (id != null) {
597
                idExists = true;
598
            }
599
        } catch (McdbDocNotFoundException e) {
600
            idExists = false;
601
        }
602
        return idExists;
603
    }
604
    
605
    /**
606
     * 
607
     * @param guid
608
     * @param rev
609
     * @return
610
     */
611
    public String generateLocalId(String guid, int rev)
612
    {
613
        return generateLocalId(guid, rev, false);
614
    }
615

    
616
    /**
617
     * Given a global identifier (guid), create a suitable local identifier that
618
     * follows Metacat's docid semantics and format (scope.id.rev), and create
619
     * a mapping between these two identifiers.  This effectively reserves both
620
     * the global and the local identifier, as they will now be present in the
621
     * identifier mapping table.  If the incoming guid has the syntax of a
622
     * Metacat docid (scope.id.rev), then simply use it.
623
     * 
624
     * @param guid the global string identifier
625
     * @param rev the revision number to be used in the localId
626
     * @return String containing the localId to be used for Metacat operations
627
     */
628
    public String generateLocalId(String guid, int rev, boolean isSystemMetadata) 
629
    {
630
        String localId = "";
631
        boolean conformsToDocidFormat = false;
632
        
633
        // Check if the guid passed in is already in docid (scope.id.rev) format
634
        try {
635
            AccessionNumber acc = new AccessionNumber(guid, "NONE");
636
            if (new Integer(acc.getRev()).intValue() > 0) {
637
                conformsToDocidFormat = true;
638
            }
639
        } catch (NumberFormatException e) {
640
            // No action needed, simply detecting invalid AccessionNumbers
641
        } catch (AccessionNumberException e) {
642
            // No action needed, simply detecting invalid AccessionNumbers
643
        } catch (SQLException e) {
644
            // No action needed, simply detecting invalid AccessionNumbers
645
        }
646
        
647
        if (conformsToDocidFormat) {
648
            // if it conforms, use it for both guid and localId
649
            localId = guid;
650
        } else {
651
            // if not, then generate a new unique localId
652
            localId = DocumentUtil.generateDocumentId(rev);
653
        }
654
        
655
        // Register this new pair in the identifier mapping table
656
        logMetacat.debug("creating mapping in generateLocalId");
657
        if(!isSystemMetadata)
658
        { //don't do this if we're generating for system metadata
659
            createMapping(guid, localId);
660
        }
661
        
662
        return localId;
663
    }
664
    
665
    /**
666
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
667
     * if the docid, rev is not found in the identifiers or systemmetadata tables
668
     *
669
     * @param docid the docid to look up
670
     * @param rev the revision of the docid to look up
671
     * @return String containing the mapped guid
672
     * @throws McdbDocNotFoundException if the docid, rev is not found
673
     */
674
    public String getGUID(String docid, int rev)
675
      throws McdbDocNotFoundException
676
    {
677
        logMetacat.debug("getting guid for " + docid);
678
        String query = "select guid from identifier where docid = ? and rev = ?";
679
        String guid = null;
680
        
681
        DBConnection dbConn = null;
682
        int serialNumber = -1;
683
        try {
684
            // Get a database connection from the pool
685
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getGUID");
686
            serialNumber = dbConn.getCheckOutSerialNumber();
687
            
688
            // Execute the insert statement
689
            PreparedStatement stmt = dbConn.prepareStatement(query);
690
            stmt.setString(1, docid);
691
            stmt.setInt(2, rev);
692
            ResultSet rs = stmt.executeQuery();
693
            if (rs.next()) 
694
            {
695
                guid = rs.getString(1);
696
            } 
697
            else
698
            {
699
                query = "select guid from systemmetadata where docid = ? and rev = ?";
700
                stmt = dbConn.prepareStatement(query);
701
                stmt.setString(1, docid);
702
                stmt.setInt(2, rev);
703
                rs = stmt.executeQuery();
704
                if(rs.next())
705
                {
706
                    guid = rs.getString(1);
707
                }
708
                else
709
                {
710
                    throw new McdbDocNotFoundException("No guid registered for docid " + docid + "." + rev);
711
                }
712
            }
713
            
714
        } catch (SQLException e) {
715
            logMetacat.error("Error while looking up the guid: " 
716
                    + e.getMessage());
717
        } finally {
718
            // Return database connection to the pool
719
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
720
        }
721
        
722
        return guid;
723
    }
724
    
725
    /**
726
     * creates a system metadata mapping and adds additional fields from sysmeta
727
     * to the table for quick searching.
728
     * 
729
     * @param guid the id to insert
730
     * @param localId the systemMetadata object to get the local id for
731
     */
732
    public void createSystemMetadata(SystemMetadata sysmeta)
733
    {
734
        insertSystemMetadata(sysmeta.getIdentifier().getValue());
735
        updateSystemMetadata(sysmeta);
736
    }
737
        
738
    
739
    /**
740
     * update a mapping
741
     * @param guid
742
     * @param localId
743
     */
744
    public void updateMapping(String guid, String localId)
745
    {
746
    	
747
        logMetacat.debug("$$$$$$$$$$$$$$ updating mapping table");
748
        int serialNumber = -1;
749
        DBConnection dbConn = null;
750
        try {
751
            // Parse the localId into scope and rev parts
752
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
753
            String docid = acc.getDocid();
754
            int rev = 1;
755
            if(acc.getRev() != null)
756
            {
757
              rev = (new Integer(acc.getRev()).intValue());
758
            }
759

    
760
            // Get a database connection from the pool
761
            dbConn = 
762
                DBConnectionPool.getDBConnection("IdentifierManager.updateMapping");
763
            serialNumber = dbConn.getCheckOutSerialNumber();
764

    
765
            // Execute the update statement
766
            String query = "update " + TYPE_IDENTIFIER + " set (docid, rev) = (?, ?) where guid='" + guid + "'";
767
            PreparedStatement stmt = dbConn.prepareStatement(query);
768
            stmt.setString(1, docid);
769
            stmt.setInt(2, rev);
770
            int rows = stmt.executeUpdate();
771

    
772
            stmt.close();
773
        } catch (SQLException e) {
774
            e.printStackTrace();
775
            logMetacat.error("SQL error while updating a mapping identifier: " 
776
                    + e.getMessage());
777
        } catch (NumberFormatException e) {
778
            e.printStackTrace();
779
            logMetacat.error("NumberFormat error while updating a mapping identifier: " 
780
                    + e.getMessage());
781
        } catch (AccessionNumberException e) {
782
            e.printStackTrace();
783
            logMetacat.error("AccessionNumber error while updating a mapping identifier: " 
784
                    + e.getMessage());
785
        } finally {
786
            // Return database connection to the pool
787
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
788
        }
789
        logMetacat.debug("done updating mapping");
790
    }
791
        
792
    private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
793
            String checksum, String checksumAlgorithm, String originMemberNode,
794
            String authoritativeMemberNode, long modifiedDate, String submitter, 
795
            String guid, String objectFormat, long size)
796
    {
797
        DBConnection dbConn = null;
798
        int serialNumber = -1;
799
        
800
        try {
801
            // Get a database connection from the pool
802
            dbConn = 
803
                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
804
            serialNumber = dbConn.getCheckOutSerialNumber();
805

    
806
            // Execute the insert statement
807
            String query = "update " + TYPE_SYSTEM_METADATA + 
808
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
809
                "origin_member_node, authoritive_member_node, date_modified, " +
810
                "submitter, object_format, size) " +
811
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
812
            PreparedStatement stmt = dbConn.prepareStatement(query);
813
            
814
            //data values
815
            stmt.setTimestamp(1, new java.sql.Timestamp(dateUploaded));
816
            stmt.setString(2, rightsHolder);
817
            stmt.setString(3, checksum);
818
            stmt.setString(4, checksumAlgorithm);
819
            stmt.setString(5, originMemberNode);
820
            stmt.setString(6, authoritativeMemberNode);
821
            stmt.setTimestamp(7, new java.sql.Timestamp(modifiedDate));
822
            stmt.setString(8, submitter);
823
            stmt.setString(9, objectFormat);
824
            stmt.setString(10, new Long(size).toString());
825
            //where clause
826
            stmt.setString(11, guid);
827
            logMetacat.debug("stmt: " + stmt.toString());
828
            //execute
829
            int rows = stmt.executeUpdate();
830

    
831
            stmt.close();
832
        } catch (SQLException e) {
833
            e.printStackTrace();
834
            logMetacat.error("insertAdditionalSystemMetadataFields: SQL error while creating a mapping to the system metadata identifier: " 
835
                    + e.getMessage());
836
        } catch (NumberFormatException e) {
837
            e.printStackTrace();
838
            logMetacat.error("insertAdditionalSystemMetadataFields: NumberFormat error while creating a mapping to the system metadata identifier: " 
839
                    + e.getMessage());
840
        } finally {
841
            // Return database connection to the pool
842
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
843
        }
844
    }
845
    
846
    private void insertSystemMetadataProvenance(String guid, String relationship, List<String> targetGuids)
847
    {
848
        DBConnection dbConn = null;
849
        int serialNumber = -1;
850
        
851
        try {
852
            // Get a database connection from the pool
853
            dbConn = 
854
                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
855
            serialNumber = dbConn.getCheckOutSerialNumber();
856

    
857
            // remove existing values first
858
            String delete = "delete from systemMetadataProvenance " + 
859
            "where guid = ? and relationship = ?";
860
	        PreparedStatement stmt = dbConn.prepareStatement(delete);
861
	        //data values
862
	        stmt.setString(1, guid);
863
	        stmt.setString(2, relationship);
864
	        //execute
865
	        int deletedCount = stmt.executeUpdate();
866
	        stmt.close();
867
            
868
            for (String targetGuid: targetGuids) {
869
	            // Execute the insert statement
870
	            String insert = "insert into systemMetadataProvenance " + 
871
	                "(guid, relationship, target_guid) " +
872
	                "values (?, ?, ?)";
873
	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
874
	            
875
	            //data values
876
	            insertStatement.setString(1, guid);
877
	            insertStatement.setString(2, relationship);
878
	            insertStatement.setString(3, targetGuid);
879
	            //execute
880
	            int rows = insertStatement.executeUpdate();
881
	            insertStatement.close();
882
            }
883
        } catch (SQLException e) {
884
            logMetacat.error("SQL error while adding systemMetadataProvenance for: " + guid, e); 
885
        } finally {
886
            // Return database connection to the pool
887
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
888
        }
889
    }
890
    
891
    /**
892
     * Insert the system metadata fields into the db
893
     * @param sm
894
     */
895
    public void updateSystemMetadata(SystemMetadata sm)
896
    {
897
        updateSystemMetadataFields(
898
                sm.getDateUploaded().getTime(),
899
                sm.getRightsHolder().getValue(), 
900
                sm.getChecksum().getValue(), 
901
                sm.getChecksum().getAlgorithm().name(), 
902
                sm.getOriginMemberNode().getValue(),
903
                sm.getAuthoritativeMemberNode().getValue(), 
904
                sm.getDateSysMetadataModified().getTime(),
905
                sm.getSubmitter().getValue(), 
906
                sm.getIdentifier().getValue(),
907
                sm.getObjectFormat().toString(),
908
                sm.getSize());
909
        
910
        // add provenance information
911
        String guid = sm.getIdentifier().getValue();
912
        List<String> targetGuids = null;
913
        String relationship = null;
914
        
915
        relationship = "obsoletedBy";
916
        targetGuids = new ArrayList<String>();
917
        for (Identifier id: sm.getObsoletedByList()) {
918
        	targetGuids.add(id.getValue());
919
        }
920
        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
921
        
922
        relationship = "obsoletes";
923
        targetGuids = new ArrayList<String>();
924
        for (Identifier id: sm.getObsoleteList()) {
925
        	targetGuids.add(id.getValue());
926
        }
927
        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
928
        
929
        relationship = "describes";
930
        targetGuids = new ArrayList<String>();
931
        for (Identifier id: sm.getDescribeList()) {
932
        	targetGuids.add(id.getValue());
933
        }
934
        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
935
        
936
        relationship = "describedBy";
937
        targetGuids = new ArrayList<String>();
938
        for (Identifier id: sm.getDescribedByList()) {
939
        	targetGuids.add(id.getValue());
940
        }
941
        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
942
        
943
        relationship = "derivedFrom";
944
        targetGuids = new ArrayList<String>();
945
        for (Identifier id: sm.getDerivedFromList()) {
946
        	targetGuids.add(id.getValue());
947
        }
948
        this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
949
        
950
    }
951
    
952
    /**
953
     * Lookup a localId given the GUID. If
954
     * the identifier is not found, throw an exception.
955
     * 
956
     * @param guid the global identifier to look up
957
     * @return String containing the corresponding LocalId
958
     * @throws McdbDocNotFoundException if the identifier is not found
959
     */
960
    public String getLocalId(String guid) throws McdbDocNotFoundException {
961
      
962
      String db_guid = "";
963
      String docid = "";
964
      int rev = 0;
965
      
966
      String query = "select guid, docid, rev from " + TYPE_IDENTIFIER + " where guid = ?";
967
      
968
      DBConnection dbConn = null;
969
      int serialNumber = -1;
970
      try {
971
          // Get a database connection from the pool
972
          dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
973
          serialNumber = dbConn.getCheckOutSerialNumber();
974
          
975
          // Execute the insert statement
976
          PreparedStatement stmt = dbConn.prepareStatement(query);
977
          stmt.setString(1, guid);
978
          ResultSet rs = stmt.executeQuery();
979
          if (rs.next()) {
980
              db_guid = rs.getString(1);
981
              docid = rs.getString(2);
982
              rev = rs.getInt(3);
983
              assert(db_guid.equals(guid));
984
          } else {
985
              throw new McdbDocNotFoundException("Document not found:" + guid);
986
          }
987
          stmt.close();
988
      } catch (SQLException e) {
989
          logMetacat.error("Error while looking up the local identifier: " 
990
                  + e.getMessage());
991
      } finally {
992
          // Return database connection to the pool
993
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
994
      }
995
      return docid + "." + rev;
996
    }
997
    
998
    /**
999
     * query the systemmetadata table based on the given parameters
1000
     * @param startTime
1001
     * @param endTime
1002
     * @param objectFormat
1003
     * @param replicaStatus
1004
     * @param start
1005
     * @param count
1006
     * @return ObjectList
1007
     */
1008
    public ObjectList querySystemMetadata(Date startTime, Date endTime, 
1009
            ObjectFormat objectFormat, boolean replicaStatus, int start, int count)
1010
    {
1011
        ObjectList ol = new ObjectList();
1012
        int total = 0;
1013
        DBConnection dbConn = null;
1014
        int serialNumber = -1;
1015
        
1016
        try
1017
        {
1018
            String sql = "select guid, date_uploaded, rights_holder, checksum, " +
1019
                "checksum_algorithm, origin_member_node, authoritive_member_node, " +
1020
                "date_modified, submitter, object_format, size from systemmetadata";
1021
            
1022
            boolean f1 = false;
1023
            boolean f2 = false;
1024
            boolean f3 = false;
1025
            
1026
            if(startTime != null)
1027
            {
1028
                sql += " where systemmetadata.date_modified > ?";
1029
                f1 = true;
1030
            }
1031
            
1032
            if(endTime != null)
1033
            {
1034
                if(!f1)
1035
                {
1036
                    sql += " where systemmetadata.date_modified < ?";
1037
                }
1038
                else
1039
                {
1040
                    sql += " and systemmetadata.date_modified < ?";
1041
                }
1042
                f2 = true;
1043
            }
1044
            
1045
            if(objectFormat != null)
1046
            {
1047
                if(!f1 && !f2)
1048
                {
1049
                    sql += " where object_format = ?";
1050
                }
1051
                else 
1052
                {
1053
                    sql += " and object_format = ?";
1054
                }
1055
                f3 = true;
1056
            }
1057
            
1058
            if(replicaStatus)
1059
            {
1060
                String currentNodeId = PropertyService.getInstance().getProperty("dataone.memberNodeId");
1061
                if(!f1 && !f2 && !f3)
1062
                {
1063
                    sql += " where authoritive_member_node != '" + currentNodeId.trim() + "'";
1064
                }
1065
                else
1066
                {
1067
                    sql += " and authoritive_member_node != '" + currentNodeId.trim() + "'";
1068
                }
1069
            }
1070
            
1071
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.querySystemMetadata");
1072
            serialNumber = dbConn.getCheckOutSerialNumber();
1073
            PreparedStatement stmt = dbConn.prepareStatement(sql);
1074
            
1075
            if(f1 && f2 && f3)
1076
            {
1077
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1078
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1079
                stmt.setString(3, objectFormat.toString());
1080
            }
1081
            else if(f1 && f2 && !f3)
1082
            {
1083
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1084
                stmt.setTimestamp(2, new Timestamp(endTime.getTime()));
1085
            }
1086
            else if(f1 && !f2 && f3)
1087
            {
1088
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1089
                stmt.setString(2, objectFormat.toString());
1090
            }
1091
            else if(f1 && !f2 && !f3)
1092
            {
1093
                stmt.setTimestamp(1, new Timestamp(startTime.getTime()));
1094
            }
1095
            else if(!f1 && f2 && f3)
1096
            {
1097
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1098
                stmt.setString(2, objectFormat.toString());
1099
            }
1100
            else if(!f1 && !f2 && f3)
1101
            {
1102
                stmt.setString(1, objectFormat.toString());
1103
            }
1104
            else if(!f1 && f2 && !f3)
1105
            {
1106
                stmt.setTimestamp(1, new Timestamp(endTime.getTime()));
1107
            }
1108
            
1109
            //logMetacat.debug("LISTOBJECTS QUERY: " + stmt.toString());
1110
            
1111
            ResultSet rs = stmt.executeQuery();
1112
            for(int i=0; i<start; i++)
1113
            {
1114
                if(rs.next())
1115
                {
1116
                    total++;
1117
                }
1118
                else
1119
                {
1120
                    break;
1121
                }
1122
            }
1123
            
1124
            int countIndex = 0;
1125
                        
1126
            while(rs.next()) 
1127
            {
1128
                total++;
1129
                if(countIndex >= count)
1130
                {
1131
                    break;
1132
                }
1133
                String guid = rs.getString(1);
1134
                //logMetacat.debug("query found doc with guid " + guid);
1135
                //Timestamp dateUploaded = rs.getTimestamp(2);
1136
                //String rightsHolder = rs.getString(3);
1137
                String checksum = rs.getString(4);
1138
                String checksumAlgorithm = rs.getString(5);
1139
                //String originMemberNode = rs.getString(6);
1140
                String authoritiveMemberNode = rs.getString(7);
1141
                Timestamp dateModified = rs.getTimestamp(8);
1142
                //String submitter = rs.getString(9);
1143
                String format = rs.getString(10);
1144
                String sz = rs.getString(11);
1145
                long size = 0;
1146
                if(sz != null && !sz.trim().equals(""))
1147
                {
1148
                    size = new Long(rs.getString(11)).longValue();
1149
                }
1150
                
1151
                ObjectInfo oi = new ObjectInfo();
1152
                
1153
                Identifier id = new Identifier();
1154
                id.setValue(guid);
1155
                oi.setIdentifier(id);
1156
                
1157
                oi.setDateSysMetadataModified(new Date(dateModified.getTime()));
1158
                
1159
                Checksum cs = new Checksum();
1160
                cs.setValue(checksum);
1161
                cs.setAlgorithm(ChecksumAlgorithm.valueOf(checksumAlgorithm));
1162
                //cs.setAlgorithm(ChecksumAlgorithm.convert(checksumAlgorithm));
1163
                oi.setChecksum(cs);
1164
                
1165
                ObjectFormat oFormat = ObjectFormat.convert(format);
1166
                if(oFormat != null)
1167
                {
1168
                    oi.setObjectFormat(oFormat);
1169
                }
1170
                else
1171
                { //if there is no object format, just default to text/plain
1172
                    oi.setObjectFormat(ObjectFormat.OCTET_STREAM);
1173
                }
1174
                                
1175
                oi.setSize(size);
1176
                
1177
                ol.addObjectInfo(oi);
1178
                countIndex++;
1179
            }
1180
            
1181
            while(rs.next())
1182
            { //expend the resultset to get the total count of possible rows
1183
                total++;
1184
            }
1185
        }
1186
        catch(Exception e)
1187
        {
1188
           e.printStackTrace();
1189
           logMetacat.error("Error querying system metadata: " + e.getMessage());
1190
        }
1191
        finally 
1192
        {
1193
            // Return database connection to the pool
1194
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1195
        }
1196
        
1197
        ol.setStart(start);
1198
        ol.setCount(ol.sizeObjectInfoList());
1199
        ol.setTotal(total);
1200
        
1201
        return ol;
1202
    }
1203
    
1204
    /**
1205
     * create a mapping in the identifier table
1206
     * @param guid
1207
     * @param localId
1208
     */
1209
    public void createMapping(String guid, String localId)
1210
    {        
1211
        
1212
        int serialNumber = -1;
1213
        DBConnection dbConn = null;
1214
        try {
1215

    
1216
            // Parse the localId into scope and rev parts
1217
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
1218
            String docid = acc.getDocid();
1219
            int rev = 1;
1220
            if (acc.getRev() != null) {
1221
              rev = (new Integer(acc.getRev()).intValue());
1222
            }
1223

    
1224
            // Get a database connection from the pool
1225
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
1226
            serialNumber = dbConn.getCheckOutSerialNumber();
1227

    
1228
            // Execute the insert statement
1229
            String query = "insert into " + TYPE_IDENTIFIER + " (guid, docid, rev) values (?, ?, ?)";
1230
            PreparedStatement stmt = dbConn.prepareStatement(query);
1231
            stmt.setString(1, guid);
1232
            stmt.setString(2, docid);
1233
            stmt.setInt(3, rev);
1234
            logMetacat.debug("mapping query: " + stmt.toString());
1235
            int rows = stmt.executeUpdate();
1236

    
1237
            stmt.close();
1238
        } catch (SQLException e) {
1239
            e.printStackTrace();
1240
            logMetacat.error("createGenericMapping: SQL error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1241
                    + e.getMessage());
1242
        } catch (NumberFormatException e) {
1243
            e.printStackTrace();
1244
            logMetacat.error("createGenericMapping: NumberFormat error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1245
                    + e.getMessage());
1246
        } catch (AccessionNumberException e) {
1247
            e.printStackTrace();
1248
            logMetacat.error("createGenericMapping: AccessionNumber error while creating a mapping to the " + TYPE_IDENTIFIER + " identifier: " 
1249
                    + e.getMessage());
1250
        } finally {
1251
            // Return database connection to the pool
1252
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1253
        }
1254
    }
1255
    
1256
    /**
1257
     * create the systemmetadata record
1258
     * @param guid
1259
     */
1260
    public void insertSystemMetadata(String guid)
1261
    {        
1262
        
1263
        int serialNumber = -1;
1264
        DBConnection dbConn = null;
1265
        try {
1266

    
1267
            // Get a database connection from the pool
1268
            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadata");
1269
            serialNumber = dbConn.getCheckOutSerialNumber();
1270

    
1271
            // Execute the insert statement
1272
            String query = "insert into " + TYPE_SYSTEM_METADATA + " (guid) values (?)";
1273
            PreparedStatement stmt = dbConn.prepareStatement(query);
1274
            stmt.setString(1, guid);
1275
            logMetacat.debug("system metadata query: " + stmt.toString());
1276
            int rows = stmt.executeUpdate();
1277

    
1278
            stmt.close();
1279
        } catch (Exception e) {
1280
            e.printStackTrace();
1281
            logMetacat.error("Error while creating " + TYPE_SYSTEM_METADATA + " record: " 
1282
                    + e.getMessage());
1283
        } finally {
1284
            // Return database connection to the pool
1285
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1286
        }
1287
    }
1288
}
1289

    
(37-37/65)