Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class that gets Accession Number, check for uniqueness
4
 *             and register it into db
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Jivka Bojilova, Matt Jones
8
 *    Release: @release@
9
 *
10
 *   '$Author: bojilova $'
11
 *     '$Date: 2000-09-28 11:05:46 -0700 (Thu, 28 Sep 2000) $'
12
 * '$Revision: 476 $'
13
 */
14

    
15
package edu.ucsb.nceas.metacat;
16

    
17
import java.net.*;
18
import java.sql.*;
19

    
20
/**
21
 * (on insert of XML document)
22
 * Generates a unique Accession Number or if provided check it 
23
 * for uniqueness and register it into the db connection 
24
 * (on update or delete of XML document)
25
 * Check for existance of provided Accession Number
26
 * 
27
 */
28
public class AccessionNumber  {
29
  
30
  private Connection conn = null;
31
  private String defaultGlobalName = null;
32
  private String sep = null;
33
    
34
  /** 
35
   * Construct an AccessionNumber 
36
   */
37
  public AccessionNumber () 
38
         throws SQLException, ClassNotFoundException  {
39
        
40
    MetaCatUtil util = new MetaCatUtil();
41

    
42
    this.defaultGlobalName = util.getOption("defaultGlobalName");
43
    this.sep = util.getOption("accNumberSeparator");
44

    
45
    // Open a connection to the database
46
    this.conn = util.openDBConnection();
47
  }  
48

    
49
  /** 
50
   * Construct an AccessionNumber
51
   *
52
   * @param conn the db connection to read from and write Accession# to
53
   */
54
  public AccessionNumber (Connection conn) {
55
        
56
    MetaCatUtil util = new MetaCatUtil();
57

    
58
    this.defaultGlobalName = util.getOption("defaultGlobalName");
59
    this.sep = util.getOption("accNumberSeparator");
60
    this.conn = conn;
61

    
62
  }
63

    
64
  /**
65
   * Get an Accession Number, check it for uniqueness and 
66
   * register it into db connection. If no Accession Number is
67
   * provided, generate one from the database and return it.
68
   *
69
   * @param accNumber - Accession # if provided or null if not
70
   * @param action - INSERT, UPDATE or DELETE.
71
   * When "INSERT" and accession # provided is not unique, get new one.
72
   * If it is unique, use it.
73
   * When "INSERT" and accession # is null, get a new one.
74
   * When "UPDATE", accession # is required and it is checked for existance.
75
   * When "DELETE", accession # is required and it is checked for existance.
76
   */
77
  public String generate (String accNumber, String action) 
78
         throws AccessionNumberException, SQLException   {
79
        
80
    String globalName = null;
81
    String localId = null;
82

    
83
    try {
84

    
85
      conn.setAutoCommit(true);
86

    
87
      // split the acc # in 2 parts - global name & local id
88
      if ( accNumber != null ) {
89
        globalName = getGlobalName(accNumber, sep);
90
        localId = getLocalId(accNumber, sep);
91
      }    
92

    
93
      // INSERT
94
      if ( action.equals("INSERT")) {
95
        // get a unique Acc#
96
        if ( accNumber == null ) {
97
          return put(defaultGlobalName, null, sep);
98
        // Acc# is not used; return it
99
        } else if ( !accNumberUsed(globalName, localId) ) {
100
          return put(globalName, localId, sep);
101
        // Acc# is used; throw an exception to prevent the insertion
102
        } else {
103
          throw 
104
          new AccessionNumberException("Accession number is already in use.");
105
        }
106
      // UPDATE or DELETE
107
      } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
108
        // Acc# is not provided; throw an exception to prevent the action
109
        if ( accNumber == null ) {
110
          throw (new AccessionNumberException("Accession number is " +
111
          "required."));
112
        // Acc# is not current (not in xml_documents); throw an exception
113
        } else if (!accNumberIsCurrent(accNumber)) {
114
          throw (new AccessionNumberException("Document " +
115
          "not found for accession #: " + accNumber));
116
        // Acc# is current; return it
117
        } else {
118
          return accNumber;
119
        }
120
      }
121
 
122
      //conn.close();        
123

    
124
    } catch (StringIndexOutOfBoundsException siobe) {
125
      MetaCatUtil.debugMessage(
126
                 "Error on AccessionNumber.generate(): " + 
127
                  siobe.getMessage());
128
      throw (new AccessionNumberException("Accession number invalid, " +
129
                 "expecting character \'" + sep + "'."));
130
    } catch (SQLException e) {
131
      throw new SQLException(
132
                 "Error on AccessionNumber.generate(accNumber, action): " +
133
                  e.getMessage());
134
    }    
135
        
136
    throw (new AccessionNumberException("Fatal Error in " +
137
           "accession number generation: "));
138
  }    
139

    
140
  /** put unique accession # into db connection */
141
  private String put (String globalName, String localId, String sep) 
142
                throws SQLException
143
  {
144
        
145
    Integer l = null;
146
    try {
147
      if ( localId == null ) 
148
         l = new Integer(get(globalName) + 1); 
149
      //else if ( accNumberUsed(globalName, localId) )
150
      //   l = new Integer(get(globalName) + 1); 
151
      else
152
         l = new Integer(localId); 
153

    
154
     // insert globalName & l
155
     PreparedStatement pstmt;
156
     pstmt = conn.prepareStatement(
157
             "INSERT INTO xml_acc_numbers (global_name, local_id) " + 
158
             "VALUES (?, ?)");
159
     pstmt.setString(1,globalName);
160
     pstmt.setString(2,l.toString());
161
     pstmt.execute();
162
            
163
     pstmt.close();
164
            
165
    } catch (SQLException e) {
166
      throw new SQLException(
167
            "Error on AccessionNumber.put(globalName, localId, sep): " 
168
            + e.getMessage());
169
    }    
170

    
171
    return globalName + sep + l;
172
  }
