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 669 jones
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 145 bojilova
 */
28
29
package edu.ucsb.nceas.metacat;
30
31
import java.net.*;
32
import java.sql.*;
33
34 777 bojilova
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
35 747 bojilova
36 147 bojilova
/**
37 459 bojilova
 * (on insert of XML document)
38
 * Generates a unique Accession Number or if provided check it
39
 * for uniqueness and register it into the db connection
40
 * (on update or delete of XML document)
41
 * Check for existance of provided Accession Number
42
 *
43 147 bojilova
 */
44 145 bojilova
public class AccessionNumber  {
45 459 bojilova
46 777 bojilova
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
47 747 bojilova
48 1215 tao
  //private Connection conn = null;
49 618 bojilova
  private String sitecode = null;
50 459 bojilova
  private String sep = null;
51 779 bojilova
  private String docid = null;
52
  private String rev = null;
53 145 bojilova
54 459 bojilova
  /**
55
   * Construct an AccessionNumber
56
   */
57 1215 tao
  //public AccessionNumber ()
58
         //throws SQLException, ClassNotFoundException
59
  //{
60 779 bojilova
    // Open a connection to the database from here
61 1215 tao
    //this((new MetaCatUtil()).openDBConnection());
62
  //}
63 459 bojilova
64
  /**
65
   * Construct an AccessionNumber
66
   *
67
   * @param conn the db connection to read from and write Accession# to
68
   */
69 1215 tao
  public AccessionNumber ()
70 734 bojilova
  {
71 779 bojilova
    this.sitecode = MetaCatUtil.getOption("sitecode");
72
    this.sep = MetaCatUtil.getOption("accNumSeparator");
73 1215 tao
    //this.conn = conn;
74 459 bojilova
  }
75 160 bojilova
76 779 bojilova
  /** NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
77
   * Construct an AccessionNumber
78
   *
79
   * @param conn the db connection to read Accession number from
80
   * @param accnum the accession number to be checked for validness
81
   */
82 1215 tao
  public AccessionNumber (String accnum, String action)
83 954 tao
           throws AccessionNumberException, SQLException, NumberFormatException
84
 {
85 1215 tao
    this();
86 779 bojilova
87
    this.rev = null;
88
    this.docid = accnum;
89
    if ( accnum != null ) {
90
      int firstIndex = accnum.indexOf(this.sep);
91
      int lastIndex = accnum.lastIndexOf(this.sep);
92
      if ( firstIndex != lastIndex ) {
93
        //this docid contains a revision number
94
        this.rev = accnum.substring(lastIndex + 1);
95
        this.docid = accnum.substring(0, lastIndex);
96
      }
97
    }
98
99
    // INSERT
100
    if ( action.equals("INSERT")) {
101
102
      // check accession number for validness
103
      if ( docid == null ) {
104
        throw new AccessionNumberException("Accession number is required.");
105
106
      // rev is not provided; throw an exception to prevent the insertion
107
      } else if ( rev == null ) {
108
        throw new AccessionNumberException
109
                  ("Revision number is required and must be 1.");
110
111
      // docid is used; throw an exception to prevent the insertion
112
      } else if ( accNumberUsed(docid) ) {
113
        throw new AccessionNumberException
114
                  ("Accession number " + docid + " is already in use.");
115
116
      // rev is <> 1; throw an exception to prevent the insertion
117 1054 tao
      } /*else if ( !rev.equals("1")) {
118 779 bojilova
        throw new AccessionNumberException("Revision number must be 1.");
119 1054 tao
      }*/
120 779 bojilova
121
    // UPDATE or DELETE
122
    } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
123
      String l_rev = "";
124 954 tao
      int reversionNumber=Integer.parseInt(rev);
125 779 bojilova
126
      // Accession# is not provided; throw an exception to prevent the action
127
      if ( docid == null ) {
128
        throw new AccessionNumberException("Accession number is required.");
129
130
      // rev is not provided; throw an exception to prevent the action
131
      } else if ( rev == null ) {
132
        throw new AccessionNumberException
133
                  ("Revision number is required.");
134
135
      // Accession# is not current (not in xml_documents); throw an exception
136
      } else if ( !accNumberIsCurrent(docid) ) {
137
        throw new AccessionNumberException
138
                  ("Document not found for Accession number " + docid);
139
140 954 tao
      //Revision number is less than or equal the recent one; throw a exception
141 779 bojilova
      } else if ( action.equals("UPDATE") &&
142 954 tao
                  reversionNumber <= getLastRevisionNumber(docid) ) {
143 779 bojilova
        throw new AccessionNumberException
144 954 tao
                 ("Next revision number couldn't be less than or equal "
145
                                              + getLastRevisionNumber(docid));
146 779 bojilova
147
      // Revision number is not the recent one; throw an exception
148
      } else if ( action.equals("DELETE") &&
149
                  !rev.equals(l_rev = getLastRevision(docid)) ) {
150
        throw new AccessionNumberException
151
                  ("Last revision number is "+ l_rev);
152
      }
153
    }
154
  }
