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 2246 sgarg
 * Generates a unique Accession Number or if provided check it
39
 * for uniqueness and register it into the db connection
40 459 bojilova
 * (on update or delete of XML document)
41
 * Check for existance of provided Accession Number
42 2246 sgarg
 *
43 147 bojilova
 */
44 145 bojilova
public class AccessionNumber  {
45 2246 sgarg
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 2246 sgarg
54
  /**
55
   * Construct an AccessionNumber
56 459 bojilova
   */
57 2246 sgarg
  //public AccessionNumber ()
58
         //throws SQLException, ClassNotFoundException
59 1215 tao
  //{
60 779 bojilova
    // Open a connection to the database from here
61 1215 tao
    //this((new MetaCatUtil()).openDBConnection());
62 2246 sgarg
  //}
63 459 bojilova
64 2246 sgarg
  /**
65 459 bojilova
   * Construct an AccessionNumber
66
   *
67
   * @param conn the db connection to read from and write Accession# to
68
   */
69 2246 sgarg
  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 2246 sgarg
  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 2246 sgarg
99 779 bojilova
    // INSERT
100
    if ( action.equals("INSERT")) {
101
102 2253 sgarg
        if(rev != null){
103
            try {
104
                Integer.parseInt(rev);
105
            }
106
            catch (java.lang.NumberFormatException e) {
107
                throw new AccessionNumberException(
108
                    "Revision number is required");
109
            }
110
        }
111
112 779 bojilova
      // check accession number for validness
113
      if ( docid == null ) {
114 2253 sgarg
        throw new AccessionNumberException("Accession number is required");
115 779 bojilova
116
      // rev is not provided; throw an exception to prevent the insertion
117
      } else if ( rev == null ) {
118
        throw new AccessionNumberException
119 2253 sgarg
                  ("Revision number is required");
120 779 bojilova
121
      // docid is used; throw an exception to prevent the insertion
122
      } else if ( accNumberUsed(docid) ) {
123
        throw new AccessionNumberException
124 2253 sgarg
                  ("Accession number " + docid + " is already in use");
125 2246 sgarg
126 779 bojilova
      // rev is <> 1; throw an exception to prevent the insertion
127 1054 tao
      } /*else if ( !rev.equals("1")) {
128 2253 sgarg
        throw new AccessionNumberException("Revision number must be 1");
129 1054 tao
      }*/
130 2246 sgarg
131 779 bojilova
    // UPDATE or DELETE
132
    } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
133
      String l_rev = "";
134
135 2246 sgarg
      int reversionNumber = 1;
136
137
      if(rev != null){
138 2253 sgarg
          try{
139
              reversionNumber = Integer.parseInt(rev);
140
          } catch (java.lang.NumberFormatException e){
141
              throw new AccessionNumberException(
142
                      "Revision number is required");
143
          }
144 2246 sgarg
      }
145
146 779 bojilova
      // Accession# is not provided; throw an exception to prevent the action
147
      if ( docid == null ) {
148 2253 sgarg
        throw new AccessionNumberException("Accession number is required");
149 779 bojilova
150
      // rev is not provided; throw an exception to prevent the action
151
      } else if ( rev == null ) {
152
        throw new AccessionNumberException
153 2253 sgarg
                  ("Revision number is required");
154 779 bojilova
155
      // Accession# is not current (not in xml_documents); throw an exception
156
      } else if ( !accNumberIsCurrent(docid) ) {
157
        throw new AccessionNumberException
158
                  ("Document not found for Accession number " + docid);
159
160 954 tao
      //Revision number is less than or equal the recent one; throw a exception
161 779 bojilova
      } else if ( action.equals("UPDATE") &&
162 954 tao
                  reversionNumber <= getLastRevisionNumber(docid) ) {
163 779 bojilova
        throw new AccessionNumberException
164 954 tao
                 ("Next revision number couldn't be less than or equal "
165
                                              + getLastRevisionNumber(docid));
166 779 bojilova
167
      // Revision number is not the recent one; throw an exception
168 2246 sgarg
      } else if ( action.equals("DELETE") &&
169 779 bojilova
                  !rev.equals(l_rev = getLastRevision(docid)) ) {
170
        throw new AccessionNumberException
171
                  ("Last revision number is "+ l_rev);
172
      }
173
    }
174
  }
