0001 /*
0002 * OracleDataStore.java
0003 *
0004 * Copyright (c) 1995-2010, The University of Sheffield. See the file
0005 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0006 *
0007 * This file is part of GATE (see http://gate.ac.uk/), and is free
0008 * software, licenced under the GNU Library General Public License,
0009 * Version 2, June 1991 (in the distribution as file licence.html,
0010 * and also available at http://gate.ac.uk/gate/licence.html).
0011 *
0012 * Marin Dimitrov, 18/Sep/2001
0013 *
0014 * $Id: OracleDataStore.java 12006 2009-12-01 17:24:28Z thomas_heitz $
0015 */
0016
0017 package gate.persist;
0018
0019 import java.io.*;
0020 import java.net.URL;
0021 import java.sql.*;
0022 import java.util.*;
0023
0024 import junit.framework.Assert;
0025 import oracle.jdbc.driver.OracleCallableStatement;
0026 import oracle.sql.*;
0027
0028 import gate.*;
0029 import gate.corpora.DatabaseCorpusImpl;
0030 import gate.corpora.DatabaseDocumentImpl;
0031 import gate.security.SecurityException;
0032 import gate.security.SecurityInfo;
0033 import gate.util.*;
0034
0035 public class OracleDataStore extends JDBCDataStore {
0036
0037 /** Name of this resource */
0038 private static final String DS_COMMENT = "GATE Oracle datastore";
0039
0040 /** the icon for this resource */
0041 private static final String DS_ICON_NAME = "ora_ds";
0042
0043 /** Debug flag */
0044 private static final boolean DEBUG = false;
0045
0046 /** "true" value for Oracle (supports no boolean type) */
0047 private static final int ORACLE_TRUE = 1;
0048 /** "false" value for Oracle (supports no boolean type) */
0049 private static final int ORACLE_FALSE = 0;
0050
0051 /** size of the Oracle varrays used for bulc inserts */
0052 private static final int VARRAY_SIZE = 10;
0053
0054 /** the size in bytes if varchar2 column in Oracle
0055 * when a String is stored in Oracle it may be too long
0056 * for a varchar2 value, and then CLOB will be used
0057 * Note that the limit is in bytes, not in characters, so
0058 * in the worst case this will limit the string to 4000/3 characters
0059 * */
0060 private static final int ORACLE_VARCHAR_LIMIT_BYTES = 4000;
0061
0062 /** maximum number of bytes that represent a char in UTF8 database */
0063 private static final int UTF_BYTES_PER_CHAR_MAX = 3;
0064
0065 /** maximum number of characters per string stored as varchar2
0066 * if longer then stored as CLOB
0067 * */
0068 private static final int ORACLE_VARCHAR_MAX_SYMBOLS =
0069 ORACLE_VARCHAR_LIMIT_BYTES/UTF_BYTES_PER_CHAR_MAX;
0070
0071 /** read buffer size (for reading CLOBs) */
0072 private static final int INTERNAL_BUFFER_SIZE = 16*1024;
0073
0074 /** default constructor - just call the super constructor
0075 * (may change in the future)
0076 * */
0077 public OracleDataStore() {
0078
0079 super();
0080
0081 this.datastoreComment = DS_COMMENT;
0082 this.iconName = DS_ICON_NAME;
0083 }
0084
0085
0086
0087 /** Set the URL for the underlying storage mechanism. */
0088 public void setStorageUrl(String storageUrl) throws PersistenceException {
0089
0090 super.setStorageUrl(storageUrl);
0091
0092 }
0093
0094
0095
0096 /** Get the URL for the underlying storage mechanism. */
0097 public String getStorageUrl() {
0098
0099 return super.getStorageUrl();
0100 }
0101
0102
0103
0104 /**
0105 * Create a new data store. <B>NOTE:</B> for some data stores
0106 * creation is an system administrator task; in such cases this
0107 * method will throw an UnsupportedOperationException.
0108 */
0109 public void create()
0110 throws PersistenceException, UnsupportedOperationException {
0111
0112 super.create();
0113 }
0114
0115
0116
0117 /** Open a connection to the data store. */
0118 public void open() throws PersistenceException {
0119
0120 super.open();
0121
0122 /*try {
0123 //set statement caching for Oracle
0124 ((OracleConnection)this.jdbcConn).setStmtCacheSize(50);
0125 }
0126 catch(SQLException sqle) {
0127 throw new PersistenceException(sqle);
0128 }*/
0129 }
0130
0131
0132
0133 /** Close the data store. */
0134 public void close() throws PersistenceException {
0135
0136 super.close();
0137 }
0138
0139
0140
0141 /**
0142 * Delete a resource from the data store.
0143 * @param lrId a data-store specific unique identifier for the resource
0144 * @param lrClassName class name of the type of resource
0145 */
0146 /*
0147 public void delete(String lrClassName, Object lrId)
0148 throws PersistenceException,SecurityException {
0149 //0. preconditions
0150 if (false == lrId instanceof Long) {
0151 throw new IllegalArgumentException();
0152 }
0153
0154 if (!lrClassName.equals(DBHelper.DOCUMENT_CLASS) &&
0155 !lrClassName.equals(DBHelper.CORPUS_CLASS)) {
0156 throw new IllegalArgumentException("Only Corpus and Document classes are supported" +
0157 " by Database data store");
0158 }
0159
0160 //1. check session
0161 if (null == this.session) {
0162 throw new SecurityException("session not set");
0163 }
0164
0165 if (false == this.ac.isValidSession(this.session)) {
0166 throw new SecurityException("invalid session supplied");
0167 }
0168
0169 //2. check permissions
0170 if (false == canWriteLR(lrId)) {
0171 throw new SecurityException("insufficient privileges");
0172 }
0173
0174 //3. try to lock document, so that we'll be sure no one is editing it
0175 //NOTE: use the private method
0176 User lockingUser = this.getLockingUser((Long)lrId);
0177 User currUser = this.session.getUser();
0178
0179 if (null != lockingUser && false == lockingUser.equals(currUser)) {
0180 //oops, someone is editing now
0181 throw new PersistenceException("LR locked by another user");
0182 }
0183
0184 boolean transFailed = false;
0185 try {
0186 //4. autocommit should be FALSE because of LOBs
0187 beginTrans();
0188
0189 //5. perform changes, if anything goes wrong, rollback
0190 if (lrClassName.equals(DBHelper.DOCUMENT_CLASS)) {
0191 deleteDocument((Long)lrId);
0192 }
0193 else {
0194 deleteCorpus((Long)lrId);
0195 }
0196
0197 //6. done, commit
0198 commitTrans();
0199 }
0200 catch(PersistenceException pe) {
0201 transFailed = true;
0202 throw(pe);
0203 }
0204 finally {
0205 //problems?
0206 if (transFailed) {
0207 rollbackTrans();
0208 }
0209 }
0210
0211 //7, unlock
0212 //do nothing - the resource does not exist anymore
0213
0214 //8. delete from the list of dependent resources
0215 boolean resourceFound = false;
0216 Iterator it = this.dependentResources.iterator();
0217 while (it.hasNext()) {
0218 LanguageResource lr = (LanguageResource)it.next();
0219 if (lr.getLRPersistenceId().equals(lrId)) {
0220 resourceFound = true;
0221 it.remove();
0222 break;
0223 }
0224 }
0225
0226 //Assert.assertTrue(resourceFound);
0227
0228 //9. let the world know about it
0229 fireResourceDeleted(
0230 new DatastoreEvent(this, DatastoreEvent.RESOURCE_DELETED, null, lrId));
0231
0232 //10. unload the resource form the GUI
0233 try {
0234 unloadLR((Long)lrId);
0235 }
0236 catch(GateException ge) {
0237 Err.prln("can't unload resource from GUI...");
0238 }
0239 }
0240 */
0241
0242
0243 /**
0244 * helper method for delete()
0245 * never call it directly beause proper events will not be fired
0246 */
0247 protected void deleteDocument(Long lrId)
0248 throws PersistenceException {
0249
0250 //0. preconditions
0251 Assert.assertNotNull(lrId);
0252
0253 CallableStatement stmt = null;
0254
0255 //1. delete from DB
0256 try {
0257 stmt = this.jdbcConn.prepareCall(
0258 "{ call "+Gate.DB_OWNER+".persist.delete_document(?) }");
0259 stmt.setLong(1,lrId.longValue());
0260 stmt.execute();
0261 }
0262 catch(SQLException sqle) {
0263 throw new PersistenceException("can't delete LR from DB: ["+ sqle.getMessage()+"]");
0264 }
0265 finally {
0266 DBHelper.cleanup(stmt);
0267 }
0268 }
0269
0270
0271
0272 /**
0273 * helper method for delete()
0274 * never call it directly beause proper events will not be fired
0275 */
0276 protected void deleteCorpus(Long lrId)
0277 throws PersistenceException {
0278
0279 Long ID = (Long)lrId;
0280
0281 CallableStatement stmt = null;
0282
0283 try {
0284 stmt = this.jdbcConn.prepareCall(
0285 "{ call "+Gate.DB_OWNER+".persist.delete_corpus(?) }");
0286 stmt.setLong(1,ID.longValue());
0287 stmt.execute();
0288 }
0289 catch(SQLException sqle) {
0290 throw new PersistenceException("can't delete LR from DB: ["+ sqle.getMessage()+"]");
0291 }
0292 finally {
0293 DBHelper.cleanup(stmt);
0294 }
0295 }
0296
0297
0298
0299
0300
0301 /**
0302 * Set method for the autosaving behaviour of the data store.
0303 * <B>NOTE:</B> many types of datastore have no auto-save function,
0304 * in which case this will throw an UnsupportedOperationException.
0305 */
0306 public void setAutoSaving(boolean autoSaving)
0307 throws UnsupportedOperationException,PersistenceException {
0308
0309 super.setAutoSaving(autoSaving);
0310 }
0311
0312
0313
0314 /** Get the autosaving behaviour of the LR. */
0315 public boolean isAutoSaving() {
0316 throw new MethodNotImplementedException();
0317 }
0318
0319
0320 /**
0321 * helper for adopt()
0322 * never call directly
0323 */
0324 protected Long createLR(String lrType,
0325 String lrName,
0326 SecurityInfo si,
0327 Long lrParentID)
0328 throws PersistenceException,SecurityException {
0329
0330 //0. preconditions
0331 Assert.assertNotNull(lrName);
0332
0333 //1. check the session
0334 // if (this.ac.isValidSession(s) == false) {
0335 // throw new SecurityException("invalid session provided");
0336 // }
0337
0338 //2. create a record in DB
0339 CallableStatement stmt = null;
0340
0341 try {
0342 stmt = this.jdbcConn.prepareCall(
0343 "{ call "+Gate.DB_OWNER+".persist.create_lr(?,?,?,?,?,?,?) }");
0344 stmt.setLong(1,si.getUser().getID().longValue());
0345 stmt.setLong(2,si.getGroup().getID().longValue());
0346 stmt.setString(3,lrType);
0347 stmt.setString(4,lrName);
0348 stmt.setInt(5,si.getAccessMode());
0349 if (null == lrParentID) {
0350 stmt.setNull(6,java.sql.Types.BIGINT);
0351 }
0352 else {
0353 stmt.setLong(6,lrParentID.longValue());
0354 }
0355 //Oracle numbers are BIGNINT
0356 stmt.registerOutParameter(7,java.sql.Types.BIGINT);
0357 stmt.execute();
0358
0359 Long result = new Long(stmt.getLong(7));
0360 return result;
0361 }
0362 catch(SQLException sqle) {
0363
0364 switch(sqle.getErrorCode()) {
0365 case DBHelper.X_ORACLE_INVALID_LR_TYPE:
0366 throw new PersistenceException("can't create LR [step 3] in DB, invalid LR Type");
0367 default:
0368 throw new PersistenceException(
0369 "can't create LR [step 3] in DB : ["+ sqle.getMessage()+"]");
0370 }
0371 }
0372 finally {
0373 DBHelper.cleanup(stmt);
0374 }
0375 }
0376
0377
0378
0379 /**
0380 * updates the content of the document if it is binary or a long string
0381 * (that does not fit into VARCHAR2)
0382 */
0383 // private void updateDocumentContent(Long docContentID,DocumentContent content)
0384 protected void updateDocumentContent(Long docID,DocumentContent content)
0385 throws PersistenceException {
0386
0387 //1. get LOB locators from DB
0388 PreparedStatement pstmt = null;
0389 ResultSet rs = null;
0390 CallableStatement cstmt = null;
0391 try {
0392 String sql = "select dc.dc_id, "+
0393 " dc.dc_content_type, " +
0394 " dc.dc_character_content, " +
0395 " dc.dc_binary_content " +
0396 "from "+gate.Gate.DB_OWNER+".t_doc_content dc , " +
0397 gate.Gate.DB_OWNER+".t_document doc " +
0398 "where dc.dc_id = doc.doc_content_id " +
0399 //--was " and doc.doc_content_id = ? " +
0400 " and doc.doc_id = ? " +
0401 "for update ";
0402 pstmt = this.jdbcConn.prepareStatement(sql);
0403 pstmt.setLong(1,docID.longValue());
0404 rs = pstmt.executeQuery();
0405
0406 //rs = pstmt.getResultSet();
0407
0408 rs.next();
0409 //important: read the objects in the order they appear in
0410 //the ResultSet, otherwise data may be lost
0411 Long contentID = new Long(rs.getLong("dc_id"));
0412 long contentType = rs.getLong("DC_CONTENT_TYPE");
0413 Clob clob = (Clob)rs.getClob("dc_character_content");
0414 Blob blob = (Blob)rs.getBlob("dc_binary_content");
0415
0416 Assert.assertTrue(contentType == DBHelper.CHARACTER_CONTENT ||
0417 contentType == DBHelper.BINARY_CONTENT ||
0418 contentType == DBHelper.EMPTY_CONTENT);
0419
0420
0421 //2. write data using the LOB locators
0422 //NOTE: so far only character content is supported
0423 writeCLOB(content.toString(),clob);
0424 long newContentType = DBHelper.CHARACTER_CONTENT;
0425
0426 //3. update content type
0427 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.change_content_type(?,?) }");
0428 cstmt.setLong(1,contentID.longValue());
0429 cstmt.setLong(2,newContentType);
0430 cstmt.execute();
0431 }
0432 catch(IOException ioe) {
0433 throw new PersistenceException("can't update document content in DB : ["+
0434 ioe.getMessage()+"]");
0435 }
0436 catch(SQLException sqle) {
0437 throw new PersistenceException("can't update document content in DB : ["+
0438 sqle.getMessage()+"]");
0439 }
0440 finally {
0441 DBHelper.cleanup(rs);
0442 DBHelper.cleanup(pstmt);
0443 DBHelper.cleanup(cstmt);
0444 }
0445
0446 }
0447
0448
0449
0450 /**
0451 * helper for adopt
0452 * creates a LR of type Document
0453 */
0454 /* protected Document createDocument(Document doc,SecurityInfo secInfo)
0455 throws PersistenceException,SecurityException {
0456
0457 //delegate, set to Null
0458 return createDocument(doc,null,secInfo);
0459 }
0460 */
0461
0462 /**
0463 * helper for adopt
0464 * never call directly
0465 */
0466 protected Long createDoc(Long _lrID,
0467 URL _docURL,
0468 String _docEncoding,
0469 Long _docStartOffset,
0470 Long _docEndOffset,
0471 Boolean _docIsMarkupAware,
0472 Long _corpusID)
0473 throws PersistenceException {
0474
0475 CallableStatement cstmt = null;
0476 Long docID = null;
0477
0478 try {
0479 cstmt = this.jdbcConn.prepareCall(
0480 "{ call "+Gate.DB_OWNER+".persist.create_document(?,?,?,?,?,?,?,?) }");
0481 cstmt.setLong(1,_lrID.longValue());
0482 if (_docURL == null) {
0483 cstmt.setNull(2,java.sql.Types.VARCHAR);
0484 }else{
0485 cstmt.setString(2,_docURL.toString());
0486 }
0487 //do we have doc encoding?
0488 if (null == _docEncoding) {
0489 cstmt.setNull(3,java.sql.Types.VARCHAR);
0490 }
0491 else {
0492 cstmt.setString(3,_docEncoding);
0493 }
0494 //do we have start offset?
0495 if (null==_docStartOffset) {
0496 cstmt.setNull(4,java.sql.Types.NUMERIC);
0497 }
0498 else {
0499 cstmt.setLong(4,_docStartOffset.longValue());
0500 }
0501 //do we have end offset?
0502 if (null==_docEndOffset) {
0503 cstmt.setNull(5,java.sql.Types.NUMERIC);
0504 }
0505 else {
0506 cstmt.setLong(5,_docEndOffset.longValue());
0507 }
0508
0509 cstmt.setBoolean(6,_docIsMarkupAware.booleanValue());
0510
0511 //is the document part of a corpus?
0512 if (null == _corpusID) {
0513 cstmt.setNull(7,java.sql.Types.BIGINT);
0514 }
0515 else {
0516 cstmt.setLong(7,_corpusID.longValue());
0517 }
0518
0519 //results
0520 cstmt.registerOutParameter(8,java.sql.Types.BIGINT);
0521
0522 cstmt.execute();
0523 docID = new Long(cstmt.getLong(8));
0524 return docID;
0525
0526 }
0527 catch(SQLException sqle) {
0528 throw new PersistenceException("can't create document [step 4] in DB: ["+ sqle.getMessage()+"]");
0529 }
0530 finally {
0531 DBHelper.cleanup(cstmt);
0532 }
0533
0534 }
0535
0536
0537
0538 /** creates an entry for annotation set in the database */
0539 protected void createAnnotationSet(Long lrID, AnnotationSet aset)
0540 throws PersistenceException {
0541
0542 //1. create a-set
0543 String asetName = aset.getName();
0544 Long asetID = null;
0545
0546 //DB stuff
0547 CallableStatement stmt = null;
0548 try {
0549 stmt = this.jdbcConn.prepareCall(
0550 "{ call "+Gate.DB_OWNER+".persist.create_annotation_set(?,?,?) }");
0551 stmt.setLong(1,lrID.longValue());
0552
0553 if (null == asetName) {
0554 stmt.setNull(2,java.sql.Types.VARCHAR);
0555 }
0556 else {
0557 stmt.setString(2,asetName);
0558 }
0559 stmt.registerOutParameter(3,java.sql.Types.BIGINT);
0560 stmt.execute();
0561
0562 asetID = new Long(stmt.getLong(3));
0563 }
0564 catch(SQLException sqle) {
0565 throw new PersistenceException("can't create a-set [step 1] in DB: ["+ sqle.getMessage()+"]");
0566 }
0567 finally {
0568 DBHelper.cleanup(stmt);
0569 }
0570
0571
0572 //2. insert annotations/nodes for DEFAULT a-set
0573 //for now use a stupid cycle
0574 //TODO: pass all the data with one DB call (?)
0575
0576 try {
0577 stmt = this.jdbcConn.prepareCall(
0578 "{ call "+Gate.DB_OWNER+".persist.create_annotation(?,?,?,?,?,?,?,?,?) }");
0579
0580 Iterator itAnnotations = aset.iterator();
0581
0582 while (itAnnotations.hasNext()) {
0583 Annotation ann = (Annotation)itAnnotations.next();
0584 Node start = (Node)ann.getStartNode();
0585 Node end = (Node)ann.getEndNode();
0586 String type = ann.getType();
0587
0588 //DB stuff
0589 Long annGlobalID = null;
0590 stmt.setLong(1,lrID.longValue());
0591 stmt.setLong(2,ann.getId().longValue());
0592 stmt.setLong(3,asetID.longValue());
0593 stmt.setLong(4,start.getId().longValue());
0594 stmt.setLong(5,start.getOffset().longValue());
0595 stmt.setLong(6,end.getId().longValue());
0596 stmt.setLong(7,end.getOffset().longValue());
0597 stmt.setString(8,type);
0598 stmt.registerOutParameter(9,java.sql.Types.BIGINT);
0599
0600 stmt.execute();
0601
0602 annGlobalID = new Long(stmt.getLong(9));
0603
0604 //2.1. set annotation features
0605 FeatureMap features = ann.getFeatures();
0606 Assert.assertNotNull(features);
0607 // createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features);
0608 createFeaturesBulk(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features);
0609 } //while
0610 }//try
0611 catch(SQLException sqle) {
0612
0613 switch(sqle.getErrorCode()) {
0614
0615 case DBHelper.X_ORACLE_INVALID_ANNOTATION_TYPE:
0616 throw new PersistenceException(
0617 "can't create annotation in DB, [invalid annotation type]");
0618 default:
0619 throw new PersistenceException(
0620 "can't create annotation in DB: ["+ sqle.getMessage()+"]");
0621 }//switch
0622 }//catch
0623 finally {
0624 DBHelper.cleanup(stmt);
0625 }
0626 }//func
0627
0628
0629
0630 /** creates a LR of type Corpus */
0631 /* protected Corpus createCorpus(Corpus corp,SecurityInfo secInfo, boolean newTransPerDocument)
0632 throws PersistenceException,SecurityException {
0633
0634 //1. create an LR entry for the corpus (T_LANG_RESOURCE table)
0635 Long lrID = createLR(DBHelper.CORPUS_CLASS,corp.getName(),secInfo,null);
0636
0637 //2.create am entry in the T_COPRUS table
0638 Long corpusID = null;
0639 //DB stuff
0640 CallableStatement stmt = null;
0641 try {
0642 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.create_corpus(?,?) }");
0643 stmt.setLong(1,lrID.longValue());
0644 stmt.registerOutParameter(2,java.sql.Types.BIGINT);
0645 stmt.execute();
0646 corpusID = new Long(stmt.getLong(2));
0647 }
0648 catch(SQLException sqle) {
0649 throw new PersistenceException("can't create corpus [step 2] in DB: ["+ sqle.getMessage()+"]");
0650 }
0651 finally {
0652 DBHelper.cleanup(stmt);
0653 }
0654
0655 //3. for each document in the corpus call createDocument()
0656 Iterator itDocuments = corp.iterator();
0657 Vector dbDocs = new Vector();
0658 while (itDocuments.hasNext()) {
0659 Document doc = (Document)itDocuments.next();
0660
0661 //3.1. ensure that the document is either transient or is from the ...
0662 // same DataStore
0663 if (doc.getLRPersistenceId() == null) {
0664 //transient document
0665
0666 //now this is a bit ugly patch, the transaction related functionality
0667 //should not be in this method
0668 if (newTransPerDocument) {
0669 beginTrans();
0670 }
0671
0672 Document dbDoc = createDocument(doc,corpusID,secInfo);
0673
0674 if (newTransPerDocument) {
0675 commitTrans();
0676 }
0677
0678 dbDocs.add(dbDoc);
0679 //8. let the world know
0680 fireResourceAdopted(new DatastoreEvent(this,
0681 DatastoreEvent.RESOURCE_ADOPTED,
0682 dbDoc,
0683 dbDoc.getLRPersistenceId()
0684 )
0685 );
0686
0687 //9. fire also resource written event because it's now saved
0688 fireResourceWritten(new DatastoreEvent(this,
0689 DatastoreEvent.RESOURCE_WRITTEN,
0690 dbDoc,
0691 dbDoc.getLRPersistenceId()
0692 )
0693 );
0694
0695 }
0696 else if (doc.getDataStore().equals(this)) {
0697 //persistent doc from the same DataStore
0698 fireResourceAdopted(
0699 new DatastoreEvent(this, DatastoreEvent.RESOURCE_ADOPTED,
0700 doc,
0701 doc.getLRPersistenceId()));
0702
0703 //6. fire also resource written event because it's now saved
0704 fireResourceWritten(
0705 new DatastoreEvent(this, DatastoreEvent.RESOURCE_WRITTEN,
0706 doc,
0707 doc.getLRPersistenceId()));
0708 }
0709 else {
0710 //persistent doc from other datastore
0711 //skip
0712 gate.util.Err.prln("document ["+doc.getLRPersistenceId()+"] is adopted from another "+
0713 " datastore. Skipped.");
0714 }
0715 }
0716
0717 //4. create features
0718 // createFeatures(lrID,DBHelper.FEATURE_OWNER_CORPUS,corp.getFeatures());
0719 createFeaturesBulk(lrID,DBHelper.FEATURE_OWNER_CORPUS,corp.getFeatures());
0720
0721 //5. create a DatabaseCorpusImpl and return it
0722 /// Corpus dbCorpus = new DatabaseCorpusImpl(corp.getName(),
0723 /// this,
0724 /// lrID,
0725 /// corp.getFeatures(),
0726 /// dbDocs);
0727 ///
0728
0729 Corpus dbCorpus = null;
0730 FeatureMap params = Factory.newFeatureMap();
0731 HashMap initData = new HashMap();
0732
0733 initData.put("DS",this);
0734 initData.put("LR_ID",lrID);
0735 initData.put("CORP_NAME",corp.getName());
0736 initData.put("CORP_FEATURES",corp.getFeatures());
0737 initData.put("CORP_SUPPORT_LIST",dbDocs);
0738
0739 params.put("initData__$$__", initData);
0740
0741 try {
0742 //here we create the persistent LR via Factory, so it's registered
0743 //in GATE
0744 dbCorpus = (Corpus)Factory.createResource("gate.corpora.DatabaseCorpusImpl", params);
0745 }
0746 catch (gate.creole.ResourceInstantiationException ex) {
0747 throw new GateRuntimeException(ex.getMessage());
0748 }
0749
0750 //6. done
0751 return dbCorpus;
0752 }
0753
0754 */
0755
0756 /**
0757 * Get a resource from the persistent store.
0758 * <B>Don't use this method - use Factory.createResource with
0759 * DataStore and DataStoreInstanceId parameters set instead.</B>
0760 */
0761 /* public LanguageResource getLr(String lrClassName, Object lrPersistenceId)
0762 throws PersistenceException,SecurityException {
0763
0764 LanguageResource result = null;
0765
0766 //0. preconditions
0767 Assert.assertNotNull(lrPersistenceId);
0768
0769 //1. check session
0770 if (null == this.session) {
0771 throw new SecurityException("session not set");
0772 }
0773
0774 if (false == this.ac.isValidSession(this.session)) {
0775 throw new SecurityException("invalid session supplied");
0776 }
0777
0778 //2. check permissions
0779 if (false == canReadLR(lrPersistenceId)) {
0780 throw new SecurityException("insufficient privileges");
0781 }
0782
0783 //3. get resource from DB
0784 if (lrClassName.equals(DBHelper.DOCUMENT_CLASS)) {
0785 result = readDocument(lrPersistenceId);
0786 Assert.assertTrue(result instanceof DatabaseDocumentImpl);
0787 }
0788 else if (lrClassName.equals(DBHelper.CORPUS_CLASS)) {
0789 result = readCorpus(lrPersistenceId);
0790 Assert.assertTrue(result instanceof DatabaseCorpusImpl);
0791 }
0792 else {
0793 throw new IllegalArgumentException("resource class should be either Document or Corpus");
0794 }
0795
0796 //4. postconditions
0797 Assert.assertNotNull(result.getDataStore());
0798 Assert.assertTrue(result.getDataStore() instanceof DatabaseDataStore);
0799 Assert.assertNotNull(result.getLRPersistenceId());
0800
0801 //5. register the read doc as listener for sync events
0802 addDatastoreListener((DatastoreListener)result);
0803
0804 //6. add the resource to the list of dependent resources - i.e. the ones that the
0805 //data store should take care upon closing [and call sync()]
0806 this.dependentResources.add(result);
0807
0808 //7. done
0809 return result;
0810 }
0811 */
0812
0813 /** Gets a timestamp marker that will be used for all changes made in
0814 * the database so that subsequent calls to deleteSince() could restore (partly)
0815 * the database state as it was before the update. <B>NOTE:</B> Restoring the previous
0816 * state may not be possible at all (i.e. if DELETE is performed)
0817 * */
0818 public Long timestamp()
0819 throws PersistenceException{
0820
0821 CallableStatement stmt = null;
0822
0823 try {
0824 stmt = this.jdbcConn.prepareCall(
0825 "{ call "+Gate.DB_OWNER+".persist.get_timestamp(?)} ");
0826 //numbers generated from Oracle sequences are BIGINT
0827 stmt.registerOutParameter(1,java.sql.Types.BIGINT);
0828 stmt.execute();
0829 long result = stmt.getLong(1);
0830
0831 return new Long(result);
0832 }
0833 catch(SQLException sqle) {
0834 throw new PersistenceException("can't get a timestamp from DB: ["+ sqle.getMessage()+"]");
0835 }
0836 finally {
0837 DBHelper.cleanup(stmt);
0838 }
0839 }
0840
0841
0842 /**
0843 * Checks if the user (identified by the sessionID)
0844 * has some access (read/write) to the LR
0845 */
0846 protected boolean canAccessLR(Long lrID,int mode)
0847 throws PersistenceException, SecurityException{
0848
0849 //0. preconditions
0850 Assert.assertTrue(DBHelper.READ_ACCESS == mode || DBHelper.WRITE_ACCESS == mode);
0851
0852 //1. is session initialised?
0853 if (null == this.session) {
0854 throw new SecurityException("user session not set");
0855 }
0856
0857 //2.first check the session and then check whether the user is member of the group
0858 if (this.ac.isValidSession(this.session) == false) {
0859 throw new SecurityException("invalid session supplied");
0860 }
0861
0862 CallableStatement stmt = null;
0863
0864 try {
0865 stmt = this.jdbcConn.prepareCall(
0866 "{ call "+Gate.DB_OWNER+".security.has_access_to_lr(?,?,?,?,?)} ");
0867 stmt.setLong(1,lrID.longValue());
0868 stmt.setLong(2,this.session.getUser().getID().longValue());
0869 stmt.setLong(3,this.session.getGroup().getID().longValue());
0870 stmt.setLong(4,mode);
0871
0872 stmt.registerOutParameter(5,java.sql.Types.NUMERIC);
0873 stmt.execute();
0874 int result = stmt.getInt(5);
0875
0876 return (ORACLE_TRUE == result);
0877 }
0878 catch(SQLException sqle) {
0879 throw new PersistenceException("can't check permissions in DB: ["+ sqle.getMessage()+"]");
0880 }
0881 finally {
0882 DBHelper.cleanup(stmt);
0883 }
0884 }
0885
0886
0887
0888 /** reads the content of a CLOB into the specified StringBuffer */
0889 public static void readCLOB(java.sql.Clob src, StringBuffer dest)
0890 throws SQLException, IOException {
0891
0892 int readLength = 0;
0893
0894 //1. empty the dest buffer
0895 dest.delete(0,dest.length());
0896
0897 //2. get Oracle CLOB
0898 CLOB clo = (CLOB)src;
0899
0900 //3. create temp buffer
0901 int buffSize = Math.max(INTERNAL_BUFFER_SIZE,clo.getBufferSize());
0902 char[] readBuffer = new char[buffSize];
0903
0904 //3. get Unicode stream
0905 Reader input = clo.getCharacterStream();
0906
0907 //4. read
0908 BufferedReader buffInput = new BufferedReader(input,INTERNAL_BUFFER_SIZE);
0909
0910 while ((readLength = buffInput.read(readBuffer, 0, INTERNAL_BUFFER_SIZE)) != -1) {
0911 dest.append(readBuffer, 0, readLength);
0912 }
0913
0914 //5.close streams
0915 buffInput.close();
0916 input.close();
0917
0918 }
0919
0920
0921
0922 /** writes the content of a String into the specified CLOB object */
0923 public static void writeCLOB(String src,java.sql.Clob dest)
0924 throws SQLException, IOException {
0925
0926 //preconditions
0927 Assert.assertNotNull(src);
0928
0929 //1. get Oracle CLOB
0930 CLOB clo = (CLOB)dest;
0931
0932 //2. get Unicode stream
0933 Writer output = clo.getCharacterOutputStream();
0934
0935 //3. write
0936 BufferedWriter buffOutput = new BufferedWriter(output,INTERNAL_BUFFER_SIZE);
0937 buffOutput.write(src.toString());
0938
0939 //4. flushing is a good idea [although BufferedWriter::close() calls it this is
0940 //implementation specific]
0941 buffOutput.flush();
0942 output.flush();
0943
0944 //5.close streams
0945 buffOutput.close();
0946 output.close();
0947 }
0948
0949
0950
0951 /** writes the content of a StringBuffer into the specified CLOB object */
0952 public static void writeCLOB(StringBuffer src,java.sql.Clob dest)
0953 throws SQLException, IOException {
0954
0955 //delegate
0956 writeCLOB(src.toString(),dest);
0957 }
0958
0959
0960
0961 /**
0962 * reads the content of the specified BLOB object and returns the object
0963 * contained.
0964 * NOTE: the BLOB is expected to contain serializable objects, not just any
0965 * binary stream
0966 */
0967 public static Object readBLOB(java.sql.Blob src)
0968 throws SQLException, IOException,ClassNotFoundException {
0969
0970 int readLength = 0;
0971 Object result = null;
0972
0973 //0. preconditions
0974 Assert.assertNotNull(src);
0975
0976 //2. get Oracle BLOB
0977 BLOB blo = (BLOB)src;
0978
0979 //3. get binary stream
0980 InputStream input = blo.getBinaryStream();
0981 Assert.assertNotNull(input);
0982
0983 //4. read
0984 ObjectInputStream ois = new ObjectInputStream(input);
0985 result = ois.readObject();
0986
0987 //5.close streams
0988 ois.close();
0989 input.close();
0990
0991 return result;
0992 }
0993
0994
0995
0996 /**
0997 * writes the specified object into the BLOB
0998 * NOTE: the object should be serializable
0999 */
1000 public static void writeBLOB(Object src,java.sql.Blob dest)
1001 throws SQLException, IOException {
1002
1003 //preconditions
1004 Assert.assertNotNull(src);
1005
1006 //1. get Oracle CLOB
1007 BLOB blo = (BLOB)dest;
1008
1009 //2. get Unicode stream
1010 OutputStream output = blo.getBinaryOutputStream();
1011
1012 //3. write
1013 ObjectOutputStream oos = new ObjectOutputStream(output);
1014 oos.writeObject(src);
1015
1016 //4. flushing is a good idea
1017 //[although ::close() calls it this is implementation specific]
1018 oos.flush();
1019 output.flush();
1020
1021 //5.close streams
1022 oos.close();
1023 output.close();
1024 }
1025
1026
1027
1028 /**
1029 * creates a feature of the specified type/value/valueType/key for the specified entity
1030 * Entity is one of: LR, Annotation
1031 * Value types are: boolean, int, long, string, float, Object
1032 */
1033 private Long _createFeature(Long entityID,
1034 int entityType,
1035 String key,
1036 Object value,
1037 int valueType,
1038 CallableStatement stmt)
1039 throws PersistenceException {
1040
1041 //1. store in DB
1042 Long featID = null;
1043 // CallableStatement stmt = null;
1044
1045 try {
1046 // stmt = this.jdbcConn.prepareCall(
1047 // "{ call "+Gate.DB_OWNER+".persist.create_feature(?,?,?,?,?,?,?)} ");
1048
1049 //1.1 set known values + NULLs
1050 stmt.setLong(1,entityID.longValue());
1051 stmt.setLong(2,entityType);
1052 stmt.setString(3,key);
1053 stmt.setNull(4,java.sql.Types.NUMERIC);
1054 stmt.setNull(5,java.sql.Types.VARCHAR);
1055 stmt.setLong(6,valueType);
1056 stmt.registerOutParameter(7,java.sql.Types.BIGINT);
1057
1058 //1.2 set proper data
1059 switch(valueType) {
1060
1061 case DBHelper.VALUE_TYPE_NULL:
1062 break;
1063
1064 case DBHelper.VALUE_TYPE_BOOLEAN:
1065
1066 boolean b = ((Boolean)value).booleanValue();
1067 stmt.setLong(4, b ? OracleDataStore.ORACLE_TRUE : OracleDataStore.ORACLE_FALSE);
1068 break;
1069
1070 case DBHelper.VALUE_TYPE_INTEGER:
1071
1072 stmt.setLong(4,((Integer)value).intValue());
1073 break;
1074
1075 case DBHelper.VALUE_TYPE_LONG:
1076
1077 stmt.setLong(4,((Long)value).longValue());
1078 break;
1079
1080 case DBHelper.VALUE_TYPE_FLOAT:
1081
1082 Double d = (Double)value;
1083 stmt.setDouble(4,d.doubleValue());
1084 break;
1085
1086 case DBHelper.VALUE_TYPE_BINARY:
1087 //ignore
1088 //will be handled later in processing
1089 break;
1090
1091 case DBHelper.VALUE_TYPE_STRING:
1092
1093 String s = (String)value;
1094 //does it fin into a varchar2?
1095 if (fitsInVarchar2(s)) {
1096 stmt.setString(5,s);
1097 }
1098 break;
1099
1100 default:
1101 throw new IllegalArgumentException("unsuppoeted feature type");
1102 }
1103
1104 stmt.execute();
1105 featID = new Long(stmt.getLong(7));
1106 }
1107 catch(SQLException sqle) {
1108
1109 switch(sqle.getErrorCode()) {
1110 case DBHelper.X_ORACLE_INVALID_FEATURE_TYPE:
1111 throw new PersistenceException("can't create feature [step 1],"+
1112 "[invalid feature type] in DB: ["+ sqle.getMessage()+"]");
1113 default:
1114 throw new PersistenceException("can't create feature [step 1] in DB: ["+
1115 sqle.getMessage()+"]");
1116 }
1117 }
1118 finally {
1119 // DBHelper.cleanup(stmt);
1120 }
1121
1122 return featID;
1123 }
1124
1125
1126 /**
1127 * creates a feature of the specified type/value/valueType/key for the specified entity
1128 * Entity is one of: LR, Annotation
1129 * Value types are: boolean, int, long, string, float, Object
1130 */
1131 private void _createFeatureBulk(Vector features,
1132 CallableStatement stmt,
1133 ArrayDescriptor adNumber,
1134 ArrayDescriptor adString)
1135 throws PersistenceException {
1136
1137 String[] stringValues = new String[VARRAY_SIZE];
1138 long[] numberValues = new long[VARRAY_SIZE];
1139 double[] floatValues = new double[VARRAY_SIZE];
1140 long[] entityIDs = new long[VARRAY_SIZE];
1141 long[] entityTypes = new long[VARRAY_SIZE];
1142 String[] keys = new String[VARRAY_SIZE];
1143 long[] valueTypes = new long[VARRAY_SIZE];
1144
1145 //System.out.println("num features=["+features.size()+"]");
1146 //1. store in DB
1147 try {
1148
1149 int ftInd = 0;
1150 int arrInd = 0;
1151 Iterator it = features.iterator();
1152
1153 while (it.hasNext()) {
1154
1155 Feature currFeature = (Feature)it.next();
1156 entityIDs[arrInd] = currFeature.entityID.longValue();
1157 entityTypes[arrInd] = currFeature.entityType;
1158 keys[arrInd] = currFeature.key;
1159 valueTypes[arrInd] = currFeature.valueType;
1160 //System.out.println("ftype=["+currFeature.valueType+"]");
1161 //preconditions
1162 Assert.assertTrue(currFeature.valueType == DBHelper.VALUE_TYPE_BOOLEAN ||
1163 currFeature.valueType == DBHelper.VALUE_TYPE_FLOAT ||
1164 currFeature.valueType == DBHelper.VALUE_TYPE_INTEGER ||
1165 currFeature.valueType == DBHelper.VALUE_TYPE_LONG ||
1166 currFeature.valueType == DBHelper.VALUE_TYPE_NULL ||
1167 currFeature.valueType == DBHelper.VALUE_TYPE_STRING
1168 );
1169
1170
1171 Object value = currFeature.value;
1172
1173 switch(currFeature.valueType) {
1174
1175 case DBHelper.VALUE_TYPE_NULL:
1176 numberValues[arrInd] = 0;
1177 floatValues[arrInd] = 0;
1178 stringValues[arrInd] = "";
1179 break;
1180
1181 case DBHelper.VALUE_TYPE_BOOLEAN:
1182 boolean b = ((Boolean)value).booleanValue();
1183 numberValues[arrInd] = b ? OracleDataStore.ORACLE_TRUE : OracleDataStore.ORACLE_FALSE;
1184 floatValues[arrInd] = 0;
1185 stringValues[arrInd] = "";
1186 break;
1187
1188 case DBHelper.VALUE_TYPE_INTEGER:
1189 numberValues[arrInd] = ((Integer)value).intValue();
1190 floatValues[arrInd] = 0;
1191 stringValues[arrInd] = "";
1192 break;
1193
1194 case DBHelper.VALUE_TYPE_LONG:
1195 numberValues[arrInd] = ((Long)value).longValue();
1196 floatValues[arrInd] = 0;
1197 stringValues[arrInd] = "";
1198 break;
1199
1200 case DBHelper.VALUE_TYPE_FLOAT:
1201 floatValues[arrInd] = ((Double)value).doubleValue();
1202 numberValues[arrInd] = 0;
1203 stringValues[arrInd] = "";
1204 break;
1205
1206 case DBHelper.VALUE_TYPE_BINARY:
1207 Assert.fail();
1208 break;
1209
1210 case DBHelper.VALUE_TYPE_STRING:
1211 String s = (String)value;
1212 //does it fin into a varchar2?
1213
1214 if (fitsInVarchar2(s)) {
1215 stringValues[arrInd] = s;
1216 floatValues[arrInd] = 0;
1217 numberValues[arrInd] = 0;
1218 }
1219 else {
1220 Assert.fail();
1221 }
1222 break;
1223
1224 default:
1225 throw new IllegalArgumentException("unsuppoeted feature type");
1226 }
1227
1228 //save the features?
1229 ftInd++;
1230 arrInd++;
1231
1232 if (ftInd == features.size() || arrInd == VARRAY_SIZE) {
1233
1234 if (arrInd == VARRAY_SIZE) {
1235 arrInd = 0;
1236 }
1237 //System.out.println("1");
1238 ARRAY arrEntityIDs = new ARRAY(adNumber, this.jdbcConn,entityIDs);
1239 ARRAY arrEntityTypes = new ARRAY(adNumber, this.jdbcConn,entityTypes);
1240 ARRAY arrKeys = new ARRAY(adString, this.jdbcConn,keys);
1241 ARRAY arrValueTypes = new ARRAY(adNumber, this.jdbcConn,valueTypes);
1242 ARRAY arrNumberValues = new ARRAY(adNumber, this.jdbcConn,numberValues);
1243 ARRAY arrFloatValues = new ARRAY(adNumber, this.jdbcConn,floatValues);
1244 ARRAY arrStringValues = new ARRAY(adString, this.jdbcConn,stringValues);
1245
1246 OracleCallableStatement ostmt = (OracleCallableStatement)stmt;
1247 ostmt.setARRAY(1,arrEntityIDs);
1248 ostmt.setARRAY(2,arrEntityTypes);
1249 ostmt.setARRAY(3,arrKeys);
1250 ostmt.setARRAY(4,arrNumberValues);
1251 ostmt.setARRAY(5,arrFloatValues);
1252 ostmt.setARRAY(6,arrStringValues);
1253 ostmt.setARRAY(7,arrValueTypes);
1254 ostmt.setInt(8, arrInd == 0 ? VARRAY_SIZE : arrInd);
1255
1256 ostmt.execute();
1257 }
1258 }
1259 }
1260 catch(SQLException sqle) {
1261
1262 switch(sqle.getErrorCode()) {
1263
1264 case DBHelper.X_ORACLE_INVALID_FEATURE_TYPE:
1265 throw new PersistenceException("can't create feature [step 1],"+
1266 "[invalid feature type] in DB: ["+ sqle.getMessage()+"]");
1267 default:
1268 throw new PersistenceException("can't create feature [step 1] in DB: ["+
1269 sqle.getMessage()+"]");
1270 }
1271 }
1272 }
1273
1274 /**
1275 * updates the value of a feature where the value is string (>4000 bytes, stored as CLOB)
1276 * or Object (stored as BLOB)
1277 */
1278 private void _updateFeatureLOB(Long featID,Object value, int valueType)
1279 throws PersistenceException {
1280
1281 //NOTE: at this point value is never an array,
1282 // although the type may claim so
1283
1284 //0. preconditions
1285 Assert.assertTrue(valueType == DBHelper.VALUE_TYPE_BINARY ||
1286 valueType == DBHelper.VALUE_TYPE_STRING);
1287
1288
1289 //1. get the row to be updated
1290 PreparedStatement stmtA = null;
1291 ResultSet rsA = null;
1292 Clob clobValue = null;
1293 Blob blobValue = null;
1294
1295 try {
1296 String sql = " select ft_long_character_value, " +
1297 " ft_binary_value " +
1298 " from "+Gate.DB_OWNER+".t_feature " +
1299 " where ft_id = ? ";
1300
1301 stmtA = this.jdbcConn.prepareStatement(sql);
1302 stmtA.setLong(1,featID.longValue());
1303 stmtA.execute();
1304 rsA = stmtA.getResultSet();
1305
1306 if (false == rsA.next()) {
1307 throw new PersistenceException("Incorrect feature ID supplied ["+featID+"]");
1308 }
1309
1310 //NOTE1: if the result set contains LOBs always read them
1311 // in the order they appear in the SQL query
1312 // otherwise data will be lost
1313 //NOTE2: access by index rather than name is usually faster
1314 clobValue = rsA.getClob(1);
1315 blobValue = rsA.getBlob(2);
1316
1317 //blob or clob?
1318 if (valueType == DBHelper.VALUE_TYPE_BINARY) {
1319 //blob
1320 writeBLOB(value,blobValue);
1321 }
1322 else if (valueType == DBHelper.VALUE_TYPE_STRING) {
1323 //clob
1324 String s = (String)value;
1325 writeCLOB(s,clobValue);
1326 }
1327 else {
1328 Assert.fail();
1329 }
1330 }
1331 catch(SQLException sqle) {
1332 throw new PersistenceException("can't create feature [step 2] in DB: ["+ sqle.getMessage()+"]");
1333 }
1334 catch(IOException ioe) {
1335 throw new PersistenceException("can't create feature [step 2] in DB: ["+ ioe.getMessage()+"]");
1336 }
1337 finally {
1338 DBHelper.cleanup(rsA);
1339 DBHelper.cleanup(stmtA);
1340 }
1341
1342 }
1343
1344
1345
1346 /**
1347 * creates a feature with the specified type/key/value for the specified entity
1348 * entitties are either LRs ot Annotations
1349 * valid values are: boolean,
1350 * int,
1351 * long,
1352 * string,
1353 * float,
1354 * Object,
1355 * boolean List,
1356 * int List,
1357 * long List,
1358 * string List,
1359 * float List,
1360 * Object List
1361 *
1362 */
1363 private void createFeature(Long entityID, int entityType,String key, Object value, CallableStatement stmt)
1364 throws PersistenceException {
1365
1366 //1. what kind of feature value is this?
1367 //System.out.println("key=["+key+"], val=["+value+"]");
1368 int valueType = findFeatureType(value);
1369
1370 //2. how many elements do we store?
1371 Vector elementsToStore = new Vector();
1372
1373 switch(valueType) {
1374 case DBHelper.VALUE_TYPE_NULL:
1375 case DBHelper.VALUE_TYPE_BINARY:
1376 case DBHelper.VALUE_TYPE_BOOLEAN:
1377 case DBHelper.VALUE_TYPE_FLOAT:
1378 case DBHelper.VALUE_TYPE_INTEGER:
1379 case DBHelper.VALUE_TYPE_LONG:
1380 case DBHelper.VALUE_TYPE_STRING:
1381 elementsToStore.add(value);
1382 break;
1383
1384 default:
1385 //arrays
1386 List arr = (List)value;
1387 Iterator itValues = arr.iterator();
1388
1389 while (itValues.hasNext()) {
1390 elementsToStore.add(itValues.next());
1391 }
1392
1393 //normalize , i.e. ignore arrays
1394 if (valueType == DBHelper.VALUE_TYPE_BINARY_ARR)
1395 valueType = DBHelper.VALUE_TYPE_BINARY;
1396 else if (valueType == DBHelper.VALUE_TYPE_BOOLEAN_ARR)
1397 valueType = DBHelper.VALUE_TYPE_BOOLEAN;
1398 else if (valueType == DBHelper.VALUE_TYPE_FLOAT_ARR)
1399 valueType = DBHelper.VALUE_TYPE_FLOAT;
1400 else if (valueType == DBHelper.VALUE_TYPE_INTEGER_ARR)
1401 valueType = DBHelper.VALUE_TYPE_INTEGER;
1402 else if (valueType == DBHelper.VALUE_TYPE_LONG_ARR)
1403 valueType = DBHelper.VALUE_TYPE_LONG;
1404 else if (valueType == DBHelper.VALUE_TYPE_STRING_ARR)
1405 valueType = DBHelper.VALUE_TYPE_STRING;
1406 }
1407
1408 //3. for all elements:
1409 for (int i=0; i< elementsToStore.size(); i++) {
1410
1411 Object currValue = elementsToStore.elementAt(i);
1412
1413 //3.1. create a dummy feature [LOB hack]
1414 Long featID = _createFeature(entityID,entityType,key,currValue,valueType,stmt);
1415
1416 //3.2. update CLOBs if needed
1417 if (valueType == DBHelper.VALUE_TYPE_STRING) {
1418 //does this string fit into a varchar2 or into clob?
1419 String s = (String)currValue;
1420 if (false == this.fitsInVarchar2(s)) {
1421 // Houston, we have a problem
1422 // put the string into a clob
1423 _updateFeatureLOB(featID,value,valueType);
1424 }
1425 }
1426 else if (valueType == DBHelper.VALUE_TYPE_BINARY) {
1427 //3.3. BLOBs
1428 _updateFeatureLOB(featID,value,valueType);
1429 }
1430 }
1431
1432
1433 }
1434
1435
1436 /**
1437 * splits complex features (Lists) into a vector of Feature entries
1438 * each entry contains the entity id,
1439 * entity type,
1440 * feature key
1441 * feature value
1442 * value type
1443 *
1444 */
1445 private Vector normalizeFeature(Long entityID, int entityType,String key, Object value)
1446 throws PersistenceException {
1447
1448 //1. what kind of feature value is this?
1449 int valueType = findFeatureType(value);
1450
1451 //2. how many elements do we store?
1452 Vector elementsToStore = new Vector();
1453 Vector features = new Vector();
1454
1455 switch(valueType) {
1456 case DBHelper.VALUE_TYPE_NULL:
1457 case DBHelper.VALUE_TYPE_BINARY:
1458 case DBHelper.VALUE_TYPE_BOOLEAN:
1459 case DBHelper.VALUE_TYPE_FLOAT:
1460 case DBHelper.VALUE_TYPE_INTEGER:
1461 case DBHelper.VALUE_TYPE_LONG:
1462 case DBHelper.VALUE_TYPE_STRING:
1463 elementsToStore.add(value);
1464 break;
1465
1466 default:
1467 //arrays
1468 List arr = (List)value;
1469 Iterator itValues = arr.iterator();
1470
1471 while (itValues.hasNext()) {
1472 elementsToStore.add(itValues.next());
1473 }
1474
1475 //normalize , i.e. ignore arrays
1476 if (valueType == DBHelper.VALUE_TYPE_BINARY_ARR)
1477 valueType = DBHelper.VALUE_TYPE_BINARY;
1478 else if (valueType == DBHelper.VALUE_TYPE_BOOLEAN_ARR)
1479 valueType = DBHelper.VALUE_TYPE_BOOLEAN;
1480 else if (valueType == DBHelper.VALUE_TYPE_FLOAT_ARR)
1481 valueType = DBHelper.VALUE_TYPE_FLOAT;
1482 else if (valueType == DBHelper.VALUE_TYPE_INTEGER_ARR)
1483 valueType = DBHelper.VALUE_TYPE_INTEGER;
1484 else if (valueType == DBHelper.VALUE_TYPE_LONG_ARR)
1485 valueType = DBHelper.VALUE_TYPE_LONG;
1486 else if (valueType == DBHelper.VALUE_TYPE_STRING_ARR)
1487 valueType = DBHelper.VALUE_TYPE_STRING;
1488 }
1489
1490 for (int i=0; i< elementsToStore.size(); i++) {
1491
1492 Object currValue = elementsToStore.elementAt(i);
1493 Feature currFeature = new Feature(entityID,entityType,key,currValue,valueType);
1494 features.add(currFeature);
1495 }
1496
1497 return features;
1498 }
1499
1500
1501 /**
1502 * checks if a String should be stores as VARCHAR2 or CLOB
1503 * because the VARCHAR2 in Oracle is limited to 4000 <b>bytes</b>, not all
1504 * the strings fit there. If a String is too long then it is store in the
1505 * database as CLOB.
1506 * Note that in the worst case 3 bytes are needed to represent a single character
1507 * in a database with UTF8 encoding, which limits the string length to 4000/3
1508 * (ORACLE_VARCHAR_LIMIT_BYTES)
1509 * @see #ORACLE_VARCHAR_LIMIT_BYTES
1510 */
1511 private boolean fitsInVarchar2(String s) {
1512
1513 return s.getBytes().length < OracleDataStore.ORACLE_VARCHAR_LIMIT_BYTES;
1514 }
1515
1516
1517
1518 /**
1519 * helper metod
1520 * iterates a FeatureMap and creates all its features in the database
1521 */
1522 protected void createFeatures(Long entityID, int entityType, FeatureMap features)
1523 throws PersistenceException {
1524
1525 //0. prepare statement ad use it for all features
1526 CallableStatement stmt = null;
1527 CallableStatement stmtBulk = null;
1528 ArrayDescriptor adNumber = null;
1529 ArrayDescriptor adString = null;
1530
1531 try {
1532 stmt = this.jdbcConn.prepareCall(
1533 "{ call "+Gate.DB_OWNER+".persist.create_feature(?,?,?,?,?,?,?)} ");
1534
1535 stmtBulk = this.jdbcConn.prepareCall(
1536 "{ call "+Gate.DB_OWNER+".persist.create_feature_bulk(?,?,?,?,?,?,?,?)} ");
1537
1538 adNumber = ArrayDescriptor.createDescriptor("GATEADMIN.PERSIST.INTARRAY", this.jdbcConn);
1539 adString = ArrayDescriptor.createDescriptor("GATEADMIN.PERSIST.CHARARRAY", this.jdbcConn);
1540 }
1541 catch (SQLException sqle) {
1542 throw new PersistenceException(sqle);
1543 }
1544
1545 /* when some day Java has macros, this will be a macro */
1546 Set entries = features.entrySet();
1547 Iterator itFeatures = entries.iterator();
1548 while (itFeatures.hasNext()) {
1549 Map.Entry entry = (Map.Entry)itFeatures.next();
1550 String key = (String)entry.getKey();
1551 Object value = entry.getValue();
1552 createFeature(entityID,entityType,key,value,stmt);
1553 }
1554
1555 //3. cleanup
1556 DBHelper.cleanup(stmt);
1557 }
1558
1559
1560 /**
1561 * helper metod
1562 * iterates a FeatureMap and creates all its features in the database
1563 *
1564 * since it uses Oracle VARRAYs the roundtrips between the client and the server
1565 * are minimized
1566 *
1567 * make sure the two types STRING_ARRAY and INT_ARRAY have the same name in the
1568 * PL/SQL files
1569 *
1570 * also when referencing the types always use the schema owner in upper case
1571 * because the jdbc driver is buggy (see MetaLink note if u care)
1572 */
1573 protected void createFeaturesBulk(Long entityID, int entityType, FeatureMap features)
1574 throws PersistenceException {
1575
1576 //0. prepare statement ad use it for all features
1577 CallableStatement stmt = null;
1578 CallableStatement stmtBulk = null;
1579 ArrayDescriptor adNumber = null;
1580 ArrayDescriptor adString = null;
1581
1582 try {
1583 stmt = this.jdbcConn.prepareCall(
1584 "{ call "+Gate.DB_OWNER+".persist.create_feature(?,?,?,?,?,?,?)} ");
1585
1586 stmtBulk = this.jdbcConn.prepareCall(
1587 "{ call "+Gate.DB_OWNER+".persist.create_feature_bulk(?,?,?,?,?,?,?,?)} ");
1588
1589 //ACHTUNG!!!
1590 //using toUpper for schema owner is necessary because of the dull JDBC driver
1591 //otherwise u'll end up with "invalid name pattern" Oracle error
1592 adString = ArrayDescriptor.createDescriptor(Gate.DB_OWNER.toUpperCase()+".STRING_ARRAY", this.jdbcConn);
1593 adNumber = ArrayDescriptor.createDescriptor(Gate.DB_OWNER.toUpperCase()+".INT_ARRAY", this.jdbcConn);
1594 }
1595 catch (SQLException sqle) {
1596 throw new PersistenceException(sqle);
1597 }
1598
1599 /* when some day Java has macros, this will be a macro */
1600 Vector entityFeatures = new Vector();
1601
1602 Set entries = features.entrySet();
1603 Iterator itFeatures = entries.iterator();
1604 while (itFeatures.hasNext()) {
1605 Map.Entry entry = (Map.Entry)itFeatures.next();
1606 String key = (String)entry.getKey();
1607 Object value = entry.getValue();
1608 Vector normalizedFeatures = normalizeFeature(entityID,entityType,key,value);
1609 entityFeatures.addAll(normalizedFeatures);
1610 }
1611
1612 //iterate all features, store LOBs directly and other features with bulk store
1613 Iterator itEntityFeatures = entityFeatures.iterator();
1614
1615 while (itEntityFeatures.hasNext()) {
1616
1617 Feature currFeature = (Feature)itEntityFeatures.next();
1618
1619 if (currFeature.valueType == DBHelper.VALUE_TYPE_STRING) {
1620 //does this string fit into a varchar2 or into clob?
1621 String s = (String)currFeature.value;
1622 if (false == this.fitsInVarchar2(s)) {
1623 // Houston, we have a problem
1624 // put the string into a clob
1625 Long featID = _createFeature(currFeature.entityID,
1626 currFeature.entityType,
1627 currFeature.key,
1628 currFeature.value,
1629 currFeature.valueType,
1630 stmt);
1631 _updateFeatureLOB(featID,currFeature.value,currFeature.valueType);
1632 itEntityFeatures.remove();
1633 }
1634 }
1635 else if (currFeature.valueType == DBHelper.VALUE_TYPE_BINARY) {
1636 //3.3. BLOBs
1637 Long featID = _createFeature(currFeature.entityID,
1638 currFeature.entityType,
1639 currFeature.key,
1640 currFeature.value,
1641 currFeature.valueType,
1642 stmt);
1643 _updateFeatureLOB(featID,currFeature.value,currFeature.valueType);
1644 itEntityFeatures.remove();
1645 }
1646 }
1647
1648 //now we have the data for the bulk store
1649 _createFeatureBulk(entityFeatures, stmtBulk, adNumber, adString);
1650
1651 //3. cleanup
1652 DBHelper.cleanup(stmt);
1653 DBHelper.cleanup(stmtBulk);
1654 }
1655
1656
1657
1658 /** set security information for LR . */
1659 public void setSecurityInfo(LanguageResource lr,SecurityInfo si)
1660 throws PersistenceException, SecurityException {
1661 throw new MethodNotImplementedException();
1662 }
1663
1664
1665
1666 /**
1667 * helper method for getLR - reads LR of type Corpus
1668 */
1669 /*
1670 private DatabaseCorpusImpl readCorpus(Object lrPersistenceId)
1671 throws PersistenceException {
1672
1673 //0. preconditions
1674 Assert.assertNotNull(lrPersistenceId);
1675
1676 if (false == lrPersistenceId instanceof Long) {
1677 throw new IllegalArgumentException();
1678 }
1679
1680 //3. read from DB
1681 PreparedStatement pstmt = null;
1682 ResultSet rs = null;
1683 DatabaseCorpusImpl result = null;
1684
1685 try {
1686 String sql = " select lr_name " +
1687 " from "+Gate.DB_OWNER+".t_lang_resource " +
1688 " where lr_id = ? ";
1689 pstmt = this.jdbcConn.prepareStatement(sql);
1690 pstmt.setLong(1,((Long)lrPersistenceId).longValue());
1691 pstmt.execute();
1692 rs = pstmt.getResultSet();
1693
1694 if (false == rs.next()) {
1695 //ooops mo data found
1696 throw new PersistenceException("Invalid LR ID supplied - no data found");
1697 }
1698
1699 //4. fill data
1700
1701 //4.1 name
1702 String lrName = rs.getString("lr_name");
1703 Assert.assertNotNull(lrName);
1704
1705 //4.8 features
1706 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_CORPUS);
1707
1708 //4.9 cleanup
1709 DBHelper.cleanup(rs);
1710 DBHelper.cleanup(pstmt);
1711
1712 sql = " select lr_id ," +
1713 " lr_name " +
1714 " from "+Gate.DB_OWNER+".t_document doc, " +
1715 " "+Gate.DB_OWNER+".t_lang_resource lr, " +
1716 " "+Gate.DB_OWNER+".t_corpus_document corpdoc, " +
1717 " "+Gate.DB_OWNER+".t_corpus corp " +
1718 " where lr.lr_id = doc.doc_lr_id " +
1719 " and doc.doc_id = corpdoc.cd_doc_id " +
1720 " and corpdoc.cd_corp_id = corp.corp_id " +
1721 " and corp_lr_id = ? ";
1722 pstmt = this.jdbcConn.prepareStatement(sql);
1723 pstmt.setLong(1,((Long)lrPersistenceId).longValue());
1724 pstmt.execute();
1725 rs = pstmt.getResultSet();
1726
1727 //--Vector docLRIDs = new Vector();
1728 Vector documentData = new Vector();
1729 while (rs.next()) {
1730 Long docLRID = new Long(rs.getLong("lr_id"));
1731 String docName = rs.getString("lr_name");
1732 //--docLRIDs.add(docLRID);
1733 documentData.add(new DocumentData(docName, docLRID));
1734 }
1735 DBHelper.cleanup(rs);
1736 DBHelper.cleanup(pstmt);
1737
1738
1739 // Vector dbDocs = new Vector();
1740 // for (int i=0; i< docLRIDs.size(); i++) {
1741 // Long currLRID = (Long)docLRIDs.elementAt(i);
1742 //kalina: replaced by a Factory call, so the doc gets registered
1743 //properly in GATE. Otherwise strange behaviour results in the GUI
1744 //and no events come about it
1745 //// Document dbDoc = (Document)getLr(DBHelper.DOCUMENT_CLASS,currLRID);
1746 // FeatureMap params = Factory.newFeatureMap();
1747 // params.put(DataStore.DATASTORE_FEATURE_NAME, this);
1748 // params.put(DataStore.LR_ID_FEATURE_NAME, currLRID);
1749 // Document dbDoc = (Document)Factory.createResource(DBHelper.DOCUMENT_CLASS, params);
1750
1751
1752 // dbDocs.add(dbDoc);
1753 // }
1754
1755 result = new DatabaseCorpusImpl(lrName,
1756 this,
1757 (Long)lrPersistenceId,
1758 features,
1759 // dbDocs);
1760 documentData);
1761 }
1762 catch(SQLException sqle) {
1763 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]");
1764 }
1765 catch(Exception e) {
1766 throw new PersistenceException(e);
1767 }
1768 finally {
1769 DBHelper.cleanup(rs);
1770 DBHelper.cleanup(pstmt);
1771 }
1772
1773 return result;
1774 }
1775 */
1776
1777 /** helper method for getLR - reads LR of type Document */
1778 /*
1779 private DatabaseDocumentImpl readDocument(Object lrPersistenceId)
1780 throws PersistenceException {
1781
1782 //0. preconditions
1783 Assert.assertNotNull(lrPersistenceId);
1784
1785 if (false == lrPersistenceId instanceof Long) {
1786 throw new IllegalArgumentException();
1787 }
1788
1789 // 1. dummy document to be initialized
1790 DatabaseDocumentImpl result = new DatabaseDocumentImpl(this.jdbcConn);
1791
1792 PreparedStatement pstmt = null;
1793 ResultSet rs = null;
1794
1795 //3. read from DB
1796 try {
1797 String sql = " select lr_name, " +
1798 " lrtp_type, " +
1799 " lr_id, " +
1800 " lr_parent_id, " +
1801 " doc_id, " +
1802 " doc_url, " +
1803 " doc_start, " +
1804 " doc_end, " +
1805 " doc_is_markup_aware " +
1806 " from "+Gate.DB_OWNER+".v_document " +
1807 " where lr_id = ? ";
1808
1809 pstmt = this.jdbcConn.prepareStatement(sql);
1810 pstmt.setLong(1,((Long)lrPersistenceId).longValue());
1811 pstmt.execute();
1812 rs = pstmt.getResultSet();
1813
1814 if (false == rs.next()) {
1815 //ooops mo data found
1816 throw new PersistenceException("Invalid LR ID supplied - no data found");
1817 }
1818
1819 //4. fill data
1820
1821 //4.0 name
1822 String lrName = rs.getString("lr_name");
1823 Assert.assertNotNull(lrName);
1824 result.setName(lrName);
1825
1826 //4.1 parent
1827 Long parentID = null;
1828 long parent_id = rs.getLong("lr_parent_id");
1829 if (false == rs.wasNull()) {
1830 parentID = new Long(parent_id);
1831
1832 //read parent resource
1833 LanguageResource parentLR = this.getLr(DBHelper.DOCUMENT_CLASS,parentID);
1834 Assert.assertNotNull(parentLR);
1835 Assert.assertTrue(parentLR instanceof DatabaseDocumentImpl);
1836
1837 result.setParent(parentLR);
1838 }
1839
1840
1841 //4.2. markup aware
1842 long markup = rs.getLong("doc_is_markup_aware");
1843 Assert.assertTrue(markup == this.ORACLE_FALSE || markup == this.ORACLE_TRUE);
1844 if (markup == this.ORACLE_FALSE) {
1845 result.setMarkupAware(Boolean.FALSE);
1846 }
1847 else {
1848 result.setMarkupAware(Boolean.TRUE);
1849
1850 }
1851
1852 //4.3 datastore
1853 result.setDataStore(this);
1854
1855 //4.4. persist ID
1856 Long persistID = new Long(rs.getLong("lr_id"));
1857 result.setLRPersistenceId(persistID);
1858
1859 //4.5 source url
1860 String url = rs.getString("doc_url");
1861 result.setSourceUrl(new URL(url));
1862
1863 //4.6. start offset
1864 Long start = null;
1865 long longVal = rs.getLong("doc_start");
1866 //null?
1867 //if NULL is stored in the DB, Oracle returns 0 which is not what we want
1868 if (false == rs.wasNull()) {
1869 start = new Long(longVal);
1870 }
1871 result.setSourceUrlStartOffset(start);
1872 // initData.put("DOC_SOURCE_URL_START",start);
1873
1874 //4.7. end offset
1875 Long end = null;
1876 longVal = rs.getLong("doc_end");
1877 //null?
1878 //if NULL is stored in the DB, Oracle returns 0 which is not what we want
1879 if (false == rs.wasNull()) {
1880 end = new Long(longVal);
1881 }
1882 result.setSourceUrlEndOffset(end);
1883 // initData.put("DOC_SOURCE_URL_END",end);
1884
1885 //4.8 features
1886 FeatureMap features = readFeatures((Long)lrPersistenceId,DBHelper.FEATURE_OWNER_DOCUMENT);
1887 result.setFeatures(features);
1888 //initData.put("DOC_FEATURES",features);
1889
1890 //4.9 set the nextAnnotationID correctly
1891 long doc_id = rs.getLong("doc_id");
1892
1893 DBHelper.cleanup(rs);
1894 DBHelper.cleanup(pstmt);
1895 sql = " select max(ann_local_id),'ann_id'" +
1896 " from "+Gate.DB_OWNER+".t_annotation " +
1897 " where ann_doc_id = ?" +
1898 " union " +
1899 " select max(node_local_id),'node_id' " +
1900 " from "+Gate.DB_OWNER+".t_node " +
1901 " where node_doc_id = ?";
1902
1903 pstmt = this.jdbcConn.prepareStatement(sql);
1904 pstmt.setLong(1,doc_id);
1905 pstmt.setLong(2,doc_id);
1906 pstmt.execute();
1907 rs = pstmt.getResultSet();
1908
1909 int maxAnnID = 0 , maxNodeID = 0;
1910 //ann id
1911 if (false == rs.next()) {
1912 //ooops no data found
1913 throw new PersistenceException("Invalid LR ID supplied - no data found");
1914 }
1915 if (rs.getString(2).equals("ann_id"))
1916 maxAnnID = rs.getInt(1);
1917 else
1918 maxNodeID = rs.getInt(1);
1919
1920 if (false == rs.next()) {
1921 //ooops no data found
1922 throw new PersistenceException("Invalid LR ID supplied - no data found");
1923 }
1924 if (rs.getString(2).equals("node_id"))
1925 maxNodeID = rs.getInt(1);
1926 else
1927 maxAnnID = rs.getInt(1);
1928
1929 result.setNextNodeId(maxNodeID+1);
1930 // initData.put("DOC_NEXT_NODE_ID",new Integer(maxNodeID+1));
1931 result.setNextAnnotationId(maxAnnID+1);
1932 // initData.put("DOC_NEXT_ANN_ID",new Integer(maxAnnID+1));
1933
1934
1935 // params.put("initData__$$__", initData);
1936 // try {
1937 //here we create the persistent LR via Factory, so it's registered
1938 //in GATE
1939 // result = (DatabaseDocumentImpl)Factory.createResource("gate.corpora.DatabaseDocumentImpl", params);
1940 // }
1941 // catch (gate.creole.ResourceInstantiationException ex) {
1942 // throw new GateRuntimeException(ex.getMessage());
1943 // }
1944 }
1945 catch(SQLException sqle) {
1946 throw new PersistenceException("can't read LR from DB: ["+ sqle.getMessage()+"]");
1947 }
1948 catch(Exception e) {
1949 throw new PersistenceException(e);
1950 }
1951 finally {
1952 DBHelper.cleanup(rs);
1953 DBHelper.cleanup(pstmt);
1954 }
1955
1956 return result;
1957 }
1958 */
1959
1960
1961 /**
1962 * reads the features of an entity
1963 * entities are of type LR or Annotation
1964 */
1965 protected FeatureMap readFeatures(Long entityID, int entityType)
1966 throws PersistenceException {
1967
1968 //0. preconditions
1969 Assert.assertNotNull(entityID);
1970 Assert.assertTrue(entityType == DBHelper.FEATURE_OWNER_ANNOTATION ||
1971 entityType == DBHelper.FEATURE_OWNER_CORPUS ||
1972 entityType == DBHelper.FEATURE_OWNER_DOCUMENT);
1973
1974
1975 PreparedStatement pstmt = null;
1976 ResultSet rs = null;
1977 FeatureMap fm = new SimpleFeatureMapImpl();
1978
1979 //1. read from DB
1980 try {
1981 String sql = " select v2.fk_string, " +
1982 " v1.ft_value_type, " +
1983 " v1.ft_number_value, " +
1984 " v1.ft_binary_value, " +
1985 " v1.ft_character_value, " +
1986 " v1.ft_long_character_value " +
1987 " from "+Gate.DB_OWNER+".t_feature v1, " +
1988 " "+Gate.DB_OWNER+".t_feature_key v2 " +
1989 " where v1.ft_entity_id = ? " +
1990 " and v1.ft_entity_type = ? " +
1991 " and v1.ft_key_id = v2.fk_id " +
1992 " order by v2.fk_string,v1.ft_id";
1993
1994 pstmt = this.jdbcConn.prepareStatement(sql);
1995 pstmt.setLong(1,entityID.longValue());
1996 pstmt.setLong(2,entityType);
1997 pstmt.execute();
1998 rs = pstmt.getResultSet();
1999
2000 //3. fill feature map
2001 Vector arrFeatures = new Vector();
2002 String prevKey = null;
2003 String currKey = null;
2004 Object currFeature = null;
2005
2006
2007 while (rs.next()) {
2008 //NOTE: because there are LOBs in the resulset
2009 //the columns should be read in the order they appear
2010 //in the query
2011 currKey = rs.getString(1);
2012
2013 Long valueType = new Long(rs.getLong(2));
2014
2015 //we don't quite know what is the type of the NUMBER
2016 //stored in DB
2017 Object numberValue = null;
2018
2019 //for all numeric types + boolean -> read from DB as appropriate
2020 //Java object
2021 switch(valueType.intValue()) {
2022
2023 case DBHelper.VALUE_TYPE_BOOLEAN:
2024 numberValue = new Boolean(rs.getBoolean(3));
2025 break;
2026
2027 case DBHelper.VALUE_TYPE_FLOAT:
2028 numberValue = new Double(rs.getDouble(3));
2029 break;
2030
2031 case DBHelper.VALUE_TYPE_INTEGER:
2032 numberValue = new Integer(rs.getInt(3));
2033 break;
2034
2035 case DBHelper.VALUE_TYPE_LONG:
2036 numberValue = new Long(rs.getLong(3));
2037 break;
2038 }
2039
2040 //don't forget to read the rest of the current row
2041 Blob blobValue = rs.getBlob(4);
2042 String stringValue = rs.getString(5);
2043 Clob clobValue = rs.getClob(6);
2044
2045 switch(valueType.intValue()) {
2046
2047 case DBHelper.VALUE_TYPE_NULL:
2048 currFeature = null;
2049 break;
2050
2051 case DBHelper.VALUE_TYPE_BOOLEAN:
2052 case DBHelper.VALUE_TYPE_FLOAT:
2053 case DBHelper.VALUE_TYPE_INTEGER:
2054 case DBHelper.VALUE_TYPE_LONG:
2055 currFeature = numberValue;
2056 break;
2057
2058 case DBHelper.VALUE_TYPE_BINARY:
2059 currFeature = readBLOB(blobValue);
2060 break;
2061
2062 case DBHelper.VALUE_TYPE_STRING:
2063 //this one is tricky too
2064 //if the string is < 4000 bytes long then it's stored as varchar2
2065 //otherwise as CLOB
2066 if (null == stringValue) {
2067 //oops, we got CLOB
2068 StringBuffer temp = new StringBuffer();
2069 readCLOB(clobValue,temp);
2070 currFeature = temp.toString();
2071 }
2072 else {
2073 currFeature = stringValue;
2074 }
2075 break;
2076
2077 default:
2078 throw new PersistenceException("Invalid feature type found in DB, type is ["+valueType.intValue()+"]");
2079 }//switch
2080
2081 //new feature or part of an array?
2082 if (currKey.equals(prevKey) && prevKey != null) {
2083 //part of array
2084 arrFeatures.add(currFeature);
2085 }
2086 else {
2087 //add prev feature to feature map
2088
2089 //is the prev feature an array or a single object?
2090 if (arrFeatures.size() > 1) {
2091 //put a clone, because this is a temp array that will
2092 //be cleared in few lines
2093 fm.put(prevKey, new Vector(arrFeatures));
2094 }
2095 else if (arrFeatures.size() == 1) {
2096 fm.put(prevKey,arrFeatures.elementAt(0));
2097 }
2098 else {
2099 //do nothing, this is the dummy feature
2100 ;
2101 }//if
2102
2103 //now clear the array from previous fesature(s) and put the new
2104 //one there
2105 arrFeatures.clear();
2106
2107 prevKey = currKey;
2108 arrFeatures.add(currFeature);
2109 }//if
2110 }//while
2111
2112 //add the last feature
2113 if (arrFeatures.size() > 1) {
2114 fm.put(currKey,arrFeatures);
2115 }
2116 else if (arrFeatures.size() == 1) {
2117 fm.put(currKey,arrFeatures.elementAt(0));
2118 }
2119 }//try
2120 catch(SQLException sqle) {
2121 throw new PersistenceException("can't read features from DB: ["+ sqle.getMessage()+"]");
2122 }
2123 catch(IOException ioe) {
2124 throw new PersistenceException("can't read features from DB: ["+ ioe.getMessage()+"]");
2125 }
2126 catch(ClassNotFoundException cnfe) {
2127 throw new PersistenceException("can't read features from DB: ["+ cnfe.getMessage()+"]");
2128 }
2129 finally {
2130 DBHelper.cleanup(rs);
2131 DBHelper.cleanup(pstmt);
2132 }
2133
2134 return fm;
2135 }
2136
2137
2138
2139 /**
2140 * checks if two databases are identical
2141 * @see #readDatabaseID()
2142 * NOTE: the same database may be represented by different OracleDataStore instances
2143 * but the IDs will be the same
2144 */
2145 public boolean equals(Object obj) {
2146
2147 if (false == obj instanceof OracleDataStore) {
2148 return false;
2149 }
2150
2151 OracleDataStore db2 = (OracleDataStore)obj;
2152
2153 if (false == this.getDatabaseID().equals(db2.getDatabaseID())) {
2154 return false;
2155 }
2156
2157 return true;
2158 }
2159
2160
2161
2162
2163 /**
2164 * helper for sync()
2165 * NEVER call directly
2166 */
2167 protected void _syncLR(LanguageResource lr)
2168 throws PersistenceException,SecurityException {
2169
2170 //0.preconditions
2171 Assert.assertTrue(lr instanceof DatabaseDocumentImpl ||
2172 lr instanceof DatabaseCorpusImpl);;
2173 Assert.assertNotNull(lr.getLRPersistenceId());
2174
2175 CallableStatement stmt = null;
2176
2177 try {
2178 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.update_lr(?,?,?) }");
2179 stmt.setLong(1,((Long)lr.getLRPersistenceId()).longValue());
2180 stmt.setString(2,lr.getName());
2181 //do we have a parent resource?
2182 if (lr instanceof Document &&
2183 null != lr.getParent()) {
2184 stmt.setLong(3,((Long)lr.getParent().getLRPersistenceId()).longValue());
2185 }
2186 else {
2187 stmt.setNull(3,java.sql.Types.BIGINT);
2188 }
2189
2190 stmt.execute();
2191 }
2192 catch(SQLException sqle) {
2193
2194 switch(sqle.getErrorCode()) {
2195 case DBHelper.X_ORACLE_INVALID_LR:
2196 throw new PersistenceException("can't set LR name in DB: [invalid LR ID]");
2197 default:
2198 throw new PersistenceException(
2199 "can't set LR name in DB: ["+ sqle.getMessage()+"]");
2200 }
2201
2202 }
2203 finally {
2204 DBHelper.cleanup(stmt);
2205 }
2206 }
2207
2208
2209
2210 /** helper for sync() - never call directly */
2211 protected void _syncDocumentHeader(Document doc)
2212 throws PersistenceException {
2213
2214 Long lrID = (Long)doc.getLRPersistenceId();
2215
2216 CallableStatement stmt = null;
2217
2218 try {
2219 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+
2220 ".persist.update_document(?,?,?,?,?) }");
2221 stmt.setLong(1,lrID.longValue());
2222 //do we have URL or create from string
2223 if (null==doc.getSourceUrl()) {
2224 stmt.setNull(2,java.sql.Types.VARCHAR);
2225 }
2226 else {
2227 stmt.setString(2,doc.getSourceUrl().toString());
2228 }
2229 //do we have start offset?
2230 if (null==doc.getSourceUrlStartOffset()) {
2231 stmt.setNull(3,java.sql.Types.NUMERIC);
2232 }
2233 else {
2234 stmt.setLong(3,doc.getSourceUrlStartOffset().longValue());
2235 }
2236 //do we have end offset?
2237 if (null==doc.getSourceUrlEndOffset()) {
2238 stmt.setNull(4,java.sql.Types.NUMERIC);
2239 }
2240 else {
2241 stmt.setLong(4,doc.getSourceUrlEndOffset().longValue());
2242 }
2243
2244 stmt.setLong(5,true == doc.getMarkupAware().booleanValue() ? OracleDataStore.ORACLE_TRUE
2245 : OracleDataStore.ORACLE_FALSE);
2246
2247 stmt.execute();
2248 }
2249 catch(SQLException sqle) {
2250
2251 switch(sqle.getErrorCode()) {
2252 case DBHelper.X_ORACLE_INVALID_LR :
2253 throw new PersistenceException("invalid LR supplied: no such document: ["+
2254 sqle.getMessage()+"]");
2255 default:
2256 throw new PersistenceException("can't change document data: ["+
2257 sqle.getMessage()+"]");
2258 }
2259 }
2260 finally {
2261 DBHelper.cleanup(stmt);
2262 }
2263
2264 }
2265
2266
2267
2268 /** helper for sync() - never call directly */
2269 protected void _syncDocumentContent(Document doc)
2270 throws PersistenceException {
2271 /*
2272 PreparedStatement pstmt = null;
2273 ResultSet rs = null;
2274 Long docContID = null;
2275
2276 //1. read from DB
2277 try {
2278
2279 String sql = " select dc_id " +
2280 " from "+Gate.DB_OWNER+".v_content " +
2281 " where lr_id = ? ";
2282
2283 pstmt = this.jdbcConn.prepareStatement(sql);
2284 pstmt.setLong(1,((Long)doc.getLRPersistenceId()).longValue());
2285 pstmt.execute();
2286 rs = pstmt.getResultSet();
2287
2288 if (false == rs.next()) {
2289 throw new PersistenceException("invalid LR ID supplied");
2290 }
2291
2292 //1, get DC_ID
2293 docContID = new Long(rs.getLong(1));
2294 */
2295 //2, update LOBs
2296 //was: updateDocumentContent(docContID,doc.getContent());
2297 Long docID = (Long)doc.getLRPersistenceId();
2298 updateDocumentContent(docID,doc.getContent());
2299
2300 /*
2301 }
2302 catch(SQLException sqle) {
2303 throw new PersistenceException("Cannot update document content ["+
2304 sqle.getMessage()+"]");
2305 }
2306 finally {
2307 DBHelper.cleanup(rs);
2308 DBHelper.cleanup(pstmt);
2309 }
2310 */
2311
2312 }
2313
2314
2315
2316 /** helper for sync() - never call directly */
2317 /* protected void _syncAddedAnnotations(Document doc, AnnotationSet as, Collection changes)
2318 throws PersistenceException {
2319
2320 //0.preconditions
2321 Assert.assertNotNull(doc);
2322 Assert.assertNotNull(as);
2323 Assert.assertNotNull(changes);
2324 Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
2325 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl);
2326 Assert.assertTrue(changes.size() > 0);
2327
2328
2329 PreparedStatement pstmt = null;
2330 ResultSet rs = null;
2331 CallableStatement cstmt = null;
2332 Long lrID = (Long)doc.getLRPersistenceId();
2333 // Long docID = null;
2334 Long asetID = null;
2335
2336 try {
2337 //1. get the a-set ID in the database
2338 String sql = " select as_id " +
2339 // " as_doc_id " +
2340 " from "+Gate.DB_OWNER+".v_annotation_set " +
2341 " where lr_id = ? ";
2342 //do we have aset name?
2343 String clause = null;
2344 String name = as.getName();
2345 if (null != name) {
2346 clause = " and as_name = ? ";
2347 }
2348 else {
2349 clause = " and as_name is null ";
2350 }
2351 sql = sql + clause;
2352
2353 pstmt = this.jdbcConn.prepareStatement(sql);
2354 pstmt.setLong(1,lrID.longValue());
2355 if (null != name) {
2356 pstmt.setString(2,name);
2357 }
2358 pstmt.execute();
2359 rs = pstmt.getResultSet();
2360
2361 if (rs.next()) {
2362 asetID = new Long(rs.getLong("as_id"));
2363 // docID = new Long(rs.getLong("as_doc_id"));
2364 //System.out.println("syncing annots, lr_id=["+lrID+"],doc_id=["+docID+"], set_id=["+asetID+"]");
2365 }
2366 else {
2367 throw new PersistenceException("cannot find annotation set with" +
2368 " name=["+name+"] , LRID=["+lrID+"] in database");
2369 }
2370
2371 //3. insert the new annotations from this set
2372
2373 //3.1. prepare call
2374 cstmt = this.jdbcConn.prepareCall(
2375 "{ call "+Gate.DB_OWNER+".persist.create_annotation(?,?,?,?,?,?,?,?,?) }");
2376
2377 Long annGlobalID = null;
2378 Iterator it = changes.iterator();
2379
2380 while (it.hasNext()) {
2381
2382 //3.2. insert annotation
2383 Annotation ann = (Annotation)it.next();
2384
2385 Node start = (Node)ann.getStartNode();
2386 Node end = (Node)ann.getEndNode();
2387 String type = ann.getType();
2388
2389 cstmt.setLong(1,lrID.longValue());
2390 cstmt.setLong(2,ann.getId().longValue());
2391 cstmt.setLong(3,asetID.longValue());
2392 cstmt.setLong(4,start.getId().longValue());
2393 cstmt.setLong(5,start.getOffset().longValue());
2394 cstmt.setLong(6,end.getId().longValue());
2395 cstmt.setLong(7,end.getOffset().longValue());
2396 cstmt.setString(8,type);
2397 cstmt.registerOutParameter(9,java.sql.Types.BIGINT);
2398
2399 cstmt.execute();
2400 annGlobalID = new Long(cstmt.getLong(9));
2401
2402 //3.3. set annotation features
2403 FeatureMap features = ann.getFeatures();
2404 Assert.assertNotNull(features);
2405 // createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features);
2406 createFeaturesBulk(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features);
2407 }
2408 }
2409 catch(SQLException sqle) {
2410 throw new PersistenceException("can't add annotations in DB : ["+
2411 sqle.getMessage()+"]");
2412 }
2413 finally {
2414 DBHelper.cleanup(rs);
2415 DBHelper.cleanup(pstmt);
2416 DBHelper.cleanup(cstmt);
2417 }
2418 }
2419 */
2420
2421
2422 /** helper for sync() - never call directly */
2423 /* protected void _syncChangedAnnotations(Document doc,AnnotationSet as, Collection changes)
2424 throws PersistenceException {
2425
2426 //technically this approach sux
2427 //at least it works
2428
2429 //1. delete
2430 _syncRemovedAnnotations(doc,as,changes);
2431 //2. recreate
2432 _syncAddedAnnotations(doc,as,changes);
2433 }
2434 */
2435
2436 /** helper for sync() - never call directly */
2437 protected void _syncRemovedDocumentsFromCorpus(List docLRIDs, Long corpLRID)
2438 throws PersistenceException {
2439
2440 //0.preconditions
2441 Assert.assertNotNull(docLRIDs);
2442 Assert.assertNotNull(corpLRID);
2443 Assert.assertTrue(docLRIDs.size() > 0);
2444
2445 CallableStatement cstmt = null;
2446
2447 try {
2448 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+
2449 ".persist.remove_document_from_corpus(?,?) }");
2450
2451 Iterator it = docLRIDs.iterator();
2452 while (it.hasNext()) {
2453 Long currLRID = (Long)it.next();
2454 cstmt.setLong(1,currLRID.longValue());
2455 cstmt.setLong(2,corpLRID.longValue());
2456 cstmt.execute();
2457 }
2458 }
2459 catch(SQLException sqle) {
2460
2461 switch(sqle.getErrorCode()) {
2462 case DBHelper.X_ORACLE_INVALID_LR :
2463 throw new PersistenceException("invalid LR supplied: no such document: ["+
2464 sqle.getMessage()+"]");
2465 default:
2466 throw new PersistenceException("can't change document data: ["+
2467 sqle.getMessage()+"]");
2468 }
2469 }
2470 finally {
2471 DBHelper.cleanup(cstmt);
2472 }
2473
2474 }
2475
2476
2477 /** helper for sync() - never call directly */
2478 /* protected void _syncRemovedAnnotations(Document doc,AnnotationSet as, Collection changes)
2479 throws PersistenceException {
2480 //0.preconditions
2481 Assert.assertNotNull(doc);
2482 Assert.assertNotNull(as);
2483 Assert.assertNotNull(changes);
2484 Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
2485 Assert.assertTrue(as instanceof DatabaseAnnotationSetImpl);
2486 Assert.assertTrue(changes.size() > 0);
2487
2488
2489 PreparedStatement pstmt = null;
2490 ResultSet rs = null;
2491 CallableStatement cstmt = null;
2492 Long lrID = (Long)doc.getLRPersistenceId();
2493 Long docID = null;
2494 Long asetID = null;
2495
2496 try {
2497 //1. get the a-set ID in the database
2498 String sql = " select as_id, " +
2499 " as_doc_id " +
2500 " from "+Gate.DB_OWNER+".v_annotation_set " +
2501 " where lr_id = ? ";
2502 //do we have aset name?
2503 String clause = null;
2504 String name = as.getName();
2505 if (null != name) {
2506 clause = " and as_name = ? ";
2507 }
2508 else {
2509 clause = " and as_name is null ";
2510 }
2511 sql = sql + clause;
2512
2513 pstmt = this.jdbcConn.prepareStatement(sql);
2514 pstmt.setLong(1,lrID.longValue());
2515 if (null != name) {
2516 pstmt.setString(2,name);
2517 }
2518 pstmt.execute();
2519 rs = pstmt.getResultSet();
2520
2521 if (rs.next()) {
2522 asetID = new Long(rs.getLong("as_id"));
2523 docID = new Long(rs.getLong("as_doc_id"));
2524 }
2525 else {
2526 throw new PersistenceException("cannot find annotation set with" +
2527 " name=["+name+"] , LRID=["+lrID+"] in database");
2528 }
2529
2530 //3. delete the removed annotations from this set
2531
2532 //3.1. prepare call
2533 cstmt = this.jdbcConn.prepareCall(
2534 "{ call "+Gate.DB_OWNER+".persist.delete_annotation(?,?) }");
2535
2536
2537 Iterator it = changes.iterator();
2538
2539 while (it.hasNext()) {
2540
2541 //3.2. insert annotation
2542 Annotation ann = (Annotation)it.next();
2543
2544 cstmt.setLong(1,docID.longValue()); //annotations are linked with documents, not LRs!
2545 cstmt.setLong(2,ann.getId().longValue());
2546 cstmt.execute();
2547 }
2548 }
2549 catch(SQLException sqle) {
2550 throw new PersistenceException("can't delete annotations in DB : ["+
2551 sqle.getMessage()+"]");
2552 }
2553 finally {
2554 DBHelper.cleanup(rs);
2555 DBHelper.cleanup(pstmt);
2556 DBHelper.cleanup(cstmt);
2557 }
2558 }
2559 */
2560
2561
2562 /** helper for sync() - never call directly */
2563 /* protected void _syncAnnotationSets(Document doc,Collection removedSets,Collection addedSets)
2564 throws PersistenceException {
2565
2566 //0. preconditions
2567 Assert.assertNotNull(doc);
2568 Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
2569 Assert.assertNotNull(doc.getLRPersistenceId());
2570 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(),
2571 this.getDatabaseID());
2572 Assert.assertNotNull(removedSets);
2573 Assert.assertNotNull(addedSets);
2574
2575 Long lrID = (Long)doc.getLRPersistenceId();
2576
2577 //1. delete from DB removed a-sets
2578 CallableStatement cstmt = null;
2579
2580 try {
2581 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+
2582 ".persist.delete_annotation_set(?,?) }");
2583
2584 Iterator it = removedSets.iterator();
2585 while (it.hasNext()) {
2586 String setName = (String)it.next();
2587 cstmt.setLong(1,lrID.longValue());
2588 cstmt.setString(2,setName);
2589 cstmt.execute();
2590 }
2591 }
2592 catch(SQLException sqle) {
2593 throw new PersistenceException("can't remove annotation set from DB: ["+ sqle.getMessage()+"]");
2594 }
2595 finally {
2596 DBHelper.cleanup(cstmt);
2597 }
2598
2599 //2. create in DB new a-sets
2600 Iterator it = addedSets.iterator();
2601 while (it.hasNext()) {
2602 String setName = (String)it.next();
2603 AnnotationSet aset = doc.getAnnotations(setName);
2604
2605 Assert.assertNotNull(aset);
2606 Assert.assertTrue(aset instanceof DatabaseAnnotationSetImpl);
2607
2608 createAnnotationSet(lrID,aset);
2609 }
2610 }
2611
2612 */
2613
2614 /** helper for sync() - never call directly */
2615 /* protected void _syncAnnotations(Document doc)
2616 throws PersistenceException {
2617
2618 //0. preconditions
2619 Assert.assertNotNull(doc);
2620 Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
2621 Assert.assertNotNull(doc.getLRPersistenceId());
2622 Assert.assertEquals(((DatabaseDataStore)doc.getDataStore()).getDatabaseID(),
2623 this.getDatabaseID());
2624
2625
2626 EventAwareDocument ead = (EventAwareDocument)doc;
2627 //1. get the sets read from the DB for this document
2628 //chnaged annotations can occur only in such sets
2629 Collection loadedSets = ead.getLoadedAnnotationSets();
2630
2631 Iterator it = loadedSets.iterator();
2632 while (it.hasNext()) {
2633 AnnotationSet as = (AnnotationSet)it.next();
2634 //check that this set is neither NEW nor DELETED
2635 //they should be already synced
2636 if (ead.getAddedAnnotationSets().contains(as.getName()) ||
2637 ead.getRemovedAnnotationSets().contains(as.getName())) {
2638 //oops, ignore it
2639 continue;
2640 }
2641
2642 EventAwareAnnotationSet eas = (EventAwareAnnotationSet)as;
2643 Assert.assertNotNull(as);
2644
2645 Collection anns = null;
2646 anns = eas.getAddedAnnotations();
2647 Assert.assertNotNull(anns);
2648 if (anns.size()>0) {
2649 _syncAddedAnnotations(doc,as,anns);
2650 }
2651
2652 anns = eas.getRemovedAnnotations();
2653 Assert.assertNotNull(anns);
2654 if (anns.size()>0) {
2655 _syncRemovedAnnotations(doc,as,anns);
2656 }
2657
2658 anns = eas.getChangedAnnotations();
2659 Assert.assertNotNull(anns);
2660 if (anns.size()>0) {
2661 _syncChangedAnnotations(doc,as,anns);
2662 }
2663 }
2664 }
2665 */
2666
2667
2668 /** helper for sync() - never call directly */
2669 protected void _syncFeatures(LanguageResource lr)
2670 throws PersistenceException {
2671
2672 //0. preconditions
2673 Assert.assertNotNull(lr);
2674 Assert.assertNotNull(lr.getLRPersistenceId());
2675 Assert.assertEquals(((DatabaseDataStore)lr.getDataStore()).getDatabaseID(),
2676 this.getDatabaseID());
2677 Assert.assertTrue(lr instanceof Document || lr instanceof Corpus);
2678 //we have to be in the context of transaction
2679
2680 //1, get ID in the DB
2681 Long lrID = (Long)lr.getLRPersistenceId();
2682 int entityType;
2683
2684 //2. delete features
2685 CallableStatement stmt = null;
2686 try {
2687 Assert.assertTrue(false == this.jdbcConn.getAutoCommit());
2688 stmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+
2689 ".persist.delete_features(?,?) }");
2690 stmt.setLong(1,lrID.longValue());
2691
2692 if (lr instanceof Document) {
2693 entityType = DBHelper.FEATURE_OWNER_DOCUMENT;
2694 }
2695 else if (lr instanceof Corpus) {
2696 entityType = DBHelper.FEATURE_OWNER_CORPUS;
2697 }
2698 else {
2699 throw new IllegalArgumentException();
2700 }
2701
2702 stmt.setInt(2,entityType);
2703 stmt.execute();
2704 }
2705 catch(SQLException sqle) {
2706 throw new PersistenceException("can't delete features in DB: ["+ sqle.getMessage()+"]");
2707 }
2708 finally {
2709 DBHelper.cleanup(stmt);
2710 }
2711
2712 //3. recreate them
2713 //createFeatures(lrID,entityType, lr.getFeatures());
2714 createFeaturesBulk(lrID,entityType, lr.getFeatures());
2715
2716 }
2717
2718
2719
2720 /** helper for sync() - saves a Corpus in the database */
2721 /* protected void syncCorpus(Corpus corp)
2722 throws PersistenceException,SecurityException {
2723
2724 //0. preconditions
2725 Assert.assertNotNull(corp);
2726 Assert.assertTrue(corp instanceof DatabaseCorpusImpl);
2727 Assert.assertEquals(this,corp.getDataStore());
2728 Assert.assertNotNull(corp.getLRPersistenceId());
2729
2730 EventAwareCorpus dbCorpus = (EventAwareCorpus)corp;
2731
2732 //1. sync the corpus name?
2733 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_NAME)) {
2734 _syncLR(corp);
2735 }
2736
2737 //2. sync the corpus features?
2738 if (dbCorpus.isResourceChanged(EventAwareLanguageResource.RES_FEATURES)) {
2739 _syncFeatures(corp);
2740 }
2741
2742 //2.5 get removed documents and detach (not remove) them from the corpus in the
2743 //database
2744 List removedDocLRIDs = dbCorpus.getRemovedDocuments();
2745 if (removedDocLRIDs.size() > 0) {
2746 _syncRemovedDocumentsFromCorpus(removedDocLRIDs,(Long)corp.getLRPersistenceId());
2747 }
2748
2749 //3. get all documents
2750 //--Iterator it = corp.iterator();
2751 Iterator it = dbCorpus.getLoadedDocuments().iterator();
2752
2753 while (it.hasNext()) {
2754 Document dbDoc = (Document)it.next();
2755 //note - document may be NULL which means it was not loaded (load on demand)
2756 //just ignore it then
2757 if (null == dbDoc) {
2758 continue;
2759 }
2760
2761 //adopt/sync?
2762 if (null == dbDoc.getLRPersistenceId()) {
2763 //doc was never adopted, adopt it
2764
2765 //3.1 remove the transient doc from the corpus
2766 it.remove();
2767
2768 //3.2 get the security info for the corpus
2769 SecurityInfo si = getSecurityInfo(corp);
2770
2771
2772 Document adoptedDoc = null;
2773 try {
2774 //3.3. adopt the doc with the sec info
2775 //System.out.println("adopting ["+dbDoc.getName()+"] ...");
2776 //don't open a new transaction, since sync() already has opended one
2777 adoptedDoc = (Document)_adopt(dbDoc,si,true);
2778
2779 //3.4. add doc to corpus in DB
2780 addDocumentToCorpus((Long)adoptedDoc.getLRPersistenceId(),
2781 (Long)corp.getLRPersistenceId());
2782 }
2783 catch(SecurityException se) {
2784 throw new PersistenceException(se);
2785 }
2786
2787 //3.5 add back to corpus the new DatabaseDocument
2788 corp.add(adoptedDoc);
2789 }
2790 else {
2791 //don't open a new transaction, the sync() called for corpus has already
2792 //opened one
2793 try {
2794 _sync(dbDoc,true);
2795
2796 // let the world know about it
2797 fireResourceWritten( new DatastoreEvent(this,
2798 DatastoreEvent.RESOURCE_WRITTEN,
2799 dbDoc,
2800 dbDoc.getLRPersistenceId()
2801 )
2802 );
2803
2804 //if the document is form the same DS but did not belong to the corpus add it now
2805 //NOTE: if the document already belongs to the corpus then nothing will be changed
2806 //in the DB
2807 addDocumentToCorpus((Long)dbDoc.getLRPersistenceId(),
2808 (Long)corp.getLRPersistenceId());
2809 }
2810 catch(SecurityException se) {
2811 gate.util.Err.prln("document cannot be synced: ["+se.getMessage()+"]");
2812 }
2813 }
2814 }
2815 }
2816 */
2817
2818
2819 /**
2820 * Try to acquire exlusive lock on a resource from the persistent store.
2821 * Always call unlockLR() when the lock is no longer needed
2822 */
2823 public boolean lockLr(LanguageResource lr)
2824 throws PersistenceException,SecurityException {
2825
2826 //0. preconditions
2827 Assert.assertNotNull(lr);
2828 Assert.assertTrue(lr instanceof DatabaseDocumentImpl ||
2829 lr instanceof DatabaseCorpusImpl);
2830 Assert.assertNotNull(lr.getLRPersistenceId());
2831 Assert.assertEquals(lr.getDataStore(),this);
2832
2833 //1. delegate
2834 return _lockLr((Long)lr.getLRPersistenceId());
2835 }
2836
2837
2838
2839 /**
2840 * helper for lockLR()
2841 * never call directly
2842 */
2843 private boolean _lockLr(Long lrID)
2844 throws PersistenceException,SecurityException {
2845
2846 //0. preconditions
2847 Assert.assertNotNull(lrID);
2848
2849 //1. check session
2850 if (null == this.session) {
2851 throw new SecurityException("session not set");
2852 }
2853
2854 if (false == this.ac.isValidSession(this.session)) {
2855 throw new SecurityException("invalid session supplied");
2856 }
2857
2858 //2. check permissions
2859 if (false == canWriteLR(lrID)) {
2860 throw new SecurityException("no write access granted to the user");
2861 }
2862
2863 //3. try to lock
2864 CallableStatement cstmt = null;
2865 boolean lockSucceeded = false;
2866
2867 try {
2868 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.lock_lr(?,?,?,?) }");
2869 cstmt.setLong(1,lrID.longValue());
2870 cstmt.setLong(2,this.session.getUser().getID().longValue());
2871 cstmt.setLong(3,this.session.getGroup().getID().longValue());
2872 cstmt.registerOutParameter(4,java.sql.Types.NUMERIC);
2873 cstmt.execute();
2874
2875 lockSucceeded = cstmt.getLong(4) == OracleDataStore.ORACLE_TRUE
2876 ? true
2877 : false;
2878 }
2879 catch(SQLException sqle) {
2880
2881 switch(sqle.getErrorCode()) {
2882 case DBHelper.X_ORACLE_INVALID_LR:
2883 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]");
2884 default:
2885 throw new PersistenceException(
2886 "can't lock LR in DB : ["+ sqle.getMessage()+"]");
2887 }
2888 }
2889 finally {
2890 DBHelper.cleanup(cstmt);
2891 }
2892
2893 return lockSucceeded;
2894 }
2895
2896
2897
2898 /**
2899 * Releases the exlusive lock on a resource from the persistent store.
2900 */
2901 public void unlockLr(LanguageResource lr)
2902 throws PersistenceException,SecurityException {
2903
2904 //0. preconditions
2905 Assert.assertNotNull(lr);
2906 Assert.assertTrue(lr instanceof DatabaseDocumentImpl ||
2907 lr instanceof DatabaseCorpusImpl);
2908 Assert.assertNotNull(lr.getLRPersistenceId());
2909 Assert.assertEquals(lr.getDataStore(),this);
2910
2911 //1. check session
2912 if (null == this.session) {
2913 throw new SecurityException("session not set");
2914 }
2915
2916 if (false == this.ac.isValidSession(this.session)) {
2917 throw new SecurityException("invalid session supplied");
2918 }
2919
2920 //2. check permissions
2921 if (false == canWriteLR(lr.getLRPersistenceId())) {
2922 throw new SecurityException("no write access granted to the user");
2923 }
2924
2925 //3. try to unlock
2926 CallableStatement cstmt = null;
2927 boolean lockSucceeded = false;
2928
2929 try {
2930 cstmt = this.jdbcConn.prepareCall("{ call "+Gate.DB_OWNER+".persist.unlock_lr(?,?) }");
2931 cstmt.setLong(1,((Long)lr.getLRPersistenceId()).longValue());
2932 cstmt.setLong(2,this.session.getUser().getID().longValue());
2933 cstmt.execute();
2934 }
2935 catch(SQLException sqle) {
2936
2937 switch(sqle.getErrorCode()) {
2938 case DBHelper.X_ORACLE_INVALID_LR:
2939 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]");
2940 default:
2941 throw new PersistenceException(
2942 "can't unlock LR in DB : ["+ sqle.getMessage()+"]");
2943 }
2944 }
2945 finally {
2946 DBHelper.cleanup(cstmt);
2947 }
2948 }
2949
2950
2951
2952
2953 /**
2954 * adds document to corpus in the database
2955 * if the document is already part of the corpus nothing
2956 * changes
2957 */
2958 protected void addDocumentToCorpus(Long docID,Long corpID)
2959 throws PersistenceException,SecurityException {
2960
2961 //0. preconditions
2962 Assert.assertNotNull(docID);
2963 Assert.assertNotNull(corpID);
2964
2965 //1. check session
2966 if (null == this.session) {
2967 throw new SecurityException("session not set");
2968 }
2969
2970 if (false == this.ac.isValidSession(this.session)) {
2971 throw new SecurityException("invalid session supplied");
2972 }
2973
2974 //2. check permissions
2975 if (false == canWriteLR(corpID)) {
2976 throw new SecurityException("no write access granted to the user");
2977 }
2978
2979 if (false == canWriteLR(docID)) {
2980 throw new SecurityException("no write access granted to the user");
2981 }
2982
2983 //3. database
2984 CallableStatement cstmt = null;
2985
2986 try {
2987 cstmt = this.jdbcConn.prepareCall("{ call "+
2988 Gate.DB_OWNER+".persist.add_document_to_corpus(?,?) }");
2989 cstmt.setLong(1,docID.longValue());
2990 cstmt.setLong(2,corpID.longValue());
2991 cstmt.execute();
2992 }
2993 catch(SQLException sqle) {
2994
2995 switch(sqle.getErrorCode()) {
2996 case DBHelper.X_ORACLE_INVALID_LR:
2997 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]");
2998 default:
2999 throw new PersistenceException(
3000 "can't add document to corpus : ["+ sqle.getMessage()+"]");
3001 }
3002 }
3003 finally {
3004 DBHelper.cleanup(cstmt);
3005 }
3006 }
3007
3008
3009
3010 /**
3011 * unloads a LR from the GUI
3012 */
3013 /* protected void unloadLR(Long lrID)
3014 throws GateException{
3015
3016 //0. preconfitions
3017 Assert.assertNotNull(lrID);
3018
3019 //1. get all LRs in the system
3020 List resources = Gate.getCreoleRegister().getAllInstances("gate.LanguageResource");
3021
3022 Iterator it = resources.iterator();
3023 while (it.hasNext()) {
3024 LanguageResource lr = (LanguageResource)it.next();
3025 if (lrID.equals(lr.getLRPersistenceId()) &&
3026 this.equals(lr.getDataStore())) {
3027 //found it - unload it
3028 Factory.deleteResource(lr);
3029 break;
3030 }
3031 }
3032 }
3033 */
3034
3035 /** Get a list of LRs that satisfy some set or restrictions
3036 *
3037 * @param constraints list of Restriction objects
3038 */
3039 public List findLrIds(List constraints) throws PersistenceException {
3040 return findLrIds(constraints,null);
3041 }
3042
3043 /**
3044 * Get a list of LRs IDs that satisfy some set or restrictions and are
3045 * of a particular type
3046 *
3047 * @param constraints list of Restriction objects
3048 * @param lrType type of Lrs. DBHelper.DOCUMENT_CLASS or DBHelper.CORPUS_CLASS
3049 */
3050 public List findLrIds(List constraints, String lrType) throws PersistenceException {
3051 return findLrIds(constraints, lrType, null, -1);
3052 }
3053
3054 /**
3055 * Get a list of LRs IDs that satisfy some set or restrictions and are
3056 * of a particular type
3057 *
3058 * @param constraints list of Restriction objects
3059 * @param lrType type of Lrs. DBHelper.DOCUMENT_CLASS or DBHelper.CORPUS_CLASS
3060 * @param orderByConstraints liat of OrderByRestriction objects
3061 * @param limitcount limit returning objects -1 for unlimited
3062 */
3063 public List findLrIds(List constraints, String lrType,
3064 List orderByConstraints, int limitcount) throws PersistenceException {
3065 Vector lrsIDs = new Vector();
3066 CallableStatement stmt = null;
3067 ResultSet rs = null;
3068 Connection conn = null;
3069
3070 try {
3071 Vector sqlValues = new Vector();
3072 String sql = getSQLQuery(constraints, lrType, false, orderByConstraints, limitcount, sqlValues);
3073 conn = DBHelper.connect(this.getStorageUrl(), true);
3074 stmt = conn.prepareCall(sql);
3075 for (int i = 0; i<sqlValues.size(); i++){
3076 if (sqlValues.elementAt(i) instanceof String){
3077 stmt.setString(i+1,sqlValues.elementAt(i).toString());
3078 }
3079 else if (sqlValues.elementAt(i) instanceof Long){
3080 stmt.setLong(i+1,((Long) sqlValues.elementAt(i)).longValue());
3081 }
3082 else if (sqlValues.elementAt(i) instanceof Integer){
3083 stmt.setLong(i+1,((Integer) sqlValues.elementAt(i)).intValue());
3084 }
3085 }
3086 stmt.execute();
3087 rs = stmt.getResultSet();
3088
3089 while (rs.next()) {
3090 long lr_ID = rs.getLong(1);
3091 lrsIDs.addElement(new Long(lr_ID));
3092 }
3093 return lrsIDs;
3094 }
3095 catch(SQLException sqle) {
3096 throw new PersistenceException("can't get LRs from DB: ["+ sqle+"]");
3097 }
3098 catch (ClassNotFoundException cnfe){
3099 throw new PersistenceException("can't not find driver: ["+ cnfe +"]");
3100 }
3101 finally {
3102 DBHelper.cleanup(rs);
3103 DBHelper.cleanup(stmt);
3104 DBHelper.disconnect(conn, true);
3105 }
3106 }
3107 /**
3108 * Return count of LRs which matches the constraints.
3109 *
3110 * @param constraints list of Restriction objects
3111 * @param lrType type of Lrs. DBHelper.DOCUMENT_CLASS or DBHelper.CORPUS_CLASS
3112 */
3113 public long getLrsCount(List constraints, String lrType) throws PersistenceException {
3114 Vector lrs = new Vector();
3115 CallableStatement stmt = null;
3116 ResultSet rs = null;
3117 Connection conn = null;
3118
3119 try {
3120 Vector sqlValues = new Vector();
3121 String sql = getSQLQuery(constraints,lrType, true, null, -1, sqlValues);
3122 conn = DBHelper.connect(this.getStorageUrl(), true);
3123 stmt = conn.prepareCall(sql);
3124 for (int i = 0; i<sqlValues.size(); i++){
3125 if (sqlValues.elementAt(i) instanceof String){
3126 stmt.setString(i+1,sqlValues.elementAt(i).toString());
3127 }
3128 else if (sqlValues.elementAt(i) instanceof Long){
3129 stmt.setLong(i+1,((Long) sqlValues.elementAt(i)).longValue());
3130 }
3131 else if (sqlValues.elementAt(i) instanceof Integer){
3132 stmt.setLong(i+1,((Integer) sqlValues.elementAt(i)).intValue());
3133 }
3134 }
3135
3136 stmt.execute();
3137 rs = stmt.getResultSet();
3138 rs.next();
3139 return rs.getLong(1);
3140 }
3141 catch(SQLException sqle) {
3142 throw new PersistenceException("can't get LRs Count from DB: ["+ sqle+"]");
3143 }
3144 catch (ClassNotFoundException cnfe){
3145 throw new PersistenceException("can't not find driver: ["+ cnfe +"]");
3146 }
3147 finally {
3148 DBHelper.cleanup(rs);
3149 DBHelper.cleanup(stmt);
3150 DBHelper.disconnect(conn, true);
3151 }
3152 }
3153
3154 private String getSQLQuery(List filter, String lrType, boolean count,
3155 List orderByFilter, int limitcount, Vector sqlValues){
3156 StringBuffer query = new StringBuffer("");
3157 String join = getJoinQuery(filter, orderByFilter, sqlValues);
3158 String select = "lr_id";
3159 if (count){
3160 select = "count(*)";
3161 }
3162
3163 query = query.append(" SELECT " + select + " " +
3164 " FROM "+Gate.DB_OWNER+".t_lang_resource LR " + join);
3165
3166 if (filter != null && filter.size()>0) {
3167 query = query.append(" ( ");
3168 query = query.append(getIntersectionPart(filter, sqlValues));
3169 query = query.append(" ) intersected_feat_restr ");
3170 }
3171
3172 String endPartOfJoin = getEndPartOfJoin(filter,orderByFilter, lrType,sqlValues);
3173 query = query.append(endPartOfJoin);
3174
3175 if (limitcount>0){
3176 query = query.insert(0,"select lr_id from ( ");
3177 query = query.append( ") where rownum<"+(limitcount+1));
3178 }
3179
3180 return query.toString();
3181 }
3182
3183 private String getIntersectionPart(List filter, Vector sqlValues){
3184 StringBuffer query = new StringBuffer(" ");
3185
3186 Collections.sort(filter, new RestrictionComepator());
3187 Vector list_of_filters = new Vector();
3188 for (int i=0; i<filter.size(); i++){
3189 if (i>0){
3190 Restriction rest = (Restriction) filter.get(i);
3191 Restriction prev = (Restriction) filter.get(i-1);
3192 if (rest.getKey().equals(prev.getKey())){
3193 Vector temp = (Vector) list_of_filters.get(list_of_filters.size()-1);
3194 temp.add(rest);
3195 } else {
3196 Vector temp = new Vector();
3197 temp.add(rest);
3198 list_of_filters.add(temp);
3199 }
3200 } else {
3201 Vector temp = new Vector();
3202 temp.add(filter.get(0));
3203 list_of_filters.add(temp);
3204 }
3205 }
3206
3207 if (filter!=null && filter.size()>0){
3208 for (int i=0; i<list_of_filters.size(); i++){
3209 query = query.append(getRestrictionPartOfQuery((List) list_of_filters.get(i),sqlValues));
3210 if (i<list_of_filters.size()-1) {
3211 query = query.append(" intersect ");
3212 }
3213 }
3214 }
3215 return query.toString();
3216 }
3217
3218 private String getRestrictionPartOfQuery(List list, Vector sqlValues){
3219 StringBuffer expresion = new StringBuffer(
3220 " SELECT ft_entity_id "+
3221 " FROM "+Gate.DB_OWNER+".t_feature FEATURE, " +
3222 Gate.DB_OWNER + ".t_feature_key FTK" +
3223 " WHERE FEATURE.ft_entity_type = 2 ");
3224
3225 Restriction restr = (Restriction) list.get(0);
3226
3227 if (restr.getKey() != null){
3228 expresion = expresion.append(" AND FTK.fk_id = FEATURE.ft_key_id ");
3229 expresion = expresion.append(" AND FTK.fk_string = ? ");
3230 sqlValues.addElement(restr.getKey());
3231 }
3232
3233 for (int i =0; i<list.size(); i++) {
3234 restr = (Restriction) list.get(i);
3235 if (restr.getValue() != null){
3236 expresion = expresion.append(" AND ");
3237 switch (this.findFeatureType(restr.getValue())){
3238 case DBHelper.VALUE_TYPE_INTEGER:
3239 expresion = expresion.append(getNumberExpresion(restr, sqlValues));
3240 break;
3241 case DBHelper.VALUE_TYPE_LONG:
3242 expresion = expresion.append(getNumberExpresion(restr, sqlValues));
3243 break;
3244 default:
3245 if (restr.getOperator()==Restriction.OPERATOR_EQUATION){
3246 expresion = expresion.append(" FEATURE.ft_character_value = ? ");
3247 sqlValues.addElement(restr.getStringValue());
3248 }
3249 if (restr.getOperator()==Restriction.OPERATOR_LIKE){
3250 expresion = expresion.append(" upper(FEATURE.ft_character_value) like ? ");
3251 sqlValues.addElement("%"+restr.getStringValue().toUpperCase()+"%");
3252 }
3253 break;
3254 }
3255 }
3256 }
3257
3258 return expresion.toString();
3259 }
3260
3261 private String getNumberExpresion(Restriction restr, Vector sqlValues){
3262 StringBuffer expr = new StringBuffer("FEATURE.ft_number_value ");
3263
3264 switch (restr.getOperator()){
3265 case Restriction.OPERATOR_EQUATION:
3266 expr = expr.append(" = ");
3267 break;
3268 case Restriction.OPERATOR_BIGGER:
3269 expr = expr.append(" > ");
3270 break;
3271 case Restriction.OPERATOR_LESS:
3272 expr = expr.append(" < ");
3273 break;
3274 case Restriction.OPERATOR_EQUATION_OR_BIGGER:
3275 expr = expr.append(" >= ");
3276 break;
3277 case Restriction.OPERATOR_EQUATION_OR_LESS:
3278 expr = expr.append(" <= ");
3279 break;
3280 default:
3281 return " 0 = 0 ";
3282 }
3283
3284 expr.append(" ? ");
3285 sqlValues.addElement(restr.getValue());
3286
3287 return expr.toString();
3288 }
3289
3290 private String getJoinQuery(List filter, List orderByFilter, Vector sqlValues){
3291 StringBuffer join = new StringBuffer("");
3292 if (filter !=null && filter.size()>0) {
3293 join = join.append(" , ");
3294 }
3295 if (orderByFilter!=null){
3296 for (int i = 0; i<orderByFilter.size(); i++){
3297 join = join.append(Gate.DB_OWNER+".t_feature FT"+i);
3298 join = join.append(" , "+Gate.DB_OWNER+".t_feature_key FTK"+i +" , ");
3299 }
3300 }
3301 return join.toString();
3302 }
3303
3304 private String getEndPartOfJoin(List filter, List orderByFilter, String lrType, Vector sqlValues){
3305 StringBuffer endJoin = new StringBuffer("");
3306 endJoin = endJoin.append(" WHERE ");
3307
3308 endJoin = endJoin.append(" LR.lr_type_id = ? ");
3309 if (lrType.equals(DBHelper.CORPUS_CLASS)) {
3310 sqlValues.addElement(new Long(2));
3311 }// if DBHelper.CORPUS_CLASS
3312 if (lrType.equals(DBHelper.DOCUMENT_CLASS)) {
3313 sqlValues.addElement(new Long(1));
3314 }// if DBHelper.DOCUMENT_CLASS
3315
3316 if (filter != null && filter.size()>0){
3317 endJoin = endJoin.append(" and intersected_feat_restr.ft_entity_id = lr.lr_id ");
3318 }
3319
3320 if (orderByFilter!=null && orderByFilter.size()>0){
3321 for (int i=0; i<orderByFilter.size(); i++){
3322 endJoin = endJoin.append(" and lr_id=FT"+i+".ft_entity_id ");
3323 endJoin = endJoin.append(" and FT"+i+".ft_key_id = FTK"+i+".fk_id ");
3324 endJoin = endJoin.append(" and FTK"+i+".fk_string= ? ");
3325 OrderByRestriction restr = (OrderByRestriction) orderByFilter.get(i);
3326 sqlValues.addElement(restr.getKey());
3327 }
3328 endJoin = endJoin.append(" order by ");
3329 for (int i=0; i<orderByFilter.size(); i++){
3330 OrderByRestriction restr = (OrderByRestriction) orderByFilter.get(i);
3331
3332 endJoin = endJoin.append(" FT"+i+".ft_number_value ");
3333 if (restr.getOperator()==OrderByRestriction.OPERATOR_ASCENDING){
3334 endJoin = endJoin.append(" asc ");
3335 } else {
3336 endJoin = endJoin.append(" desc ");
3337 }
3338 /* endJoin = endJoin.append(", FT"+i+".ft_character_value ");
3339 if (restr.getOperator()==OrderByRestriction.OPERATOR_ASCENDING){
3340 endJoin = endJoin.append(" asc ");
3341 } else {
3342 endJoin = endJoin.append(" desc ");
3343 }*/
3344 if (i<orderByFilter.size()-1){
3345 endJoin = endJoin.append(" , ");
3346 }
3347 }
3348 }
3349 return endJoin.toString();
3350 }
3351
3352 public List findDocIdsByAnn(List constraints, int limitcount) throws PersistenceException {
3353 Vector lrsIDs = new Vector();
3354 CallableStatement stmt = null;
3355 ResultSet rs = null;
3356 Connection conn = null;
3357
3358 try {
3359 Vector sqlValues = new Vector();
3360 String sql = getSQLQueryAnn(constraints, limitcount, sqlValues);
3361 conn = DBHelper.connect(this.getStorageUrl(), true);
3362 stmt = conn.prepareCall(sql);
3363 for (int i = 0; i<sqlValues.size(); i++){
3364 if (sqlValues.elementAt(i) instanceof String){
3365 stmt.setString(i+1,sqlValues.elementAt(i).toString());
3366 }
3367 else if (sqlValues.elementAt(i) instanceof Long){
3368 stmt.setLong(i+1,((Long) sqlValues.elementAt(i)).longValue());
3369 }
3370 else if (sqlValues.elementAt(i) instanceof Integer){
3371 stmt.setLong(i+1,((Integer) sqlValues.elementAt(i)).intValue());
3372 }
3373 }
3374 stmt.execute();
3375 rs = stmt.getResultSet();
3376
3377 while (rs.next()) {
3378 long lr_ID = rs.getLong(1);
3379 lrsIDs.addElement(new Long(lr_ID));
3380 }
3381 return lrsIDs;
3382 }
3383 catch(SQLException sqle) {
3384 throw new PersistenceException("can't get LRs from DB: ["+ sqle+"]");
3385 }
3386 catch (ClassNotFoundException cnfe){
3387 throw new PersistenceException("can't not find driver: ["+ cnfe +"]");
3388 }
3389 finally {
3390 DBHelper.cleanup(rs);
3391 DBHelper.cleanup(stmt);
3392 DBHelper.disconnect(conn, true);
3393 }
3394 }
3395
3396 private String getSQLQueryAnn(List constraints, int limitcount, Vector sqlValues){
3397 StringBuffer sql = new StringBuffer("");
3398 sql.append("SELECT lr_id ");
3399 sql.append(" FROM gateadmin.t_lang_resource LR ");
3400 sql.append(" WHERE LR.lr_type_id = 1 ");
3401
3402 for (int i = 0; i<constraints.size(); i++){
3403 Restriction rest = (Restriction) constraints.get(i);
3404 sql.append(" AND EXISTS( ");
3405 sql.append(" SELECT F.ft_id ");
3406 sql.append(" FROM gateadmin.t_feature F, ");
3407 sql.append(" gateadmin.T_AS_ANNOTATION A, ");
3408 sql.append(" gateadmin.T_ANNOT_SET S, ");
3409 sql.append(" gateadmin.T_DOCUMENT D, ");
3410 sql.append(" gateadmin.t_feature_key FK ");
3411 sql.append(" WHERE F.ft_entity_id = A.asann_ann_id ");
3412 sql.append(" AND A.asann_as_id = S.as_id ");
3413 sql.append(" AND S.as_doc_id = D.doc_id ");
3414 sql.append(" AND D.doc_lr_id = LR.LR_ID ");
3415 sql.append(" AND S.AS_NAME = ? ");
3416 sqlValues.add("NewsCollector");
3417 sql.append(" AND FK.fk_id = F.ft_key_id ");
3418 sql.append(" AND FK.fk_string= ? ");
3419 sqlValues.add(rest.getKey());
3420 sql.append(" AND F.FT_CHARACTER_VALUE = ? ");
3421 sqlValues.add(rest.getStringValue());
3422 sql.append(" ) ");
3423 }
3424 sql.append(" group by lr_id ");
3425 if (limitcount>0){
3426 sql = sql.insert(0,"select lr_id from ( ");
3427 sql = sql.append( ") where rownum<"+(limitcount+1));
3428 }
3429 return sql.toString();
3430 }
3431 private class Feature {
3432
3433 Long entityID;
3434 int entityType;
3435 String key;
3436 Object value;
3437 int valueType;
3438
3439 public Feature(Long eid, int eType, String key, Object value, int vType) {
3440
3441 this.entityID = eid;
3442 this.entityType = eType;
3443 this.key = key;
3444 this.value = value;
3445 this.valueType = vType;
3446 }
3447 }
3448
3449 private class RestrictionComepator implements Comparator{
3450 public int compare(Object o1, Object o2){
3451 Restriction r1 = (Restriction) o1;
3452 Restriction r2 = (Restriction) o2;
3453 return r1.getKey().compareTo(r2.getKey());
3454 }
3455
3456 public boolean equals(Object o){
3457 return false;
3458 }
3459 }
3460
3461
3462 }
|