Project

General

Profile

1 145 bojilova
/**
2 203 jones
 *  '$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 349 jones
 *    Release: @release@
9 145 bojilova
 *
10 203 jones
 *   '$Author$'
11
 *     '$Date$'
12
 * '$Revision$'
13 145 bojilova
 */
14
15
package edu.ucsb.nceas.metacat;
16
17
import java.net.*;
18
import java.sql.*;
19
20 147 bojilova
/**
21 459 bojilova
 * (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 147 bojilova
 */
28 145 bojilova
public class AccessionNumber  {
29 459 bojilova
30
  private Connection conn = null;
31
  private String defaultGlobalName = null;
32
  private String sep = null;
33 145 bojilova
34 459 bojilova
  /**
35
   * Construct an AccessionNumber
36
   */
37
  public AccessionNumber ()
38
         throws SQLException, ClassNotFoundException  {
39 145 bojilova
40 459 bojilova
    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 160 bojilova
56 459 bojilova
    MetaCatUtil util = new MetaCatUtil();
57 160 bojilova
58 459 bojilova
    this.defaultGlobalName = util.getOption("defaultGlobalName");
59
    this.sep = util.getOption("accNumberSeparator");
60
    this.conn = conn;
61 160 bojilova
62 459 bojilova
  }
63 160 bojilova
64 459 bojilova
  /**
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 160 bojilova
83 459 bojilova
    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
      // register unique acc #
94
      if ( action.equals("INSERT")) {
95
        if ( accNumber == null )
96
          return put(defaultGlobalName, null, sep);
97
        else
98
          return put(globalName, localId, sep);
99
      } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
100
        if ( accNumber == null ) {
101
          throw (new AccessionNumberException("Accession number is " +
102
          "required."));
103
        } else if (!accNumberIsCurrent(accNumber)) {
104
          throw (new AccessionNumberException("Document " +
105
          "not found for accession #: " + accNumber));
106
        } else {
107
          return (globalName + sep + localId);
108
        }
109
      }
110 203 jones
111 459 bojilova
      //conn.close();
112 160 bojilova
113 459 bojilova
    } catch (StringIndexOutOfBoundsException siobe) {
114
      MetaCatUtil.debugMessage(
115
                 "Error on AccessionNumber.generate(): " +
116
                  siobe.getMessage());
117
      throw (new AccessionNumberException("Accession number invalid, " +
118
                 "expecting character \'" + sep + "'."));
119
    } catch (SQLException e) {
120
      throw new SQLException(
121
                 "Error on AccessionNumber.generate(accNumber, action): " +
122
                  e.getMessage());
123
    }
124 160 bojilova
125 459 bojilova
    throw (new AccessionNumberException("Fatal Error in " +
126
           "accession number generation: "));
127
  }
128 160 bojilova
129 459 bojilova
  /** put unique accession # into db connection */
130
  private String put (String globalName, String localId, String sep)
131 160 bojilova
                throws SQLException
132 459 bojilova
  {
133 160 bojilova
134 459 bojilova
    Integer l = null;
135
    try {
136
      if ( localId == null )
137
         l = new Integer(get(globalName) + 1);
138
      else if ( accNumberUsed(globalName, localId) )
139
         l = new Integer(get(globalName) + 1);
140
      else
141
         l = new Integer(localId);
142 160 bojilova
143 459 bojilova
     // insert globalName & l
144
     PreparedStatement pstmt;
145
     pstmt = conn.prepareStatement(
146
             "INSERT INTO xml_acc_numbers (global_name, local_id) " +
147
             "VALUES (?, ?)");
148
     pstmt.setString(1,globalName);
149
     pstmt.setString(2,l.toString());
150
     pstmt.execute();
151 160 bojilova
152 459 bojilova
     pstmt.close();
153 171 bojilova
154 459 bojilova
    } catch (SQLException e) {
155
      throw new SQLException(
156
            "Error on AccessionNumber.put(globalName, localId, sep): "
157
            + e.getMessage());
158
    }
159 160 bojilova
160 459 bojilova
    return globalName + sep + l;
161
  }
162
163
  /** check for existence of Accesssion Number xml_acc_numbers table */
164
  private boolean accNumberUsed(String globalName, String localId)
165
                      throws SQLException {
166 145 bojilova
167 459 bojilova
    boolean hasAccNumber = false;
168 145 bojilova
169 459 bojilova
    try {
170
      PreparedStatement pstmt;
171
      pstmt = conn.prepareStatement(
172 203 jones
                "SELECT 'x' FROM xml_acc_numbers " +
173
                "WHERE global_name LIKE ? AND local_id = ?");
174 459 bojilova
      pstmt.setString(1,globalName);
175
      pstmt.setString(2,localId);
176
      pstmt.execute();
177
      ResultSet rs = pstmt.getResultSet();
178
      hasAccNumber = rs.next();
179
      pstmt.close();
180 145 bojilova
181 459 bojilova
    } catch (SQLException e) {
182
      throw new SQLException(
183
                "Error on AccessionNumber.accNumberUsed(globalName, " +
184
                  "localId): " + e.getMessage());
185
    }
186 145 bojilova
187 459 bojilova
    return hasAccNumber;
188
  }
189 145 bojilova
190 459 bojilova
  /** check for existence of Accesssion Number in xml_documents table */
191
  private boolean accNumberIsCurrent(String accNumber) throws SQLException {
192 203 jones
193 459 bojilova
    boolean hasCurrentAccNumber = false;
194 203 jones
195 459 bojilova
    try {
196
      PreparedStatement pstmt;
197
      pstmt = conn.prepareStatement(
198 203 jones
                "SELECT 'x' FROM xml_documents " +
199
                "WHERE docid LIKE ?");
200 459 bojilova
      pstmt.setString(1, accNumber);
201
      pstmt.execute();
202
      ResultSet rs = pstmt.getResultSet();
203
      hasCurrentAccNumber = rs.next();
204
      pstmt.close();
205 203 jones
206 459 bojilova
    } catch (SQLException e) {
207
      throw new SQLException(
208
          "Error on AccessionNumber.accNumberIsCurrent(String accNumber): " +
209
          e.getMessage());
210 203 jones
    }
211 459 bojilova
212
    return hasCurrentAccNumber;
213
  }
214 203 jones
215 459 bojilova
  /** get the last in order local ID by a given global name */
216
  private int get (String globalName) throws SQLException  {
217
218
    try {
219
      PreparedStatement pstmt;
220
      pstmt = conn.prepareStatement(
221
              "SELECT max(local_id) FROM xml_acc_numbers " +
222
              "WHERE global_name LIKE ?");
223
      pstmt.setString(1,globalName);
224
      pstmt.execute();
225
      ResultSet rs = pstmt.getResultSet();
226
      boolean hasLocalId = rs.next();
227 145 bojilova
228 459 bojilova
      if (hasLocalId) {
229
        return rs.getInt(1);
230
      }
231 145 bojilova
232 459 bojilova
      pstmt.close();
233
    } catch (SQLException e) {
234
      throw new SQLException(
235
            "Error on AccessionNumber.get(globalName): " + e.getMessage());
236
    }
237 145 bojilova
238 459 bojilova
    return 0;
239
  }
240 145 bojilova
241
242 459 bojilova
  // get the global part of the accession number
243
  private String getGlobalName (String accNumber, String sep)
244
          throws StringIndexOutOfBoundsException {
245 145 bojilova
246 459 bojilova
    return accNumber.substring(0, accNumber.lastIndexOf(sep));
247
  }
248 145 bojilova
249 459 bojilova
  // get the local part of the accession number
250
  private String getLocalId (String accNumber, String sep)
251
          throws StringIndexOutOfBoundsException {
252 145 bojilova
253 459 bojilova
    return accNumber.substring(accNumber.lastIndexOf(sep)+1);
254
  }
255 203 jones
}
256 145 bojilova
257 203 jones
/**
258
 * '$Log$
259 459 bojilova
 * 'Revision 1.12  2000/08/30 18:19:41  bojilova
260
 * 'cleared static methods in AccessionNumber classes for fixing bug found
261
 * 'when multiple requests to the servlet at a time.
262
 * '
263 421 bojilova
 * 'Revision 1.11  2000/08/14 20:53:33  jones
264
 * 'Added "release" keyword to all metacat source files so that the release
265
 * 'number will be evident in software distributions.
266
 * '
267 349 jones
 * 'Revision 1.10  2000/06/27 04:31:07  jones
268
 * 'Fixed bugs associated with the new UPDATE and DELETE functions of
269
 * 'DBWriter.  There were problematic interactions between some static
270
 * 'variables used in DBEntityResolver and the way in which the
271
 * 'Servlet objects are re-used across multiple client invocations.
272
 * '
273
 * 'Generally cleaned up error reporting.  Now all errors and success
274
 * 'results are reported as XML documents from MetaCatServlet.  Need
275
 * 'to make the command line tools do the same.
276
 * '
277 204 jones
 * 'Revision 1.9  2000/06/26 10:35:04  jones
278
 * 'Merged in substantial changes to DBWriter and associated classes and to
279
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
280
 * 'functions.  The command line tools and the parameters for the
281
 * 'servlet have changed substantially.
282
 * '
283 203 jones
 * 'Revision 1.8.2.5  2000/06/26 08:38:01  jones
284
 * 'Added DELETE feature to DBWriter.  Now takes an action "DELETE" and a
285
 * 'docid and will move the record from the xml_documents table to the
286
 * 'xml_revisions table.
287
 * 'Modified option parsing to support option symbols on command line.
288
 * '
289
 * 'Revision 1.8.2.4  2000/06/25 23:11:40  jones
290
 * 'Documentation update
291
 * '
292
 * 'Revision 1.8.2.3  2000/06/25 23:08:31  jones
293
 * 'Minor change to excpetion handling
294
 * ''
295
 */