175
176 459 bojilova
  /**
177 735 bojilova
   * Generate an Accession Number of form <sidecode>.<uniqueid>.<revisionid>
178
   * where <revisionid> is always 1.
179
   *
180
   * @param docid <sitecode>.<uniqueid> part of Accession Number
181
   * @param action INSERT, UPDATE or DELETE action
182 576 bojilova
   */
183 2246 sgarg
  public String generate(String docid, String action)
184
                throws AccessionNumberException, SQLException
185 735 bojilova
  {
186
    return generate(docid, "1", action);
187
  }
188
189
  /**
190
   * Generate an Accession Number of form <sidecode>.<uniqueid>.<revisionid>
191
   *
192
   * @param docid <sitecode>.<uniqueid> part of Accession Number
193
   * @param rev <revisionid> of Accession Number
194
   * @param action INSERT, UPDATE or DELETE action
195
   */
196 2246 sgarg
  public String generate(String docid, String rev, String action)
197
                throws AccessionNumberException, SQLException
198 576 bojilova
  {
199
    try {
200
      // INSERT
201
      if ( action.equals("INSERT")) {
202
203 734 bojilova
        // get a new docid
204
        if ( docid == null ) {
205 618 bojilova
          String sitecode = getSitecode();
206 758 bojilova
          String uniqueid = getUniqueID(sitecode);
207 576 bojilova
208 618 bojilova
          return sitecode + sep + uniqueid;
209
210 734 bojilova
        // docid is used; throw an exception to prevent the insertion
211
        } else if ( accNumberUsed(docid) ) {
212
          throw new AccessionNumberException
213 2253 sgarg
                    ("Accession number " + docid + " is already in use");
214 734 bojilova
        // rev is <> 1; throw an exception to prevent the insertion
215
        } else if ( !rev.equals("1") ) {
216
          throw new AccessionNumberException
217 2253 sgarg
                    ("Revision number must be 1");
218 734 bojilova
        // docid is not used and rev=1; return it
219 576 bojilova
        } else {
220 734 bojilova
          return docid;
221 576 bojilova
        }
222
223
      // UPDATE or DELETE
224
      } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
225
226
        // Accession# is not provided; throw an exception to prevent the action
227 734 bojilova
        if ( docid == null ) {
228 2253 sgarg
          throw new AccessionNumberException("Accession number is required");
229 576 bojilova
230
        // Accession# is not current (not in xml_documents); throw an exception
231 734 bojilova
        } else if ( !accNumberIsCurrent(docid) ) {
232 576 bojilova
          throw new AccessionNumberException
233 734 bojilova
          ("Document not found for Accession number " + docid);
234 576 bojilova
235 734 bojilova
        // Revision number is not the recent one; throw an exception
236
        } else if ( !rev.equals(getLastRevision(docid)) ) {
237
          throw new AccessionNumberException
238 2253 sgarg
          ("Revision number must be the recent");
239 734 bojilova
240 576 bojilova
        // Accession# is current (present in xml_documents); return it
241
        } else {
242 734 bojilova
          return docid;
243 576 bojilova
        }
244
      }
245 2246 sgarg
246 576 bojilova
    } catch (SQLException e) {
247
      throw new SQLException
248 734 bojilova
      ("Error on AccessionNumber.generate(): " + e.getMessage());
249 2246 sgarg
    }
250
251 576 bojilova
    // never comes here
252
    throw new
253 2253 sgarg
    AccessionNumberException("Fatal Error in accession number generation");
254 576 bojilova
  }
255 2246 sgarg
256 618 bojilova
  // get local sitecode
257
  private String getSitecode()
258 576 bojilova
  {
259 618 bojilova
    return this.sitecode;
260 576 bojilova
  }
261
262 618 bojilova
  // get Unique ID from DB sequence
263 758 bojilova
  private String getUniqueID (String sitecode) throws SQLException
