|
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.82 2002/04/09 13:45:26 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 import oracle.jdbc.driver.*; 25 26 import gate.*; 27 import gate.util.*; 28 import gate.event.*; 29 import gate.security.*; 30 import gate.security.SecurityException; 31 import gate.corpora.*; 32 import gate.annotation.*; 33 34 public abstract class JDBCDataStore extends AbstractFeatureBearer 35 implements DatabaseDataStore, 36 CreoleListener { 37 38 /** --- */ 39 private static final boolean DEBUG = false; 40 41 /** jdbc url for the database */ 42 private String dbURL; 43 protected String dbSchema; 44 protected int dbType; 45 46 protected String datastoreComment; 47 protected String iconName; 48 49 /** jdbc driver name */ 50 // private String driverName; 51 52 /** 53 * GUID of the datastore 54 * read from T_PARAMETER table 55 * */ 56 private String dbID; 57 58 /** security session identifying all access to the datastore */ 59 protected Session session; 60 61 /** datastore name? */ 62 protected String name; 63 64 /** jdbc connection, all access to the database is made through this connection 65 */ 66 protected transient Connection jdbcConn; 67 68 /** Security factory that contols access to objects in the datastore 69 * the security session is from this factory 70 * */ 71 protected transient AccessController ac; 72 73 /** anyone interested in datastore related events */ 74 private transient Vector datastoreListeners; 75 76 /** resources that should be sync-ed if datastore is close()-d */ 77 protected transient Vector dependentResources; 78 79 /** Do not use this class directly - use one of the subclasses */ 80 protected JDBCDataStore() { 81 82 this.datastoreListeners = new Vector(); 83 this.dependentResources = new Vector(); 84 } 85 86 87 /* interface DataStore */ 88 89 /** 90 * Save: synchonise the in-memory image of the LR with the persistent 91 * image. 92 */ 93 public String getComment() { 94 95 Assert.assertNotNull(this.datastoreComment); 96 return this.datastoreComment; 97 } 98 99 /** 100 * Returns the name of the icon to be used when this datastore is displayed 101 * in the GUI 102 */ 103 public String getIconName() { 104 Assert.assertNotNull(this.iconName); 105 return this.iconName; 106 } 107 108 109 110 /** Get the name of an LR from its ID. */ 111 public String getLrName(Object lrId) 112 throws PersistenceException { 113 114 if (false == lrId instanceof Long) { 115 throw new IllegalArgumentException(); 116 } 117 118 Long ID = (Long)lrId; 119 120 PreparedStatement pstmt = null; 121 ResultSet rset = null; 122 123 try { 124 String sql = " select lr_name " + 125 " from "+this.dbSchema+"t_lang_resource " + 126 " where lr_id = ?"; 127 128 pstmt = this.jdbcConn.prepareStatement(sql); 129 pstmt.setLong(1,ID.longValue()); 130 pstmt.execute(); 131 rset = pstmt.getResultSet(); 132 133 rset.next(); 134 String result = rset.getString("lr_name"); 135 136 return result; 137 } 138 catch(SQLException sqle) { 139 throw new PersistenceException("can't get LR name from DB: ["+ sqle.getMessage()+"]"); 140 } 141 finally { 142 DBHelper.cleanup(pstmt); 143 DBHelper.cleanup(rset); 144 } 145 } 146 147 148 149 /** Set the URL for the underlying storage mechanism. */ 150 public void setStorageUrl(String storageUrl) throws PersistenceException { 151 152 if (!storageUrl.startsWith("jdbc:")) { 153 throw new PersistenceException("Incorrect JDBC url (should start with \"jdbc:\")"); 154 } 155 else { 156 this.dbURL = storageUrl; 157 this.dbSchema = DBHelper.getSchemaPrefix(this.dbURL); 158 this.dbType = DBHelper.getDatabaseType(this.dbURL); 159 Assert.assertNotNull(this.dbSchema); 160 Assert.assertTrue(this.dbType > 0); 161 } 162 163 } 164 165 /** Get the URL for the underlying storage mechanism. */ 166 public String getStorageUrl() { 167 168 return this.dbURL; 169 } 170 171 172 /** 173 * Create a new data store. <B>NOTE:</B> for some data stores 174 * creation is an system administrator task; in such cases this 175 * method will throw an UnsupportedOperationException. 176 */ 177 public void create() 178 throws PersistenceException, UnsupportedOperationException { 179 180 throw new UnsupportedOperationException("create() is not supported for DatabaseDataStore"); 181 } 182 183 184 185 /** Open a connection to the data store. */ 186 public void open() throws PersistenceException { 187 try { 188 189 //1, get connection to the DB 190 jdbcConn = DBHelper.connect(dbURL); 191 192 //2. create security factory 193 // this.ac = new AccessControllerImpl(); 194 this.ac = Factory.createAccessController(dbURL); 195 196 //3. open and init the security factory with the same DB repository 197 ac.open(); 198 199 //4. get DB ID 200 this.dbID = this.readDatabaseID(); 201 202 } 203 catch(SQLException sqle) { 204 throw new PersistenceException("could not get DB connection ["+ sqle.getMessage() +"]"); 205 } 206 catch(ClassNotFoundException clse) { 207 throw new PersistenceException("cannot locate JDBC driver ["+ clse.getMessage() +"]"); 208 } 209 210 //5. register for Creole events 211 Gate.getCreoleRegister().addCreoleListener(this); 212 } 213 214 /** Close the data store. */ 215 public void close() throws PersistenceException { 216 217 //-1. Unregister for Creole events 218 Gate.getCreoleRegister().removeCreoleListener(this); 219 220 //0. sync all dependednt resources 221 for (int i=0; i< this.dependentResources.size(); i++) { 222 LanguageResource lr = (LanguageResource)this.dependentResources.elementAt(i); 223 224 try { 225 sync(lr); 226 } 227 catch(SecurityException se) { 228 //do nothing 229 //there was an oper and modified resource for which the user has no write 230 //privileges 231 //not doing anything is perfectly ok because the resource won't bechanged in DB 232 } 233 234 //unload UI component 235 Factory.deleteResource(lr); 236 } 237 238 //1. close security factory 239 ac.close(); 240 241 DBHelper.disconnect(this.jdbcConn); 242 243 //finally unregister this datastore from the GATE register of datastores 244 Gate.getDataStoreRegister().remove(this); 245 } 246 247 /** 248 * Delete the data store. <B>NOTE:</B> for some data stores 249 * deletion is an system administrator task; in such cases this 250 * method will throw an UnsupportedOperationException. 251 */ 252 public void delete() 253 throws PersistenceException, UnsupportedOperationException { 254 255 throw new UnsupportedOperationException("delete() is not supported for DatabaseDataStore"); 256 } 257 258 /** 259 * Delete a resource from the data store. 260 * @param lrId a data-store specific unique identifier for the resource 261 * @param lrClassName class name of the type of resource 262 */ 263 264 public void delete(String lrClassName, Object lrId) 265 throws PersistenceException,SecurityException { 266 //0. preconditions 267 if (false == lrId instanceof Long) { 268 throw new IllegalArgumentException(); 269 } 270 271 if (!lrClassName.equals(DBHelper.DOCUMENT_CLASS) && 272 !lrClassName.equals(DBHelper.CORPUS_CLASS)) { 273 throw new IllegalArgumentException("Only Corpus and Document classes are supported" + 274 " by Database data store"); 275 } 276 277 //1. check session 278 if (null == this.session) { 279 throw new SecurityException("session not set"); 280 } 281 282 if (false == this.ac.isValidSession(this.session)) { 283 throw new SecurityException("invalid session supplied"); 284 } 285 286 //2. check permissions 287 if (false == canWriteLR(lrId)) { 288 throw new SecurityException("insufficient privileges"); 289 } 290 291 //3. try to lock document, so that we'll be sure no one is editing it 292 //NOTE: use the private method 293 User lockingUser = this.getLockingUser((Long)lrId); 294 User currUser = this.session.getUser(); 295 296 if (null != lockingUser && false == lockingUser.equals(currUser)) { 297 //oops, someone is editing now 298 throw new PersistenceException("LR locked by another user"); 299 } 300 301 boolean transFailed = false; 302 try { 303 //4. autocommit should be FALSE because of LOBs 304 beginTrans(); 305 306 //5. perform changes, if anything goes wrong, rollback 307 if (lrClassName.equals(DBHelper.DOCUMENT_CLASS)) { 308 deleteDocument((Long)lrId); 309 } 310 else { 311 deleteCorpus((Long)lrId); 312 } 313 314 //6. done, commit 315 commitTrans(); 316 } 317 catch(PersistenceException pe) { 318 transFailed = true; 319 throw(pe); 320 } 321 finally { 322 //problems? 323 if (transFailed) { 324 rollbackTrans(); 325 } 326 } 327 328 //7, unlock 329 //do nothing - the resource does not exist anymore 330 331 //8. delete from the list of dependent resources 332 boolean resourceFound = false; 333 Iterator it = this.dependentResources.iterator(); 334 while (it.hasNext()) { 335 LanguageResource lr = (LanguageResource)it.next(); 336 if (lr.getLRPersistenceId().equals(lrId)) { 337 resourceFound = true; 338 it.remove(); 339 break; 340 } 341 } 342 343 //Assert.assertTrue(resourceFound); 344 345 //9. let the world know about it 346 fireResourceDeleted( 347 new DatastoreEvent(this, DatastoreEvent.RESOURCE_DELETED, null, lrId)); 348 349 //10. unload the resource form the GUI 350 try { 351 unloadLR((Long)lrId); 352 } 353 catch(GateException ge) { 354 Err.prln("can't unload resource from GUI..."); 355 } 356 } 357 358 359 360 /** 361 * Save: synchonise the in-memory image of the LR with the persistent 362 * image. 363 */ 364 public void sync(LanguageResource lr) 365 throws PersistenceException,SecurityException { 366 367 //4.delegate (open a new transaction) 368 _sync(lr,true); 369 } 370 371 372 /** 373 * Set method for the autosaving behaviour of the data store. 374 * <B>NOTE:</B> many types of datastore have no auto-save function, 375 * in which case this will throw an UnsupportedOperationException. 376 */ 377 public void setAutoSaving(boolean autoSaving) 378 throws UnsupportedOperationException,PersistenceException { 379 try { 380 this.jdbcConn.setAutoCommit(true); 381 } 382 catch(SQLException sqle) { 383 throw new PersistenceException("cannot change autosave mode ["+sqle.getMessage()+"]"); 384 } 385 386 } 387 388 /** Get the autosaving behaviour of the LR. */ 389 public boolean isAutoSaving() { 390 throw new MethodNotImplementedException(); 391 } 392 393 /** Adopt a resource for persistence. */ 394 public LanguageResource adopt(LanguageResource lr, SecurityInfo secInfo) 395 throws PersistenceException,SecurityException { 396 //open a new transaction 397 return _adopt(lr,secInfo,true); 398 } 399 400 401 protected LanguageResource _adopt(LanguageResource lr, 402 SecurityInfo secInfo, 403 boolean openNewTrans) 404 throws PersistenceException,SecurityException { 405 406 LanguageResource result = null; 407 408 //-1. preconditions 409 Assert.assertNotNull(lr); 410 Assert.assertNotNull(secInfo); 411 if (false == lr instanceof Document && 412 false == lr instanceof Corpus) { 413 //only documents and corpuses could be serialized in DB 414 throw new IllegalArgumentException("only Documents and Corpuses could "+ 415 "be serialized in DB"); 416 } 417 418 //0. check SecurityInfo 419 if (false == this.ac.isValidSecurityInfo(secInfo)) { 420 throw new SecurityException("Invalid security settings supplied"); 421 } 422 423 //1. user session should be set 424 if (null == this.session) { 425 throw new SecurityException("user session not set"); 426 } 427 428 //2. check the LR's current DS 429 DataStore currentDS = lr.getDataStore(); 430 if(currentDS == null) { 431 // an orphan - do the adoption (later) 432 } 433 else if(currentDS.equals(this)){ // adopted already 434 return lr; 435 } 436 else { // someone else's child 437 throw new PersistenceException( 438 "Can't adopt a resource which is already in a different datastore"); 439 } 440 441 442 //3. is the LR one of Document or Corpus? 443 if (false == lr instanceof Document && 444 false == lr instanceof Corpus) { 445 446 throw new IllegalArgumentException("Database datastore is implemented only for "+ 447 "Documents and Corpora"); 448 } 449 450 //4.is the document already stored in this storage? 451 Object persistID = lr.getLRPersistenceId(); 452 if (persistID != null) { 453 throw new PersistenceException("This LR is already stored in the " + 454 " database (persistance ID is =["+(Long)persistID+"] )"); 455 } 456 457 boolean transFailed = false; 458 try { 459 //5 autocommit should be FALSE because of LOBs 460 if (openNewTrans) { 461 // this.jdbcConn.setAutoCommit(false); 462 beginTrans(); 463 } 464 465 //6. perform changes, if anything goes wrong, rollback 466 if (lr instanceof Document) { 467 result = createDocument((Document)lr,secInfo); 468 //System.out.println("result ID=["+result.getLRPersistenceId()+"]"); 469 } 470 else { 471 //adopt each document from the corpus in a separate transaction context 472 result = createCorpus((Corpus)lr,secInfo,true); 473 } 474 475 //7. done, commit 476 if (openNewTrans) { 477 // this.jdbcConn.commit(); 478 commitTrans(); 479 } 480 } 481 /* 482 catch(SQLException sqle) { 483 transFailed = true; 484 throw new PersistenceException("Cannot start/commit a transaction, ["+sqle.getMessage()+"]"); 485 } 486 */ 487 catch(PersistenceException pe) { 488 transFailed = true; 489 throw(pe); 490 } 491 catch(SecurityException se) { 492 transFailed = true; 493 throw(se); 494 } 495 finally { 496 //problems? 497 if (transFailed) { 498 System.out.println("trans failed ...rollback"); 499 rollbackTrans(); 500 /* try { 501 this.jdbcConn.rollback(); 502 } 503 catch(SQLException sqle) { 504 throw new PersistenceException(sqle); 505 } 506 */ 507 } 508 } 509 510 //8. let the world know 511 fireResourceAdopted( 512 new DatastoreEvent(this, DatastoreEvent.RESOURCE_ADOPTED, 513 result, 514 result.getLRPersistenceId()) 515 ); 516 517 //9. fire also resource written event because it's now saved 518 fireResourceWritten( 519 new DatastoreEvent(this, DatastoreEvent.RESOURCE_WRITTEN, 520 result, 521 result.getLRPersistenceId() 522 ) 523 ); 524 525 //10. add the resource to the list of dependent resources - i.e. the ones that the 526 //data store should take care upon closing [and call sync()] 527 this.dependentResources.add(result); 528 529 return result; 530 } 531 532 533 /** Get a list of the types of LR that are present in the data store. */ 534 public List getLrTypes() throws PersistenceException { 535 536 Vector lrTypes = new Vector(); 537 Statement stmt = null; 538 ResultSet rs = null; 539 540 try { 541 stmt = this.jdbcConn.createStatement(); 542 rs = stmt.executeQuery(" SELECT lrtp_type " + 543 " FROM "+this.dbSchema+"t_lr_type LRTYPE "); 544 545 while (rs.next()) { 546 //access by index is faster 547 String lrType = rs.getString(1); 548 lrTypes.add(lrType); 549 } 550 551 return lrTypes; 552 } 553 catch(SQLException sqle) { 554 throw new PersistenceException("can't get LR types from DB: ["+ sqle.getMessage()+"]"); 555 } 556 finally { 557 DBHelper.cleanup(rs); 558 DBHelper.cleanup(stmt); 559 } 560 } 561 562 563 /** Get a list of the IDs of LRs of a particular type that are present. */ 564 public List getLrIds(String lrType) throws PersistenceException { 565 566 Vector lrIDs = new Vector(); 567 PreparedStatement stmt = null; 568 ResultSet rs = null; 569 570 try { 571 stmt = this.jdbcConn.prepareStatement( 572 " SELECT lr_id " + 573 " FROM "+this.dbSchema+"t_lang_resource LR, " + 574 " "+this.dbSchema+"t_lr_type LRTYPE " + 575 " WHERE LR.lr_type_id = LRTYPE.lrtp_id " + 576 " AND LRTYPE.lrtp_type = ? " + 577 " ORDER BY lr_name" 578 ); 579 stmt.setString(1,lrType); 580 581 //oracle special 582 if (this.dbType == DBHelper.ORACLE_DB) { 583 ((OraclePreparedStatement)stmt).setRowPrefetch(DBHelper.CHINK_SIZE_SMALL); 584 } 585 586 stmt.execute(); 587 rs = stmt.getResultSet(); 588 589 while (rs.next()) { 590 //access by index is faster 591 Long lrID = new Long(rs.getLong(1)); 592 lrIDs.add(lrID); 593 } 594 595 return lrIDs; 596 } 597 catch(SQLException sqle) { 598 throw new PersistenceException("can't get LR types from DB: ["+ sqle.getMessage()+"]"); 599 } 600 finally { 601 DBHelper.cleanup(rs); 602 DBHelper.cleanup(stmt); 603 } 604 605 } 606 607 608 /** Get a list of the names of LRs of a particular type that are present. */ 609 public List getLrNames(String lrType) throws PersistenceException { 610 611 Vector lrNames = new Vector(); 612 PreparedStatement stmt = null; 613 ResultSet rs = null; 614 615 try { 616 stmt = this.jdbcConn.prepareStatement( 617 " SELECT lr_name " + 618 " FROM "+this.dbSchema+"t_lang_resource LR, " + 619 " t_lr_type LRTYPE " + 620 " WHERE LR.lr_type_id = LRTYPE.lrtp_id " + 621 " AND LRTYPE.lrtp_type = ? " + 622 " ORDER BY lr_name desc" 623 ); 624 stmt.setString(1,lrType); 625 626 //Oracle special 627 if (this.dbType == DBHelper.ORACLE_DB) { 628 ((OraclePreparedStatement)stmt).setRowPrefetch(DBHelper.CHINK_SIZE_SMALL); 629 } 630 631 stmt.execute(); 632 rs = stmt.getResultSet(); 633 634 while (rs.next()) { 635 //access by index is faster 636 String lrName = rs.getString(1); 637 lrNames.add(lrName); 638 } 639 640 return lrNames; 641 } 642 catch(SQLException sqle) { 643 throw new PersistenceException("can't get LR types from DB: ["+ sqle.getMessage()+"]"); 644 } 645 finally { 646 DBHelper.cleanup(rs); 647 DBHelper.cleanup(stmt); 648 } 649 } 650 651 /** 652 * Checks if the user (identified by the sessionID) 653 * has read access to the LR 654 */ 655 public boolean canReadLR(Object lrID) 656 throws PersistenceException, SecurityException{ 657 658 return canAccessLR((Long) lrID,DBHelper.READ_ACCESS); 659 } 660 661 662 663 /** 664 * Checks if the user (identified by the sessionID) 665 * has write access to the LR 666 */ 667 public boolean canWriteLR(Object lrID) 668 throws PersistenceException, SecurityException{ 669 670 return canAccessLR((Long) lrID,DBHelper.WRITE_ACCESS); 671 } 672 673 /** 674 * Checks if the user (identified by the sessionID) 675 * has some access (read/write) to the LR 676 */ 677 protected boolean canAccessLR(Long lrID,int mode) 678 throws PersistenceException, SecurityException{ 679 680 //abstract 681 throw new MethodNotImplementedException(); 682 } 683 684 /* interface DatabaseDataStore */ 685 686 /** 687 * starts a transaction 688 * note that if u're already in transaction context this will not open 689 * nested transaction 690 * i.e. many consecutive calls to beginTrans() make no difference if no commit/rollback 691 * is made meanwhile 692 * */ 693 public void beginTrans() 694 throws PersistenceException,UnsupportedOperationException{ 695 696 try { 697 this.jdbcConn.setAutoCommit(false); 698 } 699 catch(SQLException sqle) { 700 throw new PersistenceException("cannot begin transaction, DB error is: [" 701 +sqle.getMessage()+"]"); 702 } 703 } 704 705 706 /** 707 * commits transaction 708 * note that this will commit all the uncommited calls made so far 709 * */ 710 public void commitTrans() 711 throws PersistenceException,UnsupportedOperationException{ 712 713 try { 714 this.jdbcConn.commit(); 715 } 716 catch(SQLException sqle) { 717 throw new PersistenceException("cannot commit transaction, DB error is: [" 718 +sqle.getMessage()+"]"); 719 } 720 721 } 722 723 /** rollsback a transaction */ 724 public void rollbackTrans() 725 throws PersistenceException,UnsupportedOperationException{ 726 727 try { 728 this.jdbcConn.rollback(); 729 } 730 catch(SQLException sqle) { 731 throw new PersistenceException("cannot commit transaction, DB error is: [" 732 +sqle.getMessage()+"]"); 733 } 734 735 } 736 737 /** not used */ 738 public Long timestamp() 739 throws PersistenceException{ 740 741 //implemented by the subclasses 742 throw new MethodNotImplementedException(); 743 } 744 745 /** not used */ 746 public void deleteSince(Long timestamp) 747 throws PersistenceException{ 748 749 throw new MethodNotImplementedException(); 750 } 751 752 /** specifies the driver to be used to connect to the database? */ 753 /* public void setDriver(String driverName) 754 throws PersistenceException{ 755 756 this.driverName = driverName; 757 } 758 */ 759 /** Sets the name of this resource*/ 760 public void setName(String name){ 761 this.name = name; 762 } 763 764 /** Returns the name of this resource*/ 765 public String getName(){ 766 return name; 767 } 768 769 770 /** --- */ 771 protected int findFeatureType(Object value) { 772 773 if (null == value) 774 return DBHelper.VALUE_TYPE_NULL; 775 else if (value instanceof Integer) 776 return DBHelper.VALUE_TYPE_INTEGER; 777 else if (value instanceof Long) 778 return DBHelper.VALUE_TYPE_LONG; 779 else if (value instanceof Boolean) 780 return DBHelper.VALUE_TYPE_BOOLEAN; 781 else if (value instanceof Double || 782 value instanceof Float) 783 return DBHelper.VALUE_TYPE_FLOAT; 784 else if (value instanceof String) 785 return DBHelper.VALUE_TYPE_STRING; 786 else if (value instanceof List) { 787 //is the array empty? 788 List arr = (List)value; 789 790 if (arr.isEmpty()) { 791 return DBHelper.VALUE_TYPE_EMPTY_ARR; 792 } 793 else { 794 Object element = arr.get(0); 795 796 if (element instanceof Integer) 797 return DBHelper.VALUE_TYPE_INTEGER_ARR; 798 else if (element instanceof Long) 799 return DBHelper.VALUE_TYPE_LONG_ARR; 800 else if (element instanceof Boolean) 801 return DBHelper.VALUE_TYPE_BOOLEAN_ARR; 802 else if (element instanceof Double || 803 element instanceof Float) 804 return DBHelper.VALUE_TYPE_FLOAT_ARR; 805 else if (element instanceof String) 806 return DBHelper.VALUE_TYPE_STRING_ARR; 807 } 808 } 809 else if (value instanceof Serializable) { 810 return DBHelper.VALUE_TYPE_BINARY; 811 } 812 813 //this should never happen 814 throw new IllegalArgumentException(); 815 } 816 817 /** --- */ 818 public String getDatabaseID() { 819 return this.dbID; 820 } 821 822 /** reads the GUID from the database */ 823 /* protected abstract String readDatabaseID() 824 throws PersistenceException; 825 */ 826 /** 827 * reads the ID of the database 828 * every database should have unique string ID 829 */ 830 protected String readDatabaseID() throws PersistenceException{ 831 832 PreparedStatement pstmt = null; 833 ResultSet rs = null; 834 String result = null; 835 836 //1. read from DB 837 try { 838 String sql = " select par_value_string " + 839 " from "+this.dbSchema+"t_parameter " + 840 " where par_key = ? "; 841 842 pstmt = this.jdbcConn.prepareStatement(sql); 843 pstmt.setString(1,DBHelper.DB_PARAMETER_GUID); 844 pstmt.execute(); 845 rs = pstmt.getResultSet(); 846 847 if (false == rs.next()) { 848 throw new PersistenceException("Can't read database parameter ["+ 849 DBHelper.DB_PARAMETER_GUID+"]"); 850 } 851 result = rs.getString(1); 852 } 853 catch(SQLException sqle) { 854 throw new PersistenceException("Can't read database parameter ["+ 855 sqle.getMessage()+"]"); 856 } 857 finally { 858 DBHelper.cleanup(rs); 859 DBHelper.cleanup(pstmt); 860 } 861 862 if (DEBUG) { 863 Out.println("reult=["+result+"]"); 864 } 865 866 return result; 867 } 868 869 870 /** 871 * Removes a a previously registered {@link gate.event.DatastoreListener} 872 * from the list listeners for this datastore 873 */ 874 public void removeDatastoreListener(DatastoreListener l) { 875 876 Assert.assertNotNull(this.datastoreListeners); 877 878 synchronized(this.datastoreListeners) { 879 this.datastoreListeners.remove(l); 880 } 881 } 882 883 884 /** 885 * Registers a new {@link gate.event.DatastoreListener} with this datastore 886 */ 887 public void addDatastoreListener(DatastoreListener l) { 888 889 Assert.assertNotNull(this.datastoreListeners); 890 891 //this is not thread safe 892 /* if (false == this.datastoreListeners.contains(l)) { 893 Vector temp = (Vector)this.datastoreListeners.clone(); 894 temp.add(l); 895 this.datastoreListeners = temp; 896 } 897 */ 898 synchronized(this.datastoreListeners) { 899 if (false == this.datastoreListeners.contains(l)) { 900 this.datastoreListeners.add(l); 901 } 902 } 903 } 904 905 protected void fireResourceAdopted(DatastoreEvent e) { 906 907 Assert.assertNotNull(datastoreListeners); 908 Vector temp = this.datastoreListeners; 909 910 int count = temp.size(); 911 for (int i = 0; i < count; i++) { 912 ((DatastoreListener)temp.elementAt(i)).resourceAdopted(e); 913 } 914 } 915 916 917 protected void fireResourceDeleted(DatastoreEvent e) { 918 919 Assert.assertNotNull(datastoreListeners); 920 Vector temp = this.datastoreListeners; 921 922 int count = temp.size(); 923 for (int i = 0; i < count; i++) { 924 ((DatastoreListener)temp.elementAt(i)).resourceDeleted(e); 925 } 926 } 927 928 929 protected void fireResourceWritten(DatastoreEvent e) { 930 Assert.assertNotNull(datastoreListeners); 931 Vector temp = this.datastoreListeners; 932 933 int count = temp.size(); 934 for (int i = 0; i < count; i++) { 935 ((DatastoreListener)temp.elementAt(i)).resourceWritten(e); 936 } 937 } 938 939 public void resourceLoaded(CreoleEvent e) { 940 if(DEBUG) 941 System.out.println("resource loaded..."); 942 } 943 944 public void resourceRenamed(Resource resource, String oldName, 945 String newName){ 946 } 947 948 949 public void resourceUnloaded(CreoleEvent e) { 950 951 Assert.assertNotNull(e.getResource()); 952 if(! (e.getResource() instanceof LanguageResource)) 953 return; 954 955 //1. check it's our resource 956 LanguageResource lr = (LanguageResource)e.getResource(); 957 958 //this is a resource from another DS, so no need to do anything 959 if(lr.getDataStore() != this) 960 return; 961 962 //2. remove from the list of reosurce that should be sunced if DS is closed 963 this.dependentResources.remove(lr); 964 965 //3. don't save it, this may not be the user's choice 966 967 //4. remove the reource as listener for events from the DataStore 968 //otherwise the DS will continue sending it events when the reource is 969 // no longer active 970 this.removeDatastoreListener((DatastoreListener)lr); 971 } 972 973 public void datastoreOpened(CreoleEvent e) { 974 if(DEBUG) 975 System.out.println("datastore opened..."); 976 } 977 978 public void datastoreCreated(CreoleEvent e) { 979 if(DEBUG) 980 System.out.println("datastore created..."); 981 } 982 983 public void datastoreClosed(CreoleEvent e) { 984 if(DEBUG) 985 System.out.println("datastore closed..."); 986 //sync all dependent resources 987 } 988 989 /** identify user using this datastore */ 990 public void setSession(Session s) 991 throws gate.security.SecurityException { 992 993 this.session = s; 994 } 995 996 997 998 /** identify user using this datastore */ 999 public Session getSession(Session s) 1000 throws gate.security.SecurityException { 1001 1002 return this.session; 1003 } 1004 1005 /** Get a list of LRs that satisfy some set or restrictions */ 1006 public abstract List findLrIds(List constraints) throws PersistenceException; 1007 1008 /** 1009 * Get a list of LRs that satisfy some set or restrictions and are 1010 * of a particular type 1011 */ 1012 public abstract List findLrIds(List constraints, String lrType) 1013 throws PersistenceException; 1014 1015 1016 /** get security information for LR . */ 1017 public SecurityInfo getSecurityInfo(LanguageResource lr) 1018 throws PersistenceException { 1019 1020 //0. preconditions 1021 Assert.assertNotNull(lr); 1022 Assert.assertNotNull(lr.getLRPersistenceId()); 1023 Assert.assertTrue(lr.getLRPersistenceId() instanceof Long); 1024 Assert.assertEquals(this,lr.getDataStore()); 1025 Assert.assertTrue(lr instanceof DatabaseDocumentImpl || 1026 lr instanceof DatabaseCorpusImpl); 1027 1028 PreparedStatement pstmt = null; 1029 ResultSet rs = null; 1030 1031 //1. read data 1032 Long userID = null; 1033 Long groupID = null; 1034 int perm; 1035 try { 1036 String sql = " select lr_owner_user_id, "+ 1037 " lr_owner_group_id, " + 1038 " lr_access_mode "+ 1039 " from "+this.dbSchema+"t_lang_resource "+ 1040 " where lr_id = ?"; 1041 pstmt = this.jdbcConn.prepareStatement(sql); 1042 pstmt.setLong(1,((Long)lr.getLRPersistenceId()).longValue()); 1043 rs = pstmt.executeQuery(); 1044 1045 if (false == rs.next()) { 1046 throw new PersistenceException("Invalid LR ID supplied - no data found"); 1047 } 1048 1049 userID = new Long(rs.getLong("lr_owner_user_id")); 1050 groupID = new Long(rs.getLong("lr_owner_group_id")); 1051 perm = rs.getInt("lr_access_mode"); 1052 1053 Assert.assertTrue(perm == SecurityInfo.ACCESS_GR_GW || 1054 perm == SecurityInfo.ACCESS_GR_OW || 1055 perm == SecurityInfo.ACCESS_OR_OW || 1056 perm == SecurityInfo.ACCESS_WR_GW); 1057 } 1058 catch(SQLException sqle) { 1059 throw new PersistenceException("Can't read document permissions from DB, error is [" + 1060 sqle.getMessage() +"]"); 1061 } 1062 finally { 1063 DBHelper.cleanup(rs); 1064 DBHelper.cleanup(pstmt); 1065 } 1066 1067 //2. get data from AccessController 1068 User usr = null; 1069 Group grp = null; 1070 try { 1071 usr = this.ac.findUser(userID); 1072 grp = this.ac.findGroup(groupID); 1073 } 1074 catch (SecurityException se) { 1075 throw new PersistenceException("Invalid security settings found in DB [" + 1076 se.getMessage() +"]"); 1077 } 1078 1079 //3. construct SecurityInfo 1080 SecurityInfo si = new SecurityInfo(perm,usr,grp); 1081 1082 1083 return si; 1084 } 1085 1086 /** creates a LR of type Corpus */ 1087 protected Corpus createCorpus(Corpus corp,SecurityInfo secInfo, boolean newTransPerDocument) 1088 throws PersistenceException,SecurityException { 1089 1090 //1. create an LR entry for the corpus (T_LANG_RESOURCE table) 1091 Long lrID = createLR(DBHelper.CORPUS_CLASS,corp.getName(),secInfo,null); 1092 1093 //2.create am entry in the T_COPRUS table 1094 Long corpusID = null; 1095 //DB stuff 1096 CallableStatement cstmt = null; 1097 PreparedStatement pstmt = null; 1098 ResultSet rs = null; 1099 1100 try { 1101 if (this.dbType == DBHelper.ORACLE_DB) { 1102 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.create_corpus(?,?) }"); 1103 cstmt.setLong(1,lrID.longValue()); 1104 cstmt.registerOutParameter(2,java.sql.Types.BIGINT); 1105 cstmt.execute(); 1106 corpusID = new Long(cstmt.getLong(2)); 1107 } 1108 else if (this.dbType == DBHelper.POSTGRES_DB) { 1109 pstmt = this.jdbcConn.prepareStatement("select persist_create_corpus(?) "); 1110 pstmt.setLong(1,lrID.longValue()); 1111 pstmt.execute(); 1112 rs = pstmt.getResultSet(); 1113 1114 if (false == rs.next()) { 1115 throw new PersistenceException("empty result set"); 1116 } 1117 1118 corpusID = new Long(rs.getLong(1)); 1119 } 1120 else { 1121 Assert.fail(); 1122 } 1123 } 1124 catch(SQLException sqle) { 1125 throw new PersistenceException("can't create corpus [step 2] in DB: ["+ sqle.getMessage()+"]"); 1126 } 1127 finally { 1128 DBHelper.cleanup(cstmt); 1129 DBHelper.cleanup(pstmt); 1130 DBHelper.cleanup(rs); 1131 } 1132 1133 //3. for each document in the corpus call createDocument() 1134 Iterator itDocuments = corp.iterator(); 1135 Vector dbDocs = new Vector(); 1136 while (itDocuments.hasNext()) { 1137 Document doc = (Document)itDocuments.next(); 1138 1139 //3.1. ensure that the document is either transient or is from the ... 1140 // same DataStore 1141 if (doc.getLRPersistenceId() == null) { 1142 //transient document 1143 1144 //now this is a bit ugly patch, the transaction related functionality 1145 //should not be in this method 1146 if (newTransPerDocument) { 1147 beginTrans(); 1148 } 1149 1150 Document dbDoc = createDocument(doc,corpusID,secInfo); 1151 1152 if (newTransPerDocument) { 1153 commitTrans(); 1154 } 1155 1156 dbDocs.add(dbDoc); 1157 //8. let the world know 1158 fireResourceAdopted(new DatastoreEvent(this, 1159 DatastoreEvent.RESOURCE_ADOPTED, 1160 dbDoc, 1161 dbDoc.getLRPersistenceId() 1162 ) 1163 ); 1164 1165 //9. fire also resource written event because it's now saved 1166 fireResourceWritten(new DatastoreEvent(this, 1167 DatastoreEvent.RESOURCE_WRITTEN, 1168 dbDoc, 1169 dbDoc.getLRPersistenceId() 1170 ) 1171 ); 1172 1173 } 1174 else if (doc.getDataStore().equals(this)) { 1175 //persistent doc from the same DataStore 1176 fireResourceAdopted( 1177 new DatastoreEvent(this, DatastoreEvent.RESOURCE_ADOPTED, 1178 doc, 1179 doc.getLRPersistenceId())); 1180 1181 //6. fire also resource written event because it's now saved 1182 fireResourceWritten( 1183 new DatastoreEvent(this, DatastoreEvent.RESOURCE_WRITTEN, 1184 doc, 1185 doc.getLRPersistenceId())); 1186 } 1187 else { 1188 //persistent doc from other datastore 1189 //skip 1190 gate.util.Err.prln("document ["+doc.getLRPersistenceId()+"] is adopted from another "+ 1191 " datastore. Skipped."); 1192 } 1193 } 1194 1195 //4. create features 1196 if (this.dbType == DBHelper.ORACLE_DB) { 1197 createFeaturesBulk(lrID,DBHelper.FEATURE_OWNER_CORPUS,corp.getFeatures()); 1198 } 1199 else if (this.dbType == DBHelper.POSTGRES_DB) { 1200 createFeatures(lrID,DBHelper.FEATURE_OWNER_CORPUS,corp.getFeatures()); 1201 } 1202 else { 1203 Assert.fail(); 1204 } 1205 1206 1207 //5. create a DatabaseCorpusImpl and return it 1208/// Corpus dbCorpus = new DatabaseCorpusImpl(corp.getName(), 1209/// this, 1210/// lrID, 1211/// corp.getFeatures(), 1212/// dbDocs); 1213/// 1214 1215 Corpus dbCorpus = null; 1216 FeatureMap params = Factory.newFeatureMap(); 1217 HashMap initData = new HashMap(); 1218 1219 initData.put("DS",this); 1220 initData.put("LR_ID",lrID); 1221 initData.put("CORP_NAME",corp.getName()); 1222 initData.put("CORP_FEATURES",corp.getFeatures()); 1223 initData.put("CORP_SUPPORT_LIST",dbDocs); 1224 1225 params.put("initData__$$__", initData); 1226 1227 try { 1228 //here we create the persistent LR via Factory, so it's registered 1229 //in GATE 1230 dbCorpus = (Corpus)Factory.createResource("gate.corpora.DatabaseCorpusImpl", params); 1231 } 1232 catch (gate.creole.ResourceInstantiationException ex) { 1233 throw new GateRuntimeException(ex.getMessage()); 1234 } 1235 1236 //6. done 1237 return dbCorpus; 1238 } 1239 1240 /** 1241 * helper for adopt 1242 * creates a LR of type Document 1243 */ 1244 protected Document createDocument(Document doc,SecurityInfo secInfo) 1245 throws PersistenceException,SecurityException { 1246 1247 //delegate, set to Null 1248 return createDocument(doc,null,secInfo); 1249 } 1250 1251 1252 /** 1253 * helper for adopt 1254 * creates a LR of type Document 1255 */ 1256 protected Document createDocument(Document doc, Long corpusID,SecurityInfo secInfo) 1257 throws PersistenceException,SecurityException { 1258 1259 //-1. preconditions 1260 Assert.assertNotNull(doc); 1261 Assert.assertNotNull(secInfo); 1262 1263 //0. check securoity settings 1264 if (false == this.ac.isValidSecurityInfo(secInfo)) { 1265 throw new SecurityException("Invalid security settings"); 1266 } 1267 1268 //1. get the data to be stored 1269 AnnotationSet defaultAnnotations = doc.getAnnotations(); 1270 DocumentContent docContent = doc.getContent(); 1271 FeatureMap docFeatures = doc.getFeatures(); 1272 String docName = doc.getName(); 1273 URL docURL = doc.getSourceUrl(); 1274 Boolean docIsMarkupAware = doc.getMarkupAware(); 1275 Long docStartOffset = doc.getSourceUrlStartOffset(); 1276 Long docEndOffset = doc.getSourceUrlEndOffset(); 1277 String docEncoding = null; 1278 try { 1279 docEncoding = (String)doc. 1280 getParameterValue(Document.DOCUMENT_ENCODING_PARAMETER_NAME); 1281 } 1282 catch(gate.creole.ResourceInstantiationException re) { 1283 throw new PersistenceException("cannot create document: error getting " + 1284 " document encoding ["+re.getMessage()+"]"); 1285 } 1286 1287 1288 //3. create a Language Resource (an entry in T_LANG_RESOURCE) for this document 1289 Long lrID = createLR(DBHelper.DOCUMENT_CLASS,docName,secInfo,null); 1290 1291 //4. create a record in T_DOCUMENT for this document 1292 Long docID = createDoc(lrID, 1293 docURL, 1294 docEncoding, 1295 docStartOffset, 1296 docEndOffset, 1297 docIsMarkupAware, 1298 corpusID); 1299 1300 1301 //5. fill document content (record[s] in T_DOC_CONTENT) 1302 1303 //do we have content at all? 1304 if (docContent.size().longValue() > 0) { 1305// updateDocumentContent(docContentID,docContent); 1306 updateDocumentContent(docID,docContent); 1307 } 1308 1309 //6. insert annotations, etc 1310 1311 //6.1. create default annotation set 1312 createAnnotationSet(lrID,defaultAnnotations); 1313 1314 //6.2. create named annotation sets 1315 Map namedAnns = doc.getNamedAnnotationSets(); 1316 //the map may be null 1317 if (null != namedAnns) { 1318 Set setAnns = namedAnns.entrySet(); 1319 Iterator itAnns = setAnns.iterator(); 1320 1321 while (itAnns.hasNext()) { 1322 Map.Entry mapEntry = (Map.Entry)itAnns.next(); 1323 //String currAnnName = (String)mapEntry.getKey(); 1324 AnnotationSet currAnnSet = (AnnotationSet)mapEntry.getValue(); 1325 1326 //create a-sets 1327 createAnnotationSet(lrID,currAnnSet); 1328 } 1329 } 1330 1331 //7. create features 1332 if (this.dbType == DBHelper.ORACLE_DB) { 1333 createFeaturesBulk(lrID,DBHelper.FEATURE_OWNER_DOCUMENT,docFeatures); 1334 } 1335 else if (this.dbType == DBHelper.POSTGRES_DB) { 1336 createFeatures(lrID,DBHelper.FEATURE_OWNER_DOCUMENT,docFeatures); 1337 } 1338 else { 1339 Assert.fail(); 1340 } 1341 1342 1343 //9. create a DatabaseDocument wrapper and return it 1344 1345/* Document dbDoc = new DatabaseDocumentImpl(this.jdbcConn, 1346 doc.getName(), 1347 this, 1348 lrID, 1349 doc.getContent(), 1350 doc.getFeatures(), 1351 doc.getMarkupAware(), 1352 doc.getSourceUrl(), 1353 doc.getSourceUrlStartOffset(), 1354 doc.getSourceUrlEndOffset(), 1355 doc.getAnnotations(), 1356 doc.getNamedAnnotationSets()); 1357*/ 1358 Document dbDoc = null; 1359 FeatureMap params = Factory.newFeatureMap(); 1360 1361 HashMap initData = new HashMap(); 1362 initData.put("JDBC_CONN",this.jdbcConn); 1363 initData.put("DS",this); 1364 initData.put("LR_ID",lrID); 1365 initData.put("DOC_NAME",doc.getName()); 1366 initData.put("DOC_CONTENT",doc.getContent()); 1367 initData.put("DOC_FEATURES",doc.getFeatures()); 1368 initData.put("DOC_MARKUP_AWARE",doc.getMarkupAware()); 1369 initData.put("DOC_SOURCE_URL",doc.getSourceUrl()); 1370 initData.put("DOC_SOURCE_URL_START",doc.getSourceUrlStartOffset()); 1371 initData.put("DOC_SOURCE_URL_END",doc.getSourceUrlEndOffset()); 1372 initData.put("DOC_DEFAULT_ANNOTATIONS",doc.getAnnotations()); 1373 initData.put("DOC_NAMED_ANNOTATION_SETS",doc.getNamedAnnotationSets()); 1374 1375 params.put("initData__$$__", initData); 1376 1377 try { 1378 //here we create the persistent LR via Factory, so it's registered 1379 //in GATE 1380 dbDoc = (Document)Factory.createResource("gate.corpora.DatabaseDocumentImpl", params); 1381 } 1382 catch (gate.creole.ResourceInstantiationException ex) { 1383 throw new GateRuntimeException(ex.getMessage()); 1384 } 1385 1386 return dbDoc; 1387 } 1388 1389 protected abstract Long createLR(String lrType, 1390 String lrName, 1391 SecurityInfo si, 1392 Long lrParentID) 1393 throws PersistenceException,SecurityException; 1394 1395 1396 protected abstract Long createDoc(Long _lrID, 1397 URL _docURL, 1398 String _docEncoding, 1399 Long _docStartOffset, 1400 Long _docEndOffset, 1401 Boolean _docIsMarkupAware, 1402 Long _corpusID) 1403 throws PersistenceException; 1404 1405 protected abstract void updateDocumentContent(Long docID,DocumentContent content) 1406 throws PersistenceException; 1407 1408 protected abstract void createAnnotationSet(Long lrID, AnnotationSet aset) 1409 throws PersistenceException; 1410 1411 protected abstract void createFeaturesBulk(Long entityID, int entityType, FeatureMap features) 1412 throws PersistenceException; 1413 1414 protected abstract void createFeatures(Long entityID, int entityType, FeatureMap features) 1415 throws PersistenceException; 1416 1417 /** 1418 * Save: synchonise the in-memory image of the LR with the persistent 1419 * image. 1420 */ 1421 protected void _sync(LanguageResource lr, boolean openNewTrans) 1422 throws PersistenceException,SecurityException { 1423 1424 //0.preconditions 1425 Assert.assertNotNull(lr); 1426 Long lrID = (Long)lr.getLRPersistenceId(); 1427 1428 if (false == lr instanceof Document && 1429 false == lr instanceof Corpus) { 1430 //only documents and corpuses could be serialized in DB 1431 throw new IllegalArgumentException("only Documents and Corpuses could "+ 1432 "be serialized in DB"); 1433 } 1434 1435 // check that this LR is one of ours (i.e. has been adopted) 1436 if( null == lr.getDataStore() || false == lr.getDataStore().equals(this)) 1437 throw new PersistenceException( 1438 "This LR is not stored in this DataStore" 1439 ); 1440 1441 1442 //1. check session 1443 if (null == this.session) { 1444 throw new SecurityException("session not set"); 1445 } 1446 1447 if (false == this.ac.isValidSession(this.session)) { 1448 throw new SecurityException("invalid session supplied"); 1449 } 1450 1451 //2. check permissions 1452 if (false == canWriteLR(lrID)) { 1453 throw new SecurityException("insufficient privileges"); 1454 } 1455 1456 //3. is the resource locked? 1457 User lockingUser = getLockingUser(lr); 1458 User currUser = this.session.getUser(); 1459 1460 if (lockingUser != null && false == lockingUser.equals(currUser)) { 1461 throw new PersistenceException("document is locked by another user and cannot be synced"); 1462 } 1463 1464 1465 boolean transFailed = false; 1466 try { 1467 //2. autocommit should be FALSE because of LOBs 1468 if (openNewTrans) { 1469 beginTrans(); 1470 } 1471 1472 //3. perform changes, if anything goes wrong, rollback 1473 if (lr instanceof Document) { 1474 syncDocument((Document)lr); 1475 } 1476 else { 1477 syncCorpus((Corpus)lr); 1478 } 1479 1480 //4. done, commit 1481 if (openNewTrans) { 1482 commitTrans(); 1483 } 1484 } 1485 catch(PersistenceException pe) { 1486 transFailed = true; 1487 throw(pe); 1488 } 1489 finally { 1490 //problems? 1491 if (transFailed) { 1492 rollbackTrans(); 1493 } 1494 } 1495 1496 // let the world know about it 1497 fireResourceWritten( 1498 new DatastoreEvent(this, DatastoreEvent.RESOURCE_WRITTEN, lr, lr.getLRPersistenceId())); 1499 } 1500 1501 /** 1502 * Releases the exlusive lock on a resource from the persistent store. 1503 */ 1504 protected User getLockingUser(LanguageResource lr) 1505 throws PersistenceException,SecurityException { 1506 1507 //0. preconditions 1508 Assert.assertNotNull(lr); 1509 Assert.assertTrue(lr instanceof DatabaseDocumentImpl || 1510 lr instanceof DatabaseCorpusImpl); 1511 Assert.assertNotNull(lr.getLRPersistenceId()); 1512 Assert.assertEquals(lr.getDataStore(),this); 1513 1514 //delegate 1515 return getLockingUser((Long)lr.getLRPersistenceId()); 1516 } 1517 1518 1519 1520 /** 1521 * Releases the exlusive lock on a resource from the persistent store. 1522 */ 1523 protected User getLockingUser(Long lrID) 1524 throws PersistenceException,SecurityException { 1525 1526 //1. check session 1527 if (null == this.session) { 1528 throw new SecurityException("session not set"); 1529 } 1530 1531 if (false == this.ac.isValidSession(this.session)) { 1532 throw new SecurityException("invalid session supplied"); 1533 } 1534 1535 //3. read from DB 1536 PreparedStatement pstmt = null; 1537 Long userID = null; 1538 ResultSet rs = null; 1539 1540 try { 1541 1542 String sql = null; 1543 1544 if (this.dbType == DBHelper.ORACLE_DB) { 1545 sql = " select nvl(lr_locking_user_id,0) as user_id" + 1546 " from "+this.dbSchema+"t_lang_resource " + 1547 " where lr_id = ?"; 1548 } 1549 else if (this.dbType == DBHelper.POSTGRES_DB) { 1550 sql = " select coalesce(lr_locking_user_id,0) as user_id" + 1551 " from t_lang_resource " + 1552 " where lr_id = ?"; 1553 } 1554 else { 1555 throw new IllegalArgumentException(); 1556 } 1557 1558 pstmt = this.jdbcConn.prepareStatement(sql); 1559 pstmt.setLong(1,lrID.longValue()); 1560 pstmt.execute(); 1561 rs = pstmt.getResultSet(); 1562 1563 if (false == rs.next()) { 1564 throw new PersistenceException("LR not found in DB"); 1565 } 1566 1567 long result = rs.getLong("user_id"); 1568 1569 return result == 0 ? null 1570 : this.ac.findUser(new Long(result)); 1571 } 1572 catch(SQLException sqle) { 1573 throw new PersistenceException("can't get locking user from DB : ["+ sqle.getMessage()+"]"); 1574 } 1575 finally { 1576 DBHelper.cleanup(rs); 1577 DBHelper.cleanup(pstmt); 1578 } 1579 } 1580 1581 /** helper for sync() - saves a Corpus in the database */ 1582 protected void syncCorpus(Corpus corp) 1583 throws PersistenceException,SecurityException { 1584 1585 //0. preconditions 1586 Assert.assertNotNull(corp); 1587 Assert.assertTrue(corp instanceof DatabaseCorpusImpl); 1588 Assert.assertEquals(this,corp.getDataStore()); 1589 Assert.assertNotNull(corp.getLRPersistenceId()); 1590 1591 EventAwareCorpus dbCorpus = (EventAwareCorpus)corp; 1592 1593 //1. sync the corpus name? 1594 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_NAME)) { 1595 _syncLR(corp); 1596 } 1597 1598 //2. sync the corpus features? 1599 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_FEATURES)) { 1600 _syncFeatures(corp); 1601 } 1602 1603 //2.5 get removed documents and detach (not remove) them from the corpus in the 1604 //database 1605 List removedDocLRIDs = dbCorpus.getRemovedDocuments(); 1606 if (removedDocLRIDs.size() > 0) { 1607 _syncRemovedDocumentsFromCorpus(removedDocLRIDs,(Long)corp.getLRPersistenceId()); 1608 } 1609 1610 //3. get all documents 1611 //--Iterator it = corp.iterator(); 1612 Iterator it = dbCorpus.getLoadedDocuments().iterator(); 1613 1614 while (it.hasNext()) { 1615 Document dbDoc = (Document)it.next(); 1616 //note - document may be NULL which means it was not loaded (load on demand) 1617 //just ignore it then 1618 if (null == dbDoc) { 1619 continue; 1620 } 1621 1622 //adopt/sync? 1623 if (null == dbDoc.getLRPersistenceId()) { 1624 //doc was never adopted, adopt it 1625 1626 //3.1 remove the transient doc from the corpus 1627 it.remove(); 1628 1629 //3.2 get the security info for the corpus 1630 SecurityInfo si = getSecurityInfo(corp); 1631 1632 1633 Document adoptedDoc = null; 1634 try { 1635 //3.3. adopt the doc with the sec info 1636//System.out.println("adopting ["+dbDoc.getName()+"] ..."); 1637 //don't open a new transaction, since sync() already has opended one 1638 adoptedDoc = (Document)_adopt(dbDoc,si,true); 1639 1640 //3.4. add doc to corpus in DB 1641 addDocumentToCorpus((Long)adoptedDoc.getLRPersistenceId(), 1642 (Long)corp.getLRPersistenceId()); 1643 } 1644 catch(SecurityException se) { 1645 throw new PersistenceException(se); 1646 } 1647 1648 //3.5 add back to corpus the new DatabaseDocument 1649 corp.add(adoptedDoc); 1650 } 1651 else { 1652 //don't open a new transaction, the sync() called for corpus has already 1653 //opened one 1654 try { 1655 _sync(dbDoc,true); 1656 1657 // let the world know about it 1658 fireResourceWritten( new DatastoreEvent(this, 1659 DatastoreEvent.RESOURCE_WRITTEN, 1660 dbDoc, 1661 dbDoc.getLRPersistenceId() 1662 ) 1663 ); 1664 1665 //if the document is form the same DS but did not belong to the corpus add it now 1666 //NOTE: if the document already belongs to the corpus then nothing will be changed 1667 //in the DB 1668 addDocumentToCorpus((Long)dbDoc.getLRPersistenceId(), 1669 (Long)corp.getLRPersistenceId()); 1670 } 1671 catch(SecurityException se) { 1672 gate.util.Err.prln("document cannot be synced: ["+se.getMessage()+"]"); 1673 } 1674 } 1675 } 1676 } 1677 1678 /** helper for sync() - saves a Document in the database */ 1679 /** helper for sync() - saves a Document in the database */ 1680 protected void syncDocument(Document doc) 1681 throws PersistenceException, SecurityException { 1682 1683 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1684 Assert.assertTrue(doc.getLRPersistenceId() instanceof Long); 1685 1686 Long lrID = (Long)doc.getLRPersistenceId(); 1687 EventAwareLanguageResource dbDoc = (EventAwareLanguageResource)doc; 1688 //1. sync LR 1689 // only name can be changed here 1690 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.RES_NAME)) { 1691 _syncLR(doc); 1692 } 1693 1694 //2. sync Document 1695 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.DOC_MAIN)) { 1696 _syncDocumentHeader(doc); 1697 } 1698 1699 //3. [optional] sync Content 1700 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.DOC_CONTENT)) { 1701 _syncDocumentContent(doc); 1702 } 1703 1704 //4. [optional] sync Features 1705 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.RES_FEATURES)) { 1706 _syncFeatures(doc); 1707 } 1708 1709 //5. [optional] delete from DB named sets that were removed from the document 1710 Collection removedSets = ((EventAwareDocument)dbDoc).getRemovedAnnotationSets(); 1711 Collection addedSets = ((EventAwareDocument)dbDoc).getAddedAnnotationSets(); 1712 if (false == removedSets.isEmpty() || false == addedSets.isEmpty()) { 1713 _syncAnnotationSets(doc,removedSets,addedSets); 1714 } 1715 1716 //6. [optional] sync Annotations 1717 _syncAnnotations(doc); 1718 } 1719 1720 1721 /** 1722 * helper for sync() 1723 * NEVER call directly 1724 */ 1725 protected abstract void _syncLR(LanguageResource lr) 1726 throws PersistenceException,SecurityException; 1727 1728 /** helper for sync() - never call directly */ 1729 protected abstract void _syncDocumentHeader(Document doc) 1730 throws PersistenceException; 1731 1732 /** helper for sync() - never call directly */ 1733 protected abstract void _syncDocumentContent(Document doc) 1734 throws PersistenceException; 1735 1736 /** helper for sync() - never call directly */ 1737 protected abstract void _syncFeatures(LanguageResource lr) 1738 throws PersistenceException; 1739 1740 /** helper for sync() - never call directly */ 1741 protected void _syncAnnotationSets(Document doc,Collection removedSets,Collection addedSets) 1742 throws PersistenceException { 1743 1744 //0. preconditions 1745 Assert.assertNotNull(doc); 1746 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1747 Assert.assertNotNull(doc.getLRPersistenceId()); 1748 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(), 1749 this.getDatabaseID()); 1750 Assert.assertNotNull(removedSets); 1751 Assert.assertNotNull(addedSets); 1752 1753 Long lrID = (Long)doc.getLRPersistenceId(); 1754 1755 //1. delete from DB removed a-sets 1756 PreparedStatement stmt = null; 1757 1758 try { 1759 1760 if (this.dbType == DBHelper.ORACLE_DB) { 1761 stmt = this.jdbcConn.prepareCall("{ call "+this.dbSchema+"persist.delete_annotation_set(?,?) }"); 1762 } 1763 else if (this.dbType == DBHelper.POSTGRES_DB) { 1764 stmt = this.jdbcConn.prepareStatement("select persist_delete_annotation_set(?,?)"); 1765 } 1766 else { 1767 Assert.fail(); 1768 } 1769 1770 Iterator it = removedSets.iterator(); 1771 while (it.hasNext()) { 1772 String setName = (String)it.next(); 1773 stmt.setLong(1,lrID.longValue()); 1774 stmt.setString(2,setName); 1775 stmt.execute(); 1776 } 1777 } 1778 catch(SQLException sqle) { 1779 throw new PersistenceException("can't remove annotation set from DB: ["+ sqle.getMessage()+"]"); 1780 } 1781 finally { 1782 DBHelper.cleanup(stmt); 1783 } 1784 1785 //2. create in DB new a-sets 1786 Iterator it = addedSets.iterator(); 1787 while (it.hasNext()) { 1788 String setName = (String)it.next(); 1789 AnnotationSet aset = doc.getAnnotations(setName); 1790 1791 Assert.assertNotNull(aset); 1792 Assert.assertTrue(aset instanceof DatabaseAnnotationSetImpl); 1793 1794 createAnnotationSet(lrID,aset); 1795 } 1796 } 1797 1798 1799 /** helper for sync() - never call directly */ 1800 protected void _syncAnnotations(Document doc) 1801 throws PersistenceException { 1802 1803 //0. preconditions 1804 Assert.assertNotNull(doc); 1805 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1806 Assert.assertNotNull(doc.getLRPersistenceId()); 1807 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(), 1808 this.getDatabaseID()); 1809 1810 1811 EventAwareDocument ead = (EventAwareDocument)doc; 1812 //1. get the sets read from the DB for this document 1813 //chnaged annotations can occur only in such sets 1814 Collection loadedSets = ead.getLoadedAnnotationSets(); 1815 1816 Iterator it = loadedSets.iterator(); 1817 while (it.hasNext()) { 1818 AnnotationSet as = (AnnotationSet)it.next(); 1819 //check that this set is neither NEW nor DELETED 1820 //they should be already synced 1821 if (ead.getAddedAnnotationSets().contains(as.getName()) || 1822 ead.getRemovedAnnotationSets().contains(as.getName())) { 1823 //oops, ignore it 1824 continue; 1825 } 1826 1827 EventAwareAnnotationSet eas = (EventAwareAnnotationSet)as; 1828 Assert.assertNotNull(as); 1829 1830 Collection anns = null; 1831 anns = eas.getAddedAnnotations(); 1832 Assert.assertNotNull(anns); 1833 if (anns.size()>0) { 1834 _syncAddedAnnotations(doc,as,anns); 1835 } 1836 1837 anns = eas.getRemovedAnnotations(); 1838 Assert.assertNotNull(anns); 1839 if (anns.size()>0) { 1840 _syncRemovedAnnotations(doc,as,anns); 1841 } 1842 1843 anns = eas.getChangedAnnotations(); 1844 Assert.assertNotNull(anns); 1845 if (anns.size()>0) { 1846 _syncChangedAnnotations(doc,as,anns); 1847 } 1848 } 1849 } 1850 1851 /** helper for sync() - never call directly */ 1852 protected void _syncAddedAnnotations(Document doc, AnnotationSet as, Collection changes) 1853 throws PersistenceException { 1854 1855 //0.preconditions 1856 Assert.assertNotNull(doc); 1857 Assert.assertNotNull(as); 1858 Assert.assertNotNull(changes); 1859 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1860 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl); 1861 Assert.assertTrue(changes.size() > 0); 1862 1863 1864 PreparedStatement pstmt = null; 1865 ResultSet rs = null; 1866 CallableStatement cstmt = null; 1867 Long lrID = (Long)doc.getLRPersistenceId(); 1868 Long asetID = null; 1869 1870 try { 1871 //1. get the a-set ID in the database 1872 String sql = " select as_id " + 1873 " from "+this.dbSchema+"v_annotation_set " + 1874 " where lr_id = ? "; 1875 //do we have aset name? 1876 String clause = null; 1877 String name = as.getName(); 1878 if (null != name) { 1879 clause = " and as_name = ? "; 1880 } 1881 else { 1882 clause = " and as_name is null "; 1883 } 1884 sql = sql + clause; 1885 1886 pstmt = this.jdbcConn.prepareStatement(sql); 1887 pstmt.setLong(1,lrID.longValue()); 1888 if (null != name) { 1889 pstmt.setString(2,name); 1890 } 1891 pstmt.execute(); 1892 rs = pstmt.getResultSet(); 1893 1894 if (rs.next()) { 1895 asetID = new Long(rs.getLong("as_id")); 1896 } 1897 else { 1898 throw new PersistenceException("cannot find annotation set with" + 1899 " name=["+name+"] , LRID=["+lrID+"] in database"); 1900 } 1901 1902 //cleanup 1903 DBHelper.cleanup(rs); 1904 DBHelper.cleanup(pstmt); 1905 1906 //3. insert the new annotations from this set 1907 1908 //3.1. prepare call 1909 if (this.dbType == DBHelper.ORACLE_DB) { 1910 1911 cstmt = this.jdbcConn.prepareCall( 1912 "{ call "+Gate.DB_OWNER+".persist.create_annotation(?,?,?,?,?,?,?,?,?) }"); 1913 1914 Long annGlobalID = null; 1915 Iterator it = changes.iterator(); 1916 1917 while (it.hasNext()) { 1918 1919 //3.2. insert annotation 1920 Annotation ann = (Annotation)it.next(); 1921 1922 Node start = (Node)ann.getStartNode(); 1923 Node end = (Node)ann.getEndNode(); 1924 String type = ann.getType(); 1925 1926 cstmt.setLong(1,lrID.longValue()); 1927 cstmt.setLong(2,ann.getId().longValue()); 1928 cstmt.setLong(3,asetID.longValue()); 1929 cstmt.setLong(4,start.getId().longValue()); 1930 cstmt.setLong(5,start.getOffset().longValue()); 1931 cstmt.setLong(6,end.getId().longValue()); 1932 cstmt.setLong(7,end.getOffset().longValue()); 1933 cstmt.setString(8,type); 1934 cstmt.registerOutParameter(9,java.sql.Types.BIGINT); 1935 1936 cstmt.execute(); 1937 annGlobalID = new Long(cstmt.getLong(9)); 1938 1939 //3.3. set annotation features 1940 FeatureMap features = ann.getFeatures(); 1941 Assert.assertNotNull(features); 1942 1943 if (this.dbType == DBHelper.ORACLE_DB) { 1944 createFeaturesBulk(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 1945 } 1946 else if (this.dbType == DBHelper.POSTGRES_DB) { 1947 createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 1948 } 1949 else { 1950 Assert.fail(); 1951 } 1952 } 1953 } 1954 else if (this.dbType == DBHelper.POSTGRES_DB) { 1955 1956 sql = "select persist_create_annotation(?,?,?,?,?,?,?,?)"; 1957 pstmt = this.jdbcConn.prepareStatement(sql); 1958 1959 Long annGlobalID = null; 1960 Iterator it = changes.iterator(); 1961 1962 while (it.hasNext()) { 1963 1964 //3.2. insert annotation 1965 Annotation ann = (Annotation)it.next(); 1966 1967 Node start = (Node)ann.getStartNode(); 1968 Node end = (Node)ann.getEndNode(); 1969 String type = ann.getType(); 1970 1971 pstmt.setLong(1,lrID.longValue()); 1972 pstmt.setLong(2,ann.getId().longValue()); 1973 pstmt.setLong(3,asetID.longValue()); 1974 pstmt.setLong(4,start.getId().longValue()); 1975 pstmt.setLong(5,start.getOffset().longValue()); 1976 pstmt.setLong(6,end.getId().longValue()); 1977 pstmt.setLong(7,end.getOffset().longValue()); 1978 pstmt.setString(8,type); 1979 pstmt.execute(); 1980 1981 rs = pstmt.getResultSet(); 1982 1983 if (false == rs.next()) { 1984 throw new PersistenceException("empty result set"); 1985 } 1986 annGlobalID = new Long(rs.getLong(1)); 1987 1988 //3.3. set annotation features 1989 FeatureMap features = ann.getFeatures(); 1990 Assert.assertNotNull(features); 1991 createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 1992 } 1993 } 1994 1995 else { 1996 throw new IllegalArgumentException(); 1997 } 1998 1999 } 2000 catch(SQLException sqle) { 2001 throw new PersistenceException("can't add annotations in DB : ["+ 2002 sqle.getMessage()+"]"); 2003 } 2004 finally { 2005 DBHelper.cleanup(rs); 2006 DBHelper.cleanup(pstmt); 2007 DBHelper.cleanup(cstmt); 2008 } 2009 } 2010 2011 /** helper for sync() - never call directly */ 2012 protected void _syncRemovedAnnotations(Document doc,AnnotationSet as, Collection changes) 2013 throws PersistenceException { 2014 2015 //0.preconditions 2016 Assert.assertNotNull(doc); 2017 Assert.assertNotNull(as); 2018 Assert.assertNotNull(changes); 2019 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 2020 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl); 2021 Assert.assertTrue(changes.size() > 0); 2022 2023 2024 PreparedStatement pstmt = null; 2025 ResultSet rs = null; 2026 Long lrID = (Long)doc.getLRPersistenceId(); 2027 Long docID = null; 2028 Long asetID = null; 2029 2030 try { 2031 //1. get the a-set ID in the database 2032 String sql = " select as_id, " + 2033 " as_doc_id " + 2034 " from "+this.dbSchema+"v_annotation_set " + 2035 " where lr_id = ? "; 2036 //do we have aset name? 2037 String clause = null; 2038 String name = as.getName(); 2039 if (null != name) { 2040 clause = " and as_name = ? "; 2041 } 2042 else { 2043 clause = " and as_name is null "; 2044 } 2045 sql = sql + clause; 2046 2047 pstmt = this.jdbcConn.prepareStatement(sql); 2048 pstmt.setLong(1,lrID.longValue()); 2049 if (null != name) { 2050 pstmt.setString(2,name); 2051 } 2052 pstmt.execute(); 2053 rs = pstmt.getResultSet(); 2054 2055 if (rs.next()) { 2056 asetID = new Long(rs.getLong("as_id")); 2057 docID = new Long(rs.getLong("as_doc_id")); 2058 } 2059 else { 2060 throw new PersistenceException("cannot find annotation set with" + 2061 " name=["+name+"] , LRID=["+lrID+"] in database"); 2062 } 2063 2064 //3. delete the removed annotations from this set 2065 2066 //cleanup 2067 DBHelper.cleanup(rs); 2068 DBHelper.cleanup(pstmt); 2069 2070 //3.1. prepare call 2071 2072 if (this.dbType == DBHelper.ORACLE_DB) { 2073 pstmt = this.jdbcConn.prepareCall("{ call "+this.dbSchema+"persist.delete_annotation(?,?) }"); 2074 } 2075 else if (this.dbType == DBHelper.POSTGRES_DB) { 2076 pstmt = this.jdbcConn.prepareStatement("select persist_delete_annotation(?,?)"); 2077 } 2078 else { 2079 throw new IllegalArgumentException(); 2080 } 2081 2082 Iterator it = changes.iterator(); 2083 2084 while (it.hasNext()) { 2085 2086 //3.2. insert annotation 2087 Annotation ann = (Annotation)it.next(); 2088 2089 pstmt.setLong(1,docID.longValue()); //annotations are linked with documents, not LRs! 2090 pstmt.setLong(2,ann.getId().longValue()); 2091 pstmt.execute(); 2092 } 2093 } 2094 catch(SQLException sqle) { 2095 throw new PersistenceException("can't delete annotations in DB : ["+ 2096 sqle.getMessage()+"]"); 2097 } 2098 finally { 2099 DBHelper.cleanup(rs); 2100 DBHelper.cleanup(pstmt); 2101 } 2102 } 2103 2104 2105 /** helper for sync() - never call directly */ 2106 protected void _syncChangedAnnotations(Document doc,AnnotationSet as, Collection changes) 2107 throws PersistenceException { 2108 2109 //technically this approach sux 2110 //at least it works 2111 2112 //1. delete 2113 _syncRemovedAnnotations(doc,as,changes); 2114 //2. recreate 2115 _syncAddedAnnotations(doc,as,changes); 2116 } 2117 2118 /** 2119 * Get a resource from the persistent store. 2120 * <B>Don't use this method - use Factory.createResource with 2121 * DataStore and DataStoreInstanceId parameters set instead.</B> 2122 */ 2123 public LanguageResource getLr(String lrClassName, Object lrPersistenceId) 2124 throws PersistenceException,SecurityException { 2125 2126 LanguageResource result = null; 2127 2128 //0. preconditions 2129 Assert.assertNotNull(lrPersistenceId); 2130 2131 //1. check session 2132 if (null == this.session) { 2133 throw new SecurityException("session not set"); 2134 } 2135 2136 if (false == this.ac.isValidSession(this.session)) { 2137 throw new SecurityException("invalid session supplied"); 2138 } 2139 2140 //2. check permissions 2141 if (false == canReadLR(lrPersistenceId)) { 2142 throw new SecurityException("insufficient privileges"); 2143 } 2144 2145 //3. get resource from DB 2146 if (lrClassName.equals(DBHelper.DOCUMENT_CLASS)) { 2147 result = readDocument(lrPersistenceId); 2148 Assert.assertTrue(result instanceof DatabaseDocumentImpl); 2149 } 2150 else if (lrClassName.equals(DBHelper.CORPUS_CLASS)) { 2151 result = readCorpus(lrPersistenceId); 2152 Assert.assertTrue(result instanceof DatabaseCorpusImpl); 2153 } 2154 else { 2155 throw new IllegalArgumentException("resource class should be either Document or Corpus"); 2156 } 2157 2158 //4. postconditions 2159 Assert.assertNotNull(result.getDataStore()); 2160 Assert.assertTrue(result.getDataStore() instanceof DatabaseDataStore); 2161 Assert.assertNotNull(result.getLRPersistenceId()); 2162 2163 //5. register the read doc as listener for sync events 2164 addDatastoreListener((DatastoreListener)result); 2165 2166 //6. add the resource to the list of dependent resources - i.e. the ones that the 2167 //data store should take care upon closing [and call sync()] 2168 this.dependentResources.add(result); 2169 2170 //7. done 2171 return result; 2172 } 2173 2174 /** helper method for getLR - reads LR of type Document */ 2175 private DatabaseDocumentImpl readDocument(Object lrPersistenceId) 2176 throws PersistenceException { 2177 2178 //0. preconditions 2179 Assert.assertNotNull(lrPersistenceId); 2180 2181 if (false == lrPersistenceId instanceof Long) { 2182 throw new IllegalArgumentException(); 2183 } 2184 2185 // 1. dummy document to be initialized 2186 DatabaseDocumentImpl result = new DatabaseDocumentImpl(this.jdbcConn); 2187 2188 PreparedStatement pstmt = null; 2189 ResultSet rs = null; 2190 2191 //3. read from DB 2192 try { 2193 String sql = " select lr_name, " + 2194 " lrtp_type, " + 2195 " lr_id, " + 2196 " lr_parent_id, " + 2197 " doc_id, " + 2198 " doc_url, " + 2199 " doc_start, " + 2200 " doc_end, " + 2201 " doc_is_markup_aware " + 2202 " from "+this.dbSchema+"v_document " + 2203 " where lr_id = ? "; 2204 2205 pstmt = this.jdbcConn.prepareStatement(sql); 2206 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 2207 pstmt.execute(); 2208 rs = pstmt.getResultSet(); 2209 2210 if (false == rs.next()) { 2211 //ooops mo data found 2212 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2213 } 2214 2215 //4. fill data 2216 2217 //4.0 name 2218 String lrName = rs.getString("lr_name"); 2219 Assert.assertNotNull(lrName); 2220 result.setName(lrName); 2221 2222 //4.1 parent 2223 Long parentID = null; 2224 long parent_id = rs.getLong("lr_parent_id"); 2225 if (false == rs.wasNull()) { 2226 parentID = new Long(parent_id); 2227 2228 //read parent resource 2229 LanguageResource parentLR = this.getLr(DBHelper.DOCUMENT_CLASS,parentID); 2230 Assert.assertNotNull(parentLR); 2231 Assert.assertTrue(parentLR instanceof DatabaseDocumentImpl); 2232 2233 result.setParent(parentLR); 2234 } 2235 2236 2237 //4.2. markup aware 2238 if (this.dbType == DBHelper.ORACLE_DB) { 2239 long markup = rs.getLong("doc_is_markup_aware"); 2240 Assert.assertTrue(markup == DBHelper.FALSE || markup == DBHelper.TRUE); 2241 if (markup == DBHelper.FALSE) { 2242 result.setMarkupAware(Boolean.FALSE); 2243 } 2244 else { 2245 result.setMarkupAware(Boolean.TRUE); 2246 2247 } 2248 } 2249 else if (this.dbType == DBHelper.POSTGRES_DB) { 2250 boolean markup = rs.getBoolean("doc_is_markup_aware"); 2251 result.setMarkupAware(new Boolean(markup)); 2252 } 2253 else { 2254 throw new IllegalArgumentException(); 2255 } 2256 2257 2258 //4.3 datastore 2259 result.setDataStore(this); 2260 2261 //4.4. persist ID 2262 Long persistID = new Long(rs.getLong("lr_id")); 2263 result.setLRPersistenceId(persistID); 2264 2265 //4.5 source url 2266 String url = rs.getString("doc_url"); 2267 result.setSourceUrl(new URL(url)); 2268 2269 //4.6. start offset 2270 Long start = null; 2271 long longVal = rs.getLong("doc_start"); 2272 //null? 2273 //if NULL is stored in the DB, Oracle returns 0 which is not what we want 2274 if (false == rs.wasNull()) { 2275 start = new Long(longVal); 2276 } 2277 result.setSourceUrlStartOffset(start); 2278// initData.put("DOC_SOURCE_URL_START",start); 2279 2280 //4.7. end offset 2281 Long end = null; 2282 longVal = rs.getLong("doc_end"); 2283 //null? 2284 //if NULL is stored in the DB, Oracle returns 0 which is not what we want 2285 if (false == rs.wasNull()) { 2286 end = new Long(longVal); 2287 } 2288 result.setSourceUrlEndOffset(end); 2289// initData.put("DOC_SOURCE_URL_END",end); 2290 2291 //4.8 features 2292 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_DOCUMENT); 2293 result.setFeatures(features); 2294 //initData.put("DOC_FEATURES",features); 2295 2296 //4.9 set the nextAnnotationID correctly 2297 long doc_id = rs.getLong("doc_id"); 2298 2299 //cleanup 2300 DBHelper.cleanup(rs); 2301 DBHelper.cleanup(pstmt); 2302 2303 sql = " select max(ann_local_id),'ann_id'" + 2304 " from "+this.dbSchema+"t_annotation " + 2305 " where ann_doc_id = ?" + 2306 " union " + 2307 " select max(node_local_id),'node_id' " + 2308 " from "+this.dbSchema+"t_node " + 2309 " where node_doc_id = ?"; 2310 2311 pstmt = this.jdbcConn.prepareStatement(sql); 2312 pstmt.setLong(1,doc_id); 2313 pstmt.setLong(2,doc_id); 2314 pstmt.execute(); 2315 rs = pstmt.getResultSet(); 2316 2317 int maxAnnID = 0 , maxNodeID = 0; 2318 //ann id 2319 if (false == rs.next()) { 2320 //ooops no data found 2321 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2322 } 2323 if (rs.getString(2).equals("ann_id")) 2324 maxAnnID = rs.getInt(1); 2325 else 2326 maxNodeID = rs.getInt(1); 2327 2328 if (false == rs.next()) { 2329 //ooops no data found 2330 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2331 } 2332 if (rs.getString(2).equals("node_id")) 2333 maxNodeID = rs.getInt(1); 2334 else 2335 maxAnnID = rs.getInt(1); 2336 2337 result.setNextNodeId(maxNodeID+1); 2338// initData.put("DOC_NEXT_NODE_ID",new Integer(maxNodeID+1)); 2339 result.setNextAnnotationId(maxAnnID+1); 2340// initData.put("DOC_NEXT_ANN_ID",new Integer(maxAnnID+1)); 2341 2342 2343// params.put("initData__$$__", initData); 2344// try { 2345 //here we create the persistent LR via Factory, so it's registered 2346 //in GATE 2347// result = (DatabaseDocumentImpl)Factory.createResource("gate.corpora.DatabaseDocumentImpl", params); 2348// } 2349// catch (gate.creole.ResourceInstantiationException ex) { 2350// throw new GateRuntimeException(ex.getMessage()); 2351// } 2352 } 2353 catch(SQLException sqle) { 2354 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]"); 2355 } 2356 catch(Exception e) { 2357 throw new PersistenceException(e); 2358 } 2359 finally { 2360 DBHelper.cleanup(rs); 2361 DBHelper.cleanup(pstmt); 2362 } 2363 2364 return result; 2365 } 2366 2367 2368 /** 2369 * helper method for getLR - reads LR of type Corpus 2370 */ 2371 private DatabaseCorpusImpl readCorpus(Object lrPersistenceId) 2372 throws PersistenceException { 2373 2374 //0. preconditions 2375 Assert.assertNotNull(lrPersistenceId); 2376 2377 if (false == lrPersistenceId instanceof Long) { 2378 throw new IllegalArgumentException(); 2379 } 2380 2381 //3. read from DB 2382 PreparedStatement pstmt = null; 2383 ResultSet rs = null; 2384 DatabaseCorpusImpl result = null; 2385 2386 try { 2387 String sql = " select lr_name " + 2388 " from "+this.dbSchema+"t_lang_resource " + 2389 " where lr_id = ? "; 2390 pstmt = this.jdbcConn.prepareStatement(sql); 2391 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 2392 pstmt.execute(); 2393 rs = pstmt.getResultSet(); 2394 2395 if (false == rs.next()) { 2396 //ooops mo data found 2397 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2398 } 2399 2400 //4. fill data 2401 2402 //4.1 name 2403 String lrName = rs.getString("lr_name"); 2404 Assert.assertNotNull(lrName); 2405 2406 //4.8 features 2407 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_CORPUS); 2408 2409 //4.9 cleanup 2410 DBHelper.cleanup(rs); 2411 DBHelper.cleanup(pstmt); 2412 2413 sql = " select lr_id ," + 2414 " lr_name " + 2415 " from "+this.dbSchema+"t_document doc, " + 2416 " "+this.dbSchema+"t_lang_resource lr, " + 2417 " "+this.dbSchema+"t_corpus_document corpdoc, " + 2418 " "+this.dbSchema+"t_corpus corp " + 2419 " where lr.lr_id = doc.doc_lr_id " + 2420 " and doc.doc_id = corpdoc.cd_doc_id " + 2421 " and corpdoc.cd_corp_id = corp.corp_id " + 2422 " and corp_lr_id = ? "; 2423 pstmt = this.jdbcConn.prepareStatement(sql); 2424 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 2425 pstmt.execute(); 2426 rs = pstmt.getResultSet(); 2427 2428 Vector documentData = new Vector(); 2429 while (rs.next()) { 2430 Long docLRID = new Long(rs.getLong("lr_id")); 2431 String docName = rs.getString("lr_name"); 2432 documentData.add(new DocumentData(docName, docLRID)); 2433 } 2434 DBHelper.cleanup(rs); 2435 DBHelper.cleanup(pstmt); 2436 2437 result = new DatabaseCorpusImpl(lrName, 2438 this, 2439 (Long)lrPersistenceId, 2440 features, 2441 documentData); 2442 } 2443 catch(SQLException sqle) { 2444 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]"); 2445 } 2446 catch(Exception e) { 2447 throw new PersistenceException(e); 2448 } 2449 finally { 2450 DBHelper.cleanup(rs); 2451 DBHelper.cleanup(pstmt); 2452 } 2453 2454 return result; 2455 } 2456 2457 /** 2458 * reads the features of an entity 2459 * entities are of type LR or Annotation 2460 */ 2461 protected abstract FeatureMap readFeatures(Long entityID, int entityType) 2462 throws PersistenceException; 2463 2464 /** 2465 * helper method for delete() 2466 * never call it directly beause proper events will not be fired 2467 */ 2468 protected abstract void deleteDocument(Long lrId) 2469 throws PersistenceException; 2470 2471 /** 2472 * helper method for delete() 2473 * never call it directly beause proper events will not be fired 2474 */ 2475 protected abstract void deleteCorpus(Long lrId) 2476 throws PersistenceException; 2477 2478 /** 2479 * unloads a LR from the GUI 2480 */ 2481 protected void unloadLR(Long lrID) 2482 throws GateException{ 2483 2484 //0. preconfitions 2485 Assert.assertNotNull(lrID); 2486 2487 //1. get all LRs in the system 2488 List resources = Gate.getCreoleRegister().getAllInstances("gate.LanguageResource"); 2489 2490 Iterator it = resources.iterator(); 2491 while (it.hasNext()) { 2492 LanguageResource lr = (LanguageResource)it.next(); 2493 if (lrID.equals(lr.getLRPersistenceId()) && 2494 this.equals(lr.getDataStore())) { 2495 //found it - unload it 2496 Factory.deleteResource(lr); 2497 break; 2498 } 2499 } 2500 } 2501 2502 /** helper for sync() - never call directly */ 2503 protected abstract void _syncRemovedDocumentsFromCorpus(List docLRIDs, Long corpLRID) 2504 throws PersistenceException; 2505 2506 /** 2507 * adds document to corpus in the database 2508 * if the document is already part of the corpus nothing 2509 * changes 2510 */ 2511 protected abstract void addDocumentToCorpus(Long docID,Long corpID) 2512 throws PersistenceException,SecurityException; 2513 2514 2515} 2516
|
JDBCDataStore |
|