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.sql.PreparedStatement;
28
import java.sql.ResultSet;
29
import java.sql.SQLException;
30

    
31
import org.apache.log4j.Logger;
32

    
33
import edu.ucsb.nceas.metacat.database.DBConnection;
34
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
35
import edu.ucsb.nceas.metacat.util.DocumentUtil;
36

    
37
/**
38
 * Manage the relationship between Metacat local identifiers (LocalIDs) that are
39
 * codified as the (docid, rev) pair with globally uniqe string identifiers
40
 * (GUIDs) that are opaque strings.  This class provides methods to manage these
41
 * identifiers, and to search for and look up LocalIDs based on their GUID and
42
 * vice versa. IdentifierManager is a singleton.
43
 * 
44
 * @author Matthew Jones
45
 */
46
public class IdentifierManager {
47
    
48
    /**
49
     * The single instance of the manager that is always returned.
50
     */
51
    private static IdentifierManager self = null;
52
    private Logger logMetacat = Logger.getLogger(EventLog.class);
53

    
54
    /**
55
     * A private constructor that initializes the class when getInstance() is
56
     * called.
57
     */
58
    private IdentifierManager()
59
    {
60
    }
61

    
62
    /**
63
     * Return the single instance of the manager after initializing it if it
64
     * wasn't previously initialized.
65
     * 
66
     * @return the single IdentifierManager instance
67
     */
68
    public static IdentifierManager getInstance()
69
    {
70
        if (self == null) {
71
            self = new IdentifierManager();
72
        }
73
        return self;
74
    }
75
    
76
    /**
77
     * Lookup a GUID from the database, and return the associated LocalID. If
78
     * the identifier is not found, throw an exception.
79
     * 
80
     * @param guid the global identifier to look up
81
     * @return String containing the corresponding LocalId
82
     * @throws McdbDocNotFoundException if the identifier is not found
83
     */
84
    public String getLocalId(String guid) throws McdbDocNotFoundException
85
    {
86
        String db_guid = "";
87
        String docid = "";
88
        int rev = 0;
89
        
90
        String query = "select guid, docid, rev from identifier where guid = ?";
91
        
92
        DBConnection dbConn = null;
93
        int serialNumber = -1;
94
        try {
95
            // Get a database connection from the pool
96
            dbConn = DBConnectionPool.getDBConnection("Identifier.getLocalId");
97
            serialNumber = dbConn.getCheckOutSerialNumber();
98
            
99
            // Execute the insert statement
100
            PreparedStatement stmt = dbConn.prepareStatement(query);
101
            stmt.setString(1, guid);
102
            ResultSet rs = stmt.executeQuery();
103
            if (rs.next()) {
104
                db_guid = rs.getString(1);
105
                docid = rs.getString(2);
106
                rev = rs.getInt(3);
107
                assert(db_guid.equals(guid));
108
            } else {
109
                throw new McdbDocNotFoundException("Document not found:" + guid);
110
            }
111
            stmt.close();
112
        } catch (SQLException e) {
113
            logMetacat.error("Error while looking up the local identifier: " 
114
                    + e.getMessage());
115
        } finally {
116
            // Return database connection to the pool
117
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
118
        }
119
        return docid + "." + rev;
120
    }
121
    
122
    /**
123
     * Determine if an identifier exists already, returning true if so.
124
     * 
125
     * @param guid the global identifier to look up
126
     * @return boolean true if the identifier exists
127
     */
128
    public boolean identifierExists(String guid)
129
    {
130
        boolean idExists = false;
131
        try {
132
            String id = getLocalId(guid);
133
            if (id != null) {
134
                idExists = true;
135
            }
136
        } catch (McdbDocNotFoundException e) {
137
            idExists = false;
138
        }
139
        return idExists;
140
    }
141
    
142
    /**
143
     * Create a mapping between two identifiers, one representing an 
144
     * unconstrained, globally unique string (guid), and one a localId 
145
     * in the Metacat docid format (scope.id.revision). 
146
     * This mapping allows one to find the global id (guid) from the localId.
147
     * 
148
     * @param guid the global string identifier to be mapped
149
     * @param localId the local identifier to be mapped
150
     */
151
    public void createMapping(String guid, String localId)
152
    {   
153
        int serialNumber = -1;
154
        DBConnection dbConn = null;
155
        try {
156

    
157
            // Parse the localId into scope and rev parts
158
            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
159
            String docid = acc.getDocid();
160
            int rev = (new Integer(acc.getRev()).intValue());
161

    
162
            // Get a database connection from the pool
163
            dbConn = 
164
                DBConnectionPool.getDBConnection("Identifier.createMapping");
165
            serialNumber = dbConn.getCheckOutSerialNumber();
166

    
167
            // Execute the insert statement
168
            String query = "insert into identifier (guid, docid, rev) values (?, ?, ?)";            
169
            PreparedStatement stmt = dbConn.prepareStatement(query);
170
            stmt.setString(1, guid);
171
            stmt.setString(2, docid);
172
            stmt.setInt(3, rev);
173
            int rows = stmt.executeUpdate();
174

    
175
            stmt.close();
176
        } catch (SQLException e) {
177
            logMetacat.error("SQL error while creating a mapping to the local identifier: " 
178
                    + e.getMessage());
179
        } catch (NumberFormatException e) {
180
            logMetacat.error("NumberFormat error while creating a mapping to the local identifier: " 
181
                    + e.getMessage());
182
        } catch (AccessionNumberException e) {
183
            logMetacat.error("AccessionNumber error while creating a mapping to the local identifier: " 
184
                    + e.getMessage());
185
        } finally {
186
            // Return database connection to the pool
187
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
188
        }
189
    }
190

    
191
    /**
192
     * Given a global identifier (guid), create a suitable local identifier that
193
     * follows Metacat's docid semantics and format (scope.id.rev), and create
194
     * a mapping between these two identifiers.  This effectively reserves both
195
     * the global and the local identifier, as they will now be present in the
196
     * identifier mapping table.  If the incoming guid has the syntax of a
197
     * Metacat docid (scope.id.rev), then simply use it.
198
     * 
199
     * @param guid the global string identifier
200
     * @param rev the revision number to be used in the localId
201
     * @return String containing the localId to be used for Metacat operations
202
     */
203
    public String generateLocalId(String guid, int rev) 
204
    {
205
        String localId = "";
206
        boolean conformsToDocidFormat = false;
207
        
208
        // Check if the guid passed in is already in docid (scope.id.rev) format
209
        try {
210
            AccessionNumber acc = new AccessionNumber(guid, "NONE");
211
            if (new Integer(acc.getRev()).intValue() > 0) {
212
                conformsToDocidFormat = true;
213
            }
214
        } catch (NumberFormatException e) {
215
            // No action needed, simply detecting invalid AccessionNumbers
216
        } catch (AccessionNumberException e) {
217
            // No action needed, simply detecting invalid AccessionNumbers
218
        } catch (SQLException e) {
219
            // No action needed, simply detecting invalid AccessionNumbers
220
        }
221
        
222
        if (conformsToDocidFormat) {
223
            // if it conforms, use it for both guid and localId
224
            localId = guid;
225
        } else {
226
            // if not, then generate a new unique localId
227
            localId = DocumentUtil.generateDocumentId(rev);
228
        }
229
        
230
        // Register this new pair in the identifier mapping table
231
        createMapping(guid, localId);
232
        
233
        return localId;
234
    }
235
    
236
    /**
237
     * given a local identifer, look up the guid.  Throw McdbDocNotFoundException
238
     * if the docid, rev is not found in the identifiers table
239
     *
240
     * @param docid the docid to look up
241
     * @param rev the revision of the docid to look up
242
     * @return String containing the mapped guid
243
     * @throws McdbDocNotFoundException if the docid, rev is not found
244
     */
245
    public String getGUID(String docid, int rev)
246
      throws McdbDocNotFoundException
247
    {
248
        String query = "select guid from identifier where docid = ? and rev = ?";
249
        String guid = null;
250
        
251
        DBConnection dbConn = null;
252
        int serialNumber = -1;
253
        try {
254
            // Get a database connection from the pool
255
            dbConn = DBConnectionPool.getDBConnection("Identifier.getGUID");
256
            serialNumber = dbConn.getCheckOutSerialNumber();
257
            
258
            // Execute the insert statement
259
            PreparedStatement stmt = dbConn.prepareStatement(query);
260
            stmt.setString(1, docid);
261
            stmt.setInt(2, rev);
262
            ResultSet rs = stmt.executeQuery();
263
            if (rs.next()) {
264
                guid = rs.getString(1);
265
                
266
            } else {
267
                throw new McdbDocNotFoundException("Document not found:" + guid);
268
            }
269
            stmt.close();
270
        } catch (SQLException e) {
271
            logMetacat.error("Error while looking up the guid: " 
272
                    + e.getMessage());
273
        } finally {
274
            // Return database connection to the pool
275
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
276
        }
277
        
278
        return guid;
279
    }
280
}
(37-37/62)