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: sgarg $'
11
 *     '$Date: 2004-08-24 15:35:02 -0700 (Tue, 24 Aug 2004) $'
12
 * '$Revision: 2253 $'
13
 *
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
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

    
31
import java.net.*;
32
import java.sql.*;
33

    
34
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
35

    
36
/**
37
 * (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
 */
44
public class AccessionNumber  {
45

    
46
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
47

    
48
  //private Connection conn = null;
49
  private String sitecode = null;
50
  private String sep = null;
51
  private String docid = null;
52
  private String rev = null;
53

    
54
  /**
55
   * Construct an AccessionNumber
56
   */
57
  //public AccessionNumber ()
58
         //throws SQLException, ClassNotFoundException
59
  //{
60
    // Open a connection to the database from here
61
    //this((new MetaCatUtil()).openDBConnection());
62
  //}
63

    
64
  /**
65
   * Construct an AccessionNumber
66
   *
67
   * @param conn the db connection to read from and write Accession# to
68
   */
69
  public AccessionNumber ()
70
  {
71
    this.sitecode = MetaCatUtil.getOption("sitecode");
72
    this.sep = MetaCatUtil.getOption("accNumSeparator");
73
    //this.conn = conn;
74
  }
75

    
76
  /** 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
  public AccessionNumber (String accnum, String action)
83
           throws AccessionNumberException, SQLException, NumberFormatException
84
 {
85
    this();
86

    
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
        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
      // check accession number for validness
113
      if ( docid == null ) {
114
        throw new AccessionNumberException("Accession number is required");
115

    
116
      // rev is not provided; throw an exception to prevent the insertion
117
      } else if ( rev == null ) {
118
        throw new AccessionNumberException
119
                  ("Revision number is required");
120

    
121
      // docid is used; throw an exception to prevent the insertion
122
      } else if ( accNumberUsed(docid) ) {
123
        throw new AccessionNumberException
124
                  ("Accession number " + docid + " is already in use");
125

    
126
      // rev is <> 1; throw an exception to prevent the insertion
127
      } /*else if ( !rev.equals("1")) {
128
        throw new AccessionNumberException("Revision number must be 1");
129
      }*/
130

    
131
    // UPDATE or DELETE
132
    } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
133
      String l_rev = "";
134

    
135
      int reversionNumber = 1;
136

    
137
      if(rev != null){
138
          try{
139
              reversionNumber = Integer.parseInt(rev);
140
          } catch (java.lang.NumberFormatException e){
141
              throw new AccessionNumberException(
142
                      "Revision number is required");
143
          }
144
      }
145

    
146
      // Accession# is not provided; throw an exception to prevent the action
147
      if ( docid == null ) {
148
        throw new AccessionNumberException("Accession number is required");
149

    
150
      // rev is not provided; throw an exception to prevent the action
151
      } else if ( rev == null ) {
152
        throw new AccessionNumberException
153
                  ("Revision number is required");
154

    
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
      //Revision number is less than or equal the recent one; throw a exception
161
      } else if ( action.equals("UPDATE") &&
162
                  reversionNumber <= getLastRevisionNumber(docid) ) {
163
        throw new AccessionNumberException
164
                 ("Next revision number couldn't be less than or equal "
165
                                              + getLastRevisionNumber(docid));
166

    
167
      // Revision number is not the recent one; throw an exception
168
      } else if ( action.equals("DELETE") &&
169
                  !rev.equals(l_rev = getLastRevision(docid)) ) {
170
        throw new AccessionNumberException
171
                  ("Last revision number is "+ l_rev);
172
      }
173
    }
174
  }
175

    
176
  /**
177
   * 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
   */
183
  public String generate(String docid, String action)
184
                throws AccessionNumberException, SQLException
