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