264 576 bojilova
  {
265 618 bojilova
    String uniqueid;
266 758 bojilova
    String sysdate = dbAdapter.getDateTimeFunction();
267 1215 tao
    DBConnection conn = null;
268
    int serialNumber = -1;
269 576 bojilova
    try {
270 1215 tao
      PreparedStatement pstmt = null;
271 2246 sgarg
272 1215 tao
      //check out DBConnection
273
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getUniqueID");
274
      serialNumber=conn.getCheckOutSerialNumber();
275 576 bojilova
      pstmt = conn.prepareStatement
276 758 bojilova
              ("INSERT INTO accession_number (site_code, date_created) " +
277
               "VALUES (?, " + sysdate + ")");
278
      pstmt.setString(1, sitecode);
279 576 bojilova
      pstmt.execute();
280
      pstmt.close();
281 2246 sgarg
282 1215 tao
      uniqueid = "" + dbAdapter.getUniqueID(conn.getConnections(),
283
                                                          "accession_number");
284
      //because we only count the connection usage one when it check in
285
      //but it use twice. So we need to increase one
286
      conn.increaseUsageCount(1);
287 758 bojilova
288 576 bojilova
    } catch (SQLException e) {
289 2246 sgarg
      throw new
290 618 bojilova
      SQLException("Error on AccessionNumber.getUniqueID(): "+e.getMessage());
291 576 bojilova
    }
292 1215 tao
    finally
293
    {
294
      DBConnectionPool.returnDBConnection(conn, serialNumber);
295
    }
296 618 bojilova
    return uniqueid;
297 576 bojilova
  }
298
299 459 bojilova
  /** check for existence of Accesssion Number xml_acc_numbers table */
300 2164 tao
  public static boolean accNumberUsed ( String accNumber )
301 576 bojilova
                  throws SQLException {
302 2246 sgarg
303 459 bojilova
    boolean hasAccNumber = false;
304 1215 tao
    DBConnection conn = null;
305
    int serialNumber = -1;
306 2246 sgarg
307 459 bojilova
    try {
308 1215 tao
      PreparedStatement pstmt = null;
309
      //check out DBConnection
310
      conn=DBConnectionPool.getDBConnection("AccessionNumber.accNumberUsed");
311
      serialNumber=conn.getCheckOutSerialNumber();
312 459 bojilova
      pstmt = conn.prepareStatement(
313 2246 sgarg
                "SELECT 'x' FROM xml_documents " +
314 770 bojilova
                "WHERE docid = ? " +
315 576 bojilova
                "UNION " +
316
                "SELECT 'x' FROM xml_revisions " +
317 770 bojilova
                "WHERE docid = ?");
318 576 bojilova
      pstmt.setString(1,accNumber);
319
      pstmt.setString(2,accNumber);
320 459 bojilova
      pstmt.execute();
321
      ResultSet rs = pstmt.getResultSet();
322
      hasAccNumber = rs.next();
323
      pstmt.close();
324 2246 sgarg
325 459 bojilova
    } catch (SQLException e) {
326 576 bojilova
      throw new SQLException
327
      ("Error on AccessionNumber.accNumberUsed(accNumber): " + e.getMessage());
328 1215 tao
    }
329
    finally
330
    {
331
      DBConnectionPool.returnDBConnection(conn, serialNumber);
332
    }
333 2246 sgarg
334 459 bojilova
    return hasAccNumber;
335 2246 sgarg
  }
336
337 734 bojilova
  // check for existence of Accesssion Number in xml_documents table
338 459 bojilova
  private boolean accNumberIsCurrent(String accNumber) throws SQLException {
339 2246 sgarg
340 459 bojilova
    boolean hasCurrentAccNumber = false;
341 1215 tao
    DBConnection conn = null;
342
    int serialNumber = -1;
343 2246 sgarg
344 459 bojilova
    try {
345 1215 tao
      PreparedStatement pstmt = null;
346
      //check out DBConnection
347
      conn=DBConnectionPool.getDBConnection("AccessionNumber.accNumberIsCurre");
348
      serialNumber=conn.getCheckOutSerialNumber();
349 459 bojilova
      pstmt = conn.prepareStatement(
350 2246 sgarg
                "SELECT 'x' FROM xml_documents " +
351 770 bojilova
                "WHERE docid = ?");
352 459 bojilova
      pstmt.setString(1, accNumber);
353
      pstmt.execute();
354
      ResultSet rs = pstmt.getResultSet();
355
      hasCurrentAccNumber = rs.next();
356
      pstmt.close();
357 2246 sgarg
358 459 bojilova
    } catch (SQLException e) {
359
      throw new SQLException(
360
          "Error on AccessionNumber.accNumberIsCurrent(String accNumber): " +
361
          e.getMessage());
362 1215 tao
    }
363
    finally
364
    {
365
      DBConnectionPool.returnDBConnection(conn, serialNumber);
366
    }
367 2246 sgarg
368 459 bojilova
    return hasCurrentAccNumber;
369 2246 sgarg
  }