155
156 459 bojilova
  /**
157 735 bojilova
   * Generate an Accession Number of form <sidecode>.<uniqueid>.<revisionid>
158
   * where <revisionid> is always 1.
159
   *
160
   * @param docid <sitecode>.<uniqueid> part of Accession Number
161
   * @param action INSERT, UPDATE or DELETE action
162 576 bojilova
   */
163 735 bojilova
  public String generate(String docid, String action)
164
                throws AccessionNumberException, SQLException
165
  {
166
    return generate(docid, "1", action);
167
  }
168
169
  /**
170
   * Generate an Accession Number of form <sidecode>.<uniqueid>.<revisionid>
171
   *
172
   * @param docid <sitecode>.<uniqueid> part of Accession Number
173
   * @param rev <revisionid> of Accession Number
174
   * @param action INSERT, UPDATE or DELETE action
175
   */
176 734 bojilova
  public String generate(String docid, String rev, String action)
177 576 bojilova
                throws AccessionNumberException, SQLException
178
  {
179
    try {
180
      // INSERT
181
      if ( action.equals("INSERT")) {
182
183 734 bojilova
        // get a new docid
184
        if ( docid == null ) {
185 618 bojilova
          String sitecode = getSitecode();
186 758 bojilova
          String uniqueid = getUniqueID(sitecode);
187 576 bojilova
188 618 bojilova
          return sitecode + sep + uniqueid;
189
190 734 bojilova
        // docid is used; throw an exception to prevent the insertion
191
        } else if ( accNumberUsed(docid) ) {
192
          throw new AccessionNumberException
193
                    ("Accession number " + docid + " is already in use.");
194
        // rev is <> 1; throw an exception to prevent the insertion
195
        } else if ( !rev.equals("1") ) {
196
          throw new AccessionNumberException
197
                    ("Revision number must be 1.");
198
        // docid is not used and rev=1; return it
199 576 bojilova
        } else {
200 734 bojilova
          return docid;
201 576 bojilova
        }
202
203
      // UPDATE or DELETE
204
      } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
205
206
        // Accession# is not provided; throw an exception to prevent the action
207 734 bojilova
        if ( docid == null ) {
208 576 bojilova
          throw new AccessionNumberException("Accession number is required.");
209
210
        // Accession# is not current (not in xml_documents); throw an exception
211 734 bojilova
        } else if ( !accNumberIsCurrent(docid) ) {
212 576 bojilova
          throw new AccessionNumberException
213 734 bojilova
          ("Document not found for Accession number " + docid);
214 576 bojilova
215 734 bojilova
        // Revision number is not the recent one; throw an exception
216
        } else if ( !rev.equals(getLastRevision(docid)) ) {
217
          throw new AccessionNumberException
218
          ("Revision number must be the recent.");
219
220 576 bojilova
        // Accession# is current (present in xml_documents); return it
221
        } else {
222 734 bojilova
          return docid;
223 576 bojilova
        }
224
      }
225
226
    } catch (SQLException e) {
227
      throw new SQLException
228 734 bojilova
      ("Error on AccessionNumber.generate(): " + e.getMessage());
229 576 bojilova
    }
230
231
    // never comes here
232
    throw new
233
    AccessionNumberException("Fatal Error in accession number generation.");
234
  }
235
236 618 bojilova
  // get local sitecode
237
  private String getSitecode()
238 576 bojilova
  {
239 618 bojilova
    return this.sitecode;
240 576 bojilova
  }
241
242 618 bojilova
  // get Unique ID from DB sequence
243 758 bojilova
  private String getUniqueID (String sitecode) throws SQLException
