|
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.84 2003/01/07 17:02:14 valyt 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 if(doc instanceof DocumentImpl){ 1371 initData.put("DOC_STRING_CONTENT", 1372 ((DocumentImpl)doc).getStringContent()); 1373 } 1374 initData.put("DOC_SOURCE_URL_START",doc.getSourceUrlStartOffset()); 1375 initData.put("DOC_SOURCE_URL_END",doc.getSourceUrlEndOffset()); 1376 initData.put("DOC_DEFAULT_ANNOTATIONS",doc.getAnnotations()); 1377 initData.put("DOC_NAMED_ANNOTATION_SETS",doc.getNamedAnnotationSets()); 1378 1379 params.put("initData__$$__", initData); 1380 1381 try { 1382 //here we create the persistent LR via Factory, so it's registered 1383 //in GATE 1384 dbDoc = (Document)Factory.createResource("gate.corpora.DatabaseDocumentImpl", params); 1385 } 1386 catch (gate.creole.ResourceInstantiationException ex) { 1387 throw new GateRuntimeException(ex.getMessage()); 1388 } 1389 1390 return dbDoc; 1391 } 1392 1393 protected abstract Long createLR(String lrType, 1394 String lrName, 1395 SecurityInfo si, 1396 Long lrParentID) 1397 throws PersistenceException,SecurityException; 1398 1399 1400 protected abstract Long createDoc(Long _lrID, 1401 URL _docURL, 1402 String _docEncoding, 1403 Long _docStartOffset, 1404 Long _docEndOffset, 1405 Boolean _docIsMarkupAware, 1406 Long _corpusID) 1407 throws PersistenceException; 1408 1409 protected abstract void updateDocumentContent(Long docID,DocumentContent content) 1410 throws PersistenceException; 1411 1412 protected abstract void createAnnotationSet(Long lrID, AnnotationSet aset) 1413 throws PersistenceException; 1414 1415 protected abstract void createFeaturesBulk(Long entityID, int entityType, FeatureMap features) 1416 throws PersistenceException; 1417 1418 protected abstract void createFeatures(Long entityID, int entityType, FeatureMap features) 1419 throws PersistenceException; 1420 1421 /** 1422 * Save: synchonise the in-memory image of the LR with the persistent 1423 * image. 1424 */ 1425 protected void _sync(LanguageResource lr, boolean openNewTrans) 1426 throws PersistenceException,SecurityException { 1427 1428 //0.preconditions 1429 Assert.assertNotNull(lr); 1430 Long lrID = (Long)lr.getLRPersistenceId(); 1431 1432 if (false == lr instanceof Document && 1433 false == lr instanceof Corpus) { 1434 //only documents and corpuses could be serialized in DB 1435 throw new IllegalArgumentException("only Documents and Corpuses could "+ 1436 "be serialized in DB"); 1437 } 1438 1439 // check that this LR is one of ours (i.e. has been adopted) 1440 if( null == lr.getDataStore() || false == lr.getDataStore().equals(this)) 1441 throw new PersistenceException( 1442 "This LR is not stored in this DataStore" 1443 ); 1444 1445 1446 //1. check session 1447 if (null == this.session) { 1448 throw new SecurityException("session not set"); 1449 } 1450 1451 if (false == this.ac.isValidSession(this.session)) { 1452 throw new SecurityException("invalid session supplied"); 1453 } 1454 1455 //2. check permissions 1456 if (false == canWriteLR(lrID)) { 1457 throw new SecurityException("insufficient privileges"); 1458 } 1459 1460 //3. is the resource locked? 1461 User lockingUser = getLockingUser(lr); 1462 User currUser = this.session.getUser(); 1463 1464 if (lockingUser != null && false == lockingUser.equals(currUser)) { 1465 throw new PersistenceException("document is locked by another user and cannot be synced"); 1466 } 1467 1468 1469 boolean transFailed = false; 1470 try { 1471 //2. autocommit should be FALSE because of LOBs 1472 if (openNewTrans) { 1473 beginTrans(); 1474 } 1475 1476 //3. perform changes, if anything goes wrong, rollback 1477 if (lr instanceof Document) { 1478 syncDocument((Document)lr); 1479 } 1480 else { 1481 syncCorpus((Corpus)lr); 1482 } 1483 1484 //4. done, commit 1485 if (openNewTrans) { 1486 commitTrans(); 1487 } 1488 } 1489 catch(PersistenceException pe) { 1490 transFailed = true; 1491 throw(pe); 1492 } 1493 finally { 1494 //problems? 1495 if (transFailed) { 1496 rollbackTrans(); 1497 } 1498 } 1499 1500 // let the world know about it 1501 fireResourceWritten( 1502 new DatastoreEvent(this, DatastoreEvent.RESOURCE_WRITTEN, lr, lr.getLRPersistenceId())); 1503 } 1504 1505 /** 1506 * Releases the exlusive lock on a resource from the persistent store. 1507 */ 1508 protected User getLockingUser(LanguageResource lr) 1509 throws PersistenceException,SecurityException { 1510 1511 //0. preconditions 1512 Assert.assertNotNull(lr); 1513 Assert.assertTrue(lr instanceof DatabaseDocumentImpl || 1514 lr instanceof DatabaseCorpusImpl); 1515 Assert.assertNotNull(lr.getLRPersistenceId()); 1516 Assert.assertEquals(lr.getDataStore(),this); 1517 1518 //delegate 1519 return getLockingUser((Long)lr.getLRPersistenceId()); 1520 } 1521 1522 1523 1524 /** 1525 * Releases the exlusive lock on a resource from the persistent store. 1526 */ 1527 protected User getLockingUser(Long lrID) 1528 throws PersistenceException,SecurityException { 1529 1530 //1. check session 1531 if (null == this.session) { 1532 throw new SecurityException("session not set"); 1533 } 1534 1535 if (false == this.ac.isValidSession(this.session)) { 1536 throw new SecurityException("invalid session supplied"); 1537 } 1538 1539 //3. read from DB 1540 PreparedStatement pstmt = null; 1541 Long userID = null; 1542 ResultSet rs = null; 1543 1544 try { 1545 1546 String sql = null; 1547 1548 if (this.dbType == DBHelper.ORACLE_DB) { 1549 sql = " select nvl(lr_locking_user_id,0) as user_id" + 1550 " from "+this.dbSchema+"t_lang_resource " + 1551 " where lr_id = ?"; 1552 } 1553 else if (this.dbType == DBHelper.POSTGRES_DB) { 1554 sql = " select coalesce(lr_locking_user_id,0) as user_id" + 1555 " from t_lang_resource " + 1556 " where lr_id = ?"; 1557 } 1558 else { 1559 throw new IllegalArgumentException(); 1560 } 1561 1562 pstmt = this.jdbcConn.prepareStatement(sql); 1563 pstmt.setLong(1,lrID.longValue()); 1564 pstmt.execute(); 1565 rs = pstmt.getResultSet(); 1566 1567 if (false == rs.next()) { 1568 throw new PersistenceException("LR not found in DB"); 1569 } 1570 1571 long result = rs.getLong("user_id"); 1572 1573 return result == 0 ? null 1574 : this.ac.findUser(new Long(result)); 1575 } 1576 catch(SQLException sqle) { 1577 throw new PersistenceException("can't get locking user from DB : ["+ sqle.getMessage()+"]"); 1578 } 1579 finally { 1580 DBHelper.cleanup(rs); 1581 DBHelper.cleanup(pstmt); 1582 } 1583 } 1584 1585 /** helper for sync() - saves a Corpus in the database */ 1586 protected void syncCorpus(Corpus corp) 1587 throws PersistenceException,SecurityException { 1588 1589 //0. preconditions 1590 Assert.assertNotNull(corp); 1591 Assert.assertTrue(corp instanceof DatabaseCorpusImpl); 1592 Assert.assertEquals(this,corp.getDataStore()); 1593 Assert.assertNotNull(corp.getLRPersistenceId()); 1594 1595 EventAwareCorpus dbCorpus = (EventAwareCorpus)corp; 1596 1597 //1. sync the corpus name? 1598 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_NAME)) { 1599 _syncLR(corp); 1600 } 1601 1602 //2. sync the corpus features? 1603 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_FEATURES)) { 1604 _syncFeatures(corp); 1605 } 1606 1607 //2.5 get removed documents and detach (not remove) them from the corpus in the 1608 //database 1609 List removedDocLRIDs = dbCorpus.getRemovedDocuments(); 1610 if (removedDocLRIDs.size() > 0) { 1611 _syncRemovedDocumentsFromCorpus(removedDocLRIDs,(Long)corp.getLRPersistenceId()); 1612 } 1613 1614 //3. get all documents 1615 //--Iterator it = corp.iterator(); 1616 Iterator it = dbCorpus.getLoadedDocuments().iterator(); 1617 1618 while (it.hasNext()) { 1619 Document dbDoc = (Document)it.next(); 1620 //note - document may be NULL which means it was not loaded (load on demand) 1621 //just ignore it then 1622 if (null == dbDoc) { 1623 continue; 1624 } 1625 1626 //adopt/sync? 1627 if (null == dbDoc.getLRPersistenceId()) { 1628 //doc was never adopted, adopt it 1629 1630 //3.1 remove the transient doc from the corpus 1631 it.remove(); 1632 1633 //3.2 get the security info for the corpus 1634 SecurityInfo si = getSecurityInfo(corp); 1635 1636 1637 Document adoptedDoc = null; 1638 try { 1639 //3.3. adopt the doc with the sec info 1640//System.out.println("adopting ["+dbDoc.getName()+"] ..."); 1641 //don't open a new transaction, since sync() already has opended one 1642 adoptedDoc = (Document)_adopt(dbDoc,si,true); 1643 1644 //3.4. add doc to corpus in DB 1645 addDocumentToCorpus((Long)adoptedDoc.getLRPersistenceId(), 1646 (Long)corp.getLRPersistenceId()); 1647 } 1648 catch(SecurityException se) { 1649 throw new PersistenceException(se); 1650 } 1651 1652 //3.5 add back to corpus the new DatabaseDocument 1653 corp.add(adoptedDoc); 1654 } 1655 else { 1656 //don't open a new transaction, the sync() called for corpus has already 1657 //opened one 1658 try { 1659 _sync(dbDoc,true); 1660 1661 // let the world know about it 1662 fireResourceWritten( new DatastoreEvent(this, 1663 DatastoreEvent.RESOURCE_WRITTEN, 1664 dbDoc, 1665 dbDoc.getLRPersistenceId() 1666 ) 1667 ); 1668 1669 //if the document is form the same DS but did not belong to the corpus add it now 1670 //NOTE: if the document already belongs to the corpus then nothing will be changed 1671 //in the DB 1672 addDocumentToCorpus((Long)dbDoc.getLRPersistenceId(), 1673 (Long)corp.getLRPersistenceId()); 1674 } 1675 catch(SecurityException se) { 1676 gate.util.Err.prln("document cannot be synced: ["+se.getMessage()+"]"); 1677 } 1678 } 1679 } 1680 } 1681 1682 /** helper for sync() - saves a Document in the database */ 1683 /** helper for sync() - saves a Document in the database */ 1684 protected void syncDocument(Document doc) 1685 throws PersistenceException, SecurityException { 1686 1687 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1688 Assert.assertTrue(doc.getLRPersistenceId() instanceof Long); 1689 1690 Long lrID = (Long)doc.getLRPersistenceId(); 1691 EventAwareLanguageResource dbDoc = (EventAwareLanguageResource)doc; 1692 //1. sync LR 1693 // only name can be changed here 1694 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.RES_NAME)) { 1695 _syncLR(doc); 1696 } 1697 1698 //2. sync Document 1699 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.DOC_MAIN)) { 1700 _syncDocumentHeader(doc); 1701 } 1702 1703 //3. [optional] sync Content 1704 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.DOC_CONTENT)) { 1705 _syncDocumentContent(doc); 1706 } 1707 1708 //4. [optional] sync Features 1709 if (true == dbDoc.isResourceChanged(EventAwareLanguageResource.RES_FEATURES)) { 1710 _syncFeatures(doc); 1711 } 1712 1713 //5. [optional] delete from DB named sets that were removed from the document 1714 Collection removedSets = ((EventAwareDocument)dbDoc).getRemovedAnnotationSets(); 1715 Collection addedSets = ((EventAwareDocument)dbDoc).getAddedAnnotationSets(); 1716 if (false == removedSets.isEmpty() || false == addedSets.isEmpty()) { 1717 _syncAnnotationSets(doc,removedSets,addedSets); 1718 } 1719 1720 //6. [optional] sync Annotations 1721 _syncAnnotations(doc); 1722 } 1723 1724 1725 /** 1726 * helper for sync() 1727 * NEVER call directly 1728 */ 1729 protected abstract void _syncLR(LanguageResource lr) 1730 throws PersistenceException,SecurityException; 1731 1732 /** helper for sync() - never call directly */ 1733 protected abstract void _syncDocumentHeader(Document doc) 1734 throws PersistenceException; 1735 1736 /** helper for sync() - never call directly */ 1737 protected abstract void _syncDocumentContent(Document doc) 1738 throws PersistenceException; 1739 1740 /** helper for sync() - never call directly */ 1741 protected abstract void _syncFeatures(LanguageResource lr) 1742 throws PersistenceException; 1743 1744 /** helper for sync() - never call directly */ 1745 protected void _syncAnnotationSets(Document doc,Collection removedSets,Collection addedSets) 1746 throws PersistenceException { 1747 1748 //0. preconditions 1749 Assert.assertNotNull(doc); 1750 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1751 Assert.assertNotNull(doc.getLRPersistenceId()); 1752 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(), 1753 this.getDatabaseID()); 1754 Assert.assertNotNull(removedSets); 1755 Assert.assertNotNull(addedSets); 1756 1757 Long lrID = (Long)doc.getLRPersistenceId(); 1758 1759 //1. delete from DB removed a-sets 1760 PreparedStatement stmt = null; 1761 1762 try { 1763 1764 if (this.dbType == DBHelper.ORACLE_DB) { 1765 stmt = this.jdbcConn.prepareCall("{ call "+this.dbSchema+"persist.delete_annotation_set(?,?) }"); 1766 } 1767 else if (this.dbType == DBHelper.POSTGRES_DB) { 1768 stmt = this.jdbcConn.prepareStatement("select persist_delete_annotation_set(?,?)"); 1769 } 1770 else { 1771 Assert.fail(); 1772 } 1773 1774 Iterator it = removedSets.iterator(); 1775 while (it.hasNext()) { 1776 String setName = (String)it.next(); 1777 stmt.setLong(1,lrID.longValue()); 1778 stmt.setString(2,setName); 1779 stmt.execute(); 1780 } 1781 } 1782 catch(SQLException sqle) { 1783 throw new PersistenceException("can't remove annotation set from DB: ["+ sqle.getMessage()+"]"); 1784 } 1785 finally { 1786 DBHelper.cleanup(stmt); 1787 } 1788 1789 //2. create in DB new a-sets 1790 Iterator it = addedSets.iterator(); 1791 while (it.hasNext()) { 1792 String setName = (String)it.next(); 1793 AnnotationSet aset = doc.getAnnotations(setName); 1794 1795 Assert.assertNotNull(aset); 1796 Assert.assertTrue(aset instanceof DatabaseAnnotationSetImpl); 1797 1798 createAnnotationSet(lrID,aset); 1799 } 1800 } 1801 1802 1803 /** helper for sync() - never call directly */ 1804 protected void _syncAnnotations(Document doc) 1805 throws PersistenceException { 1806 1807 //0. preconditions 1808 Assert.assertNotNull(doc); 1809 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1810 Assert.assertNotNull(doc.getLRPersistenceId()); 1811 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(), 1812 this.getDatabaseID()); 1813 1814 1815 EventAwareDocument ead = (EventAwareDocument)doc; 1816 //1. get the sets read from the DB for this document 1817 //chnaged annotations can occur only in such sets 1818 Collection loadedSets = ead.getLoadedAnnotationSets(); 1819 1820 Iterator it = loadedSets.iterator(); 1821 while (it.hasNext()) { 1822 AnnotationSet as = (AnnotationSet)it.next(); 1823 //check that this set is neither NEW nor DELETED 1824 //they should be already synced 1825 if (ead.getAddedAnnotationSets().contains(as.getName()) || 1826 ead.getRemovedAnnotationSets().contains(as.getName())) { 1827 //oops, ignore it 1828 continue; 1829 } 1830 1831 EventAwareAnnotationSet eas = (EventAwareAnnotationSet)as; 1832 Assert.assertNotNull(as); 1833 1834 Collection anns = null; 1835 anns = eas.getAddedAnnotations(); 1836 Assert.assertNotNull(anns); 1837 if (anns.size()>0) { 1838 _syncAddedAnnotations(doc,as,anns); 1839 } 1840 1841 anns = eas.getRemovedAnnotations(); 1842 Assert.assertNotNull(anns); 1843 if (anns.size()>0) { 1844 _syncRemovedAnnotations(doc,as,anns); 1845 } 1846 1847 anns = eas.getChangedAnnotations(); 1848 Assert.assertNotNull(anns); 1849 if (anns.size()>0) { 1850 _syncChangedAnnotations(doc,as,anns); 1851 } 1852 } 1853 } 1854 1855 /** helper for sync() - never call directly */ 1856 protected void _syncAddedAnnotations(Document doc, AnnotationSet as, Collection changes) 1857 throws PersistenceException { 1858 1859 //0.preconditions 1860 Assert.assertNotNull(doc); 1861 Assert.assertNotNull(as); 1862 Assert.assertNotNull(changes); 1863 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 1864 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl); 1865 Assert.assertTrue(changes.size() > 0); 1866 1867 1868 PreparedStatement pstmt = null; 1869 ResultSet rs = null; 1870 CallableStatement cstmt = null; 1871 Long lrID = (Long)doc.getLRPersistenceId(); 1872 Long asetID = null; 1873 1874 try { 1875 //1. get the a-set ID in the database 1876 String sql = " select as_id " + 1877 " from "+this.dbSchema+"v_annotation_set " + 1878 " where lr_id = ? "; 1879 //do we have aset name? 1880 String clause = null; 1881 String name = as.getName(); 1882 if (null != name) { 1883 clause = " and as_name = ? "; 1884 } 1885 else { 1886 clause = " and as_name is null "; 1887 } 1888 sql = sql + clause; 1889 1890 pstmt = this.jdbcConn.prepareStatement(sql); 1891 pstmt.setLong(1,lrID.longValue()); 1892 if (null != name) { 1893 pstmt.setString(2,name); 1894 } 1895 pstmt.execute(); 1896 rs = pstmt.getResultSet(); 1897 1898 if (rs.next()) { 1899 asetID = new Long(rs.getLong("as_id")); 1900 } 1901 else { 1902 throw new PersistenceException("cannot find annotation set with" + 1903 " name=["+name+"] , LRID=["+lrID+"] in database"); 1904 } 1905 1906 //cleanup 1907 DBHelper.cleanup(rs); 1908 DBHelper.cleanup(pstmt); 1909 1910 //3. insert the new annotations from this set 1911 1912 //3.1. prepare call 1913 if (this.dbType == DBHelper.ORACLE_DB) { 1914 1915 cstmt = this.jdbcConn.prepareCall( 1916 "{ call "+Gate.DB_OWNER+".persist.create_annotation(?,?,?,?,?,?,?,?,?) }"); 1917 1918 Long annGlobalID = null; 1919 Iterator it = changes.iterator(); 1920 1921 while (it.hasNext()) { 1922 1923 //3.2. insert annotation 1924 Annotation ann = (Annotation)it.next(); 1925 1926 Node start = (Node)ann.getStartNode(); 1927 Node end = (Node)ann.getEndNode(); 1928 String type = ann.getType(); 1929 1930 cstmt.setLong(1,lrID.longValue()); 1931 cstmt.setLong(2,ann.getId().longValue()); 1932 cstmt.setLong(3,asetID.longValue()); 1933 cstmt.setLong(4,start.getId().longValue()); 1934 cstmt.setLong(5,start.getOffset().longValue()); 1935 cstmt.setLong(6,end.getId().longValue()); 1936 cstmt.setLong(7,end.getOffset().longValue()); 1937 cstmt.setString(8,type); 1938 cstmt.registerOutParameter(9,java.sql.Types.BIGINT); 1939 1940 cstmt.execute(); 1941 annGlobalID = new Long(cstmt.getLong(9)); 1942 1943 //3.3. set annotation features 1944 FeatureMap features = ann.getFeatures(); 1945 Assert.assertNotNull(features); 1946 1947 if (this.dbType == DBHelper.ORACLE_DB) { 1948 createFeaturesBulk(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 1949 } 1950 else if (this.dbType == DBHelper.POSTGRES_DB) { 1951 createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 1952 } 1953 else { 1954 Assert.fail(); 1955 } 1956 } 1957 } 1958 else if (this.dbType == DBHelper.POSTGRES_DB) { 1959 1960 sql = "select persist_create_annotation(?,?,?,?,?,?,?,?)"; 1961 pstmt = this.jdbcConn.prepareStatement(sql); 1962 1963 Long annGlobalID = null; 1964 Iterator it = changes.iterator(); 1965 1966 while (it.hasNext()) { 1967 1968 //3.2. insert annotation 1969 Annotation ann = (Annotation)it.next(); 1970 1971 Node start = (Node)ann.getStartNode(); 1972 Node end = (Node)ann.getEndNode(); 1973 String type = ann.getType(); 1974 1975 pstmt.setLong(1,lrID.longValue()); 1976 pstmt.setLong(2,ann.getId().longValue()); 1977 pstmt.setLong(3,asetID.longValue()); 1978 pstmt.setLong(4,start.getId().longValue()); 1979 pstmt.setLong(5,start.getOffset().longValue()); 1980 pstmt.setLong(6,end.getId().longValue()); 1981 pstmt.setLong(7,end.getOffset().longValue()); 1982 pstmt.setString(8,type); 1983 pstmt.execute(); 1984 1985 rs = pstmt.getResultSet(); 1986 1987 if (false == rs.next()) { 1988 throw new PersistenceException("empty result set"); 1989 } 1990 annGlobalID = new Long(rs.getLong(1)); 1991 1992 //3.3. set annotation features 1993 FeatureMap features = ann.getFeatures(); 1994 Assert.assertNotNull(features); 1995 createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 1996 } 1997 } 1998 1999 else { 2000 throw new IllegalArgumentException(); 2001 } 2002 2003 } 2004 catch(SQLException sqle) { 2005 throw new PersistenceException("can't add annotations in DB : ["+ 2006 sqle.getMessage()+"]"); 2007 } 2008 finally { 2009 DBHelper.cleanup(rs); 2010 DBHelper.cleanup(pstmt); 2011 DBHelper.cleanup(cstmt); 2012 } 2013 } 2014 2015 /** helper for sync() - never call directly */ 2016 protected void _syncRemovedAnnotations(Document doc,AnnotationSet as, Collection changes) 2017 throws PersistenceException { 2018 2019 //0.preconditions 2020 Assert.assertNotNull(doc); 2021 Assert.assertNotNull(as); 2022 Assert.assertNotNull(changes); 2023 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 2024 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl); 2025 Assert.assertTrue(changes.size() > 0); 2026 2027 2028 PreparedStatement pstmt = null; 2029 ResultSet rs = null; 2030 Long lrID = (Long)doc.getLRPersistenceId(); 2031 Long docID = null; 2032 Long asetID = null; 2033 2034 try { 2035 //1. get the a-set ID in the database 2036 String sql = " select as_id, " + 2037 " as_doc_id " + 2038 " from "+this.dbSchema+"v_annotation_set " + 2039 " where lr_id = ? "; 2040 //do we have aset name? 2041 String clause = null; 2042 String name = as.getName(); 2043 if (null != name) { 2044 clause = " and as_name = ? "; 2045 } 2046 else { 2047 clause = " and as_name is null "; 2048 } 2049 sql = sql + clause; 2050 2051 pstmt = this.jdbcConn.prepareStatement(sql); 2052 pstmt.setLong(1,lrID.longValue()); 2053 if (null != name) { 2054 pstmt.setString(2,name); 2055 } 2056 pstmt.execute(); 2057 rs = pstmt.getResultSet(); 2058 2059 if (rs.next()) { 2060 asetID = new Long(rs.getLong("as_id")); 2061 docID = new Long(rs.getLong("as_doc_id")); 2062 } 2063 else { 2064 throw new PersistenceException("cannot find annotation set with" + 2065 " name=["+name+"] , LRID=["+lrID+"] in database"); 2066 } 2067 2068 //3. delete the removed annotations from this set 2069 2070 //cleanup 2071 DBHelper.cleanup(rs); 2072 DBHelper.cleanup(pstmt); 2073 2074 //3.1. prepare call 2075 2076 if (this.dbType == DBHelper.ORACLE_DB) { 2077 pstmt = this.jdbcConn.prepareCall("{ call "+this.dbSchema+"persist.delete_annotation(?,?) }"); 2078 } 2079 else if (this.dbType == DBHelper.POSTGRES_DB) { 2080 pstmt = this.jdbcConn.prepareStatement("select persist_delete_annotation(?,?)"); 2081 } 2082 else { 2083 throw new IllegalArgumentException(); 2084 } 2085 2086 Iterator it = changes.iterator(); 2087 2088 while (it.hasNext()) { 2089 2090 //3.2. insert annotation 2091 Annotation ann = (Annotation)it.next(); 2092 2093 pstmt.setLong(1,docID.longValue()); //annotations are linked with documents, not LRs! 2094 pstmt.setLong(2,ann.getId().longValue()); 2095 pstmt.execute(); 2096 } 2097 } 2098 catch(SQLException sqle) { 2099 throw new PersistenceException("can't delete annotations in DB : ["+ 2100 sqle.getMessage()+"]"); 2101 } 2102 finally { 2103 DBHelper.cleanup(rs); 2104 DBHelper.cleanup(pstmt); 2105 } 2106 } 2107 2108 2109 /** helper for sync() - never call directly */ 2110 protected void _syncChangedAnnotations(Document doc,AnnotationSet as, Collection changes) 2111 throws PersistenceException { 2112 2113 //technically this approach sux 2114 //at least it works 2115 2116 //1. delete 2117 _syncRemovedAnnotations(doc,as,changes); 2118 //2. recreate 2119 _syncAddedAnnotations(doc,as,changes); 2120 } 2121 2122 /** 2123 * Get a resource from the persistent store. 2124 * <B>Don't use this method - use Factory.createResource with 2125 * DataStore and DataStoreInstanceId parameters set instead.</B> 2126 */ 2127 public LanguageResource getLr(String lrClassName, Object lrPersistenceId) 2128 throws PersistenceException,SecurityException { 2129 2130 LanguageResource result = null; 2131 2132 //0. preconditions 2133 Assert.assertNotNull(lrPersistenceId); 2134 2135 //1. check session 2136 if (null == this.session) { 2137 throw new SecurityException("session not set"); 2138 } 2139 2140 if (false == this.ac.isValidSession(this.session)) { 2141 throw new SecurityException("invalid session supplied"); 2142 } 2143 2144 //2. check permissions 2145 if (false == canReadLR(lrPersistenceId)) { 2146 throw new SecurityException("insufficient privileges"); 2147 } 2148 2149 //3. get resource from DB 2150 if (lrClassName.equals(DBHelper.DOCUMENT_CLASS)) { 2151 result = readDocument(lrPersistenceId); 2152 Assert.assertTrue(result instanceof DatabaseDocumentImpl); 2153 } 2154 else if (lrClassName.equals(DBHelper.CORPUS_CLASS)) { 2155 result = readCorpus(lrPersistenceId); 2156 Assert.assertTrue(result instanceof DatabaseCorpusImpl); 2157 } 2158 else { 2159 throw new IllegalArgumentException("resource class should be either Document or Corpus"); 2160 } 2161 2162 //4. postconditions 2163 Assert.assertNotNull(result.getDataStore()); 2164 Assert.assertTrue(result.getDataStore() instanceof DatabaseDataStore); 2165 Assert.assertNotNull(result.getLRPersistenceId()); 2166 2167 //5. register the read doc as listener for sync events 2168 addDatastoreListener((DatastoreListener)result); 2169 2170 //6. add the resource to the list of dependent resources - i.e. the ones that the 2171 //data store should take care upon closing [and call sync()] 2172 this.dependentResources.add(result); 2173 2174 //7. done 2175 return result; 2176 } 2177 2178 /** helper method for getLR - reads LR of type Document */ 2179 private DatabaseDocumentImpl readDocument(Object lrPersistenceId) 2180 throws PersistenceException { 2181 2182 //0. preconditions 2183 Assert.assertNotNull(lrPersistenceId); 2184 2185 if (false == lrPersistenceId instanceof Long) { 2186 throw new IllegalArgumentException(); 2187 } 2188 2189 // 1. dummy document to be initialized 2190 DatabaseDocumentImpl result = new DatabaseDocumentImpl(this.jdbcConn); 2191 2192 PreparedStatement pstmt = null; 2193 ResultSet rs = null; 2194 2195 //3. read from DB 2196 try { 2197 String sql = " select lr_name, " + 2198 " lrtp_type, " + 2199 " lr_id, " + 2200 " lr_parent_id, " + 2201 " doc_id, " + 2202 " doc_url, " + 2203 " doc_start, " + 2204 " doc_end, " + 2205 " doc_is_markup_aware " + 2206 " from "+this.dbSchema+"v_document " + 2207 " where lr_id = ? "; 2208 2209 pstmt = this.jdbcConn.prepareStatement(sql); 2210 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 2211 pstmt.execute(); 2212 rs = pstmt.getResultSet(); 2213 2214 if (false == rs.next()) { 2215 //ooops mo data found 2216 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2217 } 2218 2219 //4. fill data 2220 2221 //4.0 name 2222 String lrName = rs.getString("lr_name"); 2223 Assert.assertNotNull(lrName); 2224 result.setName(lrName); 2225 2226 //4.1 parent 2227 Long parentID = null; 2228 long parent_id = rs.getLong("lr_parent_id"); 2229 if (false == rs.wasNull()) { 2230 parentID = new Long(parent_id); 2231 2232 //read parent resource 2233 LanguageResource parentLR = this.getLr(DBHelper.DOCUMENT_CLASS,parentID); 2234 Assert.assertNotNull(parentLR); 2235 Assert.assertTrue(parentLR instanceof DatabaseDocumentImpl); 2236 2237 result.setParent(parentLR); 2238 } 2239 2240 2241 //4.2. markup aware 2242 if (this.dbType == DBHelper.ORACLE_DB) { 2243 long markup = rs.getLong("doc_is_markup_aware"); 2244 Assert.assertTrue(markup == DBHelper.FALSE || markup == DBHelper.TRUE); 2245 if (markup == DBHelper.FALSE) { 2246 result.setMarkupAware(Boolean.FALSE); 2247 } 2248 else { 2249 result.setMarkupAware(Boolean.TRUE); 2250 2251 } 2252 } 2253 else if (this.dbType == DBHelper.POSTGRES_DB) { 2254 boolean markup = rs.getBoolean("doc_is_markup_aware"); 2255 result.setMarkupAware(new Boolean(markup)); 2256 } 2257 else { 2258 throw new IllegalArgumentException(); 2259 } 2260 2261 2262 //4.3 datastore 2263 result.setDataStore(this); 2264 2265 //4.4. persist ID 2266 Long persistID = new Long(rs.getLong("lr_id")); 2267 result.setLRPersistenceId(persistID); 2268 2269 //4.5 source url 2270 String url = rs.getString("doc_url"); 2271 if(url != null && url.length() > 0) result.setSourceUrl(new URL(url)); 2272 2273 //4.6. start offset 2274 Long start = null; 2275 long longVal = rs.getLong("doc_start"); 2276 //null? 2277 //if NULL is stored in the DB, Oracle returns 0 which is not what we want 2278 if (false == rs.wasNull()) { 2279 start = new Long(longVal); 2280 } 2281 result.setSourceUrlStartOffset(start); 2282// initData.put("DOC_SOURCE_URL_START",start); 2283 2284 //4.7. end offset 2285 Long end = null; 2286 longVal = rs.getLong("doc_end"); 2287 //null? 2288 //if NULL is stored in the DB, Oracle returns 0 which is not what we want 2289 if (false == rs.wasNull()) { 2290 end = new Long(longVal); 2291 } 2292 result.setSourceUrlEndOffset(end); 2293// initData.put("DOC_SOURCE_URL_END",end); 2294 2295 //4.8 features 2296 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_DOCUMENT); 2297 result.setFeatures(features); 2298 //initData.put("DOC_FEATURES",features); 2299 2300 //4.9 set the nextAnnotationID correctly 2301 long doc_id = rs.getLong("doc_id"); 2302 2303 //cleanup 2304 DBHelper.cleanup(rs); 2305 DBHelper.cleanup(pstmt); 2306 2307 sql = " select max(ann_local_id),'ann_id'" + 2308 " from "+this.dbSchema+"t_annotation " + 2309 " where ann_doc_id = ?" + 2310 " union " + 2311 " select max(node_local_id),'node_id' " + 2312 " from "+this.dbSchema+"t_node " + 2313 " where node_doc_id = ?"; 2314 2315 pstmt = this.jdbcConn.prepareStatement(sql); 2316 pstmt.setLong(1,doc_id); 2317 pstmt.setLong(2,doc_id); 2318 pstmt.execute(); 2319 rs = pstmt.getResultSet(); 2320 2321 int maxAnnID = 0 , maxNodeID = 0; 2322 //ann id 2323 if (false == rs.next()) { 2324 //ooops no data found 2325 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2326 } 2327 if (rs.getString(2).equals("ann_id")) 2328 maxAnnID = rs.getInt(1); 2329 else 2330 maxNodeID = rs.getInt(1); 2331 2332 if (false == rs.next()) { 2333 //ooops no data found 2334 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2335 } 2336 if (rs.getString(2).equals("node_id")) 2337 maxNodeID = rs.getInt(1); 2338 else 2339 maxAnnID = rs.getInt(1); 2340 2341 result.setNextNodeId(maxNodeID+1); 2342// initData.put("DOC_NEXT_NODE_ID",new Integer(maxNodeID+1)); 2343 result.setNextAnnotationId(maxAnnID+1); 2344// initData.put("DOC_NEXT_ANN_ID",new Integer(maxAnnID+1)); 2345 2346 2347// params.put("initData__$$__", initData); 2348// try { 2349 //here we create the persistent LR via Factory, so it's registered 2350 //in GATE 2351// result = (DatabaseDocumentImpl)Factory.createResource("gate.corpora.DatabaseDocumentImpl", params); 2352// } 2353// catch (gate.creole.ResourceInstantiationException ex) { 2354// throw new GateRuntimeException(ex.getMessage()); 2355// } 2356 } 2357 catch(SQLException sqle) { 2358 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]"); 2359 } 2360 catch(Exception e) { 2361 throw new PersistenceException(e); 2362 } 2363 finally { 2364 DBHelper.cleanup(rs); 2365 DBHelper.cleanup(pstmt); 2366 } 2367 2368 return result; 2369 } 2370 2371 2372 /** 2373 * helper method for getLR - reads LR of type Corpus 2374 */ 2375 private DatabaseCorpusImpl readCorpus(Object lrPersistenceId) 2376 throws PersistenceException { 2377 2378 //0. preconditions 2379 Assert.assertNotNull(lrPersistenceId); 2380 2381 if (false == lrPersistenceId instanceof Long) { 2382 throw new IllegalArgumentException(); 2383 } 2384 2385 //3. read from DB 2386 PreparedStatement pstmt = null; 2387 ResultSet rs = null; 2388 DatabaseCorpusImpl result = null; 2389 2390 try { 2391 String sql = " select lr_name " + 2392 " from "+this.dbSchema+"t_lang_resource " + 2393 " where lr_id = ? "; 2394 pstmt = this.jdbcConn.prepareStatement(sql); 2395 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 2396 pstmt.execute(); 2397 rs = pstmt.getResultSet(); 2398 2399 if (false == rs.next()) { 2400 //ooops mo data found 2401 throw new PersistenceException("Invalid LR ID supplied - no data found"); 2402 } 2403 2404 //4. fill data 2405 2406 //4.1 name 2407 String lrName = rs.getString("lr_name"); 2408 Assert.assertNotNull(lrName); 2409 2410 //4.8 features 2411 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_CORPUS); 2412 2413 //4.9 cleanup 2414 DBHelper.cleanup(rs); 2415 DBHelper.cleanup(pstmt); 2416 2417 sql = " select lr_id ," + 2418 " lr_name " + 2419 " from "+this.dbSchema+"t_document doc, " + 2420 " "+this.dbSchema+"t_lang_resource lr, " + 2421 " "+this.dbSchema+"t_corpus_document corpdoc, " + 2422 " "+this.dbSchema+"t_corpus corp " + 2423 " where lr.lr_id = doc.doc_lr_id " + 2424 " and doc.doc_id = corpdoc.cd_doc_id " + 2425 " and corpdoc.cd_corp_id = corp.corp_id " + 2426 " and corp_lr_id = ? "; 2427 pstmt = this.jdbcConn.prepareStatement(sql); 2428 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 2429 pstmt.execute(); 2430 rs = pstmt.getResultSet(); 2431 2432 Vector documentData = new Vector(); 2433 while (rs.next()) { 2434 Long docLRID = new Long(rs.getLong("lr_id")); 2435 String docName = rs.getString("lr_name"); 2436 documentData.add(new DocumentData(docName, docLRID)); 2437 } 2438 DBHelper.cleanup(rs); 2439 DBHelper.cleanup(pstmt); 2440 2441 result = new DatabaseCorpusImpl(lrName, 2442 this, 2443 (Long)lrPersistenceId, 2444 features, 2445 documentData); 2446 } 2447 catch(SQLException sqle) { 2448 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]"); 2449 } 2450 catch(Exception e) { 2451 throw new PersistenceException(e); 2452 } 2453 finally { 2454 DBHelper.cleanup(rs); 2455 DBHelper.cleanup(pstmt); 2456 } 2457 2458 return result; 2459 } 2460 2461 /** 2462 * reads the features of an entity 2463 * entities are of type LR or Annotation 2464 */ 2465 protected abstract FeatureMap readFeatures(Long entityID, int entityType) 2466 throws PersistenceException; 2467 2468 /** 2469 * helper method for delete() 2470 * never call it directly beause proper events will not be fired 2471 */ 2472 protected abstract void deleteDocument(Long lrId) 2473 throws PersistenceException; 2474 2475 /** 2476 * helper method for delete() 2477 * never call it directly beause proper events will not be fired 2478 */ 2479 protected abstract void deleteCorpus(Long lrId) 2480 throws PersistenceException; 2481 2482 /** 2483 * unloads a LR from the GUI 2484 */ 2485 protected void unloadLR(Long lrID) 2486 throws GateException{ 2487 2488 //0. preconfitions 2489 Assert.assertNotNull(lrID); 2490 2491 //1. get all LRs in the system 2492 List resources = Gate.getCreoleRegister().getAllInstances("gate.LanguageResource"); 2493 2494 Iterator it = resources.iterator(); 2495 while (it.hasNext()) { 2496 LanguageResource lr = (LanguageResource)it.next(); 2497 if (lrID.equals(lr.getLRPersistenceId()) && 2498 this.equals(lr.getDataStore())) { 2499 //found it - unload it 2500 Factory.deleteResource(lr); 2501 break; 2502 } 2503 } 2504 } 2505 2506 /** helper for sync() - never call directly */ 2507 protected abstract void _syncRemovedDocumentsFromCorpus(List docLRIDs, Long corpLRID) 2508 throws PersistenceException; 2509 2510 /** 2511 * adds document to corpus in the database 2512 * if the document is already part of the corpus nothing 2513 * changes 2514 */ 2515 protected abstract void addDocumentToCorpus(Long docID,Long corpID) 2516 throws PersistenceException,SecurityException; 2517 2518 2519} 2520
|
JDBCDataStore |
|