| 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 |