185
  {
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
  public String generate(String docid, String rev, String action)
197
                throws AccessionNumberException, SQLException
198
  {
199
    try {
200
      // INSERT
201
      if ( action.equals("INSERT")) {
202

    
203
        // get a new docid
204
        if ( docid == null ) {
205
          String sitecode = getSitecode();
206
          String uniqueid = getUniqueID(sitecode);
207

    
208
          return sitecode + sep + uniqueid;
209

    
210
        // docid is used; throw an exception to prevent the insertion
211
        } else if ( accNumberUsed(docid) ) {
212
          throw new AccessionNumberException
213
                    ("Accession number " + docid + " is already in use");
214
        // rev is <> 1; throw an exception to prevent the insertion
215
        } else if ( !rev.equals("1") ) {
216
          throw new AccessionNumberException
217
                    ("Revision number must be 1");
218
        // docid is not used and rev=1; return it
219
        } else {
220
          return docid;
221
        }
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
        if ( docid == null ) {
228
          throw new AccessionNumberException("Accession number is required");
229

    
230
        // Accession# is not current (not in xml_documents); throw an exception
231
        } else if ( !accNumberIsCurrent(docid) ) {
232
          throw new AccessionNumberException
233
          ("Document not found for Accession number " + docid);
234

    
235
        // Revision number is not the recent one; throw an exception
236
        } else if ( !rev.equals(getLastRevision(docid)) ) {
237
          throw new AccessionNumberException
238
          ("Revision number must be the recent");
239

    
240
        // Accession# is current (present in xml_documents); return it
241
        } else {
242
          return docid;
243
        }
244
      }
245

    
246
    } catch (SQLException e) {
247
      throw new SQLException
248
      ("Error on AccessionNumber.generate(): " + e.getMessage());
249
    }
250

    
251
    // never comes here
252
    throw new
253
    AccessionNumberException("Fatal Error in accession number generation");
254
  }
255

    
256
  // get local sitecode
257
  private String getSitecode()
258
  {
259
    return this.sitecode;
260
  }
261

    
262
  // get Unique ID from DB sequence
263
  private String getUniqueID (String sitecode) throws SQLException
264
  {
265
    String uniqueid;
266
    String sysdate = dbAdapter.getDateTimeFunction();
267
    DBConnection conn = null;
268
    int serialNumber = -1;
269
    try {
270
      PreparedStatement pstmt = null;
271

    
272
      //check out DBConnection
273
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getUniqueID");
274
      serialNumber=conn.getCheckOutSerialNumber();
275
      pstmt = conn.prepareStatement
276
              ("INSERT INTO accession_number (site_code, date_created) " +
277
               "VALUES (?, " + sysdate + ")");
278
      pstmt.setString(1, sitecode);
279
      pstmt.execute();
280
      pstmt.close();
281

    
282
      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

    
288
    } catch (SQLException e) {
289
      throw new
290
      SQLException("Error on AccessionNumber.getUniqueID(): "+e.getMessage());
291
    }
292
    finally
293
    {
294
      DBConnectionPool.returnDBConnection(conn, serialNumber);
295
    }
296
    return uniqueid;
297
  }
298

    
299
  /** check for existence of Accesssion Number xml_acc_numbers table */
300
  public static boolean accNumberUsed ( String accNumber )
301
                  throws SQLException {
302

    
303
    boolean hasAccNumber = false;
304
    DBConnection conn = null;
305
    int serialNumber = -1;
306

    
307
    try {
308
      PreparedStatement pstmt = null;
309
      //check out DBConnection
310
      conn=DBConnectionPool.getDBConnection("AccessionNumber.accNumberUsed");
311
      serialNumber=conn.getCheckOutSerialNumber();
312
      pstmt = conn.prepareStatement(
313
                "SELECT 'x' FROM xml_documents " +
314
                "WHERE docid = ? " +
315
                "UNION " +
316
                "SELECT 'x' FROM xml_revisions " +
317
                "WHERE docid = ?");
318
      pstmt.setString(1,accNumber);
319
      pstmt.setString(2,accNumber);
320
      pstmt.execute();
321
      ResultSet rs = pstmt.getResultSet();
322
      hasAccNumber = rs.next();
323
      pstmt.close();
324

    
325
    } catch (SQLException e) {
326
      throw new SQLException
327
      ("Error on AccessionNumber.accNumberUsed(accNumber): " + e.getMessage());
328
    }
329
    finally
330
    {
331
      DBConnectionPool.returnDBConnection(conn, serialNumber);
332
    }
333

    
334
    return hasAccNumber;
335
  }
336

    
337
  // check for existence of Accesssion Number in xml_documents table
338
  private boolean accNumberIsCurrent(String accNumber) throws SQLException {
339

    
340
    boolean hasCurrentAccNumber = false;
341
    DBConnection conn = null;
342
    int serialNumber = -1;
343

    
344
    try {
345
      PreparedStatement pstmt = null;
346
      //check out DBConnection
347
      conn=DBConnectionPool.getDBConnection("AccessionNumber.accNumberIsCurre");
348
      serialNumber=conn.getCheckOutSerialNumber();
349
      pstmt = conn.prepareStatement(
350
                "SELECT 'x' FROM xml_documents " +
351
                "WHERE docid = ?");
352
      pstmt.setString(1, accNumber);
353
      pstmt.execute();
354
      ResultSet rs = pstmt.getResultSet();
355
      hasCurrentAccNumber = rs.next();
356
      pstmt.close();
357

    
358
    } catch (SQLException e) {
359
      throw new SQLException(
360
          "Error on AccessionNumber.accNumberIsCurrent(String accNumber): " +
361
          e.getMessage());
362
    }
363
    finally
364
    {
365
      DBConnectionPool.returnDBConnection(conn, serialNumber);
366
    }
367

    
368
    return hasCurrentAccNumber;
369
  }
370

    
371
  // get the recent revision number for docid
372
  private String getLastRevision(String docid) throws SQLException
373
  {
374
    String rev = "";
375
    DBConnection conn = null;
376
    int serialNumber = -1;
377

    
378
    try {
379
      PreparedStatement pstmt = null;
380
      //check out DBConnection
381
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getLastRevision");
382
      serialNumber=conn.getCheckOutSerialNumber();
383
      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

    
392
    } catch (SQLException e) {
393
      throw new SQLException(
394
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
395
    }
396
    finally
397
    {
398
      DBConnectionPool.returnDBConnection(conn,serialNumber);
399
    }
400

    
401
    return rev;
402
  }
403

    
404
  /**
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
    DBConnection conn =null;
413
    int serialNumber = -1;
414

    
415
    try {
416
      PreparedStatement pStmt = null;
417
      //check out DBConnection
418
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getLastRevisionN");
419
      serialNumber=conn.getCheckOutSerialNumber();
420

    
421
      pStmt = conn.prepareStatement
422
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
423
      pStmt.execute();
424

    
425
      ResultSet rs = pStmt.getResultSet();
426
      boolean hasRow = rs.next();
427
      rev = rs.getInt(1);
428
      pStmt.close();
429

    
430
    } catch (SQLException e) {
431
      throw new SQLException(
432
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
433
    }
434
    finally
435
    {
436
      DBConnectionPool.returnDBConnection(conn,serialNumber);
437
    }
438
    return rev;
439
  }
440

    
441
  // get the next revision number for docid
442
  private String getNextRevision(String docid) throws SQLException
443
  {
444
    String rev = "";
445
    DBConnection conn = null;
446
    int serialNumber = -1;
447
    try {
448
      PreparedStatement pstmt = null;
449
      //check out DBConnection
450
      conn=DBConnectionPool.getDBConnection("AccessionNumber.getNextRevision");
451
      serialNumber=conn.getCheckOutSerialNumber();
452
      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

    
461
    } catch (SQLException e) {
462
      throw new SQLException(
463
      "Error on AccessionNumber.getNextRevision(): " + e.getMessage());
464
    }
465
    finally
466
    {
467
      DBConnectionPool.returnDBConnection(conn, serialNumber);
468
    }
469

    
470
    return rev;
471
  }
472

    
473
  /**
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

    
489
}
(6-6/63)