|
JDBCDataStore |
|
1 /* 2 * JDBCDataStore.java 3 * 4 * Copyright (c) 1998-2001, The University of Sheffield. 5 * 6 * This file is part of GATE (see http://gate.ac.uk/), and is free 7 * software, licenced under the GNU Library General Public License, 8 * Version 2, June 1991 (in the distribution as file licence.html, 9 * and also available at http://gate.ac.uk/gate/licence.html). 10 * 11 * Marin Dimitrov, 18/Sep/2001 12 * 13 * $Id: JDBCDataStore.java,v 1.54 2001/11/30 12:55:17 marin Exp $ 14 */ 15 16 package gate.persist; 17 18 import java.sql.*; 19 import java.net.*; 20 import java.util.*; 21 import java.io.*; 22 23 import junit.framework.*; 24 25 import gate.*; 26 import gate.util.*; 27 import gate.event.*; 28 import gate.security.*; 29 import gate.security.SecurityException; 30 31 32 public abstract class JDBCDataStore extends AbstractFeatureBearer 33 implements DatabaseDataStore, 34 CreoleListener { 35 36 /** --- */ 37 /* private static final String jdbcOracleDriverName = "oracle.jdbc.driver.OracleDriver"; 38 private static final String jdbcPostgresDriverName = "postgresql.Driver"; 39 private static final String jdbcSapDBDriverName = "com.sap.dbtech.jdbc.DriverSapDB"; 40 */ 41 private static final boolean DEBUG = false; 42 43 /** --- */ 44 private String dbURL; 45 private String driverName; 46 private String dbID; 47 48 protected Session session; 49 protected String name; 50 51 protected transient Connection jdbcConn; 52 protected transient AccessController ac; 53 private transient Vector datastoreListeners; 54 protected transient Vector dependentResources; 55 56 /** Do not use this class directly - use one of the subclasses */ 57 protected JDBCDataStore() { 58 59 this.datastoreListeners = new Vector(); 60 this.dependentResources = new Vector(); 61 } 62 63 64 /* interface DataStore */ 65 66 /** 67 * Returns the comment displayed by the GUI for this DataStore 68 */ 69 public abstract String getComment(); 70 71 /** 72 * Returns the name of the icon to be used when this datastore is displayed 73 * in the GUI 74 */ 75 public abstract String getIconName(); 76 77 78 /** Get the name of an LR from its ID. */ 79 public abstract String getLrName(Object lrId) throws PersistenceException; 80 81 82 /** Set the URL for the underlying storage mechanism. */ 83 public void setStorageUrl(String storageUrl) throws PersistenceException { 84 85 if (!storageUrl.startsWith("jdbc:")) { 86 throw new PersistenceException("Incorrect JDBC url (should start with \"jdbc:\")"); 87 } 88 else { 89 this.dbURL = storageUrl; 90 } 91 92 } 93 94 /** Get the URL for the underlying storage mechanism. */ 95 public String getStorageUrl() { 96 97 return this.dbURL; 98 } 99 100 101 /** 102 * Create a new data store. <B>NOTE:</B> for some data stores 103 * creation is an system administrator task; in such cases this 104 * method will throw an UnsupportedOperationException. 105 */ 106 public void create() 107 throws PersistenceException, UnsupportedOperationException { 108 109 throw new UnsupportedOperationException("create() is not supported for DatabaseDataStore"); 110 } 111 112 113 114 /** Open a connection to the data store. */ 115 public void open() throws PersistenceException { 116 try { 117 118 //1, get connection to the DB 119 jdbcConn = DBHelper.connect(dbURL); 120 121 //2. create security factory 122 // this.ac = new AccessControllerImpl(); 123 this.ac = Factory.createAccessController(dbURL); 124 125 //3. open and init the security factory with the same DB repository 126 ac.open(); 127 128 //4. get DB ID 129 this.dbID = this.readDatabaseID(); 130 131 } 132 catch(SQLException sqle) { 133 throw new PersistenceException("could not get DB connection ["+ sqle.getMessage() +"]"); 134 } 135 catch(ClassNotFoundException clse) { 136 throw new PersistenceException("cannot locate JDBC driver ["+ clse.getMessage() +"]"); 137 } 138 139 //5. register for Creole events 140 Gate.getCreoleRegister().addCreoleListener(this); 141 } 142 143 /** Close the data store. */ 144 public void close() throws PersistenceException { 145 146 //-1. Unregister for Creole events 147 Gate.getCreoleRegister().removeCreoleListener(this); 148 149 //0. sync all dependednt resources 150 for (int i=0; i< this.dependentResources.size(); i++) { 151 LanguageResource lr = (LanguageResource)this.dependentResources.elementAt(i); 152 153 try { 154 sync(lr); 155 } 156 catch(SecurityException se) { 157 //do nothing 158 //there was an oper and modified resource for which the user has no write 159 //privileges 160 //not doing anything is perfectly ok because the resource won't bechanged in DB 161 } 162 163 //unload UI component 164 Factory.deleteResource(lr); 165 } 166 167 //1. close security factory 168 ac.close(); 169 170 //2. close the JDBC connection 171 try { 172 //rollback uncommited transactions 173 this.jdbcConn.rollback(); 174 this.jdbcConn.close(); 175 } 176 catch (SQLException sqle) { 177 throw new PersistenceException("cannot close JDBC connection, DB error is ["+ 178 sqle.getMessage() +"]"); 179 } 180 181 //finally unregister this datastore from the GATE register of datastores 182 Gate.getDataStoreRegister().remove(this); 183 } 184 185 /** 186 * Delete the data store. <B>NOTE:</B> for some data stores 187 * deletion is an system administrator task; in such cases this 188 * method will throw an UnsupportedOperationException. 189 */ 190 public void delete() 191 throws PersistenceException, UnsupportedOperationException { 192 193 throw new UnsupportedOperationException("delete() is not supported for DatabaseDataStore"); 194 } 195 196 /** 197 * Delete a resource from the data store. 198 * @param lrId a data-store specific unique identifier for the resource 199 * @param lrClassName class name of the type of resource 200 */ 201 public abstract void delete(String lrClassName, Object lrId) 202 throws PersistenceException,SecurityException; 203 204 205 /** 206 * Save: synchonise the in-memory image of the LR with the persistent 207 * image. 208 */ 209 public abstract void sync(LanguageResource lr) 210 throws PersistenceException,SecurityException; 211 212 213 /** 214 * Set method for the autosaving behaviour of the data store. 215 * <B>NOTE:</B> many types of datastore have no auto-save function, 216 * in which case this will throw an UnsupportedOperationException. 217 */ 218 public void setAutoSaving(boolean autoSaving) 219 throws UnsupportedOperationException,PersistenceException { 220 try { 221 this.jdbcConn.setAutoCommit(true); 222 } 223 catch(SQLException sqle) { 224 throw new PersistenceException("cannot change autosave mode ["+sqle.getMessage()+"]"); 225 } 226 227 } 228 229 /** Get the autosaving behaviour of the LR. */ 230 public boolean isAutoSaving() { 231 throw new MethodNotImplementedException(); 232 } 233 234 /** Adopt a resource for persistence. */ 235 public abstract LanguageResource adopt(LanguageResource lr,SecurityInfo secInfo) 236 throws PersistenceException,gate.security.SecurityException; 237 238 /** 239 * Get a resource from the persistent store. 240 * <B>Don't use this method - use Factory.createResource with 241 * DataStore and DataStoreInstanceId parameters set instead.</B> 242 */ 243 public abstract LanguageResource getLr(String lrClassName, Object lrPersistenceId) 244 throws PersistenceException,SecurityException; 245 246 /** Get a list of the types of LR that are present in the data store. */ 247 public abstract List getLrTypes() throws PersistenceException; 248 249 250 /** Get a list of the IDs of LRs of a particular type that are present. */ 251 public abstract List getLrIds(String lrType) throws PersistenceException; 252 253 254 /** Get a list of the names of LRs of a particular type that are present. */ 255 public abstract List getLrNames(String lrType) throws PersistenceException; 256 257 /** 258 * Checks if the user (identified by the sessionID) 259 * has read access to the LR 260 */ 261 public abstract boolean canReadLR(Object lrID) 262 throws PersistenceException, gate.security.SecurityException; 263 264 265 /** 266 * Checks if the user (identified by the sessionID) 267 * has write access to the LR 268 */ 269 public abstract boolean canWriteLR(Object lrID) 270 throws PersistenceException, gate.security.SecurityException; 271 272 273 /* interface DatabaseDataStore */ 274 275 /** --- */ 276 public void beginTrans() 277 throws PersistenceException,UnsupportedOperationException{ 278 279 try { 280 this.jdbcConn.setAutoCommit(false); 281 } 282 catch(SQLException sqle) { 283 throw new PersistenceException("cannot begin transaction, DB error is: [" 284 +sqle.getMessage()+"]"); 285 } 286 } 287 288 289 /** --- */ 290 public void commitTrans() 291 throws PersistenceException,UnsupportedOperationException{ 292 293 try { 294 this.jdbcConn.commit(); 295 } 296 catch(SQLException sqle) { 297 throw new PersistenceException("cannot commit transaction, DB error is: [" 298 +sqle.getMessage()+"]"); 299 } 300 301 } 302 303 /** --- */ 304 public void rollbackTrans() 305 throws PersistenceException,UnsupportedOperationException{ 306 307 try { 308 this.jdbcConn.rollback(); 309 } 310 catch(SQLException sqle) { 311 throw new PersistenceException("cannot commit transaction, DB error is: [" 312 +sqle.getMessage()+"]"); 313 } 314 315 } 316 317 /** --- */ 318 public Long timestamp() 319 throws PersistenceException{ 320 321 //implemented by the subclasses 322 throw new MethodNotImplementedException(); 323 } 324 325 /** --- */ 326 public void deleteSince(Long timestamp) 327 throws PersistenceException{ 328 329 throw new MethodNotImplementedException(); 330 } 331 332 /** --- */ 333 public void setDriver(String driverName) 334 throws PersistenceException{ 335 336 this.driverName = driverName; 337 } 338 /** Sets the name of this resource*/ 339 public void setName(String name){ 340 this.name = name; 341 } 342 343 /** Returns the name of this resource*/ 344 public String getName(){ 345 return name; 346 } 347 348 349 /** --- */ 350 protected int findFeatureType(Object value) { 351 352 if (null == value) 353 return DBHelper.VALUE_TYPE_NULL; 354 else if (value instanceof Integer) 355 return DBHelper.VALUE_TYPE_INTEGER; 356 else if (value instanceof Long) 357 return DBHelper.VALUE_TYPE_LONG; 358 else if (value instanceof Boolean) 359 return DBHelper.VALUE_TYPE_BOOLEAN; 360 else if (value instanceof Double || 361 value instanceof Float) 362 return DBHelper.VALUE_TYPE_FLOAT; 363 else if (value instanceof String) 364 return DBHelper.VALUE_TYPE_STRING; 365 else if (value instanceof List) { 366 //is the array empty? 367 List arr = (List)value; 368 369 if (arr.isEmpty()) { 370 return DBHelper.VALUE_TYPE_EMPTY_ARR; 371 } 372 else { 373 Object element = arr.get(0); 374 375 if (element instanceof Integer) 376 return DBHelper.VALUE_TYPE_INTEGER_ARR; 377 else if (element instanceof Long) 378 return DBHelper.VALUE_TYPE_LONG_ARR; 379 else if (element instanceof Boolean) 380 return DBHelper.VALUE_TYPE_BOOLEAN_ARR; 381 else if (element instanceof Double || 382 element instanceof Float) 383 return DBHelper.VALUE_TYPE_FLOAT_ARR; 384 else if (element instanceof String) 385 return DBHelper.VALUE_TYPE_STRING_ARR; 386 } 387 } 388 else if (value instanceof Serializable) { 389 return DBHelper.VALUE_TYPE_BINARY; 390 } 391 392 //this should never happen 393 throw new IllegalArgumentException(); 394 } 395 396 /** --- */ 397 public String getDatabaseID() { 398 return this.dbID; 399 } 400 401 /** --- */ 402 public abstract String readDatabaseID() 403 throws PersistenceException; 404 405 /** 406 * Removes a a previously registered {@link gate.event.DatastoreListener} 407 * from the list listeners for this datastore 408 */ 409 public void removeDatastoreListener(DatastoreListener l) { 410 //System.out.println("listener being removed..."); 411 Assert.assertNotNull(this.datastoreListeners); 412 // Assert.assertTrue(this.datastoreListeners.contains(l)); 413 414 Vector temp = (Vector)this.datastoreListeners.clone(); 415 temp.remove(l); 416 417 this.datastoreListeners = temp; 418 } 419 420 421 /** 422 * Registers a new {@link gate.event.DatastoreListener} with this datastore 423 */ 424 public void addDatastoreListener(DatastoreListener l) { 425 //System.out.println("listener added..."); 426 Assert.assertNotNull(this.datastoreListeners); 427 if (false == this.datastoreListeners.contains(l)) { 428 Vector temp = (Vector)this.datastoreListeners.clone(); 429 temp.add(l); 430 this.datastoreListeners = temp; 431 } 432 } 433 434 protected void fireResourceAdopted(DatastoreEvent e) { 435 436 Assert.assertNotNull(datastoreListeners); 437 Vector temp = this.datastoreListeners; 438 439 int count = temp.size(); 440 for (int i = 0; i < count; i++) { 441 ((DatastoreListener)temp.elementAt(i)).resourceAdopted(e); 442 } 443 } 444 445 446 protected void fireResourceDeleted(DatastoreEvent e) { 447 448 Assert.assertNotNull(datastoreListeners); 449 Vector temp = this.datastoreListeners; 450 451 int count = temp.size(); 452 for (int i = 0; i < count; i++) { 453 //System.out.println("notifying listener..."); 454 ((DatastoreListener)temp.elementAt(i)).resourceDeleted(e); 455 } 456 } 457 458 459 protected void fireResourceWritten(DatastoreEvent e) { 460 //System.out.println("lrid=["+e.getResourceID()+"] written..."); 461 Assert.assertNotNull(datastoreListeners); 462 Vector temp = this.datastoreListeners; 463 464 int count = temp.size(); 465 for (int i = 0; i < count; i++) { 466 ((DatastoreListener)temp.elementAt(i)).resourceWritten(e); 467 } 468 } 469 470 471 public void resourceLoaded(CreoleEvent e) { 472 if(DEBUG) 473 System.out.println("resource loaded..."); 474 } 475 476 477 public void resourceUnloaded(CreoleEvent e) { 478 //Out.prln("RESOURCE UNLOADED res=["+e .getResource().getClass() .toString()+"], src=["+e.getSource().getClass().toString()+"]..."); 479 Assert.assertNotNull(e.getResource()); 480 if(! (e.getResource() instanceof LanguageResource)) 481 return; 482 483 //1. check it's our resource 484 LanguageResource lr = (LanguageResource)e.getResource(); 485 //Out.prln("CLOSING A RESOURCE..."); 486 //this is a resource from another DS, so no need to do anything 487 if(lr.getDataStore() != this) 488 return; 489 490 //2. remove from the list of reosurce that should be sunced if DS is closed 491 this.dependentResources.remove(lr); 492 493 //3. don't save it, this may not be the user's choice 494 495 //4. remove the reource as listener for events from the DataStore 496 //otherwise the DS will continue sending it events when the reource is 497 // no longer active 498 this.removeDatastoreListener((DatastoreListener)lr); 499 } 500 501 public void datastoreOpened(CreoleEvent e) { 502 if(DEBUG) 503 System.out.println("datastore opened..."); 504 } 505 506 public void datastoreCreated(CreoleEvent e) { 507 if(DEBUG) 508 System.out.println("datastore created..."); 509 } 510 511 public void datastoreClosed(CreoleEvent e) { 512 if(DEBUG) 513 System.out.println("datastore closed..."); 514 //sync all dependent resources 515 } 516 517 /** identify user using this datastore */ 518 public void setSession(Session s) 519 throws gate.security.SecurityException { 520 521 this.session = s; 522 } 523 524 525 526 /** identify user using this datastore */ 527 public Session getSession(Session s) 528 throws gate.security.SecurityException { 529 530 return this.session; 531 } 532 533 } 534
|
JDBCDataStore |
|