001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2016-07-19 06:26:44 +0000 (Tue, 19 Jul 2016) $' 007 * '$Revision: 34509 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.objectmanager.lsid; 031 032import java.sql.PreparedStatement; 033import java.sql.ResultSet; 034import java.sql.SQLException; 035import java.sql.Statement; 036 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039import org.kepler.configuration.ConfigurationManager; 040import org.kepler.configuration.ConfigurationProperty; 041import org.kepler.util.AuthNamespace; 042import org.kepler.util.sql.DatabaseFactory; 043import org.kepler.util.sql.DatabaseType; 044 045import ptolemy.util.MessageHandler; 046 047/** 048 * This class maintains a list of LSIDs in the system and can generate new LSIDs 049 * that are unique to the local system. 050 * 051 *@created June 20, 2005 052 */ 053 054public class LSIDGenerator { 055 056 private static final Log log = LogFactory.getLog(LSIDGenerator.class 057 .getName()); 058 private static final boolean isDebugging = log.isDebugEnabled(); 059 060 // singleton instance 061 private static LSIDGenerator generator = null; 062 063 /** The AuthNamespace object. */ 064 private AuthNamespace _authNamespace; 065 066 /** The name of the lsid generator table. */ 067 private static final String LSID_GENERATOR_TABLE_NAME = "LSID_GENERATOR"; 068 069 /** SQL to create the lsid generator table. 070 * 071 * FIXME convert to org.kepler.util.sql.Schema to support non-HSQL dbs 072 * 073 * The LSID_GENERATOR table is used to record the highest Revision for an 074 * object ID that has been generated by this Kepler instance for a specific 075 * authority and namespace. 076 * AUTH - the Authority 077 * NS - the NameSpace 078 * OID - the highest Object ID assigned by this Kepler instance 079 * REV - the highest Revision assigned by this Kepler instance 080 */ 081 private static final String LSID_GENERATOR_TABLE_CREATE_SQL = 082 "create cached table LSID_GENERATOR (AUTH varchar, NS varchar, " + 083 "OID bigint, REV bigint, PRIMARY KEY (AUTH,NS,OID) )"; 084 085 /** The database. */ 086 private static DatabaseType _dbType; 087 088 /** 089 * Convenience reference. Make sure to close your ResultSets since we're 090 * reusing the Statement. 091 */ 092 private static Statement _stmt; 093 094 private static PreparedStatement _insertPrepStmt; 095 private static PreparedStatement _updatePrepStmt; 096 097 /** The name of the database. */ 098 public static final String CORE_DB_STR = "coreDB"; 099 100 /** Builds a new instance of the LSIDGenerator. NOTE: the 101 * constructor is private so that only one instance may be created. 102 */ 103 private LSIDGenerator() throws Exception { 104 105 openDatabase(); 106 107 // Every time we get a new connection to the LSID_GENERATOR 108 // table, check it to make sure the current AuthorizedNamespace 109 // has at least one row in it, if it does not, get a new 110 // AuthorizedNamespace (this means the LSID_GENERATOR table was 111 // deleted somehow 112 int rows = countRowsForCurrentAuthNamespace(); 113 if (rows <= 0) { 114 AuthNamespace an = AuthNamespace.getInstance(); 115 an.getNewAuthorizedNamespace(); 116 } 117 118 _authNamespace = AuthNamespace.getInstance(); 119 120 } 121 122 /** 123 * returns a singleton instance of this class 124 */ 125 public static synchronized LSIDGenerator getInstance() { 126 if (generator == null) { 127 try { 128 generator = new LSIDGenerator(); 129 } catch (Exception e) { 130 MessageHandler.error("Error creating LSID generator.", e); 131 } 132 } 133 return generator; 134 } 135 136 /** 137 * Return a new LSID using the Authority and Namespace for this Kepler 138 * Instance and the NextObjectID for this instance with a revision number of 139 * 1. 140 * 141 * @return a new KeplerLSID that is globally unique 142 * @throws Exception 143 */ 144 public synchronized KeplerLSID getNewLSID() throws Exception { 145 if (isDebugging) 146 log.debug("getNewLSID()"); 147 148 KeplerLSID lsid = null; 149 150 Long nextObjectID = getNextObjectID(); 151 152 lsid = new KeplerLSID(_authNamespace.getAuthority(), _authNamespace 153 .getNamespace(), nextObjectID, Long.valueOf(1)); 154 155 boolean success = recordLsidGeneration(lsid); 156 if (success) { 157 if (isDebugging) 158 log.debug("newLSID: " + lsid); 159 return lsid; 160 } 161 return null; 162 } 163 164 /** 165 * Update the revision of a KeplerLSID. 166 * 167 * @param lsid 168 * @return 169 */ 170 public synchronized KeplerLSID updateLsidRevision(KeplerLSID lsid) { 171 if (isDebugging) 172 log.debug("updateLsidRevision("+lsid.toString()+")"); 173 174 if ( !lsid.getAuthority().equals(_authNamespace.getAuthority()) 175 || !lsid.getNamespace().equals(_authNamespace.getNamespace())) { 176 return null; 177 } 178 179 try { 180 Long lastRevision = null; 181 182 // FIXME make a prepared statement 183 String query = "select REV from " + LSID_GENERATOR_TABLE_NAME 184 + " where auth = '" + lsid.getAuthority() + "' " 185 + " and ns = '" + lsid.getNamespace() + "' " 186 + " and oid = " + lsid.getObject(); 187 if (isDebugging) log.debug(query); 188 ResultSet rs = null; 189 try { 190 rs = _stmt.executeQuery(query); 191 if (rs == null) 192 throw new SQLException("Query Failed: " + query); 193 if (rs.next()) { 194 lastRevision = rs.getLong(1); 195 if (rs.wasNull()) 196 throw new SQLException("Last Revision was Null"); 197 if (rs.next()) 198 throw new SQLException(LSID_GENERATOR_TABLE_NAME 199 + " table is corrupt"); 200 } 201 } finally { 202 if (rs != null) { 203 rs.close(); 204 } 205 } 206 207 // FIXME lastRevision could be null 208 lsid.setRevision(lastRevision + 1L); 209 210 _updatePrepStmt.setLong(1, lsid.getRevision()); 211 _updatePrepStmt.setString(2, lsid.getAuthority()); 212 _updatePrepStmt.setString(3, lsid.getNamespace()); 213 _updatePrepStmt.setLong(4, lsid.getObject()); 214 _updatePrepStmt.executeUpdate(); 215 _updatePrepStmt.clearParameters(); 216 217 //_conn.commit(); 218 219 } catch (SQLException e) { 220 e.printStackTrace(); 221 } 222 223 return lsid; 224 225 } 226 227 /** 228 * Record the generation of a new LSID in the LSID_GENERATOR table. 229 * 230 * @param lsid 231 * @return 232 */ 233 private boolean recordLsidGeneration(KeplerLSID lsid) { 234 if (isDebugging) 235 log.debug("recordLsidGeneration(" + lsid.toString() + ")"); 236 boolean success = false; 237 238 try { 239 insertRow(lsid.getAuthority(), lsid.getNamespace(), lsid 240 .getObject(), lsid.getRevision()); 241 success = true; 242 } catch (Exception e) { 243 e.printStackTrace(); 244 } 245 246 return success; 247 } 248 249 /** Insert a row into the LSID generator table. */ 250 public static synchronized void insertRow(String authority, String namespace, 251 long object, long revision) throws Exception { 252 253 // since this method is static, make sure the database has 254 // been opened and prepared statements created. 255 if(_dbType == null) { 256 openDatabase(); 257 } 258 259 try { 260 _insertPrepStmt.clearParameters(); 261 _insertPrepStmt.setString(1, authority); 262 _insertPrepStmt.setString(2, namespace); 263 _insertPrepStmt.setLong(3, object); 264 _insertPrepStmt.setLong(4, revision); 265 _insertPrepStmt.executeUpdate(); 266 } catch (SQLException e) { 267 throw new Exception("Error inserting into lsid generator table: " 268 + e.getMessage()); 269 } 270 } 271 272 /** Open the database containing the lsid generator table and intialize 273 * prepared statements. 274 */ 275 private static void openDatabase() throws Exception 276 { 277 if(_dbType == null) 278 { 279 ConfigurationManager configManager = ConfigurationManager.getInstance(); 280 ConfigurationProperty coreProperty = configManager 281 .getProperty(ConfigurationManager.getModule("core")); 282 ConfigurationProperty coreDBProperty = coreProperty 283 .getProperty(CORE_DB_STR); 284 285 if (coreDBProperty == null) { 286 throw new Exception("Could not find " + CORE_DB_STR 287 + " in core module's configuration.xml."); 288 } 289 290 _dbType = DatabaseFactory.getConnectedDatabaseType(coreDBProperty); 291 292 // By creating the statement and keeping it around 293 // make sure to close your resultsets to save memory 294 _stmt = _dbType.getStatement(); 295 296 // create lsid generator table if it does not exist. 297 if(!_dbType.tableExists(LSID_GENERATOR_TABLE_NAME)) 298 { 299 _stmt.execute(LSID_GENERATOR_TABLE_CREATE_SQL); 300 } 301 302 _insertPrepStmt = _dbType.getPrepStatement("insert into " 303 + LSID_GENERATOR_TABLE_NAME 304 + " (AUTH,NS,OID,REV) values (?,?,?,?)"); 305 _updatePrepStmt = _dbType.getPrepStatement("update " 306 + LSID_GENERATOR_TABLE_NAME + " SET REV=? " 307 + " WHERE AUTH=? and NS=? and OID=?"); 308 } 309 } 310 311 /** 312 * Return the next available Object ID for the current authority and namespace. 313 * 314 * @throws Exception 315 */ 316 private Long getNextObjectID() throws Exception { 317 if (isDebugging) 318 log.debug("getNextObjectID()"); 319 320 Long nextOID = null; 321 322 // FIXME make a prepared statement 323 String query = "select max(OID) from " + LSID_GENERATOR_TABLE_NAME 324 + " where auth = '" + _authNamespace.getAuthority() + "' " 325 + " and ns = '" + _authNamespace.getNamespace() + "'"; 326 if (isDebugging) log.debug(query); 327 ResultSet rs = null; 328 try { 329 rs = _stmt.executeQuery(query); 330 if (rs == null) 331 throw new SQLException("Query Failed: " + query); 332 if (rs.next()) { 333 Long maxOID = rs.getLong(1); 334 nextOID = maxOID + 1L; 335 } else { 336 nextOID = 1L; 337 } 338 } finally { 339 if (rs != null) { 340 rs.close(); 341 } 342 } 343 344 if (nextOID != null && nextOID > 0) { 345 if (isDebugging) { 346 log.debug("LastObjectID: " + nextOID); 347 } 348 return nextOID; 349 } 350 return null; 351 } 352 353 /** 354 * Return the number of rows in the LSID_GENERATOR table. 355 * 356 * @return int number of rows in the LSID_GENERATOR table 357 */ 358 public synchronized int countRowsForCurrentAuthNamespace() { 359 int cnt = -1; 360 try { 361 AuthNamespace an = AuthNamespace.getInstance(); 362 363 // FIXME make a prepared statement 364 String query = "select count(*) from " + LSID_GENERATOR_TABLE_NAME; 365 query += " where AUTH = '" + an.getAuthority() 366 + "' and NS = '" + an.getNamespace() + "'"; 367 if (isDebugging) log.debug(query); 368 ResultSet rs = null; 369 try { 370 rs = _stmt.executeQuery(query); 371 if (rs == null) 372 throw new SQLException("Query Failed: " + query); 373 if (rs.next()) { 374 cnt = rs.getInt(1); 375 if (rs.wasNull()) { 376 cnt = -1; 377 } 378 if (rs.next()) { 379 cnt = -1; 380 throw new SQLException("Should never happen"); 381 } 382 } 383 } finally { 384 if (rs != null) { 385 rs.close(); 386 } 387 } 388 } catch (SQLException sqle) { 389 System.out.println(sqle.getMessage()); 390 sqle.printStackTrace(); 391 } 392 return cnt; 393 } 394 395 /** Close the LSID database if opened. */ 396 public synchronized void closeDatabase() { 397 if(_dbType != null) { 398 399 try { 400 _stmt.close(); 401 } catch (SQLException e) { 402 MessageHandler.error("Error closing database statement.", e); 403 } 404 405 try { 406 _dbType.disconnect(); 407 } catch (SQLException e) { 408 MessageHandler.error("Error closing LSID database.", e); 409 } 410 _dbType = null; 411 generator = null; 412 } 413 } 414}