370 203 jones
371 734 bojilova
  // get the recent revision number for docid
372
  private String getLastRevision(String docid) throws SQLException
373
  {
374
    String rev = "";
375 1215 tao
    DBConnection conn = null;
376
    int serialNumber = -1;
377 2246 sgarg
378 734 bojilova
    try {
379 1215 tao
      PreparedStatement pstmt = null;
380
      //check out DBConnection
381
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getLastRevision");
382
      serialNumber=conn.getCheckOutSerialNumber();
383 734 bojilova
      pstmt = conn.prepareStatement
384
              ("SELECT rev FROM xml_documents WHERE docid='" + docid + "'");
385
      pstmt.execute();
386
387
      ResultSet rs = pstmt.getResultSet();
388
      boolean hasRow = rs.next();
389
      rev = rs.getString(1);
390
      pstmt.close();
391 2246 sgarg
392 734 bojilova
    } catch (SQLException e) {
393
      throw new SQLException(
394
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
395
    }
396 1215 tao
    finally
397
    {
398
      DBConnectionPool.returnDBConnection(conn,serialNumber);
399
    }
400 734 bojilova
401
    return rev;
402
  }
403 2246 sgarg
404 954 tao
  /**
405
    * Get last revision number from database for a docid
406
    * The return value is integer because we want compare it to there new one
407
    * @param docid <sitecode>.<uniqueid> part of Accession Number
408
    */
409
  private int getLastRevisionNumber(String docId) throws SQLException
410
  {
411
    int rev = 1;
412 1215 tao
    DBConnection conn =null;
413
    int serialNumber = -1;
414 2246 sgarg
415 954 tao
    try {
416 1215 tao
      PreparedStatement pStmt = null;
417
      //check out DBConnection
418
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getLastRevisionN");
419
      serialNumber=conn.getCheckOutSerialNumber();
420 2246 sgarg
421 954 tao
      pStmt = conn.prepareStatement
422
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
423
      pStmt.execute();
424 734 bojilova
425 954 tao
      ResultSet rs = pStmt.getResultSet();
426
      boolean hasRow = rs.next();
427
      rev = rs.getInt(1);
428
      pStmt.close();
429 2246 sgarg
430 954 tao
    } catch (SQLException e) {
431
      throw new SQLException(
432
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
433
    }
434 1215 tao
    finally
435
    {
436
      DBConnectionPool.returnDBConnection(conn,serialNumber);
437
    }
438 954 tao
    return rev;
439
  }
440 2246 sgarg
441 779 bojilova
  // get the next revision number for docid
442
  private String getNextRevision(String docid) throws SQLException
443
  {
444
    String rev = "";
445 1215 tao
    DBConnection conn = null;
446
    int serialNumber = -1;
447 779 bojilova
    try {
448 1215 tao
      PreparedStatement pstmt = null;
449
      //check out DBConnection
450
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getNextRevision");
451
      serialNumber=conn.getCheckOutSerialNumber();
452 779 bojilova
      pstmt = conn.prepareStatement
453
              ("SELECT rev+1 FROM xml_documents WHERE docid='" + docid + "'");
454
      pstmt.execute();
455
456
      ResultSet rs = pstmt.getResultSet();
457
      boolean hasRow = rs.next();
458
      rev = rs.getString(1);
459
      pstmt.close();
460 2246 sgarg
461 779 bojilova
    } catch (SQLException e) {
462
      throw new SQLException(
463
      "Error on AccessionNumber.getNextRevision(): " + e.getMessage());
464
    }
465 1215 tao
    finally
466
    {
467
      DBConnectionPool.returnDBConnection(conn, serialNumber);
468
    }
469 779 bojilova
470
    return rev;
471
  }
472 2246 sgarg
473 779 bojilova
  /**
474
   * returns the docid encoded in this accession number
475
   */
476
  public String getDocid() {
477
478
    return this.docid;
479
  }
480
481
  /**
482
   * returns the revision number encoded in this accession number
483
   */
484
  public String getRev()
485
  {
486
    return this.rev;
487
  }
488 2246 sgarg
489 203 jones
}