173

    
174
  /** check for existence of Accesssion Number xml_acc_numbers table */
175
  private boolean accNumberUsed(String globalName, String localId)
176
                      throws SQLException {
177
        
178
    boolean hasAccNumber = false;
179
        
180
    try {
181
      PreparedStatement pstmt;
182
      pstmt = conn.prepareStatement(
183
                "SELECT 'x' FROM xml_acc_numbers " + 
184
                "WHERE global_name LIKE ? AND local_id = ?");
185
      pstmt.setString(1,globalName);
186
      pstmt.setString(2,localId);
187
      pstmt.execute();
188
      ResultSet rs = pstmt.getResultSet();
189
      hasAccNumber = rs.next();
190
      pstmt.close();
191
            
192
    } catch (SQLException e) {
193
      throw new SQLException(
194
                "Error on AccessionNumber.accNumberUsed(globalName, " +
195
                  "localId): " + e.getMessage());
196
    }    
197
        
198
    return hasAccNumber;
199
  }    
200
    
201
  /** check for existence of Accesssion Number in xml_documents table */
202
  private boolean accNumberIsCurrent(String accNumber) throws SQLException {
203
        
204
    boolean hasCurrentAccNumber = false;
205
        
206
    try {
207
      PreparedStatement pstmt;
208
      pstmt = conn.prepareStatement(
209
                "SELECT 'x' FROM xml_documents " + 
210
                "WHERE docid LIKE ?");
211
      pstmt.setString(1, accNumber);
212
      pstmt.execute();
213
      ResultSet rs = pstmt.getResultSet();
214
      hasCurrentAccNumber = rs.next();
215
      pstmt.close();
216
            
217
    } catch (SQLException e) {
218
      throw new SQLException(
219
          "Error on AccessionNumber.accNumberIsCurrent(String accNumber): " +
220
          e.getMessage());
221
    }    
222
  
223
    return hasCurrentAccNumber;
224
  }    
225

    
226
  /** get the last in order local ID by a given global name */
227
  private int get (String globalName) throws SQLException  {
228
        
229
    try {
230
      PreparedStatement pstmt;
231
      pstmt = conn.prepareStatement(
232
              "SELECT max(local_id) FROM xml_acc_numbers " + 
233
              "WHERE global_name LIKE ?");
234
      pstmt.setString(1,globalName);
235
      pstmt.execute();
236
      ResultSet rs = pstmt.getResultSet();
237
      boolean hasLocalId = rs.next();
238

    
239
      if (hasLocalId) {
240
        return rs.getInt(1);
241
      }
242

    
243
      pstmt.close();
244
    } catch (SQLException e) {
245
      throw new SQLException(
246
            "Error on AccessionNumber.get(globalName): " + e.getMessage());
247
    }    
248
        
249
    return 0;
250
  }
251

    
252
    
253
  // get the global part of the accession number
254
  private String getGlobalName (String accNumber, String sep) 
255
          throws StringIndexOutOfBoundsException {
256
        
257
    return accNumber.substring(0, accNumber.lastIndexOf(sep));
258
  }    
259

    
260
  // get the local part of the accession number
261
  private String getLocalId (String accNumber, String sep)
262
          throws StringIndexOutOfBoundsException {
263

    
264
    return accNumber.substring(accNumber.lastIndexOf(sep)+1);
265
  }    
266
}
267

    
268
/**
269
 * '$Log$
270
 * 'Revision 1.13  2000/09/20 20:15:58  bojilova
271
 * 'change Assession# generation to use the same db connection
272
 * '
273
 * 'Revision 1.12  2000/08/30 18:19:41  bojilova
274
 * 'cleared static methods in AccessionNumber classes for fixing bug found
275
 * 'when multiple requests to the servlet at a time.
276
 * '
277
 * 'Revision 1.11  2000/08/14 20:53:33  jones
278
 * 'Added "release" keyword to all metacat source files so that the release
279
 * 'number will be evident in software distributions.
280
 * '
281
 * 'Revision 1.10  2000/06/27 04:31:07  jones
282
 * 'Fixed bugs associated with the new UPDATE and DELETE functions of
283
 * 'DBWriter.  There were problematic interactions between some static
284
 * 'variables used in DBEntityResolver and the way in which the
285
 * 'Servlet objects are re-used across multiple client invocations.
286
 * '
287
 * 'Generally cleaned up error reporting.  Now all errors and success
288
 * 'results are reported as XML documents from MetaCatServlet.  Need
289
 * 'to make the command line tools do the same.
290
 * '
291
 * 'Revision 1.9  2000/06/26 10:35:04  jones
292
 * 'Merged in substantial changes to DBWriter and associated classes and to
293
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
294
 * 'functions.  The command line tools and the parameters for the
295
 * 'servlet have changed substantially.
296
 * '
297
 * 'Revision 1.8.2.5  2000/06/26 08:38:01  jones
298
 * 'Added DELETE feature to DBWriter.  Now takes an action "DELETE" and a
299
 * 'docid and will move the record from the xml_documents table to the
300
 * 'xml_revisions table.
301
 * 'Modified option parsing to support option symbols on command line.
302
 * '
303
 * 'Revision 1.8.2.4  2000/06/25 23:11:40  jones
304
 * 'Documentation update
305
 * '
306
 * 'Revision 1.8.2.3  2000/06/25 23:08:31  jones
307
 * 'Minor change to excpetion handling
308
 * ''
309
 */
(1-1/38)