244 576 bojilova
  {
245 618 bojilova
    String uniqueid;
246 758 bojilova
    String sysdate = dbAdapter.getDateTimeFunction();
247 1215 tao
    DBConnection conn = null;
248
    int serialNumber = -1;
249 576 bojilova
    try {
250 1215 tao
      PreparedStatement pstmt = null;
251
252
      //check out DBConnection
253
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getUniqueID");
254
      serialNumber=conn.getCheckOutSerialNumber();
255 576 bojilova
      pstmt = conn.prepareStatement
256 758 bojilova
              ("INSERT INTO accession_number (site_code, date_created) " +
257
               "VALUES (?, " + sysdate + ")");
258
      pstmt.setString(1, sitecode);
259 576 bojilova
      pstmt.execute();
260
      pstmt.close();
261
262 1215 tao
      uniqueid = "" + dbAdapter.getUniqueID(conn.getConnections(),
263
                                                          "accession_number");
264
      //because we only count the connection usage one when it check in
265
      //but it use twice. So we need to increase one
266
      conn.increaseUsageCount(1);
267 758 bojilova
268 576 bojilova
    } catch (SQLException e) {
269
      throw new
270 618 bojilova
      SQLException("Error on AccessionNumber.getUniqueID(): "+e.getMessage());
271 576 bojilova
    }
272 1215 tao
    finally
273
    {
274
      DBConnectionPool.returnDBConnection(conn, serialNumber);
275
    }
276 618 bojilova
    return uniqueid;
277 576 bojilova
  }
278
279 459 bojilova
  /** check for existence of Accesssion Number xml_acc_numbers table */
280 582 berkley
  public boolean accNumberUsed ( String accNumber )
281 576 bojilova
                  throws SQLException {
282 145 bojilova
283 459 bojilova
    boolean hasAccNumber = false;
284 1215 tao
    DBConnection conn = null;
285
    int serialNumber = -1;
286 145 bojilova
287 459 bojilova
    try {
288 1215 tao
      PreparedStatement pstmt = null;
289
      //check out DBConnection
290
      conn=DBConnectionPool.getDBConnection("AccessionNumber.accNumberUsed");
291
      serialNumber=conn.getCheckOutSerialNumber();
292 459 bojilova
      pstmt = conn.prepareStatement(
293 576 bojilova
                "SELECT 'x' FROM xml_documents " +
294 770 bojilova
                "WHERE docid = ? " +
295 576 bojilova
                "UNION " +
296
                "SELECT 'x' FROM xml_revisions " +
297 770 bojilova
                "WHERE docid = ?");
298 576 bojilova
      pstmt.setString(1,accNumber);
299
      pstmt.setString(2,accNumber);
300 459 bojilova
      pstmt.execute();
301
      ResultSet rs = pstmt.getResultSet();
302
      hasAccNumber = rs.next();
303
      pstmt.close();
304 145 bojilova
305 459 bojilova
    } catch (SQLException e) {
306 576 bojilova
      throw new SQLException
307
      ("Error on AccessionNumber.accNumberUsed(accNumber): " + e.getMessage());
308 1215 tao
    }
309
    finally
310
    {
311
      DBConnectionPool.returnDBConnection(conn, serialNumber);
312
    }
313 145 bojilova
314 459 bojilova
    return hasAccNumber;
315
  }
316 145 bojilova
317 734 bojilova
  // check for existence of Accesssion Number in xml_documents table
318 459 bojilova
  private boolean accNumberIsCurrent(String accNumber) throws SQLException {
319 203 jones
320 459 bojilova
    boolean hasCurrentAccNumber = false;
321 1215 tao
    DBConnection conn = null;
322
    int serialNumber = -1;
323 203 jones
324 459 bojilova
    try {
325 1215 tao
      PreparedStatement pstmt = null;
326
      //check out DBConnection
327
      conn=DBConnectionPool.getDBConnection("AccessionNumber.accNumberIsCurre");
328
      serialNumber=conn.getCheckOutSerialNumber();
329 459 bojilova
      pstmt = conn.prepareStatement(
330 203 jones
                "SELECT 'x' FROM xml_documents " +
331 770 bojilova
                "WHERE docid = ?");
332 459 bojilova
      pstmt.setString(1, accNumber);
333
      pstmt.execute();
334
      ResultSet rs = pstmt.getResultSet();
335
      hasCurrentAccNumber = rs.next();
336
      pstmt.close();
337 203 jones
338 459 bojilova
    } catch (SQLException e) {
339
      throw new SQLException(
340
          "Error on AccessionNumber.accNumberIsCurrent(String accNumber): " +
341
          e.getMessage());
342 1215 tao
    }
343
    finally
344
    {
345
      DBConnectionPool.returnDBConnection(conn, serialNumber);
346
    }
347 459 bojilova
348
    return hasCurrentAccNumber;
349
  }
