|
OracleDataStore |
|
1 /* 2 * OracleDataStore.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: OracleDataStore.java,v 1.172 2003/01/28 09:59:26 marin Exp $ 14 */ 15 16 package gate.persist; 17 18 import java.sql.*; 19 import java.net.*; 20 import java.util.*; 21 import java.io.*; 22 23 import oracle.sql.*; 24 import oracle.jdbc.driver.*; 25 26 27 import junit.framework.*; 28 29 import gate.*; 30 import gate.util.*; 31 import gate.event.*; 32 import gate.security.*; 33 import gate.security.SecurityException; //hide the more general exception 34 import gate.corpora.*; 35 import gate.annotation.*; 36 import gate.creole.ResourceData; 37 38 public class OracleDataStore extends JDBCDataStore { 39 40 /** Name of this resource */ 41 private static final String DS_COMMENT = "GATE Oracle datastore"; 42 43 /** the icon for this resource */ 44 private static final String DS_ICON_NAME = "ora_ds.gif"; 45 46 /** Debug flag */ 47 private static final boolean DEBUG = false; 48 49 /** "true" value for Oracle (supports no boolean type) */ 50 private static final int ORACLE_TRUE = 1; 51 /** "false" value for Oracle (supports no boolean type) */ 52 private static final int ORACLE_FALSE = 0; 53 54 /** size of the Oracle varrays used for bulc inserts */ 55 private static final int VARRAY_SIZE = 10; 56 57 /** the size in bytes if varchar2 column in Oracle 58 * when a String is stored in Oracle it may be too long 59 * for a varchar2 value, and then CLOB will be used 60 * Note that the limit is in bytes, not in characters, so 61 * in the worst case this will limit the string to 4000/3 characters 62 * */ 63 private static final int ORACLE_VARCHAR_LIMIT_BYTES = 4000; 64 65 /** maximum number of bytes that represent a char in UTF8 database */ 66 private static final int UTF_BYTES_PER_CHAR_MAX = 3; 67 68 /** maximum number of characters per string stored as varchar2 69 * if longer then stored as CLOB 70 * */ 71 private static final int ORACLE_VARCHAR_MAX_SYMBOLS = 72 ORACLE_VARCHAR_LIMIT_BYTES/UTF_BYTES_PER_CHAR_MAX; 73 74 /** read buffer size (for reading CLOBs) */ 75 private static final int INTERNAL_BUFFER_SIZE = 16*1024; 76 77 /** default constructor - just call the super constructor 78 * (may change in the future) 79 * */ 80 public OracleDataStore() { 81 82 super(); 83 84 this.datastoreComment = DS_COMMENT; 85 this.iconName = DS_ICON_NAME; 86 } 87 88 89 90 /** Set the URL for the underlying storage mechanism. */ 91 public void setStorageUrl(String storageUrl) throws PersistenceException { 92 93 super.setStorageUrl(storageUrl); 94 95 } 96 97 98 99 /** Get the URL for the underlying storage mechanism. */ 100 public String getStorageUrl() { 101 102 return super.getStorageUrl(); 103 } 104 105 106 107 /** 108 * Create a new data store. <B>NOTE:</B> for some data stores 109 * creation is an system administrator task; in such cases this 110 * method will throw an UnsupportedOperationException. 111 */ 112 public void create() 113 throws PersistenceException, UnsupportedOperationException { 114 115 super.create(); 116 } 117 118 119 120 /** Open a connection to the data store. */ 121 public void open() throws PersistenceException { 122 123 super.open(); 124 125 /*try { 126 //set statement caching for Oracle 127 ((OracleConnection)this.jdbcConn).setStmtCacheSize(50); 128 } 129 catch(SQLException sqle) { 130 throw new PersistenceException(sqle); 131 }*/ 132 } 133 134 135 136 /** Close the data store. */ 137 public void close() throws PersistenceException { 138 139 super.close(); 140 } 141 142 143 144 /** 145 * Delete a resource from the data store. 146 * @param lrId a data-store specific unique identifier for the resource 147 * @param lrClassName class name of the type of resource 148 */ 149 /* 150 public void delete(String lrClassName, Object lrId) 151 throws PersistenceException,SecurityException { 152 //0. preconditions 153 if (false == lrId instanceof Long) { 154 throw new IllegalArgumentException(); 155 } 156 157 if (!lrClassName.equals(DBHelper.DOCUMENT_CLASS) && 158 !lrClassName.equals(DBHelper.CORPUS_CLASS)) { 159 throw new IllegalArgumentException("Only Corpus and Document classes are supported" + 160 " by Database data store"); 161 } 162 163 //1. check session 164 if (null == this.session) { 165 throw new SecurityException("session not set"); 166 } 167 168 if (false == this.ac.isValidSession(this.session)) { 169 throw new SecurityException("invalid session supplied"); 170 } 171 172 //2. check permissions 173 if (false == canWriteLR(lrId)) { 174 throw new SecurityException("insufficient privileges"); 175 } 176 177 //3. try to lock document, so that we'll be sure no one is editing it 178 //NOTE: use the private method 179 User lockingUser = this.getLockingUser((Long)lrId); 180 User currUser = this.session.getUser(); 181 182 if (null != lockingUser && false == lockingUser.equals(currUser)) { 183 //oops, someone is editing now 184 throw new PersistenceException("LR locked by another user"); 185 } 186 187 boolean transFailed = false; 188 try { 189 //4. autocommit should be FALSE because of LOBs 190 beginTrans(); 191 192 //5. perform changes, if anything goes wrong, rollback 193 if (lrClassName.equals(DBHelper.DOCUMENT_CLASS)) { 194 deleteDocument((Long)lrId); 195 } 196 else { 197 deleteCorpus((Long)lrId); 198 } 199 200 //6. done, commit 201 commitTrans(); 202 } 203 catch(PersistenceException pe) { 204 transFailed = true; 205 throw(pe); 206 } 207 finally { 208 //problems? 209 if (transFailed) { 210 rollbackTrans(); 211 } 212 } 213 214 //7, unlock 215 //do nothing - the resource does not exist anymore 216 217 //8. delete from the list of dependent resources 218 boolean resourceFound = false; 219 Iterator it = this.dependentResources.iterator(); 220 while (it.hasNext()) { 221 LanguageResource lr = (LanguageResource)it.next(); 222 if (lr.getLRPersistenceId().equals(lrId)) { 223 resourceFound = true; 224 it.remove(); 225 break; 226 } 227 } 228 229 //Assert.assertTrue(resourceFound); 230 231 //9. let the world know about it 232 fireResourceDeleted( 233 new DatastoreEvent(this, DatastoreEvent.RESOURCE_DELETED, null, lrId)); 234 235 //10. unload the resource form the GUI 236 try { 237 unloadLR((Long)lrId); 238 } 239 catch(GateException ge) { 240 Err.prln("can't unload resource from GUI..."); 241 } 242 } 243 */ 244 245 246 /** 247 * helper method for delete() 248 * never call it directly beause proper events will not be fired 249 */ 250 protected void deleteDocument(Long lrId) 251 throws PersistenceException { 252 253 //0. preconditions 254 Assert.assertNotNull(lrId); 255 256 CallableStatement stmt = null; 257 258 //1. delete from DB 259 try { 260 stmt = this.jdbcConn.prepareCall( 261 "{ call "+Gate.DB_OWNER+".persist.delete_document(?) }"); 262 stmt.setLong(1,lrId.longValue()); 263 stmt.execute(); 264 } 265 catch(SQLException sqle) { 266 throw new PersistenceException("can't delete LR from DB: ["+ sqle.getMessage()+"]"); 267 } 268 finally { 269 DBHelper.cleanup(stmt); 270 } 271 } 272 273 274 275 /** 276 * helper method for delete() 277 * never call it directly beause proper events will not be fired 278 */ 279 protected void deleteCorpus(Long lrId) 280 throws PersistenceException { 281 282 Long ID = (Long)lrId; 283 284 CallableStatement stmt = null; 285 286 try { 287 stmt = this.jdbcConn.prepareCall( 288 "{ call "+Gate.DB_OWNER+".persist.delete_corpus(?) }"); 289 stmt.setLong(1,ID.longValue()); 290 stmt.execute(); 291 } 292 catch(SQLException sqle) { 293 throw new PersistenceException("can't delete LR from DB: ["+ sqle.getMessage()+"]"); 294 } 295 finally { 296 DBHelper.cleanup(stmt); 297 } 298 } 299 300 301 302 303 304 /** 305 * Set method for the autosaving behaviour of the data store. 306 * <B>NOTE:</B> many types of datastore have no auto-save function, 307 * in which case this will throw an UnsupportedOperationException. 308 */ 309 public void setAutoSaving(boolean autoSaving) 310 throws UnsupportedOperationException,PersistenceException { 311 312 super.setAutoSaving(autoSaving); 313 } 314 315 316 317 /** Get the autosaving behaviour of the LR. */ 318 public boolean isAutoSaving() { 319 throw new MethodNotImplementedException(); 320 } 321 322 323 /** 324 * helper for adopt() 325 * never call directly 326 */ 327 protected Long createLR(String lrType, 328 String lrName, 329 SecurityInfo si, 330 Long lrParentID) 331 throws PersistenceException,SecurityException { 332 333 //0. preconditions 334 Assert.assertNotNull(lrName); 335 336 //1. check the session 337 // if (this.ac.isValidSession(s) == false) { 338 // throw new SecurityException("invalid session provided"); 339 // } 340 341 //2. create a record in DB 342 CallableStatement stmt = null; 343 344 try { 345 stmt = this.jdbcConn.prepareCall( 346 "{ call "+Gate.DB_OWNER+".persist.create_lr(?,?,?,?,?,?,?) }"); 347 stmt.setLong(1,si.getUser().getID().longValue()); 348 stmt.setLong(2,si.getGroup().getID().longValue()); 349 stmt.setString(3,lrType); 350 stmt.setString(4,lrName); 351 stmt.setInt(5,si.getAccessMode()); 352 if (null == lrParentID) { 353 stmt.setNull(6,java.sql.Types.BIGINT); 354 } 355 else { 356 stmt.setLong(6,lrParentID.longValue()); 357 } 358 //Oracle numbers are BIGNINT 359 stmt.registerOutParameter(7,java.sql.Types.BIGINT); 360 stmt.execute(); 361 362 Long result = new Long(stmt.getLong(7)); 363 return result; 364 } 365 catch(SQLException sqle) { 366 367 switch(sqle.getErrorCode()) { 368 case DBHelper.X_ORACLE_INVALID_LR_TYPE: 369 throw new PersistenceException("can't create LR [step 3] in DB, invalid LR Type"); 370 default: 371 throw new PersistenceException( 372 "can't create LR [step 3] in DB : ["+ sqle.getMessage()+"]"); 373 } 374 } 375 finally { 376 DBHelper.cleanup(stmt); 377 } 378 } 379 380 381 382 /** 383 * updates the content of the document if it is binary or a long string 384 * (that does not fit into VARCHAR2) 385 */ 386 // private void updateDocumentContent(Long docContentID,DocumentContent content) 387 protected void updateDocumentContent(Long docID,DocumentContent content) 388 throws PersistenceException { 389 390 //1. get LOB locators from DB 391 PreparedStatement pstmt = null; 392 ResultSet rs = null; 393 CallableStatement cstmt = null; 394 try { 395 String sql = "select dc.dc_id, "+ 396 " dc.dc_content_type, " + 397 " dc.dc_character_content, " + 398 " dc.dc_binary_content " + 399 "from "+gate.Gate.DB_OWNER+".t_doc_content dc , " + 400 gate.Gate.DB_OWNER+".t_document doc " + 401 "where dc.dc_id = doc.doc_content_id " + 402 " and doc.doc_content_id = ? " + 403 "for update "; 404 pstmt = this.jdbcConn.prepareStatement(sql); 405 pstmt.setLong(1,docID.longValue()); 406 rs = pstmt.executeQuery(); 407 408 //rs = pstmt.getResultSet(); 409 410 rs.next(); 411 //important: read the objects in the order they appear in 412 //the ResultSet, otherwise data may be lost 413 Long contentID = new Long(rs.getLong("dc_id")); 414 long contentType = rs.getLong("DC_CONTENT_TYPE"); 415 Clob clob = (Clob)rs.getClob("dc_character_content"); 416 Blob blob = (Blob)rs.getBlob("dc_binary_content"); 417 418 Assert.assertTrue(contentType == DBHelper.CHARACTER_CONTENT || 419 contentType == DBHelper.BINARY_CONTENT || 420 contentType == DBHelper.EMPTY_CONTENT); 421 422 423 //2. write data using the LOB locators 424 //NOTE: so far only character content is supported 425 writeCLOB(content.toString(),clob); 426 long newContentType = DBHelper.CHARACTER_CONTENT; 427 428 //3. update content type 429 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.change_content_type(?,?) }"); 430 cstmt.setLong(1,contentID.longValue()); 431 cstmt.setLong(2,newContentType); 432 cstmt.execute(); 433 } 434 catch(IOException ioe) { 435 throw new PersistenceException("can't update document content in DB : ["+ 436 ioe.getMessage()+"]"); 437 } 438 catch(SQLException sqle) { 439 throw new PersistenceException("can't update document content in DB : ["+ 440 sqle.getMessage()+"]"); 441 } 442 finally { 443 DBHelper.cleanup(rs); 444 DBHelper.cleanup(pstmt); 445 DBHelper.cleanup(cstmt); 446 } 447 448 } 449 450 451 452 /** 453 * helper for adopt 454 * creates a LR of type Document 455 */ 456 /* protected Document createDocument(Document doc,SecurityInfo secInfo) 457 throws PersistenceException,SecurityException { 458 459 //delegate, set to Null 460 return createDocument(doc,null,secInfo); 461 } 462 */ 463 464 /** 465 * helper for adopt 466 * never call directly 467 */ 468 protected Long createDoc(Long _lrID, 469 URL _docURL, 470 String _docEncoding, 471 Long _docStartOffset, 472 Long _docEndOffset, 473 Boolean _docIsMarkupAware, 474 Long _corpusID) 475 throws PersistenceException { 476 477 CallableStatement cstmt = null; 478 Long docID = null; 479 480 try { 481 cstmt = this.jdbcConn.prepareCall( 482 "{ call "+Gate.DB_OWNER+".persist.create_document(?,?,?,?,?,?,?,?) }"); 483 cstmt.setLong(1,_lrID.longValue()); 484 if (_docURL == null) { 485 cstmt.setNull(2,java.sql.Types.VARCHAR); 486 }else{ 487 cstmt.setString(2,_docURL.toString()); 488 } 489 //do we have doc encoding? 490 if (null == _docEncoding) { 491 cstmt.setNull(3,java.sql.Types.VARCHAR); 492 } 493 else { 494 cstmt.setString(3,_docEncoding); 495 } 496 //do we have start offset? 497 if (null==_docStartOffset) { 498 cstmt.setNull(4,java.sql.Types.NUMERIC); 499 } 500 else { 501 cstmt.setLong(4,_docStartOffset.longValue()); 502 } 503 //do we have end offset? 504 if (null==_docEndOffset) { 505 cstmt.setNull(5,java.sql.Types.NUMERIC); 506 } 507 else { 508 cstmt.setLong(5,_docEndOffset.longValue()); 509 } 510 511 cstmt.setBoolean(6,_docIsMarkupAware.booleanValue()); 512 513 //is the document part of a corpus? 514 if (null == _corpusID) { 515 cstmt.setNull(7,java.sql.Types.BIGINT); 516 } 517 else { 518 cstmt.setLong(7,_corpusID.longValue()); 519 } 520 521 //results 522 cstmt.registerOutParameter(8,java.sql.Types.BIGINT); 523 524 cstmt.execute(); 525 docID = new Long(cstmt.getLong(8)); 526 return docID; 527 528 } 529 catch(SQLException sqle) { 530 throw new PersistenceException("can't create document [step 4] in DB: ["+ sqle.getMessage()+"]"); 531 } 532 finally { 533 DBHelper.cleanup(cstmt); 534 } 535 536 } 537 538 539 540 /** creates an entry for annotation set in the database */ 541 protected void createAnnotationSet(Long lrID, AnnotationSet aset) 542 throws PersistenceException { 543 544 //1. create a-set 545 String asetName = aset.getName(); 546 Long asetID = null; 547 548 //DB stuff 549 CallableStatement stmt = null; 550 try { 551 stmt = this.jdbcConn.prepareCall( 552 "{ call "+Gate.DB_OWNER+".persist.create_annotation_set(?,?,?) }"); 553 stmt.setLong(1,lrID.longValue()); 554 555 if (null == asetName) { 556 stmt.setNull(2,java.sql.Types.VARCHAR); 557 } 558 else { 559 stmt.setString(2,asetName); 560 } 561 stmt.registerOutParameter(3,java.sql.Types.BIGINT); 562 stmt.execute(); 563 564 asetID = new Long(stmt.getLong(3)); 565 } 566 catch(SQLException sqle) { 567 throw new PersistenceException("can't create a-set [step 1] in DB: ["+ sqle.getMessage()+"]"); 568 } 569 finally { 570 DBHelper.cleanup(stmt); 571 } 572 573 574 //2. insert annotations/nodes for DEFAULT a-set 575 //for now use a stupid cycle 576 //TODO: pass all the data with one DB call (?) 577 578 try { 579 stmt = this.jdbcConn.prepareCall( 580 "{ call "+Gate.DB_OWNER+".persist.create_annotation(?,?,?,?,?,?,?,?,?) }"); 581 582 Iterator itAnnotations = aset.iterator(); 583 584 while (itAnnotations.hasNext()) { 585 Annotation ann = (Annotation)itAnnotations.next(); 586 Node start = (Node)ann.getStartNode(); 587 Node end = (Node)ann.getEndNode(); 588 String type = ann.getType(); 589 590 //DB stuff 591 Long annGlobalID = null; 592 stmt.setLong(1,lrID.longValue()); 593 stmt.setLong(2,ann.getId().longValue()); 594 stmt.setLong(3,asetID.longValue()); 595 stmt.setLong(4,start.getId().longValue()); 596 stmt.setLong(5,start.getOffset().longValue()); 597 stmt.setLong(6,end.getId().longValue()); 598 stmt.setLong(7,end.getOffset().longValue()); 599 stmt.setString(8,type); 600 stmt.registerOutParameter(9,java.sql.Types.BIGINT); 601 602 stmt.execute(); 603 604 annGlobalID = new Long(stmt.getLong(9)); 605 606 //2.1. set annotation features 607 FeatureMap features = ann.getFeatures(); 608 Assert.assertNotNull(features); 609 // createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 610 createFeaturesBulk(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 611 } //while 612 }//try 613 catch(SQLException sqle) { 614 615 switch(sqle.getErrorCode()) { 616 617 case DBHelper.X_ORACLE_INVALID_ANNOTATION_TYPE: 618 throw new PersistenceException( 619 "can't create annotation in DB, [invalid annotation type]"); 620 default: 621 throw new PersistenceException( 622 "can't create annotation in DB: ["+ sqle.getMessage()+"]"); 623 }//switch 624 }//catch 625 finally { 626 DBHelper.cleanup(stmt); 627 } 628 }//func 629 630 631 632 /** creates a LR of type Corpus */ 633 /* protected Corpus createCorpus(Corpus corp,SecurityInfo secInfo, boolean newTransPerDocument) 634 throws PersistenceException,SecurityException { 635 636 //1. create an LR entry for the corpus (T_LANG_RESOURCE table) 637 Long lrID = createLR(DBHelper.CORPUS_CLASS,corp.getName(),secInfo,null); 638 639 //2.create am entry in the T_COPRUS table 640 Long corpusID = null; 641 //DB stuff 642 CallableStatement stmt = null; 643 try { 644 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.create_corpus(?,?) }"); 645 stmt.setLong(1,lrID.longValue()); 646 stmt.registerOutParameter(2,java.sql.Types.BIGINT); 647 stmt.execute(); 648 corpusID = new Long(stmt.getLong(2)); 649 } 650 catch(SQLException sqle) { 651 throw new PersistenceException("can't create corpus [step 2] in DB: ["+ sqle.getMessage()+"]"); 652 } 653 finally { 654 DBHelper.cleanup(stmt); 655 } 656 657 //3. for each document in the corpus call createDocument() 658 Iterator itDocuments = corp.iterator(); 659 Vector dbDocs = new Vector(); 660 while (itDocuments.hasNext()) { 661 Document doc = (Document)itDocuments.next(); 662 663 //3.1. ensure that the document is either transient or is from the ... 664 // same DataStore 665 if (doc.getLRPersistenceId() == null) { 666 //transient document 667 668 //now this is a bit ugly patch, the transaction related functionality 669 //should not be in this method 670 if (newTransPerDocument) { 671 beginTrans(); 672 } 673 674 Document dbDoc = createDocument(doc,corpusID,secInfo); 675 676 if (newTransPerDocument) { 677 commitTrans(); 678 } 679 680 dbDocs.add(dbDoc); 681 //8. let the world know 682 fireResourceAdopted(new DatastoreEvent(this, 683 DatastoreEvent.RESOURCE_ADOPTED, 684 dbDoc, 685 dbDoc.getLRPersistenceId() 686 ) 687 ); 688 689 //9. fire also resource written event because it's now saved 690 fireResourceWritten(new DatastoreEvent(this, 691 DatastoreEvent.RESOURCE_WRITTEN, 692 dbDoc, 693 dbDoc.getLRPersistenceId() 694 ) 695 ); 696 697 } 698 else if (doc.getDataStore().equals(this)) { 699 //persistent doc from the same DataStore 700 fireResourceAdopted( 701 new DatastoreEvent(this, DatastoreEvent.RESOURCE_ADOPTED, 702 doc, 703 doc.getLRPersistenceId())); 704 705 //6. fire also resource written event because it's now saved 706 fireResourceWritten( 707 new DatastoreEvent(this, DatastoreEvent.RESOURCE_WRITTEN, 708 doc, 709 doc.getLRPersistenceId())); 710 } 711 else { 712 //persistent doc from other datastore 713 //skip 714 gate.util.Err.prln("document ["+doc.getLRPersistenceId()+"] is adopted from another "+ 715 " datastore. Skipped."); 716 } 717 } 718 719 //4. create features 720 // createFeatures(lrID,DBHelper.FEATURE_OWNER_CORPUS,corp.getFeatures()); 721 createFeaturesBulk(lrID,DBHelper.FEATURE_OWNER_CORPUS,corp.getFeatures()); 722 723 //5. create a DatabaseCorpusImpl and return it 724 /// Corpus dbCorpus = new DatabaseCorpusImpl(corp.getName(), 725 /// this, 726 /// lrID, 727 /// corp.getFeatures(), 728 /// dbDocs); 729 /// 730 731 Corpus dbCorpus = null; 732 FeatureMap params = Factory.newFeatureMap(); 733 HashMap initData = new HashMap(); 734 735 initData.put("DS",this); 736 initData.put("LR_ID",lrID); 737 initData.put("CORP_NAME",corp.getName()); 738 initData.put("CORP_FEATURES",corp.getFeatures()); 739 initData.put("CORP_SUPPORT_LIST",dbDocs); 740 741 params.put("initData__$$__", initData); 742 743 try { 744 //here we create the persistent LR via Factory, so it's registered 745 //in GATE 746 dbCorpus = (Corpus)Factory.createResource("gate.corpora.DatabaseCorpusImpl", params); 747 } 748 catch (gate.creole.ResourceInstantiationException ex) { 749 throw new GateRuntimeException(ex.getMessage()); 750 } 751 752 //6. done 753 return dbCorpus; 754 } 755 756 */ 757 758 /** 759 * Get a resource from the persistent store. 760 * <B>Don't use this method - use Factory.createResource with 761 * DataStore and DataStoreInstanceId parameters set instead.</B> 762 */ 763 /* public LanguageResource getLr(String lrClassName, Object lrPersistenceId) 764 throws PersistenceException,SecurityException { 765 766 LanguageResource result = null; 767 768 //0. preconditions 769 Assert.assertNotNull(lrPersistenceId); 770 771 //1. check session 772 if (null == this.session) { 773 throw new SecurityException("session not set"); 774 } 775 776 if (false == this.ac.isValidSession(this.session)) { 777 throw new SecurityException("invalid session supplied"); 778 } 779 780 //2. check permissions 781 if (false == canReadLR(lrPersistenceId)) { 782 throw new SecurityException("insufficient privileges"); 783 } 784 785 //3. get resource from DB 786 if (lrClassName.equals(DBHelper.DOCUMENT_CLASS)) { 787 result = readDocument(lrPersistenceId); 788 Assert.assertTrue(result instanceof DatabaseDocumentImpl); 789 } 790 else if (lrClassName.equals(DBHelper.CORPUS_CLASS)) { 791 result = readCorpus(lrPersistenceId); 792 Assert.assertTrue(result instanceof DatabaseCorpusImpl); 793 } 794 else { 795 throw new IllegalArgumentException("resource class should be either Document or Corpus"); 796 } 797 798 //4. postconditions 799 Assert.assertNotNull(result.getDataStore()); 800 Assert.assertTrue(result.getDataStore() instanceof DatabaseDataStore); 801 Assert.assertNotNull(result.getLRPersistenceId()); 802 803 //5. register the read doc as listener for sync events 804 addDatastoreListener((DatastoreListener)result); 805 806 //6. add the resource to the list of dependent resources - i.e. the ones that the 807 //data store should take care upon closing [and call sync()] 808 this.dependentResources.add(result); 809 810 //7. done 811 return result; 812 } 813 */ 814 815 /** Gets a timestamp marker that will be used for all changes made in 816 * the database so that subsequent calls to deleteSince() could restore (partly) 817 * the database state as it was before the update. <B>NOTE:</B> Restoring the previous 818 * state may not be possible at all (i.e. if DELETE is performed) 819 * */ 820 public Long timestamp() 821 throws PersistenceException{ 822 823 CallableStatement stmt = null; 824 825 try { 826 stmt = this.jdbcConn.prepareCall( 827 "{ call "+Gate.DB_OWNER+".persist.get_timestamp(?)} "); 828 //numbers generated from Oracle sequences are BIGINT 829 stmt.registerOutParameter(1,java.sql.Types.BIGINT); 830 stmt.execute(); 831 long result = stmt.getLong(1); 832 833 return new Long(result); 834 } 835 catch(SQLException sqle) { 836 throw new PersistenceException("can't get a timestamp from DB: ["+ sqle.getMessage()+"]"); 837 } 838 finally { 839 DBHelper.cleanup(stmt); 840 } 841 } 842 843 844 /** 845 * Checks if the user (identified by the sessionID) 846 * has some access (read/write) to the LR 847 */ 848 protected boolean canAccessLR(Long lrID,int mode) 849 throws PersistenceException, SecurityException{ 850 851 //0. preconditions 852 Assert.assertTrue(DBHelper.READ_ACCESS == mode || DBHelper.WRITE_ACCESS == mode); 853 854 //1. is session initialised? 855 if (null == this.session) { 856 throw new SecurityException("user session not set"); 857 } 858 859 //2.first check the session and then check whether the user is member of the group 860 if (this.ac.isValidSession(this.session) == false) { 861 throw new SecurityException("invalid session supplied"); 862 } 863 864 CallableStatement stmt = null; 865 866 try { 867 stmt = this.jdbcConn.prepareCall( 868 "{ call "+Gate.DB_OWNER+".security.has_access_to_lr(?,?,?,?,?)} "); 869 stmt.setLong(1,lrID.longValue()); 870 stmt.setLong(2,this.session.getUser().getID().longValue()); 871 stmt.setLong(3,this.session.getGroup().getID().longValue()); 872 stmt.setLong(4,mode); 873 874 stmt.registerOutParameter(5,java.sql.Types.NUMERIC); 875 stmt.execute(); 876 int result = stmt.getInt(5); 877 878 return (ORACLE_TRUE == result); 879 } 880 catch(SQLException sqle) { 881 throw new PersistenceException("can't check permissions in DB: ["+ sqle.getMessage()+"]"); 882 } 883 finally { 884 DBHelper.cleanup(stmt); 885 } 886 } 887 888 889 890 /** reads the content of a CLOB into the specified StringBuffer */ 891 public static void readCLOB(java.sql.Clob src, StringBuffer dest) 892 throws SQLException, IOException { 893 894 int readLength = 0; 895 896 //1. empty the dest buffer 897 dest.delete(0,dest.length()); 898 899 //2. get Oracle CLOB 900 CLOB clo = (CLOB)src; 901 902 //3. create temp buffer 903 int buffSize = Math.max(INTERNAL_BUFFER_SIZE,clo.getBufferSize()); 904 char[] readBuffer = new char[buffSize]; 905 906 //3. get Unicode stream 907 Reader input = clo.getCharacterStream(); 908 909 //4. read 910 BufferedReader buffInput = new BufferedReader(input,INTERNAL_BUFFER_SIZE); 911 912 while ((readLength = buffInput.read(readBuffer, 0, INTERNAL_BUFFER_SIZE)) != -1) { 913 dest.append(readBuffer, 0, readLength); 914 } 915 916 //5.close streams 917 buffInput.close(); 918 input.close(); 919 920 } 921 922 923 924 /** writes the content of a String into the specified CLOB object */ 925 public static void writeCLOB(String src,java.sql.Clob dest) 926 throws SQLException, IOException { 927 928 //preconditions 929 Assert.assertNotNull(src); 930 931 //1. get Oracle CLOB 932 CLOB clo = (CLOB)dest; 933 934 //2. get Unicode stream 935 Writer output = clo.getCharacterOutputStream(); 936 937 //3. write 938 BufferedWriter buffOutput = new BufferedWriter(output,INTERNAL_BUFFER_SIZE); 939 buffOutput.write(src.toString()); 940 941 //4. flushing is a good idea [although BufferedWriter::close() calls it this is 942 //implementation specific] 943 buffOutput.flush(); 944 output.flush(); 945 946 //5.close streams 947 buffOutput.close(); 948 output.close(); 949 } 950 951 952 953 /** writes the content of a StringBuffer into the specified CLOB object */ 954 public static void writeCLOB(StringBuffer src,java.sql.Clob dest) 955 throws SQLException, IOException { 956 957 //delegate 958 writeCLOB(src.toString(),dest); 959 } 960 961 962 963 /** 964 * reads the content of the specified BLOB object and returns the object 965 * contained. 966 * NOTE: the BLOB is expected to contain serializable objects, not just any 967 * binary stream 968 */ 969 public static Object readBLOB(java.sql.Blob src) 970 throws SQLException, IOException,ClassNotFoundException { 971 972 int readLength = 0; 973 Object result = null; 974 975 //0. preconditions 976 Assert.assertNotNull(src); 977 978 //2. get Oracle BLOB 979 BLOB blo = (BLOB)src; 980 981 //3. get binary stream 982 InputStream input = blo.getBinaryStream(); 983 Assert.assertNotNull(input); 984 985 //4. read 986 ObjectInputStream ois = new ObjectInputStream(input); 987 result = ois.readObject(); 988 989 //5.close streams 990 ois.close(); 991 input.close(); 992 993 return result; 994 } 995 996 997 998 /** 999 * writes the specified object into the BLOB 1000 * NOTE: the object should be serializable 1001 */ 1002 public static void writeBLOB(Object src,java.sql.Blob dest) 1003 throws SQLException, IOException { 1004 1005 //preconditions 1006 Assert.assertNotNull(src); 1007 1008 //1. get Oracle CLOB 1009 BLOB blo = (BLOB)dest; 1010 1011 //2. get Unicode stream 1012 OutputStream output = blo.getBinaryOutputStream(); 1013 1014 //3. write 1015 ObjectOutputStream oos = new ObjectOutputStream(output); 1016 oos.writeObject(src); 1017 1018 //4. flushing is a good idea 1019 //[although ::close() calls it this is implementation specific] 1020 oos.flush(); 1021 output.flush(); 1022 1023 //5.close streams 1024 oos.close(); 1025 output.close(); 1026 } 1027 1028 1029 1030 /** 1031 * creates a feature of the specified type/value/valueType/key for the specified entity 1032 * Entity is one of: LR, Annotation 1033 * Value types are: boolean, int, long, string, float, Object 1034 */ 1035 private Long _createFeature(Long entityID, 1036 int entityType, 1037 String key, 1038 Object value, 1039 int valueType, 1040 CallableStatement stmt) 1041 throws PersistenceException { 1042 1043 //1. store in DB 1044 Long featID = null; 1045// CallableStatement stmt = null; 1046 1047 try { 1048// stmt = this.jdbcConn.prepareCall( 1049// "{ call "+Gate.DB_OWNER+".persist.create_feature(?,?,?,?,?,?,?)} "); 1050 1051 //1.1 set known values + NULLs 1052 stmt.setLong(1,entityID.longValue()); 1053 stmt.setLong(2,entityType); 1054 stmt.setString(3,key); 1055 stmt.setNull(4,java.sql.Types.NUMERIC); 1056 stmt.setNull(5,java.sql.Types.VARCHAR); 1057 stmt.setLong(6,valueType); 1058 stmt.registerOutParameter(7,java.sql.Types.BIGINT); 1059 1060 //1.2 set proper data 1061 switch(valueType) { 1062 1063 case DBHelper.VALUE_TYPE_NULL: 1064 break; 1065 1066 case DBHelper.VALUE_TYPE_BOOLEAN: 1067 1068 boolean b = ((Boolean)value).booleanValue(); 1069 stmt.setLong(4, b ? this.ORACLE_TRUE : this.ORACLE_FALSE); 1070 break; 1071 1072 case DBHelper.VALUE_TYPE_INTEGER: 1073 1074 stmt.setLong(4,((Integer)value).intValue()); 1075 break; 1076 1077 case DBHelper.VALUE_TYPE_LONG: 1078 1079 stmt.setLong(4,((Long)value).longValue()); 1080 break; 1081 1082 case DBHelper.VALUE_TYPE_FLOAT: 1083 1084 Double d = (Double)value; 1085 stmt.setDouble(4,d.doubleValue()); 1086 break; 1087 1088 case DBHelper.VALUE_TYPE_BINARY: 1089 //ignore 1090 //will be handled later in processing 1091 break; 1092 1093 case DBHelper.VALUE_TYPE_STRING: 1094 1095 String s = (String)value; 1096 //does it fin into a varchar2? 1097 if (fitsInVarchar2(s)) { 1098 stmt.setString(5,s); 1099 } 1100 break; 1101 1102 default: 1103 throw new IllegalArgumentException("unsuppoeted feature type"); 1104 } 1105 1106 stmt.execute(); 1107 featID = new Long(stmt.getLong(7)); 1108 } 1109 catch(SQLException sqle) { 1110 1111 switch(sqle.getErrorCode()) { 1112 case DBHelper.X_ORACLE_INVALID_FEATURE_TYPE: 1113 throw new PersistenceException("can't create feature [step 1],"+ 1114 "[invalid feature type] in DB: ["+ sqle.getMessage()+"]"); 1115 default: 1116 throw new PersistenceException("can't create feature [step 1] in DB: ["+ 1117 sqle.getMessage()+"]"); 1118 } 1119 } 1120 finally { 1121// DBHelper.cleanup(stmt); 1122 } 1123 1124 return featID; 1125 } 1126 1127 1128 /** 1129 * creates a feature of the specified type/value/valueType/key for the specified entity 1130 * Entity is one of: LR, Annotation 1131 * Value types are: boolean, int, long, string, float, Object 1132 */ 1133 private void _createFeatureBulk(Vector features, 1134 CallableStatement stmt, 1135 ArrayDescriptor adNumber, 1136 ArrayDescriptor adString) 1137 throws PersistenceException { 1138 1139 String[] stringValues = new String[VARRAY_SIZE]; 1140 long[] numberValues = new long[VARRAY_SIZE]; 1141 double[] floatValues = new double[VARRAY_SIZE]; 1142 long[] entityIDs = new long[VARRAY_SIZE]; 1143 long[] entityTypes = new long[VARRAY_SIZE]; 1144 String[] keys = new String[VARRAY_SIZE]; 1145 long[] valueTypes = new long[VARRAY_SIZE]; 1146 1147//System.out.println("num features=["+features.size()+"]"); 1148 //1. store in DB 1149 try { 1150 1151 int ftInd = 0; 1152 int arrInd = 0; 1153 Iterator it = features.iterator(); 1154 1155 while (it.hasNext()) { 1156 1157 Feature currFeature = (Feature)it.next(); 1158 entityIDs[arrInd] = currFeature.entityID.longValue(); 1159 entityTypes[arrInd] = currFeature.entityType; 1160 keys[arrInd] = currFeature.key; 1161 valueTypes[arrInd] = currFeature.valueType; 1162//System.out.println("ftype=["+currFeature.valueType+"]"); 1163 //preconditions 1164 Assert.assertTrue(currFeature.valueType == DBHelper.VALUE_TYPE_BOOLEAN || 1165 currFeature.valueType == DBHelper.VALUE_TYPE_FLOAT || 1166 currFeature.valueType == DBHelper.VALUE_TYPE_INTEGER || 1167 currFeature.valueType == DBHelper.VALUE_TYPE_LONG || 1168 currFeature.valueType == DBHelper.VALUE_TYPE_NULL || 1169 currFeature.valueType == DBHelper.VALUE_TYPE_STRING 1170 ); 1171 1172 1173 Object value = currFeature.value; 1174 1175 switch(currFeature.valueType) { 1176 1177 case DBHelper.VALUE_TYPE_NULL: 1178 numberValues[arrInd] = 0; 1179 floatValues[arrInd] = 0; 1180 stringValues[arrInd] = ""; 1181 break; 1182 1183 case DBHelper.VALUE_TYPE_BOOLEAN: 1184 boolean b = ((Boolean)value).booleanValue(); 1185 numberValues[arrInd] = b ? this.ORACLE_TRUE : this.ORACLE_FALSE; 1186 floatValues[arrInd] = 0; 1187 stringValues[arrInd] = ""; 1188 break; 1189 1190 case DBHelper.VALUE_TYPE_INTEGER: 1191 numberValues[arrInd] = ((Integer)value).intValue(); 1192 floatValues[arrInd] = 0; 1193 stringValues[arrInd] = ""; 1194 break; 1195 1196 case DBHelper.VALUE_TYPE_LONG: 1197 numberValues[arrInd] = ((Long)value).longValue(); 1198 floatValues[arrInd] = 0; 1199 stringValues[arrInd] = ""; 1200 break; 1201 1202 case DBHelper.VALUE_TYPE_FLOAT: 1203 floatValues[arrInd] = ((Double)value).doubleValue(); 1204 numberValues[arrInd] = 0; 1205 stringValues[arrInd] = ""; 1206 break; 1207 1208 case DBHelper.VALUE_TYPE_BINARY: 1209 Assert.fail(); 1210 break; 1211 1212 case DBHelper.VALUE_TYPE_STRING: 1213 String s = (String)value; 1214 //does it fin into a varchar2? 1215 1216 if (fitsInVarchar2(s)) { 1217 stringValues[arrInd] = s; 1218 floatValues[arrInd] = 0; 1219 numberValues[arrInd] = 0; 1220 } 1221 else { 1222 Assert.fail(); 1223 } 1224 break; 1225 1226 default: 1227 throw new IllegalArgumentException("unsuppoeted feature type"); 1228 } 1229 1230 //save the features? 1231 ftInd++; 1232 arrInd++; 1233 1234 if (ftInd == features.size() || arrInd == VARRAY_SIZE) { 1235 1236 if (arrInd == VARRAY_SIZE) { 1237 arrInd = 0; 1238 } 1239//System.out.println("1"); 1240 ARRAY arrEntityIDs = new ARRAY(adNumber, this.jdbcConn,entityIDs); 1241 ARRAY arrEntityTypes = new ARRAY(adNumber, this.jdbcConn,entityTypes); 1242 ARRAY arrKeys = new ARRAY(adString, this.jdbcConn,keys); 1243 ARRAY arrValueTypes = new ARRAY(adNumber, this.jdbcConn,valueTypes); 1244 ARRAY arrNumberValues = new ARRAY(adNumber, this.jdbcConn,numberValues); 1245 ARRAY arrFloatValues = new ARRAY(adNumber, this.jdbcConn,floatValues); 1246 ARRAY arrStringValues = new ARRAY(adString, this.jdbcConn,stringValues); 1247 1248 OracleCallableStatement ostmt = (OracleCallableStatement)stmt; 1249 ostmt.setARRAY(1,arrEntityIDs); 1250 ostmt.setARRAY(2,arrEntityTypes); 1251 ostmt.setARRAY(3,arrKeys); 1252 ostmt.setARRAY(4,arrNumberValues); 1253 ostmt.setARRAY(5,arrFloatValues); 1254 ostmt.setARRAY(6,arrStringValues); 1255 ostmt.setARRAY(7,arrValueTypes); 1256 ostmt.setInt(8, arrInd == 0 ? VARRAY_SIZE : arrInd); 1257 1258 ostmt.execute(); 1259 } 1260 } 1261 } 1262 catch(SQLException sqle) { 1263 1264 switch(sqle.getErrorCode()) { 1265 1266 case DBHelper.X_ORACLE_INVALID_FEATURE_TYPE: 1267 throw new PersistenceException("can't create feature [step 1],"+ 1268 "[invalid feature type] in DB: ["+ sqle.getMessage()+"]"); 1269 default: 1270 throw new PersistenceException("can't create feature [step 1] in DB: ["+ 1271 sqle.getMessage()+"]"); 1272 } 1273 } 1274 } 1275 1276 /** 1277 * updates the value of a feature where the value is string (>4000 bytes, stored as CLOB) 1278 * or Object (stored as BLOB) 1279 */ 1280 private void _updateFeatureLOB(Long featID,Object value, int valueType) 1281 throws PersistenceException { 1282 1283 //NOTE: at this point value is never an array, 1284 // although the type may claim so 1285 1286 //0. preconditions 1287 Assert.assertTrue(valueType == DBHelper.VALUE_TYPE_BINARY || 1288 valueType == DBHelper.VALUE_TYPE_STRING); 1289 1290 1291 //1. get the row to be updated 1292 PreparedStatement stmtA = null; 1293 ResultSet rsA = null; 1294 Clob clobValue = null; 1295 Blob blobValue = null; 1296 1297 try { 1298 String sql = " select ft_long_character_value, " + 1299 " ft_binary_value " + 1300 " from "+Gate.DB_OWNER+".t_feature " + 1301 " where ft_id = ? "; 1302 1303 stmtA = this.jdbcConn.prepareStatement(sql); 1304 stmtA.setLong(1,featID.longValue()); 1305 stmtA.execute(); 1306 rsA = stmtA.getResultSet(); 1307 1308 if (false == rsA.next()) { 1309 throw new PersistenceException("Incorrect feature ID supplied ["+featID+"]"); 1310 } 1311 1312 //NOTE1: if the result set contains LOBs always read them 1313 // in the order they appear in the SQL query 1314 // otherwise data will be lost 1315 //NOTE2: access by index rather than name is usually faster 1316 clobValue = rsA.getClob(1); 1317 blobValue = rsA.getBlob(2); 1318 1319 //blob or clob? 1320 if (valueType == DBHelper.VALUE_TYPE_BINARY) { 1321 //blob 1322 writeBLOB(value,blobValue); 1323 } 1324 else if (valueType == DBHelper.VALUE_TYPE_STRING) { 1325 //clob 1326 String s = (String)value; 1327 writeCLOB(s,clobValue); 1328 } 1329 else { 1330 Assert.fail(); 1331 } 1332 } 1333 catch(SQLException sqle) { 1334 throw new PersistenceException("can't create feature [step 2] in DB: ["+ sqle.getMessage()+"]"); 1335 } 1336 catch(IOException ioe) { 1337 throw new PersistenceException("can't create feature [step 2] in DB: ["+ ioe.getMessage()+"]"); 1338 } 1339 finally { 1340 DBHelper.cleanup(rsA); 1341 DBHelper.cleanup(stmtA); 1342 } 1343 1344 } 1345 1346 1347 1348 /** 1349 * creates a feature with the specified type/key/value for the specified entity 1350 * entitties are either LRs ot Annotations 1351 * valid values are: boolean, 1352 * int, 1353 * long, 1354 * string, 1355 * float, 1356 * Object, 1357 * boolean List, 1358 * int List, 1359 * long List, 1360 * string List, 1361 * float List, 1362 * Object List 1363 * 1364 */ 1365 private void createFeature(Long entityID, int entityType,String key, Object value, CallableStatement stmt) 1366 throws PersistenceException { 1367 1368 //1. what kind of feature value is this? 1369//System.out.println("key=["+key+"], val=["+value+"]"); 1370 int valueType = findFeatureType(value); 1371 1372 //2. how many elements do we store? 1373 Vector elementsToStore = new Vector(); 1374 1375 switch(valueType) { 1376 case DBHelper.VALUE_TYPE_NULL: 1377 case DBHelper.VALUE_TYPE_BINARY: 1378 case DBHelper.VALUE_TYPE_BOOLEAN: 1379 case DBHelper.VALUE_TYPE_FLOAT: 1380 case DBHelper.VALUE_TYPE_INTEGER: 1381 case DBHelper.VALUE_TYPE_LONG: 1382 case DBHelper.VALUE_TYPE_STRING: 1383 elementsToStore.add(value); 1384 break; 1385 1386 default: 1387 //arrays 1388 List arr = (List)value; 1389 Iterator itValues = arr.iterator(); 1390 1391 while (itValues.hasNext()) { 1392 elementsToStore.add(itValues.next()); 1393 } 1394 1395 //normalize , i.e. ignore arrays 1396 if (valueType == DBHelper.VALUE_TYPE_BINARY_ARR) 1397 valueType = DBHelper.VALUE_TYPE_BINARY; 1398 else if (valueType == DBHelper.VALUE_TYPE_BOOLEAN_ARR) 1399 valueType = DBHelper.VALUE_TYPE_BOOLEAN; 1400 else if (valueType == DBHelper.VALUE_TYPE_FLOAT_ARR) 1401 valueType = DBHelper.VALUE_TYPE_FLOAT; 1402 else if (valueType == DBHelper.VALUE_TYPE_INTEGER_ARR) 1403 valueType = DBHelper.VALUE_TYPE_INTEGER; 1404 else if (valueType == DBHelper.VALUE_TYPE_LONG_ARR) 1405 valueType = DBHelper.VALUE_TYPE_LONG; 1406 else if (valueType == DBHelper.VALUE_TYPE_STRING_ARR) 1407 valueType = DBHelper.VALUE_TYPE_STRING; 1408 } 1409 1410 //3. for all elements: 1411 for (int i=0; i< elementsToStore.size(); i++) { 1412 1413 Object currValue = elementsToStore.elementAt(i); 1414 1415 //3.1. create a dummy feature [LOB hack] 1416 Long featID = _createFeature(entityID,entityType,key,currValue,valueType,stmt); 1417 1418 //3.2. update CLOBs if needed 1419 if (valueType == DBHelper.VALUE_TYPE_STRING) { 1420 //does this string fit into a varchar2 or into clob? 1421 String s = (String)currValue; 1422 if (false == this.fitsInVarchar2(s)) { 1423 // Houston, we have a problem 1424 // put the string into a clob 1425 _updateFeatureLOB(featID,value,valueType); 1426 } 1427 } 1428 else if (valueType == DBHelper.VALUE_TYPE_BINARY) { 1429 //3.3. BLOBs 1430 _updateFeatureLOB(featID,value,valueType); 1431 } 1432 } 1433 1434 1435 } 1436 1437 1438 /** 1439 * splits complex features (Lists) into a vector of Feature entries 1440 * each entry contains the entity id, 1441 * entity type, 1442 * feature key 1443 * feature value 1444 * value type 1445 * 1446 */ 1447 private Vector normalizeFeature(Long entityID, int entityType,String key, Object value) 1448 throws PersistenceException { 1449 1450 //1. what kind of feature value is this? 1451 int valueType = findFeatureType(value); 1452 1453 //2. how many elements do we store? 1454 Vector elementsToStore = new Vector(); 1455 Vector features = new Vector(); 1456 1457 switch(valueType) { 1458 case DBHelper.VALUE_TYPE_NULL: 1459 case DBHelper.VALUE_TYPE_BINARY: 1460 case DBHelper.VALUE_TYPE_BOOLEAN: 1461 case DBHelper.VALUE_TYPE_FLOAT: 1462 case DBHelper.VALUE_TYPE_INTEGER: 1463 case DBHelper.VALUE_TYPE_LONG: 1464 case DBHelper.VALUE_TYPE_STRING: 1465 elementsToStore.add(value); 1466 break; 1467 1468 default: 1469 //arrays 1470 List arr = (List)value; 1471 Iterator itValues = arr.iterator(); 1472 1473 while (itValues.hasNext()) { 1474 elementsToStore.add(itValues.next()); 1475 } 1476 1477 //normalize , i.e. ignore arrays 1478 if (valueType == DBHelper.VALUE_TYPE_BINARY_ARR) 1479 valueType = DBHelper.VALUE_TYPE_BINARY; 1480 else if (valueType == DBHelper.VALUE_TYPE_BOOLEAN_ARR) 1481 valueType = DBHelper.VALUE_TYPE_BOOLEAN; 1482 else if (valueType == DBHelper.VALUE_TYPE_FLOAT_ARR) 1483 valueType = DBHelper.VALUE_TYPE_FLOAT; 1484 else if (valueType == DBHelper.VALUE_TYPE_INTEGER_ARR) 1485 valueType = DBHelper.VALUE_TYPE_INTEGER; 1486 else if (valueType == DBHelper.VALUE_TYPE_LONG_ARR) 1487 valueType = DBHelper.VALUE_TYPE_LONG; 1488 else if (valueType == DBHelper.VALUE_TYPE_STRING_ARR) 1489 valueType = DBHelper.VALUE_TYPE_STRING; 1490 } 1491 1492 for (int i=0; i< elementsToStore.size(); i++) { 1493 1494 Object currValue = elementsToStore.elementAt(i); 1495 Feature currFeature = new Feature(entityID,entityType,key,currValue,valueType); 1496 features.add(currFeature); 1497 } 1498 1499 return features; 1500 } 1501 1502 1503 /** 1504 * checks if a String should be stores as VARCHAR2 or CLOB 1505 * because the VARCHAR2 in Oracle is limited to 4000 <b>bytes</b>, not all 1506 * the strings fit there. If a String is too long then it is store in the 1507 * database as CLOB. 1508 * Note that in the worst case 3 bytes are needed to represent a single character 1509 * in a database with UTF8 encoding, which limits the string length to 4000/3 1510 * (ORACLE_VARCHAR_LIMIT_BYTES) 1511 * @see ORACLE_VARCHAR_LIMIT_BYTES 1512 */ 1513 private boolean fitsInVarchar2(String s) { 1514 1515 return s.getBytes().length < this.ORACLE_VARCHAR_LIMIT_BYTES; 1516 } 1517 1518 1519 1520 /** 1521 * helper metod 1522 * iterates a FeatureMap and creates all its features in the database 1523 */ 1524 protected void createFeatures(Long entityID, int entityType, FeatureMap features) 1525 throws PersistenceException { 1526 1527 //0. prepare statement ad use it for all features 1528 CallableStatement stmt = null; 1529 CallableStatement stmtBulk = null; 1530 ArrayDescriptor adNumber = null; 1531 ArrayDescriptor adString = null; 1532 1533 try { 1534 stmt = this.jdbcConn.prepareCall( 1535 "{ call "+Gate.DB_OWNER+".persist.create_feature(?,?,?,?,?,?,?)} "); 1536 1537 stmtBulk = this.jdbcConn.prepareCall( 1538 "{ call "+Gate.DB_OWNER+".persist.create_feature_bulk(?,?,?,?,?,?,?,?)} "); 1539 1540 adNumber = ArrayDescriptor.createDescriptor("GATEADMIN.PERSIST.INTARRAY", this.jdbcConn); 1541 adString = ArrayDescriptor.createDescriptor("GATEADMIN.PERSIST.CHARARRAY", this.jdbcConn); 1542 } 1543 catch (SQLException sqle) { 1544 throw new PersistenceException(sqle); 1545 } 1546 1547 /* when some day Java has macros, this will be a macro */ 1548 Set entries = features.entrySet(); 1549 Iterator itFeatures = entries.iterator(); 1550 while (itFeatures.hasNext()) { 1551 Map.Entry entry = (Map.Entry)itFeatures.next(); 1552 String key = (String)entry.getKey(); 1553 Object value = entry.getValue(); 1554 createFeature(entityID,entityType,key,value,stmt); 1555 } 1556 1557 //3. cleanup 1558 DBHelper.cleanup(stmt); 1559 } 1560 1561 1562 /** 1563 * helper metod 1564 * iterates a FeatureMap and creates all its features in the database 1565 * 1566 * since it uses Oracle VARRAYs the roundtrips between the client and the server 1567 * are minimized 1568 * 1569 * make sure the two types STRING_ARRAY and INT_ARRAY have the same name in the 1570 * PL/SQL files 1571 * 1572 * also when referencing the types always use the schema owner in upper case 1573 * because the jdbc driver is buggy (see MetaLink note if u care) 1574 */ 1575 protected void createFeaturesBulk(Long entityID, int entityType, FeatureMap features) 1576 throws PersistenceException { 1577 1578 //0. prepare statement ad use it for all features 1579 CallableStatement stmt = null; 1580 CallableStatement stmtBulk = null; 1581 ArrayDescriptor adNumber = null; 1582 ArrayDescriptor adString = null; 1583 1584 try { 1585 stmt = this.jdbcConn.prepareCall( 1586 "{ call "+Gate.DB_OWNER+".persist.create_feature(?,?,?,?,?,?,?)} "); 1587 1588 stmtBulk = this.jdbcConn.prepareCall( 1589 "{ call "+Gate.DB_OWNER+".persist.create_feature_bulk(?,?,?,?,?,?,?,?)} "); 1590 1591 //ACHTUNG!!! 1592 //using toUpper for schema owner is necessary because of the dull JDBC driver 1593 //otherwise u'll end up with "invalid name pattern" Oracle error 1594 adString = ArrayDescriptor.createDescriptor(Gate.DB_OWNER.toUpperCase()+".STRING_ARRAY", this.jdbcConn); 1595 adNumber = ArrayDescriptor.createDescriptor(Gate.DB_OWNER.toUpperCase()+".INT_ARRAY", this.jdbcConn); 1596 } 1597 catch (SQLException sqle) { 1598 throw new PersistenceException(sqle); 1599 } 1600 1601 /* when some day Java has macros, this will be a macro */ 1602 Vector entityFeatures = new Vector(); 1603 1604 Set entries = features.entrySet(); 1605 Iterator itFeatures = entries.iterator(); 1606 while (itFeatures.hasNext()) { 1607 Map.Entry entry = (Map.Entry)itFeatures.next(); 1608 String key = (String)entry.getKey(); 1609 Object value = entry.getValue(); 1610 Vector normalizedFeatures = normalizeFeature(entityID,entityType,key,value); 1611 entityFeatures.addAll(normalizedFeatures); 1612 } 1613 1614 //iterate all features, store LOBs directly and other features with bulk store 1615 Iterator itEntityFeatures = entityFeatures.iterator(); 1616 1617 while (itEntityFeatures.hasNext()) { 1618 1619 Feature currFeature = (Feature)itEntityFeatures.next(); 1620 1621 if (currFeature.valueType == DBHelper.VALUE_TYPE_STRING) { 1622 //does this string fit into a varchar2 or into clob? 1623 String s = (String)currFeature.value; 1624 if (false == this.fitsInVarchar2(s)) { 1625 // Houston, we have a problem 1626 // put the string into a clob 1627 Long featID = _createFeature(currFeature.entityID, 1628 currFeature.entityType, 1629 currFeature.key, 1630 currFeature.value, 1631 currFeature.valueType, 1632 stmt); 1633 _updateFeatureLOB(featID,currFeature.value,currFeature.valueType); 1634 itEntityFeatures.remove(); 1635 } 1636 } 1637 else if (currFeature.valueType == DBHelper.VALUE_TYPE_BINARY) { 1638 //3.3. BLOBs 1639 Long featID = _createFeature(currFeature.entityID, 1640 currFeature.entityType, 1641 currFeature.key, 1642 currFeature.value, 1643 currFeature.valueType, 1644 stmt); 1645 _updateFeatureLOB(featID,currFeature.value,currFeature.valueType); 1646 itEntityFeatures.remove(); 1647 } 1648 } 1649 1650 //now we have the data for the bulk store 1651 _createFeatureBulk(entityFeatures, stmtBulk, adNumber, adString); 1652 1653 //3. cleanup 1654 DBHelper.cleanup(stmt); 1655 DBHelper.cleanup(stmtBulk); 1656 } 1657 1658 1659 1660 /** set security information for LR . */ 1661 public void setSecurityInfo(LanguageResource lr,SecurityInfo si) 1662 throws PersistenceException, SecurityException { 1663 throw new MethodNotImplementedException(); 1664 } 1665 1666 1667 1668 /** 1669 * helper method for getLR - reads LR of type Corpus 1670 */ 1671/* 1672 private DatabaseCorpusImpl readCorpus(Object lrPersistenceId) 1673 throws PersistenceException { 1674 1675 //0. preconditions 1676 Assert.assertNotNull(lrPersistenceId); 1677 1678 if (false == lrPersistenceId instanceof Long) { 1679 throw new IllegalArgumentException(); 1680 } 1681 1682 //3. read from DB 1683 PreparedStatement pstmt = null; 1684 ResultSet rs = null; 1685 DatabaseCorpusImpl result = null; 1686 1687 try { 1688 String sql = " select lr_name " + 1689 " from "+Gate.DB_OWNER+".t_lang_resource " + 1690 " where lr_id = ? "; 1691 pstmt = this.jdbcConn.prepareStatement(sql); 1692 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 1693 pstmt.execute(); 1694 rs = pstmt.getResultSet(); 1695 1696 if (false == rs.next()) { 1697 //ooops mo data found 1698 throw new PersistenceException("Invalid LR ID supplied - no data found"); 1699 } 1700 1701 //4. fill data 1702 1703 //4.1 name 1704 String lrName = rs.getString("lr_name"); 1705 Assert.assertNotNull(lrName); 1706 1707 //4.8 features 1708 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_CORPUS); 1709 1710 //4.9 cleanup 1711 DBHelper.cleanup(rs); 1712 DBHelper.cleanup(pstmt); 1713 1714 sql = " select lr_id ," + 1715 " lr_name " + 1716 " from "+Gate.DB_OWNER+".t_document doc, " + 1717 " "+Gate.DB_OWNER+".t_lang_resource lr, " + 1718 " "+Gate.DB_OWNER+".t_corpus_document corpdoc, " + 1719 " "+Gate.DB_OWNER+".t_corpus corp " + 1720 " where lr.lr_id = doc.doc_lr_id " + 1721 " and doc.doc_id = corpdoc.cd_doc_id " + 1722 " and corpdoc.cd_corp_id = corp.corp_id " + 1723 " and corp_lr_id = ? "; 1724 pstmt = this.jdbcConn.prepareStatement(sql); 1725 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 1726 pstmt.execute(); 1727 rs = pstmt.getResultSet(); 1728 1729 //--Vector docLRIDs = new Vector(); 1730 Vector documentData = new Vector(); 1731 while (rs.next()) { 1732 Long docLRID = new Long(rs.getLong("lr_id")); 1733 String docName = rs.getString("lr_name"); 1734 //--docLRIDs.add(docLRID); 1735 documentData.add(new DocumentData(docName, docLRID)); 1736 } 1737 DBHelper.cleanup(rs); 1738 DBHelper.cleanup(pstmt); 1739 1740 1741// Vector dbDocs = new Vector(); 1742// for (int i=0; i< docLRIDs.size(); i++) { 1743// Long currLRID = (Long)docLRIDs.elementAt(i); 1744 //kalina: replaced by a Factory call, so the doc gets registered 1745 //properly in GATE. Otherwise strange behaviour results in the GUI 1746 //and no events come about it 1747//// Document dbDoc = (Document)getLr(DBHelper.DOCUMENT_CLASS,currLRID); 1748// FeatureMap params = Factory.newFeatureMap(); 1749// params.put(DataStore.DATASTORE_FEATURE_NAME, this); 1750// params.put(DataStore.LR_ID_FEATURE_NAME, currLRID); 1751// Document dbDoc = (Document)Factory.createResource(DBHelper.DOCUMENT_CLASS, params); 1752 1753 1754// dbDocs.add(dbDoc); 1755// } 1756 1757 result = new DatabaseCorpusImpl(lrName, 1758 this, 1759 (Long)lrPersistenceId, 1760 features, 1761 // dbDocs); 1762 documentData); 1763 } 1764 catch(SQLException sqle) { 1765 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]"); 1766 } 1767 catch(Exception e) { 1768 throw new PersistenceException(e); 1769 } 1770 finally { 1771 DBHelper.cleanup(rs); 1772 DBHelper.cleanup(pstmt); 1773 } 1774 1775 return result; 1776 } 1777*/ 1778 1779 /** helper method for getLR - reads LR of type Document */ 1780/* 1781 private DatabaseDocumentImpl readDocument(Object lrPersistenceId) 1782 throws PersistenceException { 1783 1784 //0. preconditions 1785 Assert.assertNotNull(lrPersistenceId); 1786 1787 if (false == lrPersistenceId instanceof Long) { 1788 throw new IllegalArgumentException(); 1789 } 1790 1791 // 1. dummy document to be initialized 1792 DatabaseDocumentImpl result = new DatabaseDocumentImpl(this.jdbcConn); 1793 1794 PreparedStatement pstmt = null; 1795 ResultSet rs = null; 1796 1797 //3. read from DB 1798 try { 1799 String sql = " select lr_name, " + 1800 " lrtp_type, " + 1801 " lr_id, " + 1802 " lr_parent_id, " + 1803 " doc_id, " + 1804 " doc_url, " + 1805 " doc_start, " + 1806 " doc_end, " + 1807 " doc_is_markup_aware " + 1808 " from "+Gate.DB_OWNER+".v_document " + 1809 " where lr_id = ? "; 1810 1811 pstmt = this.jdbcConn.prepareStatement(sql); 1812 pstmt.setLong(1,((Long)lrPersistenceId).longValue()); 1813 pstmt.execute(); 1814 rs = pstmt.getResultSet(); 1815 1816 if (false == rs.next()) { 1817 //ooops mo data found 1818 throw new PersistenceException("Invalid LR ID supplied - no data found"); 1819 } 1820 1821 //4. fill data 1822 1823 //4.0 name 1824 String lrName = rs.getString("lr_name"); 1825 Assert.assertNotNull(lrName); 1826 result.setName(lrName); 1827 1828 //4.1 parent 1829 Long parentID = null; 1830 long parent_id = rs.getLong("lr_parent_id"); 1831 if (false == rs.wasNull()) { 1832 parentID = new Long(parent_id); 1833 1834 //read parent resource 1835 LanguageResource parentLR = this.getLr(DBHelper.DOCUMENT_CLASS,parentID); 1836 Assert.assertNotNull(parentLR); 1837 Assert.assertTrue(parentLR instanceof DatabaseDocumentImpl); 1838 1839 result.setParent(parentLR); 1840 } 1841 1842 1843 //4.2. markup aware 1844 long markup = rs.getLong("doc_is_markup_aware"); 1845 Assert.assertTrue(markup == this.ORACLE_FALSE || markup == this.ORACLE_TRUE); 1846 if (markup == this.ORACLE_FALSE) { 1847 result.setMarkupAware(Boolean.FALSE); 1848 } 1849 else { 1850 result.setMarkupAware(Boolean.TRUE); 1851 1852 } 1853 1854 //4.3 datastore 1855 result.setDataStore(this); 1856 1857 //4.4. persist ID 1858 Long persistID = new Long(rs.getLong("lr_id")); 1859 result.setLRPersistenceId(persistID); 1860 1861 //4.5 source url 1862 String url = rs.getString("doc_url"); 1863 result.setSourceUrl(new URL(url)); 1864 1865 //4.6. start offset 1866 Long start = null; 1867 long longVal = rs.getLong("doc_start"); 1868 //null? 1869 //if NULL is stored in the DB, Oracle returns 0 which is not what we want 1870 if (false == rs.wasNull()) { 1871 start = new Long(longVal); 1872 } 1873 result.setSourceUrlStartOffset(start); 1874// initData.put("DOC_SOURCE_URL_START",start); 1875 1876 //4.7. end offset 1877 Long end = null; 1878 longVal = rs.getLong("doc_end"); 1879 //null? 1880 //if NULL is stored in the DB, Oracle returns 0 which is not what we want 1881 if (false == rs.wasNull()) { 1882 end = new Long(longVal); 1883 } 1884 result.setSourceUrlEndOffset(end); 1885// initData.put("DOC_SOURCE_URL_END",end); 1886 1887 //4.8 features 1888 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_DOCUMENT); 1889 result.setFeatures(features); 1890 //initData.put("DOC_FEATURES",features); 1891 1892 //4.9 set the nextAnnotationID correctly 1893 long doc_id = rs.getLong("doc_id"); 1894 1895 DBHelper.cleanup(rs); 1896 DBHelper.cleanup(pstmt); 1897 sql = " select max(ann_local_id),'ann_id'" + 1898 " from "+Gate.DB_OWNER+".t_annotation " + 1899 " where ann_doc_id = ?" + 1900 " union " + 1901 " select max(node_local_id),'node_id' " + 1902 " from "+Gate.DB_OWNER+".t_node " + 1903 " where node_doc_id = ?"; 1904 1905 pstmt = this.jdbcConn.prepareStatement(sql); 1906 pstmt.setLong(1,doc_id); 1907 pstmt.setLong(2,doc_id); 1908 pstmt.execute(); 1909 rs = pstmt.getResultSet(); 1910 1911 int maxAnnID = 0 , maxNodeID = 0; 1912 //ann id 1913 if (false == rs.next()) { 1914 //ooops no data found 1915 throw new PersistenceException("Invalid LR ID supplied - no data found"); 1916 } 1917 if (rs.getString(2).equals("ann_id")) 1918 maxAnnID = rs.getInt(1); 1919 else 1920 maxNodeID = rs.getInt(1); 1921 1922 if (false == rs.next()) { 1923 //ooops no data found 1924 throw new PersistenceException("Invalid LR ID supplied - no data found"); 1925 } 1926 if (rs.getString(2).equals("node_id")) 1927 maxNodeID = rs.getInt(1); 1928 else 1929 maxAnnID = rs.getInt(1); 1930 1931 result.setNextNodeId(maxNodeID+1); 1932// initData.put("DOC_NEXT_NODE_ID",new Integer(maxNodeID+1)); 1933 result.setNextAnnotationId(maxAnnID+1); 1934// initData.put("DOC_NEXT_ANN_ID",new Integer(maxAnnID+1)); 1935 1936 1937// params.put("initData__$$__", initData); 1938// try { 1939 //here we create the persistent LR via Factory, so it's registered 1940 //in GATE 1941// result = (DatabaseDocumentImpl)Factory.createResource("gate.corpora.DatabaseDocumentImpl", params); 1942// } 1943// catch (gate.creole.ResourceInstantiationException ex) { 1944// throw new GateRuntimeException(ex.getMessage()); 1945// } 1946 } 1947 catch(SQLException sqle) { 1948 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]"); 1949 } 1950 catch(Exception e) { 1951 throw new PersistenceException(e); 1952 } 1953 finally { 1954 DBHelper.cleanup(rs); 1955 DBHelper.cleanup(pstmt); 1956 } 1957 1958 return result; 1959 } 1960*/ 1961 1962 1963 /** 1964 * reads the features of an entity 1965 * entities are of type LR or Annotation 1966 */ 1967 protected FeatureMap readFeatures(Long entityID, int entityType) 1968 throws PersistenceException { 1969 1970 //0. preconditions 1971 Assert.assertNotNull(entityID); 1972 Assert.assertTrue(entityType == DBHelper.FEATURE_OWNER_ANNOTATION || 1973 entityType == DBHelper.FEATURE_OWNER_CORPUS || 1974 entityType == DBHelper.FEATURE_OWNER_DOCUMENT); 1975 1976 1977 PreparedStatement pstmt = null; 1978 ResultSet rs = null; 1979 FeatureMap fm = new SimpleFeatureMapImpl(); 1980 1981 //1. read from DB 1982 try { 1983 String sql = " select v2.fk_string, " + 1984 " v1.ft_value_type, " + 1985 " v1.ft_number_value, " + 1986 " v1.ft_binary_value, " + 1987 " v1.ft_character_value, " + 1988 " v1.ft_long_character_value " + 1989 " from "+Gate.DB_OWNER+".t_feature v1, " + 1990 " "+Gate.DB_OWNER+".t_feature_key v2 " + 1991 " where v1.ft_entity_id = ? " + 1992 " and v1.ft_entity_type = ? " + 1993 " and v1.ft_key_id = v2.fk_id " + 1994 " order by v2.fk_string,v1.ft_id"; 1995 1996 pstmt = this.jdbcConn.prepareStatement(sql); 1997 pstmt.setLong(1,entityID.longValue()); 1998 pstmt.setLong(2,entityType); 1999 pstmt.execute(); 2000 rs = pstmt.getResultSet(); 2001 2002 //3. fill feature map 2003 Vector arrFeatures = new Vector(); 2004 String prevKey = null; 2005 String currKey = null; 2006 Object currFeature = null; 2007 2008 2009 while (rs.next()) { 2010 //NOTE: because there are LOBs in the resulset 2011 //the columns should be read in the order they appear 2012 //in the query 2013 currKey = rs.getString(1); 2014 2015 Long valueType = new Long(rs.getLong(2)); 2016 2017 //we don't quite know what is the type of the NUMBER 2018 //stored in DB 2019 Object numberValue = null; 2020 2021 //for all numeric types + boolean -> read from DB as appropriate 2022 //Java object 2023 switch(valueType.intValue()) { 2024 2025 case DBHelper.VALUE_TYPE_BOOLEAN: 2026 numberValue = new Boolean(rs.getBoolean(3)); 2027 break; 2028 2029 case DBHelper.VALUE_TYPE_FLOAT: 2030 numberValue = new Double(rs.getDouble(3)); 2031 break; 2032 2033 case DBHelper.VALUE_TYPE_INTEGER: 2034 numberValue = new Integer(rs.getInt(3)); 2035 break; 2036 2037 case DBHelper.VALUE_TYPE_LONG: 2038 numberValue = new Long(rs.getLong(3)); 2039 break; 2040 } 2041 2042 //don't forget to read the rest of the current row 2043 Blob blobValue = rs.getBlob(4); 2044 String stringValue = rs.getString(5); 2045 Clob clobValue = rs.getClob(6); 2046 2047 switch(valueType.intValue()) { 2048 2049 case DBHelper.VALUE_TYPE_NULL: 2050 currFeature = null; 2051 break; 2052 2053 case DBHelper.VALUE_TYPE_BOOLEAN: 2054 case DBHelper.VALUE_TYPE_FLOAT: 2055 case DBHelper.VALUE_TYPE_INTEGER: 2056 case DBHelper.VALUE_TYPE_LONG: 2057 currFeature = numberValue; 2058 break; 2059 2060 case DBHelper.VALUE_TYPE_BINARY: 2061 currFeature = readBLOB(blobValue); 2062 break; 2063 2064 case DBHelper.VALUE_TYPE_STRING: 2065 //this one is tricky too 2066 //if the string is < 4000 bytes long then it's stored as varchar2 2067 //otherwise as CLOB 2068 if (null == stringValue) { 2069 //oops, we got CLOB 2070 StringBuffer temp = new StringBuffer(); 2071 readCLOB(clobValue,temp); 2072 currFeature = temp.toString(); 2073 } 2074 else { 2075 currFeature = stringValue; 2076 } 2077 break; 2078 2079 default: 2080 throw new PersistenceException("Invalid feature type found in DB, type is ["+valueType.intValue()+"]"); 2081 }//switch 2082 2083 //new feature or part of an array? 2084 if (currKey.equals(prevKey) && prevKey != null) { 2085 //part of array 2086 arrFeatures.add(currFeature); 2087 } 2088 else { 2089 //add prev feature to feature map 2090 2091 //is the prev feature an array or a single object? 2092 if (arrFeatures.size() > 1) { 2093 //put a clone, because this is a temp array that will 2094 //be cleared in few lines 2095 fm.put(prevKey, new Vector(arrFeatures)); 2096 } 2097 else if (arrFeatures.size() == 1) { 2098 fm.put(prevKey,arrFeatures.elementAt(0)); 2099 } 2100 else { 2101 //do nothing, this is the dummy feature 2102 ; 2103 }//if 2104 2105 //now clear the array from previous fesature(s) and put the new 2106 //one there 2107 arrFeatures.clear(); 2108 2109 prevKey = currKey; 2110 arrFeatures.add(currFeature); 2111 }//if 2112 }//while 2113 2114 //add the last feature 2115 if (arrFeatures.size() > 1) { 2116 fm.put(currKey,arrFeatures); 2117 } 2118 else if (arrFeatures.size() == 1) { 2119 fm.put(currKey,arrFeatures.elementAt(0)); 2120 } 2121 }//try 2122 catch(SQLException sqle) { 2123 throw new PersistenceException("can't read features from DB: ["+ sqle.getMessage()+"]"); 2124 } 2125 catch(IOException ioe) { 2126 throw new PersistenceException("can't read features from DB: ["+ ioe.getMessage()+"]"); 2127 } 2128 catch(ClassNotFoundException cnfe) { 2129 throw new PersistenceException("can't read features from DB: ["+ cnfe.getMessage()+"]"); 2130 } 2131 finally { 2132 DBHelper.cleanup(rs); 2133 DBHelper.cleanup(pstmt); 2134 } 2135 2136 return fm; 2137 } 2138 2139 2140 2141 /** 2142 * checks if two databases are identical 2143 * @see readDatabaseID() 2144 * NOTE: the same database may be represented by different OracleDataStore instances 2145 * but the IDs will be the same 2146 */ 2147 public boolean equals(Object obj) { 2148 2149 if (false == obj instanceof OracleDataStore) { 2150 return false; 2151 } 2152 2153 OracleDataStore db2 = (OracleDataStore)obj; 2154 2155 if (false == this.getDatabaseID().equals(db2.getDatabaseID())) { 2156 return false; 2157 } 2158 2159 return true; 2160 } 2161 2162 2163 2164 2165 /** 2166 * helper for sync() 2167 * NEVER call directly 2168 */ 2169 protected void _syncLR(LanguageResource lr) 2170 throws PersistenceException,SecurityException { 2171 2172 //0.preconditions 2173 Assert.assertTrue(lr instanceof DatabaseDocumentImpl || 2174 lr instanceof DatabaseCorpusImpl);; 2175 Assert.assertNotNull(lr.getLRPersistenceId()); 2176 2177 CallableStatement stmt = null; 2178 2179 try { 2180 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.update_lr(?,?,?) }"); 2181 stmt.setLong(1,((Long)lr.getLRPersistenceId()).longValue()); 2182 stmt.setString(2,lr.getName()); 2183 //do we have a parent resource? 2184 if (lr instanceof Document && 2185 null != lr.getParent()) { 2186 stmt.setLong(3,((Long)lr.getParent().getLRPersistenceId()).longValue()); 2187 } 2188 else { 2189 stmt.setNull(3,java.sql.Types.BIGINT); 2190 } 2191 2192 stmt.execute(); 2193 } 2194 catch(SQLException sqle) { 2195 2196 switch(sqle.getErrorCode()) { 2197 case DBHelper.X_ORACLE_INVALID_LR: 2198 throw new PersistenceException("can't set LR name in DB: [invalid LR ID]"); 2199 default: 2200 throw new PersistenceException( 2201 "can't set LR name in DB: ["+ sqle.getMessage()+"]"); 2202 } 2203 2204 } 2205 finally { 2206 DBHelper.cleanup(stmt); 2207 } 2208 } 2209 2210 2211 2212 /** helper for sync() - never call directly */ 2213 protected void _syncDocumentHeader(Document doc) 2214 throws PersistenceException { 2215 2216 Long lrID = (Long)doc.getLRPersistenceId(); 2217 2218 CallableStatement stmt = null; 2219 2220 try { 2221 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+ 2222 ".persist.update_document(?,?,?,?,?) }"); 2223 stmt.setLong(1,lrID.longValue()); 2224 stmt.setString(2,doc.getSourceUrl().toString()); 2225 //do we have start offset? 2226 if (null==doc.getSourceUrlStartOffset()) { 2227 stmt.setNull(3,java.sql.Types.NUMERIC); 2228 } 2229 else { 2230 stmt.setLong(3,doc.getSourceUrlStartOffset().longValue()); 2231 } 2232 //do we have end offset? 2233 if (null==doc.getSourceUrlEndOffset()) { 2234 stmt.setNull(4,java.sql.Types.NUMERIC); 2235 } 2236 else { 2237 stmt.setLong(4,doc.getSourceUrlEndOffset().longValue()); 2238 } 2239 2240 stmt.setLong(5,true == doc.getMarkupAware().booleanValue() ? this.ORACLE_TRUE 2241 : this.ORACLE_FALSE); 2242 2243 stmt.execute(); 2244 } 2245 catch(SQLException sqle) { 2246 2247 switch(sqle.getErrorCode()) { 2248 case DBHelper.X_ORACLE_INVALID_LR : 2249 throw new PersistenceException("invalid LR supplied: no such document: ["+ 2250 sqle.getMessage()+"]"); 2251 default: 2252 throw new PersistenceException("can't change document data: ["+ 2253 sqle.getMessage()+"]"); 2254 } 2255 } 2256 finally { 2257 DBHelper.cleanup(stmt); 2258 } 2259 2260 } 2261 2262 2263 2264 /** helper for sync() - never call directly */ 2265 protected void _syncDocumentContent(Document doc) 2266 throws PersistenceException { 2267 2268 PreparedStatement pstmt = null; 2269 ResultSet rs = null; 2270 Long docContID = null; 2271 2272 //1. read from DB 2273 try { 2274 String sql = " select dc_id " + 2275 " from "+Gate.DB_OWNER+".v_content " + 2276 " where lr_id = ? "; 2277 2278 pstmt = this.jdbcConn.prepareStatement(sql); 2279 pstmt.setLong(1,((Long)doc.getLRPersistenceId()).longValue()); 2280 pstmt.execute(); 2281 rs = pstmt.getResultSet(); 2282 2283 if (false == rs.next()) { 2284 throw new PersistenceException("invalid LR ID supplied"); 2285 } 2286 2287 //1, get DC_ID 2288 docContID = new Long(rs.getLong(1)); 2289 2290 //2, update LOBs 2291 updateDocumentContent(docContID,doc.getContent()); 2292 2293 } 2294 catch(SQLException sqle) { 2295 throw new PersistenceException("Cannot update document content ["+ 2296 sqle.getMessage()+"]"); 2297 } 2298 finally { 2299 DBHelper.cleanup(rs); 2300 DBHelper.cleanup(pstmt); 2301 } 2302 } 2303 2304 2305 2306 /** helper for sync() - never call directly */ 2307/* protected void _syncAddedAnnotations(Document doc, AnnotationSet as, Collection changes) 2308 throws PersistenceException { 2309 2310 //0.preconditions 2311 Assert.assertNotNull(doc); 2312 Assert.assertNotNull(as); 2313 Assert.assertNotNull(changes); 2314 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 2315 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl); 2316 Assert.assertTrue(changes.size() > 0); 2317 2318 2319 PreparedStatement pstmt = null; 2320 ResultSet rs = null; 2321 CallableStatement cstmt = null; 2322 Long lrID = (Long)doc.getLRPersistenceId(); 2323// Long docID = null; 2324 Long asetID = null; 2325 2326 try { 2327 //1. get the a-set ID in the database 2328 String sql = " select as_id " + 2329// " as_doc_id " + 2330 " from "+Gate.DB_OWNER+".v_annotation_set " + 2331 " where lr_id = ? "; 2332 //do we have aset name? 2333 String clause = null; 2334 String name = as.getName(); 2335 if (null != name) { 2336 clause = " and as_name = ? "; 2337 } 2338 else { 2339 clause = " and as_name is null "; 2340 } 2341 sql = sql + clause; 2342 2343 pstmt = this.jdbcConn.prepareStatement(sql); 2344 pstmt.setLong(1,lrID.longValue()); 2345 if (null != name) { 2346 pstmt.setString(2,name); 2347 } 2348 pstmt.execute(); 2349 rs = pstmt.getResultSet(); 2350 2351 if (rs.next()) { 2352 asetID = new Long(rs.getLong("as_id")); 2353// docID = new Long(rs.getLong("as_doc_id")); 2354//System.out.println("syncing annots, lr_id=["+lrID+"],doc_id=["+docID+"], set_id=["+asetID+"]"); 2355 } 2356 else { 2357 throw new PersistenceException("cannot find annotation set with" + 2358 " name=["+name+"] , LRID=["+lrID+"] in database"); 2359 } 2360 2361 //3. insert the new annotations from this set 2362 2363 //3.1. prepare call 2364 cstmt = this.jdbcConn.prepareCall( 2365 "{ call "+Gate.DB_OWNER+".persist.create_annotation(?,?,?,?,?,?,?,?,?) }"); 2366 2367 Long annGlobalID = null; 2368 Iterator it = changes.iterator(); 2369 2370 while (it.hasNext()) { 2371 2372 //3.2. insert annotation 2373 Annotation ann = (Annotation)it.next(); 2374 2375 Node start = (Node)ann.getStartNode(); 2376 Node end = (Node)ann.getEndNode(); 2377 String type = ann.getType(); 2378 2379 cstmt.setLong(1,lrID.longValue()); 2380 cstmt.setLong(2,ann.getId().longValue()); 2381 cstmt.setLong(3,asetID.longValue()); 2382 cstmt.setLong(4,start.getId().longValue()); 2383 cstmt.setLong(5,start.getOffset().longValue()); 2384 cstmt.setLong(6,end.getId().longValue()); 2385 cstmt.setLong(7,end.getOffset().longValue()); 2386 cstmt.setString(8,type); 2387 cstmt.registerOutParameter(9,java.sql.Types.BIGINT); 2388 2389 cstmt.execute(); 2390 annGlobalID = new Long(cstmt.getLong(9)); 2391 2392 //3.3. set annotation features 2393 FeatureMap features = ann.getFeatures(); 2394 Assert.assertNotNull(features); 2395// createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 2396 createFeaturesBulk(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features); 2397 } 2398 } 2399 catch(SQLException sqle) { 2400 throw new PersistenceException("can't add annotations in DB : ["+ 2401 sqle.getMessage()+"]"); 2402 } 2403 finally { 2404 DBHelper.cleanup(rs); 2405 DBHelper.cleanup(pstmt); 2406 DBHelper.cleanup(cstmt); 2407 } 2408 } 2409*/ 2410 2411 2412 /** helper for sync() - never call directly */ 2413/* protected void _syncChangedAnnotations(Document doc,AnnotationSet as, Collection changes) 2414 throws PersistenceException { 2415 2416 //technically this approach sux 2417 //at least it works 2418 2419 //1. delete 2420 _syncRemovedAnnotations(doc,as,changes); 2421 //2. recreate 2422 _syncAddedAnnotations(doc,as,changes); 2423 } 2424*/ 2425 2426 /** helper for sync() - never call directly */ 2427 protected void _syncRemovedDocumentsFromCorpus(List docLRIDs, Long corpLRID) 2428 throws PersistenceException { 2429 2430 //0.preconditions 2431 Assert.assertNotNull(docLRIDs); 2432 Assert.assertNotNull(corpLRID); 2433 Assert.assertTrue(docLRIDs.size() > 0); 2434 2435 CallableStatement cstmt = null; 2436 2437 try { 2438 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+ 2439 ".persist.remove_document_from_corpus(?,?) }"); 2440 2441 Iterator it = docLRIDs.iterator(); 2442 while (it.hasNext()) { 2443 Long currLRID = (Long)it.next(); 2444 cstmt.setLong(1,currLRID.longValue()); 2445 cstmt.setLong(2,corpLRID.longValue()); 2446 cstmt.execute(); 2447 } 2448 } 2449 catch(SQLException sqle) { 2450 2451 switch(sqle.getErrorCode()) { 2452 case DBHelper.X_ORACLE_INVALID_LR : 2453 throw new PersistenceException("invalid LR supplied: no such document: ["+ 2454 sqle.getMessage()+"]"); 2455 default: 2456 throw new PersistenceException("can't change document data: ["+ 2457 sqle.getMessage()+"]"); 2458 } 2459 } 2460 finally { 2461 DBHelper.cleanup(cstmt); 2462 } 2463 2464 } 2465 2466 2467 /** helper for sync() - never call directly */ 2468/* protected void _syncRemovedAnnotations(Document doc,AnnotationSet as, Collection changes) 2469 throws PersistenceException { 2470 //0.preconditions 2471 Assert.assertNotNull(doc); 2472 Assert.assertNotNull(as); 2473 Assert.assertNotNull(changes); 2474 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 2475 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl); 2476 Assert.assertTrue(changes.size() > 0); 2477 2478 2479 PreparedStatement pstmt = null; 2480 ResultSet rs = null; 2481 CallableStatement cstmt = null; 2482 Long lrID = (Long)doc.getLRPersistenceId(); 2483 Long docID = null; 2484 Long asetID = null; 2485 2486 try { 2487 //1. get the a-set ID in the database 2488 String sql = " select as_id, " + 2489 " as_doc_id " + 2490 " from "+Gate.DB_OWNER+".v_annotation_set " + 2491 " where lr_id = ? "; 2492 //do we have aset name? 2493 String clause = null; 2494 String name = as.getName(); 2495 if (null != name) { 2496 clause = " and as_name = ? "; 2497 } 2498 else { 2499 clause = " and as_name is null "; 2500 } 2501 sql = sql + clause; 2502 2503 pstmt = this.jdbcConn.prepareStatement(sql); 2504 pstmt.setLong(1,lrID.longValue()); 2505 if (null != name) { 2506 pstmt.setString(2,name); 2507 } 2508 pstmt.execute(); 2509 rs = pstmt.getResultSet(); 2510 2511 if (rs.next()) { 2512 asetID = new Long(rs.getLong("as_id")); 2513 docID = new Long(rs.getLong("as_doc_id")); 2514 } 2515 else { 2516 throw new PersistenceException("cannot find annotation set with" + 2517 " name=["+name+"] , LRID=["+lrID+"] in database"); 2518 } 2519 2520 //3. delete the removed annotations from this set 2521 2522 //3.1. prepare call 2523 cstmt = this.jdbcConn.prepareCall( 2524 "{ call "+Gate.DB_OWNER+".persist.delete_annotation(?,?) }"); 2525 2526 2527 Iterator it = changes.iterator(); 2528 2529 while (it.hasNext()) { 2530 2531 //3.2. insert annotation 2532 Annotation ann = (Annotation)it.next(); 2533 2534 cstmt.setLong(1,docID.longValue()); //annotations are linked with documents, not LRs! 2535 cstmt.setLong(2,ann.getId().longValue()); 2536 cstmt.execute(); 2537 } 2538 } 2539 catch(SQLException sqle) { 2540 throw new PersistenceException("can't delete annotations in DB : ["+ 2541 sqle.getMessage()+"]"); 2542 } 2543 finally { 2544 DBHelper.cleanup(rs); 2545 DBHelper.cleanup(pstmt); 2546 DBHelper.cleanup(cstmt); 2547 } 2548 } 2549*/ 2550 2551 2552 /** helper for sync() - never call directly */ 2553/* protected void _syncAnnotationSets(Document doc,Collection removedSets,Collection addedSets) 2554 throws PersistenceException { 2555 2556 //0. preconditions 2557 Assert.assertNotNull(doc); 2558 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 2559 Assert.assertNotNull(doc.getLRPersistenceId()); 2560 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(), 2561 this.getDatabaseID()); 2562 Assert.assertNotNull(removedSets); 2563 Assert.assertNotNull(addedSets); 2564 2565 Long lrID = (Long)doc.getLRPersistenceId(); 2566 2567 //1. delete from DB removed a-sets 2568 CallableStatement cstmt = null; 2569 2570 try { 2571 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+ 2572 ".persist.delete_annotation_set(?,?) }"); 2573 2574 Iterator it = removedSets.iterator(); 2575 while (it.hasNext()) { 2576 String setName = (String)it.next(); 2577 cstmt.setLong(1,lrID.longValue()); 2578 cstmt.setString(2,setName); 2579 cstmt.execute(); 2580 } 2581 } 2582 catch(SQLException sqle) { 2583 throw new PersistenceException("can't remove annotation set from DB: ["+ sqle.getMessage()+"]"); 2584 } 2585 finally { 2586 DBHelper.cleanup(cstmt); 2587 } 2588 2589 //2. create in DB new a-sets 2590 Iterator it = addedSets.iterator(); 2591 while (it.hasNext()) { 2592 String setName = (String)it.next(); 2593 AnnotationSet aset = doc.getAnnotations(setName); 2594 2595 Assert.assertNotNull(aset); 2596 Assert.assertTrue(aset instanceof DatabaseAnnotationSetImpl); 2597 2598 createAnnotationSet(lrID,aset); 2599 } 2600 } 2601 2602*/ 2603 2604 /** helper for sync() - never call directly */ 2605/* protected void _syncAnnotations(Document doc) 2606 throws PersistenceException { 2607 2608 //0. preconditions 2609 Assert.assertNotNull(doc); 2610 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 2611 Assert.assertNotNull(doc.getLRPersistenceId()); 2612 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(), 2613 this.getDatabaseID()); 2614 2615 2616 EventAwareDocument ead = (EventAwareDocument)doc; 2617 //1. get the sets read from the DB for this document 2618 //chnaged annotations can occur only in such sets 2619 Collection loadedSets = ead.getLoadedAnnotationSets(); 2620 2621 Iterator it = loadedSets.iterator(); 2622 while (it.hasNext()) { 2623 AnnotationSet as = (AnnotationSet)it.next(); 2624 //check that this set is neither NEW nor DELETED 2625 //they should be already synced 2626 if (ead.getAddedAnnotationSets().contains(as.getName()) || 2627 ead.getRemovedAnnotationSets().contains(as.getName())) { 2628 //oops, ignore it 2629 continue; 2630 } 2631 2632 EventAwareAnnotationSet eas = (EventAwareAnnotationSet)as; 2633 Assert.assertNotNull(as); 2634 2635 Collection anns = null; 2636 anns = eas.getAddedAnnotations(); 2637 Assert.assertNotNull(anns); 2638 if (anns.size()>0) { 2639 _syncAddedAnnotations(doc,as,anns); 2640 } 2641 2642 anns = eas.getRemovedAnnotations(); 2643 Assert.assertNotNull(anns); 2644 if (anns.size()>0) { 2645 _syncRemovedAnnotations(doc,as,anns); 2646 } 2647 2648 anns = eas.getChangedAnnotations(); 2649 Assert.assertNotNull(anns); 2650 if (anns.size()>0) { 2651 _syncChangedAnnotations(doc,as,anns); 2652 } 2653 } 2654 } 2655*/ 2656 2657 2658 /** helper for sync() - never call directly */ 2659 protected void _syncFeatures(LanguageResource lr) 2660 throws PersistenceException { 2661 2662 //0. preconditions 2663 Assert.assertNotNull(lr); 2664 Assert.assertNotNull(lr.getLRPersistenceId()); 2665 Assert.assertEquals(((DatabaseDataStore)lr.getDataStore()).getDatabaseID(), 2666 this.getDatabaseID()); 2667 Assert.assertTrue(lr instanceof Document || lr instanceof Corpus); 2668 //we have to be in the context of transaction 2669 2670 //1, get ID in the DB 2671 Long lrID = (Long)lr.getLRPersistenceId(); 2672 int entityType; 2673 2674 //2. delete features 2675 CallableStatement stmt = null; 2676 try { 2677 Assert.assertTrue(false == this.jdbcConn.getAutoCommit()); 2678 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+ 2679 ".persist.delete_features(?,?) }"); 2680 stmt.setLong(1,lrID.longValue()); 2681 2682 if (lr instanceof Document) { 2683 entityType = DBHelper.FEATURE_OWNER_DOCUMENT; 2684 } 2685 else if (lr instanceof Corpus) { 2686 entityType = DBHelper.FEATURE_OWNER_CORPUS; 2687 } 2688 else { 2689 throw new IllegalArgumentException(); 2690 } 2691 2692 stmt.setInt(2,entityType); 2693 stmt.execute(); 2694 } 2695 catch(SQLException sqle) { 2696 throw new PersistenceException("can't delete features in DB: ["+ sqle.getMessage()+"]"); 2697 } 2698 finally { 2699 DBHelper.cleanup(stmt); 2700 } 2701 2702 //3. recreate them 2703 //createFeatures(lrID,entityType, lr.getFeatures()); 2704 createFeaturesBulk(lrID,entityType, lr.getFeatures()); 2705 2706 } 2707 2708 2709 2710 /** helper for sync() - saves a Corpus in the database */ 2711/* protected void syncCorpus(Corpus corp) 2712 throws PersistenceException,SecurityException { 2713 2714 //0. preconditions 2715 Assert.assertNotNull(corp); 2716 Assert.assertTrue(corp instanceof DatabaseCorpusImpl); 2717 Assert.assertEquals(this,corp.getDataStore()); 2718 Assert.assertNotNull(corp.getLRPersistenceId()); 2719 2720 EventAwareCorpus dbCorpus = (EventAwareCorpus)corp; 2721 2722 //1. sync the corpus name? 2723 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_NAME)) { 2724 _syncLR(corp); 2725 } 2726 2727 //2. sync the corpus features? 2728 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_FEATURES)) { 2729 _syncFeatures(corp); 2730 } 2731 2732 //2.5 get removed documents and detach (not remove) them from the corpus in the 2733 //database 2734 List removedDocLRIDs = dbCorpus.getRemovedDocuments(); 2735 if (removedDocLRIDs.size() > 0) { 2736 _syncRemovedDocumentsFromCorpus(removedDocLRIDs,(Long)corp.getLRPersistenceId()); 2737 } 2738 2739 //3. get all documents 2740 //--Iterator it = corp.iterator(); 2741 Iterator it = dbCorpus.getLoadedDocuments().iterator(); 2742 2743 while (it.hasNext()) { 2744 Document dbDoc = (Document)it.next(); 2745 //note - document may be NULL which means it was not loaded (load on demand) 2746 //just ignore it then 2747 if (null == dbDoc) { 2748 continue; 2749 } 2750 2751 //adopt/sync? 2752 if (null == dbDoc.getLRPersistenceId()) { 2753 //doc was never adopted, adopt it 2754 2755 //3.1 remove the transient doc from the corpus 2756 it.remove(); 2757 2758 //3.2 get the security info for the corpus 2759 SecurityInfo si = getSecurityInfo(corp); 2760 2761 2762 Document adoptedDoc = null; 2763 try { 2764 //3.3. adopt the doc with the sec info 2765//System.out.println("adopting ["+dbDoc.getName()+"] ..."); 2766 //don't open a new transaction, since sync() already has opended one 2767 adoptedDoc = (Document)_adopt(dbDoc,si,true); 2768 2769 //3.4. add doc to corpus in DB 2770 addDocumentToCorpus((Long)adoptedDoc.getLRPersistenceId(), 2771 (Long)corp.getLRPersistenceId()); 2772 } 2773 catch(SecurityException se) { 2774 throw new PersistenceException(se); 2775 } 2776 2777 //3.5 add back to corpus the new DatabaseDocument 2778 corp.add(adoptedDoc); 2779 } 2780 else { 2781 //don't open a new transaction, the sync() called for corpus has already 2782 //opened one 2783 try { 2784 _sync(dbDoc,true); 2785 2786 // let the world know about it 2787 fireResourceWritten( new DatastoreEvent(this, 2788 DatastoreEvent.RESOURCE_WRITTEN, 2789 dbDoc, 2790 dbDoc.getLRPersistenceId() 2791 ) 2792 ); 2793 2794 //if the document is form the same DS but did not belong to the corpus add it now 2795 //NOTE: if the document already belongs to the corpus then nothing will be changed 2796 //in the DB 2797 addDocumentToCorpus((Long)dbDoc.getLRPersistenceId(), 2798 (Long)corp.getLRPersistenceId()); 2799 } 2800 catch(SecurityException se) { 2801 gate.util.Err.prln("document cannot be synced: ["+se.getMessage()+"]"); 2802 } 2803 } 2804 } 2805 } 2806*/ 2807 2808 2809 /** 2810 * Try to acquire exlusive lock on a resource from the persistent store. 2811 * Always call unlockLR() when the lock is no longer needed 2812 */ 2813 public boolean lockLr(LanguageResource lr) 2814 throws PersistenceException,SecurityException { 2815 2816 //0. preconditions 2817 Assert.assertNotNull(lr); 2818 Assert.assertTrue(lr instanceof DatabaseDocumentImpl || 2819 lr instanceof DatabaseCorpusImpl); 2820 Assert.assertNotNull(lr.getLRPersistenceId()); 2821 Assert.assertEquals(lr.getDataStore(),this); 2822 2823 //1. delegate 2824 return _lockLr((Long)lr.getLRPersistenceId()); 2825 } 2826 2827 2828 2829 /** 2830 * helper for lockLR() 2831 * never call directly 2832 */ 2833 private boolean _lockLr(Long lrID) 2834 throws PersistenceException,SecurityException { 2835 2836 //0. preconditions 2837 Assert.assertNotNull(lrID); 2838 2839 //1. check session 2840 if (null == this.session) { 2841 throw new SecurityException("session not set"); 2842 } 2843 2844 if (false == this.ac.isValidSession(this.session)) { 2845 throw new SecurityException("invalid session supplied"); 2846 } 2847 2848 //2. check permissions 2849 if (false == canWriteLR(lrID)) { 2850 throw new SecurityException("no write access granted to the user"); 2851 } 2852 2853 //3. try to lock 2854 CallableStatement cstmt = null; 2855 boolean lockSucceeded = false; 2856 2857 try { 2858 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.lock_lr(?,?,?,?) }"); 2859 cstmt.setLong(1,lrID.longValue()); 2860 cstmt.setLong(2,this.session.getUser().getID().longValue()); 2861 cstmt.setLong(3,this.session.getGroup().getID().longValue()); 2862 cstmt.registerOutParameter(4,java.sql.Types.NUMERIC); 2863 cstmt.execute(); 2864 2865 lockSucceeded = cstmt.getLong(4) == this.ORACLE_TRUE 2866 ? true 2867 : false; 2868 } 2869 catch(SQLException sqle) { 2870 2871 switch(sqle.getErrorCode()) { 2872 case DBHelper.X_ORACLE_INVALID_LR: 2873 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]"); 2874 default: 2875 throw new PersistenceException( 2876 "can't lock LR in DB : ["+ sqle.getMessage()+"]"); 2877 } 2878 } 2879 finally { 2880 DBHelper.cleanup(cstmt); 2881 } 2882 2883 return lockSucceeded; 2884 } 2885 2886 2887 2888 /** 2889 * Releases the exlusive lock on a resource from the persistent store. 2890 */ 2891 public void unlockLr(LanguageResource lr) 2892 throws PersistenceException,SecurityException { 2893 2894 //0. preconditions 2895 Assert.assertNotNull(lr); 2896 Assert.assertTrue(lr instanceof DatabaseDocumentImpl || 2897 lr instanceof DatabaseCorpusImpl); 2898 Assert.assertNotNull(lr.getLRPersistenceId()); 2899 Assert.assertEquals(lr.getDataStore(),this); 2900 2901 //1. check session 2902 if (null == this.session) { 2903 throw new SecurityException("session not set"); 2904 } 2905 2906 if (false == this.ac.isValidSession(this.session)) { 2907 throw new SecurityException("invalid session supplied"); 2908 } 2909 2910 //2. check permissions 2911 if (false == canWriteLR(lr.getLRPersistenceId())) { 2912 throw new SecurityException("no write access granted to the user"); 2913 } 2914 2915 //3. try to unlock 2916 CallableStatement cstmt = null; 2917 boolean lockSucceeded = false; 2918 2919 try { 2920 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.unlock_lr(?,?) }"); 2921 cstmt.setLong(1,((Long)lr.getLRPersistenceId()).longValue()); 2922 cstmt.setLong(2,this.session.getUser().getID().longValue()); 2923 cstmt.execute(); 2924 } 2925 catch(SQLException sqle) { 2926 2927 switch(sqle.getErrorCode()) { 2928 case DBHelper.X_ORACLE_INVALID_LR: 2929 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]"); 2930 default: 2931 throw new PersistenceException( 2932 "can't unlock LR in DB : ["+ sqle.getMessage()+"]"); 2933 } 2934 } 2935 finally { 2936 DBHelper.cleanup(cstmt); 2937 } 2938 } 2939 2940 2941 2942 2943 /** 2944 * adds document to corpus in the database 2945 * if the document is already part of the corpus nothing 2946 * changes 2947 */ 2948 protected void addDocumentToCorpus(Long docID,Long corpID) 2949 throws PersistenceException,SecurityException { 2950 2951 //0. preconditions 2952 Assert.assertNotNull(docID); 2953 Assert.assertNotNull(corpID); 2954 2955 //1. check session 2956 if (null == this.session) { 2957 throw new SecurityException("session not set"); 2958 } 2959 2960 if (false == this.ac.isValidSession(this.session)) { 2961 throw new SecurityException("invalid session supplied"); 2962 } 2963 2964 //2. check permissions 2965 if (false == canWriteLR(corpID)) { 2966 throw new SecurityException("no write access granted to the user"); 2967 } 2968 2969 if (false == canWriteLR(docID)) { 2970 throw new SecurityException("no write access granted to the user"); 2971 } 2972 2973 //3. database 2974 CallableStatement cstmt = null; 2975 2976 try { 2977 cstmt = this.jdbcConn.prepareCall("{ call "+ 2978 Gate.DB_OWNER+".persist.add_document_to_corpus(?,?) }"); 2979 cstmt.setLong(1,docID.longValue()); 2980 cstmt.setLong(2,corpID.longValue()); 2981 cstmt.execute(); 2982 } 2983 catch(SQLException sqle) { 2984 2985 switch(sqle.getErrorCode()) { 2986 case DBHelper.X_ORACLE_INVALID_LR: 2987 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]"); 2988 default: 2989 throw new PersistenceException( 2990 "can't add document to corpus : ["+ sqle.getMessage()+"]"); 2991 } 2992 } 2993 finally { 2994 DBHelper.cleanup(cstmt); 2995 } 2996 } 2997 2998 2999 3000 /** 3001 * unloads a LR from the GUI 3002 */ 3003/* protected void unloadLR(Long lrID) 3004 throws GateException{ 3005 3006 //0. preconfitions 3007 Assert.assertNotNull(lrID); 3008 3009 //1. get all LRs in the system 3010 List resources = Gate.getCreoleRegister().getAllInstances("gate.LanguageResource"); 3011 3012 Iterator it = resources.iterator(); 3013 while (it.hasNext()) { 3014 LanguageResource lr = (LanguageResource)it.next(); 3015 if (lrID.equals(lr.getLRPersistenceId()) && 3016 this.equals(lr.getDataStore())) { 3017 //found it - unload it 3018 Factory.deleteResource(lr); 3019 break; 3020 } 3021 } 3022 } 3023*/ 3024 3025 /** Get a list of LRs that satisfy some set or restrictions 3026 * 3027 * @param constraints list of Restriction objects 3028 */ 3029 public List findLrIds(List constraints) throws PersistenceException { 3030 return findLrIds(constraints,null); 3031 } 3032 3033 /** 3034 * Get a list of LRs IDs that satisfy some set or restrictions and are 3035 * of a particular type 3036 * 3037 * @param constraints list of Restriction objects 3038 * @param lrType type of Lrs. DBHelper.DOCUMENT_CLASS or DBHelper.CORPUS_CLASS 3039 */ 3040 public List findLrIds(List constraints, String lrType) throws PersistenceException { 3041 return findLrIds(constraints, lrType, null, -1); 3042 } 3043 3044 /** 3045 * Get a list of LRs IDs that satisfy some set or restrictions and are 3046 * of a particular type 3047 * 3048 * @param constraints list of Restriction objects 3049 * @param lrType type of Lrs. DBHelper.DOCUMENT_CLASS or DBHelper.CORPUS_CLASS 3050 * @param orderByConstraints liat of OrderByRestriction objects 3051 * @param limitcount limit returning objects -1 for unlimited 3052 */ 3053 public List findLrIds(List constraints, String lrType, 3054 List orderByConstraints, int limitcount) throws PersistenceException { 3055 Vector lrsIDs = new Vector(); 3056 CallableStatement stmt = null; 3057 ResultSet rs = null; 3058 Connection conn = null; 3059 3060 try { 3061 Vector sqlValues = new Vector(); 3062 String sql = getSQLQuery(constraints, lrType, false, orderByConstraints, limitcount, sqlValues); 3063 conn = DBHelper.connect(this.getStorageUrl(), true); 3064 stmt = conn.prepareCall(sql); 3065///System.out.println(" " + sql); 3066 for (int i = 0; i<sqlValues.size(); i++){ 3067 if (sqlValues.elementAt(i) instanceof String){ 3068 stmt.setString(i+1,sqlValues.elementAt(i).toString()); 3069 } 3070 else if (sqlValues.elementAt(i) instanceof Long){ 3071 stmt.setLong(i+1,((Long) sqlValues.elementAt(i)).longValue()); 3072 } 3073 else if (sqlValues.elementAt(i) instanceof Integer){ 3074 stmt.setLong(i+1,((Integer) sqlValues.elementAt(i)).intValue()); 3075 } 3076 } 3077 stmt.execute(); 3078 rs = stmt.getResultSet(); 3079 3080 while (rs.next()) { 3081 long lr_ID = rs.getLong(1); 3082 lrsIDs.addElement(new Long(lr_ID)); 3083 } 3084 return lrsIDs; 3085 } 3086 catch(SQLException sqle) { 3087 throw new PersistenceException("can't get LRs from DB: ["+ sqle+"]"); 3088 } 3089 catch (ClassNotFoundException cnfe){ 3090 throw new PersistenceException("can't not find driver: ["+ cnfe +"]"); 3091 } 3092 finally { 3093 DBHelper.cleanup(rs); 3094 DBHelper.cleanup(stmt); 3095 DBHelper.disconnect(conn, true); 3096 } 3097 } 3098 /** 3099 * Return count of LRs which matches the constraints. 3100 * 3101 * @param constraints list of Restriction objects 3102 * @param lrType type of Lrs. DBHelper.DOCUMENT_CLASS or DBHelper.CORPUS_CLASS 3103 */ 3104 public long getLrsCount(List constraints, String lrType) throws PersistenceException { 3105 Vector lrs = new Vector(); 3106 CallableStatement stmt = null; 3107 ResultSet rs = null; 3108 Connection conn = null; 3109 3110 try { 3111 Vector sqlValues = new Vector(); 3112 String sql = getSQLQuery(constraints,lrType, true, null, -1, sqlValues); 3113 conn = DBHelper.connect(this.getStorageUrl(), true); 3114 stmt = conn.prepareCall(sql); 3115 for (int i = 0; i<sqlValues.size(); i++){ 3116 if (sqlValues.elementAt(i) instanceof String){ 3117 stmt.setString(i+1,sqlValues.elementAt(i).toString()); 3118 } 3119 else if (sqlValues.elementAt(i) instanceof Long){ 3120 stmt.setLong(i+1,((Long) sqlValues.elementAt(i)).longValue()); 3121 } 3122 else if (sqlValues.elementAt(i) instanceof Integer){ 3123 stmt.setLong(i+1,((Integer) sqlValues.elementAt(i)).intValue()); 3124 } 3125 } 3126 3127 stmt.execute(); 3128 rs = stmt.getResultSet(); 3129 rs.next(); 3130 return rs.getLong(1); 3131 } 3132 catch(SQLException sqle) { 3133 throw new PersistenceException("can't get LRs Count from DB: ["+ sqle+"]"); 3134 } 3135 catch (ClassNotFoundException cnfe){ 3136 throw new PersistenceException("can't not find driver: ["+ cnfe +"]"); 3137 } 3138 finally { 3139 DBHelper.cleanup(rs); 3140 DBHelper.cleanup(stmt); 3141 DBHelper.disconnect(conn, true); 3142 } 3143 } 3144 3145 private String getSQLQuery(List filter, String lrType, boolean count, 3146 List orderByFilter, int limitcount, Vector sqlValues){ 3147 StringBuffer query = new StringBuffer(""); 3148 String join = getJoinQuery(orderByFilter, sqlValues); 3149 String select = "lr_id"; 3150 if (count){ 3151 select = "count(*)"; 3152 } 3153 3154 query = query.append(" SELECT " + select + " " + 3155 " FROM "+Gate.DB_OWNER+".t_lang_resource LR " + join + 3156 " ( "); 3157 3158 3159 query = query.append(getIntersectionPart(filter, sqlValues)); 3160 3161 query = query.append(" ) intersected_feat_restr "); 3162 3163 String endPartOfJoin = getEndPartOfJoin(orderByFilter, lrType,sqlValues); 3164 query = query.append(endPartOfJoin); 3165 3166 if (limitcount>0){ 3167 query = query.insert(0,"select lr_id from ( "); 3168 query = query.append( ") where rownum<"+limitcount); 3169 } 3170 3171 return query.toString(); 3172 } 3173 3174 private String getIntersectionPart(List filter, Vector sqlValues){ 3175 StringBuffer query = new StringBuffer(" "); 3176 3177 Collections.sort(filter, new RestrictionComepator()); 3178 Vector list_of_filters = new Vector(); 3179 for (int i=0; i<filter.size(); i++){ 3180 if (i>0){ 3181 Restriction rest = (Restriction) filter.get(i); 3182 Restriction prev = (Restriction) filter.get(i-1); 3183 if (rest.getKey().equals(prev.getKey())){ 3184 Vector temp = (Vector) list_of_filters.get(list_of_filters.size()-1); 3185 temp.add(rest); 3186 } else { 3187 Vector temp = new Vector(); 3188 temp.add(rest); 3189 list_of_filters.add(temp); 3190 } 3191 } else { 3192 Vector temp = new Vector(); 3193 temp.add(filter.get(0)); 3194 list_of_filters.add(temp); 3195 } 3196 } 3197 3198 if (filter!=null && filter.size()>0){ 3199 for (int i=0; i<list_of_filters.size(); i++){ 3200 query = query.append(getRestrictionPartOfQuery((List) list_of_filters.get(i),sqlValues)); 3201 if (i<list_of_filters.size()-1) { 3202 query = query.append(" intersect "); 3203 } 3204 } 3205 } 3206 return query.toString(); 3207 } 3208 3209 private String getRestrictionPartOfQuery(List list, Vector sqlValues){ 3210 StringBuffer expresion = new StringBuffer( 3211 " SELECT ft_entity_id "+ 3212 " FROM "+Gate.DB_OWNER+".t_feature FEATURE, " + 3213 Gate.DB_OWNER + ".t_feature_key FTK" + 3214 " WHERE FEATURE.ft_entity_type = 2 "); 3215 3216 Restriction restr = (Restriction) list.get(0); 3217 3218 if (restr.getKey() != null){ 3219 expresion = expresion.append(" AND FTK.fk_id = FEATURE.ft_key_id "); 3220 expresion = expresion.append(" AND FTK.fk_string = ? "); 3221 sqlValues.addElement(restr.getKey()); 3222 } 3223 3224 for (int i =0; i<list.size(); i++) { 3225 restr = (Restriction) list.get(i); 3226 if (restr.getValue() != null){ 3227 expresion = expresion.append(" AND "); 3228 switch (this.findFeatureType(restr.getValue())){ 3229 case DBHelper.VALUE_TYPE_INTEGER: 3230 expresion = expresion.append(getNumberExpresion(restr, sqlValues)); 3231 break; 3232 case DBHelper.VALUE_TYPE_LONG: 3233 expresion = expresion.append(getNumberExpresion(restr, sqlValues)); 3234 break; 3235 default: 3236 if (restr.getOperator()==Restriction.OPERATOR_EQUATION){ 3237 expresion = expresion.append(" FEATURE.ft_character_value = ? "); 3238 sqlValues.addElement(restr.getStringValue()); 3239 } 3240 if (restr.getOperator()==Restriction.OPERATOR_LIKE){ 3241 expresion = expresion.append(" upper(FEATURE.ft_character_value) like ? "); 3242 sqlValues.addElement("%"+restr.getStringValue().toUpperCase()+"%"); 3243 } 3244 break; 3245 } 3246 } 3247 } 3248 3249 return expresion.toString(); 3250 } 3251 3252 private String getNumberExpresion(Restriction restr, Vector sqlValues){ 3253 StringBuffer expr = new StringBuffer("FEATURE.ft_number_value "); 3254 3255 switch (restr.getOperator()){ 3256 case Restriction.OPERATOR_EQUATION: 3257 expr = expr.append(" = "); 3258 break; 3259 case Restriction.OPERATOR_BIGGER: 3260 expr = expr.append(" > "); 3261 break; 3262 case Restriction.OPERATOR_LESS: 3263 expr = expr.append(" < "); 3264 break; 3265 case Restriction.OPERATOR_EQUATION_OR_BIGGER: 3266 expr = expr.append(" >= "); 3267 break; 3268 case Restriction.OPERATOR_EQUATION_OR_LESS: 3269 expr = expr.append(" <= "); 3270 break; 3271 default: 3272 return " 0 = 0 "; 3273 } 3274 3275 expr.append(" ? "); 3276 sqlValues.addElement(restr.getValue()); 3277 3278 return expr.toString(); 3279 } 3280 3281 private String getJoinQuery(List orderByFilter, Vector sqlValues){ 3282 StringBuffer join = new StringBuffer(""); 3283 join = join.append(" , "); 3284 if (orderByFilter!=null){ 3285 for (int i = 0; i<orderByFilter.size(); i++){ 3286 join = join.append(Gate.DB_OWNER+".t_feature FT"+i); 3287 join = join.append(" , "+Gate.DB_OWNER+".t_feature_key FTK"+i +" , "); 3288 } 3289 } 3290 return join.toString(); 3291 } 3292 3293 private String getEndPartOfJoin(List orderByFilter, String lrType, Vector sqlValues){ 3294 StringBuffer endJoin = new StringBuffer(""); 3295 endJoin = endJoin.append(" WHERE "); 3296 3297 endJoin = endJoin.append(" LR.lr_type_id = ? "); 3298 if (lrType.equals(DBHelper.CORPUS_CLASS)) { 3299 sqlValues.addElement(new Long(2)); 3300 }// if DBHelper.CORPUS_CLASS 3301 if (lrType.equals(DBHelper.DOCUMENT_CLASS)) { 3302 sqlValues.addElement(new Long(1)); 3303 }// if DBHelper.DOCUMENT_CLASS 3304 3305 endJoin = endJoin.append(" and intersected_feat_restr.ft_entity_id = lr.lr_id "); 3306 3307 if (orderByFilter!=null && orderByFilter.size()>0){ 3308 for (int i=0; i<orderByFilter.size(); i++){ 3309 endJoin = endJoin.append(" and lr_id=FT"+i+".ft_entity_id "); 3310 endJoin = endJoin.append(" and FT"+i+".ft_key_id = FTK"+i+".fk_id "); 3311 endJoin = endJoin.append(" and FTK"+i+".fk_string= ? "); 3312 OrderByRestriction restr = (OrderByRestriction) orderByFilter.get(i); 3313 sqlValues.addElement(restr.getKey()); 3314 } 3315 endJoin = endJoin.append(" order by "); 3316 for (int i=0; i<orderByFilter.size(); i++){ 3317 OrderByRestriction restr = (OrderByRestriction) orderByFilter.get(i); 3318 3319 endJoin = endJoin.append(" FT"+i+".ft_number_value "); 3320 if (restr.getOperator()==OrderByRestriction.OPERATOR_ASCENDING){ 3321 endJoin = endJoin.append(" asc "); 3322 } else { 3323 endJoin = endJoin.append(" desc "); 3324 } 3325 /* endJoin = endJoin.append(", FT"+i+".ft_character_value "); 3326 if (restr.getOperator()==OrderByRestriction.OPERATOR_ASCENDING){ 3327 endJoin = endJoin.append(" asc "); 3328 } else { 3329 endJoin = endJoin.append(" desc "); 3330 }*/ 3331 if (i<orderByFilter.size()-1){ 3332 endJoin = endJoin.append(" , "); 3333 } 3334 } 3335 } 3336 return endJoin.toString(); 3337 } 3338 3339 public List findDocIdsByAnn(List constraints, int limitcount) throws PersistenceException { 3340 Vector lrsIDs = new Vector(); 3341 CallableStatement stmt = null; 3342 ResultSet rs = null; 3343 Connection conn = null; 3344 3345 try { 3346 Vector sqlValues = new Vector(); 3347 String sql = getSQLQueryAnn(constraints, limitcount, sqlValues); 3348 conn = DBHelper.connect(this.getStorageUrl(), true); 3349 stmt = conn.prepareCall(sql); 3350///System.out.println(sql); 3351 for (int i = 0; i<sqlValues.size(); i++){ 3352 if (sqlValues.elementAt(i) instanceof String){ 3353 stmt.setString(i+1,sqlValues.elementAt(i).toString()); 3354 } 3355 else if (sqlValues.elementAt(i) instanceof Long){ 3356 stmt.setLong(i+1,((Long) sqlValues.elementAt(i)).longValue()); 3357 } 3358 else if (sqlValues.elementAt(i) instanceof Integer){ 3359 stmt.setLong(i+1,((Integer) sqlValues.elementAt(i)).intValue()); 3360 } 3361///System.out.println(" -> " +sqlValues.elementAt(i).toString()); 3362 } 3363 stmt.execute(); 3364 rs = stmt.getResultSet(); 3365 3366 while (rs.next()) { 3367 long lr_ID = rs.getLong(1); 3368 lrsIDs.addElement(new Long(lr_ID)); 3369 } 3370 return lrsIDs; 3371 } 3372 catch(SQLException sqle) { 3373 throw new PersistenceException("can't get LRs from DB: ["+ sqle+"]"); 3374 } 3375 catch (ClassNotFoundException cnfe){ 3376 throw new PersistenceException("can't not find driver: ["+ cnfe +"]"); 3377 } 3378 finally { 3379 DBHelper.cleanup(rs); 3380 DBHelper.cleanup(stmt); 3381 DBHelper.disconnect(conn, true); 3382 } 3383 } 3384 3385 private String getSQLQueryAnn(List constraints, int limitcount, Vector sqlValues){ 3386 StringBuffer sql = new StringBuffer(""); 3387 sql.append("SELECT lr_id "); 3388 sql.append(" FROM gateadmin.t_lang_resource LR "); 3389 sql.append(" WHERE LR.lr_type_id = 1 "); 3390 3391 for (int i = 0; i<constraints.size(); i++){ 3392 Restriction rest = (Restriction) constraints.get(i); 3393 sql.append(" AND EXISTS( "); 3394 sql.append(" SELECT F.ft_id "); 3395 sql.append(" FROM gateadmin.t_feature F, "); 3396 sql.append(" gateadmin.T_AS_ANNOTATION A, "); 3397 sql.append(" gateadmin.T_ANNOT_SET S, "); 3398 sql.append(" gateadmin.T_DOCUMENT D, "); 3399 sql.append(" gateadmin.t_feature_key FK "); 3400 sql.append(" WHERE F.ft_entity_id = A.asann_ann_id "); 3401 sql.append(" AND A.asann_as_id = S.as_id "); 3402 sql.append(" AND S.as_doc_id = D.doc_id "); 3403 sql.append(" AND D.doc_lr_id = LR.LR_ID "); 3404 sql.append(" AND S.AS_NAME = ? "); 3405 sqlValues.add("NewsCollector"); 3406 sql.append(" AND FK.fk_id = F.ft_key_id "); 3407 sql.append(" AND FK.fk_string= ? "); 3408 sqlValues.add(rest.getKey()); 3409 sql.append(" AND F.FT_CHARACTER_VALUE = ? "); 3410 sqlValues.add(rest.getStringValue()); 3411 sql.append(" ) "); 3412 } 3413 sql.append(" group by lr_id "); 3414 if (limitcount>0){ 3415 sql = sql.insert(0,"select lr_id from ( "); 3416 sql = sql.append( ") where rownum<"+limitcount); 3417 } 3418 return sql.toString(); 3419 } 3420 3421 private class Feature { 3422 3423 Long entityID; 3424 int entityType; 3425 String key; 3426 Object value; 3427 int valueType; 3428 3429 public Feature(Long eid, int eType, String key, Object value, int vType) { 3430 3431 this.entityID = eid; 3432 this.entityType = eType; 3433 this.key = key; 3434 this.value = value; 3435 this.valueType = vType; 3436 } 3437 } 3438 3439 private class RestrictionComepator implements Comparator{ 3440 public int compare(Object o1, Object o2){ 3441 Restriction r1 = (Restriction) o1; 3442 Restriction r2 = (Restriction) o2; 3443 return r1.getKey().compareTo(r2.getKey()); 3444 } 3445 3446 public boolean equals(Object o){ 3447 return false; 3448 } 3449 } 3450 3451 3452} 3453 3454
|
OracleDataStore |
|