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: tao $'
11
 *     '$Date: 2002-03-05 11:28:32 -0800 (Tue, 05 Mar 2002) $'
12
 * '$Revision: 954 $'
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 (Connection conn) 
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 (Connection conn, String accnum, String action) 
83
           throws AccessionNumberException, SQLException, NumberFormatException
84
 {
85
    this(conn);
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
      // 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
      } else if ( !rev.equals("1") ) {
118
        throw new AccessionNumberException("Revision number must be 1.");
119
      }
120
          
121
    // UPDATE or DELETE
122
    } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
123
      String l_rev = "";
124
      int reversionNumber=Integer.parseInt(rev);
125

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

    
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
  /**
157
   * 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
   */
163
  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
  public String generate(String docid, String rev, String action) 
177
                throws AccessionNumberException, SQLException 
178
  {
179
    try {
180
      // INSERT
181
      if ( action.equals("INSERT")) {
182

    
183
        // get a new docid
184
        if ( docid == null ) {
185
          String sitecode = getSitecode();
186
          String uniqueid = getUniqueID(sitecode);
187

    
188
          return sitecode + sep + uniqueid;
189

    
190
        // 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
        } else {
200
          return docid;
201
        }
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
        if ( docid == null ) {
208
          throw new AccessionNumberException("Accession number is required.");
209

    
210
        // Accession# is not current (not in xml_documents); throw an exception
211
        } else if ( !accNumberIsCurrent(docid) ) {
212
          throw new AccessionNumberException
213
          ("Document not found for Accession number " + docid);
214

    
215
        // 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
        // Accession# is current (present in xml_documents); return it
221
        } else {
222
          return docid;
223
        }
224
      }
225
 
226
    } catch (SQLException e) {
227
      throw new SQLException
228
      ("Error on AccessionNumber.generate(): " + e.getMessage());
229
    }    
230
 
231
    // never comes here
232
    throw new
233
    AccessionNumberException("Fatal Error in accession number generation.");
234
  }
235
  
236
  // get local sitecode
237
  private String getSitecode()
238
  {
239
    return this.sitecode;
240
  }
241

    
242
  // get Unique ID from DB sequence
243
  private String getUniqueID (String sitecode) throws SQLException
244
  {
245
    String uniqueid;
246
    String sysdate = dbAdapter.getDateTimeFunction();
247
    
248
    try {
249
      PreparedStatement pstmt;
250
      pstmt = conn.prepareStatement
251
              ("INSERT INTO accession_number (site_code, date_created) " +
252
               "VALUES (?, " + sysdate + ")");
253
      pstmt.setString(1, sitecode);
254
      pstmt.execute();
255
      pstmt.close();
256
      
257
      uniqueid = "" + dbAdapter.getUniqueID(conn, "accession_number");
258

    
259
    } catch (SQLException e) {
260
      throw new 
261
      SQLException("Error on AccessionNumber.getUniqueID(): "+e.getMessage());
262
    }
263

    
264
    return uniqueid;
265
  }
266

    
267
  /** check for existence of Accesssion Number xml_acc_numbers table */
268
  public boolean accNumberUsed ( String accNumber )
269
                  throws SQLException {
270
        
271
    boolean hasAccNumber = false;
272
        
273
    try {
274
      PreparedStatement pstmt;
275
      pstmt = conn.prepareStatement(
276
                "SELECT 'x' FROM xml_documents " + 
277
                "WHERE docid = ? " +
278
                "UNION " +
279
                "SELECT 'x' FROM xml_revisions " +
280
                "WHERE docid = ?");
281
      pstmt.setString(1,accNumber);
282
      pstmt.setString(2,accNumber);
283
      pstmt.execute();
284
      ResultSet rs = pstmt.getResultSet();
285
      hasAccNumber = rs.next();
286
      pstmt.close();
287
            
288
    } catch (SQLException e) {
289
      throw new SQLException
290
      ("Error on AccessionNumber.accNumberUsed(accNumber): " + e.getMessage());
291
    }    
292
        
293
    return hasAccNumber;
294
  }    
295
    
296
  // check for existence of Accesssion Number in xml_documents table
297
  private boolean accNumberIsCurrent(String accNumber) throws SQLException {
298
        
299
    boolean hasCurrentAccNumber = false;
300
        
301
    try {
302
      PreparedStatement pstmt;
303
      pstmt = conn.prepareStatement(
304
                "SELECT 'x' FROM xml_documents " + 
305
                "WHERE docid = ?");
306
      pstmt.setString(1, accNumber);
307
      pstmt.execute();
308
      ResultSet rs = pstmt.getResultSet();
309
      hasCurrentAccNumber = rs.next();
310
      pstmt.close();
311
            
312
    } catch (SQLException e) {
313
      throw new SQLException(
314
          "Error on AccessionNumber.accNumberIsCurrent(String accNumber): " +
315
          e.getMessage());
316
    }    
317
  
318
    return hasCurrentAccNumber;
319
  }    
320

    
321
  // get the recent revision number for docid
322
  private String getLastRevision(String docid) throws SQLException
323
  {
324
    String rev = "";
325
    
326
    try {
327
      PreparedStatement pstmt;
328
      pstmt = conn.prepareStatement
329
              ("SELECT rev FROM xml_documents WHERE docid='" + docid + "'");
330
      pstmt.execute();
331

    
332
      ResultSet rs = pstmt.getResultSet();
333
      boolean hasRow = rs.next();
334
      rev = rs.getString(1);
335
      pstmt.close();
336
      
337
    } catch (SQLException e) {
338
      throw new SQLException(
339
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
340
    }
341

    
342
    return rev;
343
  }
344
  
345
  /**
346
    * Get last revision number from database for a docid
347
    * The return value is integer because we want compare it to there new one
348
    * @param docid <sitecode>.<uniqueid> part of Accession Number
349
    */
350
  private int getLastRevisionNumber(String docId) throws SQLException
351
  {
352
    int rev = 1;
353
    
354
    try {
355
      PreparedStatement pStmt;
356
      pStmt = conn.prepareStatement
357
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
358
      pStmt.execute();
359

    
360
      ResultSet rs = pStmt.getResultSet();
361
      boolean hasRow = rs.next();
362
      rev = rs.getInt(1);
363
      pStmt.close();
364
      
365
    } catch (SQLException e) {
366
      throw new SQLException(
367
      "Error on AccessionNumber.getLastRevision(): " + e.getMessage());
368
    }
369

    
370
    return rev;
371
  }
372
  
373
  // get the next revision number for docid
374
  private String getNextRevision(String docid) throws SQLException
375
  {
376
    String rev = "";
377
    
378
    try {
379
      PreparedStatement pstmt;
380
      pstmt = conn.prepareStatement
381
              ("SELECT rev+1 FROM xml_documents WHERE docid='" + docid + "'");
382
      pstmt.execute();
383

    
384
      ResultSet rs = pstmt.getResultSet();
385
      boolean hasRow = rs.next();
386
      rev = rs.getString(1);
387
      pstmt.close();
388
      
389
    } catch (SQLException e) {
390
      throw new SQLException(
391
      "Error on AccessionNumber.getNextRevision(): " + e.getMessage());
392
    }
393

    
394
    return rev;
395
  }
396
  
397
  /**
398
   * returns the docid encoded in this accession number
399
   */
400
  public String getDocid() {
401

    
402
    return this.docid;
403
  }
404

    
405
  /**
406
   * returns the revision number encoded in this accession number
407
   */
408
  public String getRev()
409
  {
410
    return this.rev;
411
  }
412
  
413
}
(2-2/41)