350 203 jones
351 734 bojilova
  // get the recent revision number for docid
352
  private String getLastRevision(String docid) throws SQLException
353
  {
354
    String rev = "";
355 1215 tao
    DBConnection conn = null;
356
    int serialNumber = -1;
357 734 bojilova
358
    try {
359 1215 tao
      PreparedStatement pstmt = null;
360
      //check out DBConnection
361
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getLastRevision");
362
      serialNumber=conn.getCheckOutSerialNumber();
363 734 bojilova
      pstmt = conn.prepareStatement
364
              ("SELECT rev FROM xml_documents WHERE docid='" + docid + "'");
365
      pstmt.execute();
366
367
      ResultSet rs = pstmt.getResultSet();
368
      boolean hasRow = rs.next();
369
      rev = rs.getString(1);
370
      pstmt.close();
371
372
    } catch (SQLException e) {
373
      throw new SQLException(
374
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
375
    }
376 1215 tao
    finally
377
    {
378
      DBConnectionPool.returnDBConnection(conn,serialNumber);
379
    }
380 734 bojilova
381
    return rev;
382
  }
383 954 tao
384
  /**
385
    * Get last revision number from database for a docid
386
    * The return value is integer because we want compare it to there new one
387
    * @param docid <sitecode>.<uniqueid> part of Accession Number
388
    */
389
  private int getLastRevisionNumber(String docId) throws SQLException
390
  {
391
    int rev = 1;
392 1215 tao
    DBConnection conn =null;
393
    int serialNumber = -1;
394 954 tao
395
    try {
396 1215 tao
      PreparedStatement pStmt = null;
397
      //check out DBConnection
398
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getLastRevisionN");
399
      serialNumber=conn.getCheckOutSerialNumber();
400
401 954 tao
      pStmt = conn.prepareStatement
402
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
403
      pStmt.execute();
404 734 bojilova
405 954 tao
      ResultSet rs = pStmt.getResultSet();
406
      boolean hasRow = rs.next();
407
      rev = rs.getInt(1);
408
      pStmt.close();
409
410
    } catch (SQLException e) {
411
      throw new SQLException(
412
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
413
    }
414 1215 tao
    finally
415
    {
416
      DBConnectionPool.returnDBConnection(conn,serialNumber);
417
    }
418 954 tao
    return rev;
419
  }
420
421 779 bojilova
  // get the next revision number for docid
422
  private String getNextRevision(String docid) throws SQLException
423
  {
424
    String rev = "";
425 1215 tao
    DBConnection conn = null;
426
    int serialNumber = -1;
427 779 bojilova
    try {
428 1215 tao
      PreparedStatement pstmt = null;
429
      //check out DBConnection
430
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getNextRevision");
431
      serialNumber=conn.getCheckOutSerialNumber();
432 779 bojilova
      pstmt = conn.prepareStatement
433
              ("SELECT rev+1 FROM xml_documents WHERE docid='" + docid + "'");
434
      pstmt.execute();
435
436
      ResultSet rs = pstmt.getResultSet();
437
      boolean hasRow = rs.next();
438
      rev = rs.getString(1);
439
      pstmt.close();
440
441
    } catch (SQLException e) {
442
      throw new SQLException(
443
      "Error on AccessionNumber.getNextRevision(): " + e.getMessage());
444
    }
445 1215 tao
    finally
446
    {
447
      DBConnectionPool.returnDBConnection(conn, serialNumber);
448
    }
449 779 bojilova
450
    return rev;
451
  }
452
453
  /**
454
   * returns the docid encoded in this accession number
455
   */
456
  public String getDocid() {
457
458
    return this.docid;
459
  }
460
461
  /**
462
   * returns the revision number encoded in this accession number
463
   */
464
  public String getRev()
465
  {
466
    return this.rev;
467
  }
468
469 203 jones
}