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: bojilova $'
11
 *     '$Date: 2001-06-12 10:15:49 -0700 (Tue, 12 Jun 2001) $'
12
 * '$Revision: 779 $'
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 
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

    
125
      // Accession# is not provided; throw an exception to prevent the action
126
      if ( docid == null ) {
127
        throw new AccessionNumberException("Accession number is required.");
128

    
129
      // rev is not provided; throw an exception to prevent the action
130
      } else if ( rev == null ) {
131
        throw new AccessionNumberException
132
                  ("Revision number is required.");
133

    
134
      // Accession# is not current (not in xml_documents); throw an exception
135
      } else if ( !accNumberIsCurrent(docid) ) {
136
        throw new AccessionNumberException
137
                  ("Document not found for Accession number " + docid);
138

    
139
      // Revision number is not the recent one; throw an exception
140
      } else if ( action.equals("UPDATE") &&
141
                  !rev.equals(l_rev = getNextRevision(docid)) ) {
142
        throw new AccessionNumberException
143
                  ("Next revision number must be "+ l_rev);
144

    
145
      // Revision number is not the recent one; throw an exception
146
      } else if ( action.equals("DELETE") && 
147
                  !rev.equals(l_rev = getLastRevision(docid)) ) {
148
        throw new AccessionNumberException
149
                  ("Last revision number is "+ l_rev);
150
      }
151
    }
152
  }
153

    
154
  /**
155
   * Generate an Accession Number of form <sidecode>.<uniqueid>.<revisionid>
156
   * where <revisionid> is always 1.
157
   *
158
   * @param docid <sitecode>.<uniqueid> part of Accession Number
159
   * @param action INSERT, UPDATE or DELETE action
160
   */
161
  public String generate(String docid, String action) 
162
                throws AccessionNumberException, SQLException 
163
  {
164
    return generate(docid, "1", action);
165
  }
166

    
167
  /**
168
   * Generate an Accession Number of form <sidecode>.<uniqueid>.<revisionid>
169
   *
170
   * @param docid <sitecode>.<uniqueid> part of Accession Number
171
   * @param rev <revisionid> of Accession Number
172
   * @param action INSERT, UPDATE or DELETE action
173
   */
174
  public String generate(String docid, String rev, String action) 
175
                throws AccessionNumberException, SQLException 
176
  {
177
    try {
178
      // INSERT
179
      if ( action.equals("INSERT")) {
180

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

    
186
          return sitecode + sep + uniqueid;
187

    
188
        // docid is used; throw an exception to prevent the insertion
189
        } else if ( accNumberUsed(docid) ) {
190
          throw new AccessionNumberException
191
                    ("Accession number " + docid + " is already in use.");
192
        // rev is <> 1; throw an exception to prevent the insertion
193
        } else if ( !rev.equals("1") ) {
194
          throw new AccessionNumberException
195
                    ("Revision number must be 1.");
196
        // docid is not used and rev=1; return it
197
        } else {
198
          return docid;
199
        }
200

    
201
      // UPDATE or DELETE
202
      } else if ( action.equals("UPDATE") || action.equals("DELETE")) {
203

    
204
        // Accession# is not provided; throw an exception to prevent the action
205
        if ( docid == null ) {
206
          throw new AccessionNumberException("Accession number is required.");
207

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

    
213
        // Revision number is not the recent one; throw an exception
214
        } else if ( !rev.equals(getLastRevision(docid)) ) {
215
          throw new AccessionNumberException
216
          ("Revision number must be the recent.");
217

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

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

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

    
262
    return uniqueid;
263
  }
264

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

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

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

    
340
    return rev;
341
  }
342

    
343
  // get the next revision number for docid
344
  private String getNextRevision(String docid) throws SQLException
345
  {
346
    String rev = "";
347
    
348
    try {
349
      PreparedStatement pstmt;
350
      pstmt = conn.prepareStatement
351
              ("SELECT rev+1 FROM xml_documents WHERE docid='" + docid + "'");
352
      pstmt.execute();
353

    
354
      ResultSet rs = pstmt.getResultSet();
355
      boolean hasRow = rs.next();
356
      rev = rs.getString(1);
357
      pstmt.close();
358
      
359
    } catch (SQLException e) {
360
      throw new SQLException(
361
      "Error on AccessionNumber.getNextRevision(): " + e.getMessage());
362
    }
363

    
364
    return rev;
365
  }
366
  
367
  /**
368
   * returns the docid encoded in this accession number
369
   */
370
  public String getDocid() {
371

    
372
    return this.docid;
373
  }
374

    
375
  /**
376
   * returns the revision number encoded in this accession number
377
   */
378
  public String getRev()
379
  {
380
    return this.rev;
381
  }
382
  
383
}
(2-2/40)