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