0001 /*
0002 * PostgresDataStore.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/Mar/2001
0013 *
0014 * $Id: PostgresDataStore.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
0026 import gate.*;
0027 import gate.corpora.DatabaseCorpusImpl;
0028 import gate.corpora.DatabaseDocumentImpl;
0029 import gate.security.SecurityException;
0030 import gate.security.SecurityInfo;
0031 import gate.util.MethodNotImplementedException;
0032 import gate.util.SimpleFeatureMapImpl;
0033
0034 public class PostgresDataStore extends JDBCDataStore {
0035
0036 /** Name of this resource */
0037 private static final String DS_COMMENT = "GATE PostgreSQL datastore";
0038
0039 /** the icon for this resource */
0040 public static final String DS_ICON_NAME = "pgsql_ds";
0041
0042 /** Debug flag */
0043 private static final boolean DEBUG = true;
0044
0045 public PostgresDataStore() {
0046
0047 super();
0048 this.datastoreComment = DS_COMMENT;
0049 this.iconName = DS_ICON_NAME;
0050 }
0051
0052
0053 public void setSecurityInfo(LanguageResource parm1, SecurityInfo parm2) throws gate.persist.PersistenceException, gate.security.SecurityException {
0054 /**@todo: implement this gate.persist.JDBCDataStore abstract method*/
0055 throw new MethodNotImplementedException();
0056 }
0057
0058 public List findLrIds(List constraints, String lrType) throws gate.persist.PersistenceException {
0059 /**@todo: implement this gate.persist.JDBCDataStore abstract method*/
0060 throw new MethodNotImplementedException();
0061 }
0062
0063 /* public LanguageResource getLr(String lrClassName, Object lrPersistenceId) throws gate.security.SecurityException, gate.persist.PersistenceException {
0064 throw new MethodNotImplementedException();
0065 }
0066 */
0067
0068 /* public void delete(String lrClassName, Object lrId) throws gate.security.SecurityException, gate.persist.PersistenceException {
0069
0070 throw new MethodNotImplementedException();
0071 }
0072 */
0073
0074 public List findLrIds(List constraints) throws gate.persist.PersistenceException {
0075 /**@todo: implement this gate.persist.JDBCDataStore abstract method*/
0076 throw new MethodNotImplementedException();
0077 }
0078
0079
0080 /**
0081 * Releases the exlusive lock on a resource from the persistent store.
0082 */
0083 public void unlockLr(LanguageResource lr)
0084 throws PersistenceException,SecurityException {
0085
0086 //0. preconditions
0087 Assert.assertNotNull(lr);
0088 Assert.assertTrue(lr instanceof DatabaseDocumentImpl ||
0089 lr instanceof DatabaseCorpusImpl);
0090 Assert.assertNotNull(lr.getLRPersistenceId());
0091 Assert.assertEquals(lr.getDataStore(),this);
0092
0093 //1. check session
0094 if (null == this.session) {
0095 throw new SecurityException("session not set");
0096 }
0097
0098 if (false == this.ac.isValidSession(this.session)) {
0099 throw new SecurityException("invalid session supplied");
0100 }
0101
0102 //2. check permissions
0103 if (false == canWriteLR(lr.getLRPersistenceId())) {
0104 throw new SecurityException("no write access granted to the user");
0105 }
0106
0107 //3. try to unlock
0108 PreparedStatement pstmt = null;
0109 boolean lockSucceeded = false;
0110
0111 try {
0112 String sql = " select persist_unlock_lr(?,?) ";
0113 pstmt = this.jdbcConn.prepareStatement(sql);
0114 pstmt.setLong(1,((Long)lr.getLRPersistenceId()).longValue());
0115 pstmt.setLong(2,this.session.getUser().getID().longValue());
0116 pstmt.execute();
0117 //we don't care about the result set
0118 }
0119 catch(SQLException sqle) {
0120
0121 switch(sqle.getErrorCode()) {
0122 case DBHelper.X_ORACLE_INVALID_LR:
0123 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]");
0124 default:
0125 throw new PersistenceException(
0126 "can't unlock LR in DB : ["+ sqle.getMessage()+"]");
0127 }
0128 }
0129 finally {
0130 DBHelper.cleanup(pstmt);
0131 }
0132 }
0133
0134
0135 /**
0136 * Checks if the user (identified by the sessionID)
0137 * has some access (read/write) to the LR
0138 */
0139 protected boolean canAccessLR(Long lrID,int mode)
0140 throws PersistenceException, SecurityException{
0141
0142 //0. preconditions
0143 Assert.assertTrue(DBHelper.READ_ACCESS == mode || DBHelper.WRITE_ACCESS == mode);
0144
0145 //1. is session initialised?
0146 if (null == this.session) {
0147 throw new SecurityException("user session not set");
0148 }
0149
0150 //2.first check the session and then check whether the user is member of the group
0151 if (this.ac.isValidSession(this.session) == false) {
0152 throw new SecurityException("invalid session supplied");
0153 }
0154
0155 PreparedStatement pstmt = null;
0156 ResultSet rs = null;
0157
0158 try {
0159 String sql = "select security_has_access_to_lr(?,?,?,?)";
0160 pstmt = this.jdbcConn.prepareStatement(sql);
0161 pstmt.setLong(1,lrID.longValue());
0162 pstmt.setLong(2,this.session.getUser().getID().longValue());
0163 pstmt.setLong(3,this.session.getGroup().getID().longValue());
0164 pstmt.setLong(4,mode);
0165 pstmt.execute();
0166 rs = pstmt.getResultSet();
0167
0168 if (false == rs.next()) {
0169 throw new PersistenceException("empty result set");
0170 }
0171
0172 return rs.getBoolean(1);
0173 }
0174 catch(SQLException sqle) {
0175 throw new PersistenceException("can't check permissions in DB: ["+ sqle.getMessage()+"]");
0176 }
0177 finally {
0178 DBHelper.cleanup(rs);
0179 DBHelper.cleanup(pstmt);
0180 }
0181
0182 }
0183
0184
0185
0186 /**
0187 * Try to acquire exlusive lock on a resource from the persistent store.
0188 * Always call unlockLR() when the lock is no longer needed
0189 */
0190 public boolean lockLr(LanguageResource lr)
0191 throws PersistenceException,SecurityException {
0192
0193 //0. preconditions
0194 Assert.assertNotNull(lr);
0195 Assert.assertTrue(lr instanceof DatabaseDocumentImpl ||
0196 lr instanceof DatabaseCorpusImpl);
0197 Assert.assertNotNull(lr.getLRPersistenceId());
0198 Assert.assertEquals(lr.getDataStore(),this);
0199
0200 //1. delegate
0201 return _lockLr((Long)lr.getLRPersistenceId());
0202 }
0203
0204
0205 /**
0206 * helper for lockLR()
0207 * never call directly
0208 */
0209 private boolean _lockLr(Long lrID)
0210 throws PersistenceException,SecurityException {
0211
0212 //0. preconditions
0213 Assert.assertNotNull(lrID);
0214
0215 //1. check session
0216 if (null == this.session) {
0217 throw new SecurityException("session not set");
0218 }
0219
0220 if (false == this.ac.isValidSession(this.session)) {
0221 throw new SecurityException("invalid session supplied");
0222 }
0223
0224 //2. check permissions
0225 if (false == canWriteLR(lrID)) {
0226 throw new SecurityException("no write access granted to the user");
0227 }
0228
0229 //3. try to lock
0230 PreparedStatement pstmt = null;
0231 ResultSet rset = null;
0232 boolean lockSucceeded = false;
0233
0234 try {
0235 pstmt = this.jdbcConn.prepareStatement(" select persist_lock_lr(?,?,?) ");
0236 pstmt.setLong(1,lrID.longValue());
0237 pstmt.setLong(2,this.session.getUser().getID().longValue());
0238 pstmt.setLong(3,this.session.getGroup().getID().longValue());
0239
0240 pstmt.execute();
0241 rset = pstmt.getResultSet();
0242
0243 if (false == rset.next()) {
0244 throw new PersistenceException("empty result set");
0245 }
0246
0247 lockSucceeded = rset.getBoolean(1);
0248 }
0249 catch(SQLException sqle) {
0250
0251 switch(sqle.getErrorCode()) {
0252 case DBHelper.X_ORACLE_INVALID_LR:
0253 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]");
0254 default:
0255 throw new PersistenceException(
0256 "can't lock LR in DB : ["+ sqle.getMessage()+"]");
0257 }
0258 }
0259 finally {
0260 DBHelper.cleanup(rset);
0261 DBHelper.cleanup(pstmt);
0262 }
0263
0264 return lockSucceeded;
0265 }
0266
0267
0268 /* protected Corpus createCorpus(Corpus corp,SecurityInfo secInfo, boolean newTransPerDocument)
0269 throws PersistenceException,SecurityException {
0270
0271 throw new MethodNotImplementedException();
0272 }
0273 */
0274 /**
0275 * helper for adopt()
0276 * never call directly
0277 */
0278 protected Long createLR(String lrType,
0279 String lrName,
0280 SecurityInfo si,
0281 Long lrParentID)
0282 throws PersistenceException,SecurityException {
0283
0284 //0. preconditions
0285 Assert.assertNotNull(lrName);
0286
0287 //1. check the session
0288 // if (this.ac.isValidSession(s) == false) {
0289 // throw new SecurityException("invalid session provided");
0290 // }
0291
0292 //2. create a record in DB
0293 PreparedStatement pstmt = null;
0294 ResultSet rset = null;
0295
0296 try {
0297 String sql = " select persist_create_lr(?,?,?,?,?,?) ";
0298 pstmt = this.jdbcConn.prepareStatement(sql);
0299 pstmt.setLong(1,si.getUser().getID().longValue());
0300 pstmt.setLong(2,si.getGroup().getID().longValue());
0301 pstmt.setString(3,lrType);
0302 pstmt.setString(4,lrName);
0303 pstmt.setInt(5,si.getAccessMode());
0304 if (null == lrParentID) {
0305 pstmt.setNull(6,java.sql.Types.INTEGER);
0306 }
0307 else {
0308 pstmt.setLong(6,lrParentID.longValue());
0309 }
0310
0311 pstmt.execute();
0312 rset = pstmt.getResultSet();
0313 if (false == rset.next()) {
0314 throw new PersistenceException("empty result set");
0315 }
0316
0317 Long result = new Long(rset.getLong(1));
0318
0319 return result;
0320 }
0321 catch(SQLException sqle) {
0322
0323 switch(sqle.getErrorCode()) {
0324 case DBHelper.X_ORACLE_INVALID_LR_TYPE:
0325 throw new PersistenceException("can't create LR [step 3] in DB, invalid LR Type");
0326 default:
0327 throw new PersistenceException(
0328 "can't create LR [step 3] in DB : ["+ sqle.getMessage()+"]");
0329 }
0330 }
0331 finally {
0332 DBHelper.cleanup(rset);
0333 DBHelper.cleanup(pstmt);
0334 }
0335 }
0336
0337
0338 /**
0339 * helper for adopt
0340 * never call directly
0341 */
0342 protected Long createDoc(Long _lrID,
0343 URL _docURL,
0344 String _docEncoding,
0345 Long _docStartOffset,
0346 Long _docEndOffset,
0347 Boolean _docIsMarkupAware,
0348 Long _corpusID)
0349 throws PersistenceException {
0350
0351 PreparedStatement pstmt = null;
0352 ResultSet rset = null;
0353 Long docID = null;
0354
0355 try {
0356 pstmt = this.jdbcConn.prepareStatement(
0357 " select persist_create_document(?,?,?,?,?,?,?) ");
0358 pstmt.setLong(1,_lrID.longValue());
0359 pstmt.setString(2,_docURL != null ? _docURL.toString() : "" );
0360 //do we have doc encoding?
0361 if (null == _docEncoding) {
0362 pstmt.setNull(3,java.sql.Types.VARCHAR);
0363 }
0364 else {
0365 pstmt.setString(3,_docEncoding);
0366 }
0367 //do we have start offset?
0368 if (null==_docStartOffset) {
0369 pstmt.setNull(4,java.sql.Types.INTEGER);
0370 }
0371 else {
0372 pstmt.setLong(4,_docStartOffset.longValue());
0373 }
0374 //do we have end offset?
0375 if (null==_docEndOffset) {
0376 pstmt.setNull(5,java.sql.Types.INTEGER);
0377 }
0378 else {
0379 pstmt.setLong(5,_docEndOffset.longValue());
0380 }
0381
0382 pstmt.setBoolean(6,_docIsMarkupAware.booleanValue());
0383
0384 //is the document part of a corpus?
0385 if (null == _corpusID) {
0386 pstmt.setNull(7,java.sql.Types.BIGINT);
0387 }
0388 else {
0389 pstmt.setLong(7,_corpusID.longValue());
0390 }
0391
0392 pstmt.execute();
0393 rset = pstmt.getResultSet();
0394 if (false == rset.next()) {
0395 throw new PersistenceException("empty result set");
0396 }
0397
0398 docID = new Long(rset.getLong(1));
0399
0400 return docID;
0401
0402 }
0403 catch(SQLException sqle) {
0404 throw new PersistenceException("can't create document [step 4] in DB: ["+ sqle.getMessage()+"]");
0405 }
0406 finally {
0407 DBHelper.cleanup(rset);
0408 DBHelper.cleanup(pstmt);
0409 }
0410
0411 }
0412
0413
0414 /** creates an entry for annotation set in the database */
0415 protected void createAnnotationSet(Long lrID, AnnotationSet aset)
0416 throws PersistenceException {
0417
0418 //1. create a-set
0419 String asetName = aset.getName();
0420 Long asetID = null;
0421
0422 //DB stuff
0423 PreparedStatement pstmt = null;
0424 ResultSet rs = null;
0425
0426 try {
0427 String sql = "select persist_create_annotation_set(?,?)";
0428 pstmt = this.jdbcConn.prepareStatement(sql);
0429
0430 pstmt.setLong(1,lrID.longValue());
0431 if (null == asetName) {
0432 pstmt.setNull(2,java.sql.Types.VARCHAR);
0433 }
0434 else {
0435 pstmt.setString(2,asetName);
0436 }
0437 pstmt.execute();
0438 rs = pstmt.getResultSet();
0439
0440 if (false == rs.next()) {
0441 throw new PersistenceException("empty result set");
0442 }
0443
0444 asetID = new Long(rs.getLong(1));
0445 }
0446 catch(SQLException sqle) {
0447 throw new PersistenceException("can't create a-set [step 1] in DB: ["+ sqle.getMessage()+"]");
0448 }
0449 finally {
0450 DBHelper.cleanup(rs);
0451 DBHelper.cleanup(pstmt);
0452 }
0453
0454
0455 //2. insert annotations/nodes for DEFAULT a-set
0456 //for now use a stupid cycle
0457 //TODO: pass all the data with one DB call (?)
0458
0459 try {
0460 String sql = "select persist_create_annotation(?,?,?,?,?,?,?,?) ";
0461 pstmt = this.jdbcConn.prepareStatement(sql);
0462
0463
0464 Iterator itAnnotations = aset.iterator();
0465
0466 while (itAnnotations.hasNext()) {
0467 Annotation ann = (Annotation)itAnnotations.next();
0468 Node start = (Node)ann.getStartNode();
0469 Node end = (Node)ann.getEndNode();
0470 String type = ann.getType();
0471
0472 //DB stuff
0473 Long annGlobalID = null;
0474 pstmt.setLong(1,lrID.longValue());
0475 pstmt.setLong(2,ann.getId().longValue());
0476 pstmt.setLong(3,asetID.longValue());
0477 pstmt.setLong(4,start.getId().longValue());
0478 pstmt.setLong(5,start.getOffset().longValue());
0479 pstmt.setLong(6,end.getId().longValue());
0480 pstmt.setLong(7,end.getOffset().longValue());
0481 pstmt.setString(8,type);
0482 pstmt.execute();
0483 rs = pstmt.getResultSet();
0484
0485 if (false == rs.next()) {
0486 throw new PersistenceException("empty result set");
0487 }
0488
0489 annGlobalID = new Long(rs.getLong(1));
0490 DBHelper.cleanup(rs);
0491
0492 //2.1. set annotation features
0493 FeatureMap features = ann.getFeatures();
0494 Assert.assertNotNull(features);
0495 createFeatures(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features);
0496 // createFeaturesBulk(annGlobalID,DBHelper.FEATURE_OWNER_ANNOTATION,features);
0497 } //while
0498 }//try
0499 catch(SQLException sqle) {
0500
0501 switch(sqle.getErrorCode()) {
0502
0503 case DBHelper.X_ORACLE_INVALID_ANNOTATION_TYPE:
0504 throw new PersistenceException(
0505 "can't create annotation in DB, [invalid annotation type]");
0506 default:
0507 throw new PersistenceException(
0508 "can't create annotation in DB: ["+ sqle.getMessage()+"]");
0509 }//switch
0510 }//catch
0511 finally {
0512 DBHelper.cleanup(pstmt);
0513 }
0514 }
0515
0516 /**
0517 * updates the content of the document if it is binary or a long string
0518 * (that does not fit into VARCHAR2)
0519 */
0520 protected void updateDocumentContent(Long docID,DocumentContent content)
0521 throws PersistenceException {
0522
0523 //1. get LOB locators from DB
0524 PreparedStatement pstmt = null;
0525 try {
0526 String sql = " update t_doc_content " +
0527 " set dc_character_content = ?, " +
0528 " dc_content_type = ? " +
0529 " where dc_id = (select doc_content_id " +
0530 " from t_document " +
0531 " where doc_id = ?) ";
0532
0533 pstmt = this.jdbcConn.prepareStatement(sql);
0534 pstmt.setString(1,content.toString());
0535 pstmt.setInt(2,DBHelper.CHARACTER_CONTENT);
0536 pstmt.setLong(3,docID.longValue());
0537 pstmt.executeUpdate();
0538 }
0539 catch(SQLException sqle) {
0540 throw new PersistenceException("can't update document content in DB : ["+
0541 sqle.getMessage()+"]");
0542 }
0543 finally {
0544 DBHelper.cleanup(pstmt);
0545 }
0546
0547 }
0548
0549
0550
0551
0552 /**
0553 * creates a feature with the specified type/key/value for the specified entity
0554 * entitties are either LRs ot Annotations
0555 * valid values are: boolean,
0556 * int,
0557 * long,
0558 * string,
0559 * float,
0560 * Object,
0561 * boolean List,
0562 * int List,
0563 * long List,
0564 * string List,
0565 * float List,
0566 * Object List
0567 *
0568 */
0569
0570 private void createFeature(Long entityID, int entityType,String key, Object value, PreparedStatement pstmt)
0571 throws PersistenceException {
0572
0573 //1. what kind of feature value is this?
0574 int valueType = findFeatureType(value);
0575
0576 //2. how many elements do we store?
0577 Vector elementsToStore = new Vector();
0578
0579 switch(valueType) {
0580 case DBHelper.VALUE_TYPE_NULL:
0581 case DBHelper.VALUE_TYPE_BINARY:
0582 case DBHelper.VALUE_TYPE_BOOLEAN:
0583 case DBHelper.VALUE_TYPE_FLOAT:
0584 case DBHelper.VALUE_TYPE_INTEGER:
0585 case DBHelper.VALUE_TYPE_LONG:
0586 case DBHelper.VALUE_TYPE_STRING:
0587 elementsToStore.add(value);
0588 break;
0589
0590 default:
0591 //arrays
0592 List arr = (List)value;
0593 Iterator itValues = arr.iterator();
0594
0595 while (itValues.hasNext()) {
0596 elementsToStore.add(itValues.next());
0597 }
0598
0599 //normalize , i.e. ignore arrays
0600 if (valueType == DBHelper.VALUE_TYPE_BINARY_ARR)
0601 valueType = DBHelper.VALUE_TYPE_BINARY;
0602 else if (valueType == DBHelper.VALUE_TYPE_BOOLEAN_ARR)
0603 valueType = DBHelper.VALUE_TYPE_BOOLEAN;
0604 else if (valueType == DBHelper.VALUE_TYPE_FLOAT_ARR)
0605 valueType = DBHelper.VALUE_TYPE_FLOAT;
0606 else if (valueType == DBHelper.VALUE_TYPE_INTEGER_ARR)
0607 valueType = DBHelper.VALUE_TYPE_INTEGER;
0608 else if (valueType == DBHelper.VALUE_TYPE_LONG_ARR)
0609 valueType = DBHelper.VALUE_TYPE_LONG;
0610 else if (valueType == DBHelper.VALUE_TYPE_STRING_ARR)
0611 valueType = DBHelper.VALUE_TYPE_STRING;
0612 }
0613
0614 //3. for all elements:
0615 for (int i=0; i< elementsToStore.size(); i++) {
0616
0617 Object currValue = elementsToStore.elementAt(i);
0618
0619 //3.1. create a dummy feature [LOB hack]
0620 Long featID = _createFeature(entityID,entityType,key,currValue,valueType,pstmt);
0621 }
0622
0623 }
0624
0625
0626
0627 /**
0628 * helper metod
0629 * iterates a FeatureMap and creates all its features in the database
0630 */
0631 protected void createFeatures(Long entityID, int entityType, FeatureMap features)
0632 throws PersistenceException {
0633
0634 //0. prepare statement ad use it for all features
0635 PreparedStatement pstmt = null;
0636
0637 try {
0638 String sql = "select persist_create_feature(?,?,?,?,?,?,?,?) ";
0639 pstmt = this.jdbcConn.prepareStatement(sql);
0640 }
0641 catch (SQLException sqle) {
0642 throw new PersistenceException(sqle);
0643 }
0644
0645 /* when some day Java has macros, this will be a macro */
0646 Set entries = features.entrySet();
0647 Iterator itFeatures = entries.iterator();
0648 while (itFeatures.hasNext()) {
0649 Map.Entry entry = (Map.Entry)itFeatures.next();
0650 String key = (String)entry.getKey();
0651 Object value = entry.getValue();
0652 createFeature(entityID,entityType,key,value,pstmt);
0653 }
0654
0655 //3. cleanup
0656 DBHelper.cleanup(pstmt);
0657 }
0658
0659 protected void createFeaturesBulk(Long entityID, int entityType, FeatureMap features)
0660 throws PersistenceException {
0661
0662 throw new MethodNotImplementedException();
0663 }
0664
0665 /**
0666 * creates a feature of the specified type/value/valueType/key for the specified entity
0667 * Entity is one of: LR, Annotation
0668 * Value types are: boolean, int, long, string, float, Object
0669 */
0670 private Long _createFeature(Long entityID,
0671 int entityType,
0672 String key,
0673 Object value,
0674 int valueType,
0675 PreparedStatement pstmt)
0676 throws PersistenceException {
0677
0678 //1. store in DB
0679 Long featID = null;
0680 ResultSet rs = null;
0681
0682 try {
0683
0684 //1.1 set known values + NULLs
0685 pstmt.setLong(1,entityID.longValue());
0686 pstmt.setInt(2,entityType);
0687 pstmt.setString(3,key);
0688 pstmt.setNull(4,java.sql.Types.BIGINT);
0689 pstmt.setNull(5,java.sql.Types.DOUBLE);
0690 pstmt.setNull(6,java.sql.Types.LONGVARCHAR);
0691 pstmt.setNull(7,java.sql.Types.LONGVARBINARY);
0692 pstmt.setInt(8,valueType);
0693
0694 //1.2 set proper data
0695 switch(valueType) {
0696
0697 case DBHelper.VALUE_TYPE_NULL:
0698 break;
0699
0700 case DBHelper.VALUE_TYPE_BOOLEAN:
0701
0702 boolean b = ((Boolean)value).booleanValue();
0703 pstmt.setLong(4, b ? DBHelper.TRUE : DBHelper.FALSE);
0704 break;
0705
0706 case DBHelper.VALUE_TYPE_INTEGER:
0707
0708 pstmt.setLong(4,((Integer)value).intValue());
0709 break;
0710
0711 case DBHelper.VALUE_TYPE_LONG:
0712
0713 pstmt.setLong(4,((Long)value).longValue());
0714 break;
0715
0716 case DBHelper.VALUE_TYPE_FLOAT:
0717
0718 Double d = (Double)value;
0719 pstmt.setDouble(5,d.doubleValue());
0720 break;
0721
0722 case DBHelper.VALUE_TYPE_BINARY:
0723 //we serialize the value (object) in the DB
0724 ByteArrayOutputStream baos = new ByteArrayOutputStream();
0725 ObjectOutputStream oos = new ObjectOutputStream(baos);
0726 oos.writeObject(value);
0727 oos.close();
0728 baos.close();
0729 byte[] buff = baos.toByteArray();
0730 ByteArrayInputStream bais = new ByteArrayInputStream(buff);
0731 pstmt.setBinaryStream(7,bais,buff.length);
0732 bais.close();
0733 break;
0734
0735 case DBHelper.VALUE_TYPE_STRING:
0736
0737 String s = (String)value;
0738 //does it fin into a varchar2?
0739 pstmt.setString(6,s);
0740 break;
0741
0742 default:
0743 throw new IllegalArgumentException("unsuppoeted feature type");
0744 }
0745
0746 pstmt.execute();
0747 rs = pstmt.getResultSet();
0748
0749 if (false == rs.next()) {
0750 throw new PersistenceException("empty result set");
0751 }
0752
0753 featID = new Long(rs.getLong(1));
0754 }
0755 catch(IOException ioe) {
0756 throw new PersistenceException("can't write binary data ["+ioe.getMessage()+"]");
0757 }
0758 catch(SQLException sqle) {
0759
0760 switch(sqle.getErrorCode()) {
0761 case DBHelper.X_ORACLE_INVALID_FEATURE_TYPE:
0762 throw new PersistenceException("can't create feature [step 1],"+
0763 "[invalid feature type] in DB: ["+ sqle.getMessage()+"]");
0764 default:
0765 throw new PersistenceException("can't create feature [step 1] in DB: ["+
0766 sqle.getMessage()+"]");
0767 }
0768 }
0769 finally {
0770 DBHelper.cleanup(rs);
0771 // DBHelper.cleanup(stmt);
0772 }
0773
0774 return featID;
0775 }
0776
0777
0778 /**
0779 * updates the value of a feature where the value is string (>4000 bytes, stored as CLOB)
0780 * or Object (stored as BLOB)
0781 */
0782 /* private void _updateFeatureLOB(Long featID,Object value, int valueType)
0783 throws PersistenceException {
0784
0785 throw new MethodNotImplementedException();
0786 }
0787 */
0788 /** helper for sync() - saves a Corpus in the database */
0789 /* protected void syncCorpus(Corpus corp)
0790 throws PersistenceException,SecurityException {
0791
0792 throw new MethodNotImplementedException();
0793 }
0794 */
0795
0796 /**
0797 * helper for sync()
0798 * NEVER call directly
0799 */
0800 protected void _syncLR(LanguageResource lr)
0801 throws PersistenceException,SecurityException {
0802
0803 //0.preconditions
0804 Assert.assertTrue(lr instanceof DatabaseDocumentImpl ||
0805 lr instanceof DatabaseCorpusImpl);;
0806 Assert.assertNotNull(lr.getLRPersistenceId());
0807
0808 PreparedStatement pstmt = null;
0809
0810 try {
0811 pstmt = this.jdbcConn.prepareStatement("select persist_update_lr(?,?,?)");
0812 pstmt.setLong(1,((Long)lr.getLRPersistenceId()).longValue());
0813 pstmt.setString(2,lr.getName());
0814 //do we have a parent resource?
0815 if (lr instanceof Document &&
0816 null != lr.getParent()) {
0817 pstmt.setLong(3,((Long)lr.getParent().getLRPersistenceId()).longValue());
0818 }
0819 else {
0820 pstmt.setNull(3,java.sql.Types.BIGINT);
0821 }
0822
0823 pstmt.execute();
0824 }
0825 catch(SQLException sqle) {
0826
0827 switch(sqle.getErrorCode()) {
0828 case DBHelper.X_ORACLE_INVALID_LR:
0829 throw new PersistenceException("can't set LR name in DB: [invalid LR ID]");
0830 default:
0831 throw new PersistenceException(
0832 "can't set LR name in DB: ["+ sqle.getMessage()+"]");
0833 }
0834
0835 }
0836 finally {
0837 DBHelper.cleanup(pstmt);
0838 }
0839
0840 }
0841
0842 /** helper for sync() - never call directly */
0843 protected void _syncDocumentHeader(Document doc)
0844 throws PersistenceException {
0845
0846 Long lrID = (Long)doc.getLRPersistenceId();
0847
0848 PreparedStatement pstmt = null;
0849
0850 try {
0851 pstmt = this.jdbcConn.prepareStatement("select persist_update_document(?,?,?,?,?)");
0852 pstmt.setLong(1,lrID.longValue());
0853 if(doc.getSourceUrl() != null){
0854 pstmt.setString(2, doc.getSourceUrl().toString());
0855 }else{
0856 pstmt.setString(2, "");
0857 }
0858 //do we have start offset?
0859 if (null==doc.getSourceUrlStartOffset()) {
0860 pstmt.setNull(3,java.sql.Types.INTEGER);
0861 }
0862 else {
0863 pstmt.setLong(3,doc.getSourceUrlStartOffset().longValue());
0864 }
0865 //do we have end offset?
0866 if (null==doc.getSourceUrlEndOffset()) {
0867 pstmt.setNull(4,java.sql.Types.INTEGER);
0868 }
0869 else {
0870 pstmt.setLong(4,doc.getSourceUrlEndOffset().longValue());
0871 }
0872
0873 pstmt.setBoolean(5,doc.getMarkupAware().booleanValue());
0874 pstmt.execute();
0875 }
0876 catch(SQLException sqle) {
0877
0878 switch(sqle.getErrorCode()) {
0879 case DBHelper.X_ORACLE_INVALID_LR :
0880 throw new PersistenceException("invalid LR supplied: no such document: ["+
0881 sqle.getMessage()+"]");
0882 default:
0883 throw new PersistenceException("can't change document data: ["+
0884 sqle.getMessage()+"]");
0885 }
0886 }
0887 finally {
0888 DBHelper.cleanup(pstmt);
0889 }
0890
0891 }
0892
0893 /** helper for sync() - never call directly */
0894 protected void _syncDocumentContent(Document doc)
0895 throws PersistenceException {
0896
0897 //0.
0898 Assert.assertNotNull(doc);
0899 Assert.assertNotNull(doc.getLRPersistenceId());
0900 Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
0901
0902 PreparedStatement pstmt = null;
0903 //1.
0904 try {
0905 pstmt = this.jdbcConn.prepareStatement("select persist_update_document_content(?,?)");
0906 pstmt.setLong(1,((Long)doc.getLRPersistenceId()).longValue());
0907
0908 DocumentContent dc = doc.getContent();
0909 if (dc.size().longValue() > 0) {
0910 pstmt.setString(2,dc.toString());
0911 }
0912 else {
0913 pstmt.setNull(2,java.sql.Types.LONGVARCHAR);
0914 }
0915
0916 pstmt.execute();
0917 }
0918 catch(SQLException sqle) {
0919 throw new PersistenceException("Cannot update document content ["+
0920 sqle.getMessage()+"]");
0921 }
0922 finally {
0923 DBHelper.cleanup(pstmt);
0924 }
0925 }
0926
0927 /** helper for sync() - never call directly */
0928 protected void _syncFeatures(LanguageResource lr)
0929 throws PersistenceException {
0930
0931 //0. preconditions
0932 Assert.assertNotNull(lr);
0933 Assert.assertNotNull(lr.getLRPersistenceId());
0934 Assert.assertEquals(((DatabaseDataStore)lr.getDataStore()).getDatabaseID(),
0935 this.getDatabaseID());
0936 Assert.assertTrue(lr instanceof Document || lr instanceof Corpus);
0937 //we have to be in the context of transaction
0938
0939 //1, get ID in the DB
0940 Long lrID = (Long)lr.getLRPersistenceId();
0941 int entityType;
0942
0943 //2. delete features
0944 PreparedStatement pstmt = null;
0945 try {
0946 Assert.assertTrue(false == this.jdbcConn.getAutoCommit());
0947 pstmt = this.jdbcConn.prepareStatement("select persist_delete_features(?,?) ");
0948 pstmt.setLong(1,lrID.longValue());
0949
0950 if (lr instanceof Document) {
0951 entityType = DBHelper.FEATURE_OWNER_DOCUMENT;
0952 }
0953 else if (lr instanceof Corpus) {
0954 entityType = DBHelper.FEATURE_OWNER_CORPUS;
0955 }
0956 else {
0957 throw new IllegalArgumentException();
0958 }
0959
0960 pstmt.setInt(2,entityType);
0961 pstmt.execute();
0962 }
0963 catch(SQLException sqle) {
0964 throw new PersistenceException("can't delete features in DB: ["+ sqle.getMessage()+"]");
0965 }
0966 finally {
0967 DBHelper.cleanup(pstmt);
0968 }
0969
0970 //3. recreate them
0971 createFeatures(lrID,entityType, lr.getFeatures());
0972 }
0973
0974 /** helper for sync() - never call directly */
0975 /* protected void _syncAnnotationSets(Document doc,Collection removedSets,Collection addedSets)
0976 throws PersistenceException {
0977
0978 throw new MethodNotImplementedException();
0979 }
0980 */
0981
0982 /** helper for sync() - never call directly */
0983 /* protected void _syncAddedAnnotations(Document doc, AnnotationSet as, Collection changes)
0984 throws PersistenceException {
0985
0986 throw new MethodNotImplementedException();
0987 }
0988 */
0989
0990 /** helper for sync() - never call directly */
0991 /* protected void _syncRemovedAnnotations(Document doc,AnnotationSet as, Collection changes)
0992 throws PersistenceException {
0993
0994 throw new MethodNotImplementedException();
0995 }
0996 */
0997 /** helper for sync() - never call directly */
0998 /* protected void _syncChangedAnnotations(Document doc,AnnotationSet as, Collection changes)
0999 throws PersistenceException {
1000
1001 throw new MethodNotImplementedException();
1002 }
1003 */
1004
1005 /**
1006 * reads the features of an entity
1007 * entities are of type LR or Annotation
1008 */
1009 protected FeatureMap readFeatures(Long entityID, int entityType)
1010 throws PersistenceException {
1011
1012 //0. preconditions
1013 Assert.assertNotNull(entityID);
1014 Assert.assertTrue(entityType == DBHelper.FEATURE_OWNER_ANNOTATION ||
1015 entityType == DBHelper.FEATURE_OWNER_CORPUS ||
1016 entityType == DBHelper.FEATURE_OWNER_DOCUMENT);
1017
1018
1019 PreparedStatement pstmt = null;
1020 ResultSet rs = null;
1021 FeatureMap fm = new SimpleFeatureMapImpl();
1022
1023 //1. read from DB
1024 try {
1025 String sql = " select ftkey.fk_string, " +
1026 " ft.ft_value_type, " +
1027 " ft.ft_int_value, " +
1028 " ft.ft_float_value, " +
1029 " ft.ft_binary_value, " +
1030 " ft.ft_character_value " +
1031 " from t_feature ft, " +
1032 " t_feature_key ftkey " +
1033 " where ft.ft_entity_id = ? " +
1034 " and ft.ft_entity_type = ? " +
1035 " and ft.ft_key_id = ftkey.fk_id " +
1036 " order by ftkey.fk_string,ft.ft_id";
1037
1038 pstmt = this.jdbcConn.prepareStatement(sql);
1039 pstmt.setLong(1,entityID.longValue());
1040 pstmt.setLong(2,entityType);
1041 pstmt.execute();
1042 rs = pstmt.getResultSet();
1043
1044 //3. fill feature map
1045 Vector arrFeatures = new Vector();
1046 String prevKey = null;
1047 String currKey = null;
1048 Object currFeature = null;
1049
1050
1051 while (rs.next()) {
1052 //NOTE: because there are LOBs in the resulset
1053 //the columns should be read in the order they appear
1054 //in the query
1055 currKey = rs.getString("fk_string");
1056
1057 Long valueType = new Long(rs.getLong("ft_value_type"));
1058
1059 //we don't quite know what is the type of the NUMBER
1060 //stored in DB
1061 Object numberValue = null;
1062
1063 //for all numeric types + boolean -> read from DB as appropriate
1064 //Java object
1065 switch(valueType.intValue()) {
1066
1067 case DBHelper.VALUE_TYPE_BOOLEAN:
1068 numberValue = new Boolean(rs.getBoolean("ft_int_value"));
1069 break;
1070
1071 case DBHelper.VALUE_TYPE_FLOAT:
1072 numberValue = new Double(rs.getDouble("ft_float_value"));
1073 break;
1074
1075 case DBHelper.VALUE_TYPE_INTEGER:
1076 numberValue = new Integer(rs.getInt("ft_int_value"));
1077 break;
1078
1079 case DBHelper.VALUE_TYPE_LONG:
1080 numberValue = new Long(rs.getLong("ft_int_value"));
1081 break;
1082 }
1083
1084 //don't forget to read the rest of the current row
1085 InputStream blobValue = rs.getBinaryStream("ft_binary_value");
1086 String stringValue = rs.getString("ft_character_value");
1087
1088 switch(valueType.intValue()) {
1089
1090 case DBHelper.VALUE_TYPE_NULL:
1091 currFeature = null;
1092 break;
1093
1094 case DBHelper.VALUE_TYPE_BOOLEAN:
1095 case DBHelper.VALUE_TYPE_FLOAT:
1096 case DBHelper.VALUE_TYPE_INTEGER:
1097 case DBHelper.VALUE_TYPE_LONG:
1098 currFeature = numberValue;
1099 break;
1100
1101 case DBHelper.VALUE_TYPE_BINARY:
1102 //deserialize a java object
1103 ObjectInputStream ois = new ObjectInputStream(blobValue);
1104 currFeature = ois.readObject();
1105 ois.close();
1106 blobValue.close();
1107 break;
1108
1109 case DBHelper.VALUE_TYPE_STRING:
1110 currFeature = stringValue;
1111 break;
1112
1113 default:
1114 throw new PersistenceException("Invalid feature type found in DB, type is ["+valueType.intValue()+"]");
1115 }//switch
1116
1117 //new feature or part of an array?
1118 if (currKey.equals(prevKey) && prevKey != null) {
1119 //part of array
1120 arrFeatures.add(currFeature);
1121 }
1122 else {
1123 //add prev feature to feature map
1124
1125 //is the prev feature an array or a single object?
1126 if (arrFeatures.size() > 1) {
1127 //put a clone, because this is a temp array that will
1128 //be cleared in few lines
1129 fm.put(prevKey, new Vector(arrFeatures));
1130 }
1131 else if (arrFeatures.size() == 1) {
1132 fm.put(prevKey,arrFeatures.elementAt(0));
1133 }
1134 else {
1135 //do nothing, this is the dummy feature
1136 ;
1137 }//if
1138
1139 //now clear the array from previous fesature(s) and put the new
1140 //one there
1141 arrFeatures.clear();
1142
1143 prevKey = currKey;
1144 arrFeatures.add(currFeature);
1145 }//if
1146 }//while
1147
1148 //add the last feature
1149 if (arrFeatures.size() > 1) {
1150 fm.put(currKey,arrFeatures);
1151 }
1152 else if (arrFeatures.size() == 1) {
1153 fm.put(currKey,arrFeatures.elementAt(0));
1154 }
1155 }//try
1156 catch(SQLException sqle) {
1157 throw new PersistenceException("can't read features from DB: ["+ sqle.getMessage()+"]");
1158 }
1159 catch(IOException ioe) {
1160 throw new PersistenceException("can't read features from DB: ["+ ioe.getMessage()+"]");
1161 }
1162 catch(ClassNotFoundException cnfe) {
1163 throw new PersistenceException("can't read features from DB: ["+ cnfe.getMessage()+"]");
1164 }
1165 finally {
1166 DBHelper.cleanup(rs);
1167 DBHelper.cleanup(pstmt);
1168 }
1169
1170 return fm;
1171 }
1172
1173
1174 /**
1175 * helper method for delete()
1176 * never call it directly beause proper events will not be fired
1177 */
1178 protected void deleteDocument(Long lrId)
1179 throws PersistenceException {
1180 //0. preconditions
1181 Assert.assertNotNull(lrId);
1182
1183 PreparedStatement pstmt = null;
1184
1185 //1. delete from DB
1186 try {
1187 pstmt = this.jdbcConn.prepareStatement("select persist_delete_document(?) ");
1188 pstmt.setLong(1,lrId.longValue());
1189 pstmt.execute();
1190 }
1191 catch(SQLException sqle) {
1192 throw new PersistenceException("can't delete LR from DB: ["+ sqle.getMessage()+"]");
1193 }
1194 finally {
1195 DBHelper.cleanup(pstmt);
1196 }
1197 }
1198
1199 /**
1200 * helper method for delete()
1201 * never call it directly beause proper events will not be fired
1202 */
1203 protected void deleteCorpus(Long lrId)
1204 throws PersistenceException {
1205
1206 Long ID = (Long)lrId;
1207
1208 PreparedStatement pstmt = null;
1209
1210 try {
1211 pstmt = this.jdbcConn.prepareStatement("select persist_delete_corpus(?)");
1212 pstmt.setLong(1,ID.longValue());
1213 pstmt.execute();
1214 }
1215 catch(SQLException sqle) {
1216 throw new PersistenceException("can't delete LR from DB: ["+ sqle.getMessage()+"]");
1217 }
1218 finally {
1219 DBHelper.cleanup(pstmt);
1220 }
1221 }
1222
1223
1224 /** helper for sync() - never call directly */
1225 protected void _syncRemovedDocumentsFromCorpus(List docLRIDs, Long corpLRID)
1226 throws PersistenceException {
1227
1228 //0.preconditions
1229 Assert.assertNotNull(docLRIDs);
1230 Assert.assertNotNull(corpLRID);
1231 Assert.assertTrue(docLRIDs.size() > 0);
1232
1233 PreparedStatement pstmt = null;
1234
1235 try {
1236 pstmt = this.jdbcConn.prepareStatement("select persist_remove_doc_from_corpus(?,?)");
1237
1238 Iterator it = docLRIDs.iterator();
1239 while (it.hasNext()) {
1240 Long currLRID = (Long)it.next();
1241 pstmt.setLong(1,currLRID.longValue());
1242 pstmt.setLong(2,corpLRID.longValue());
1243 pstmt.execute();
1244 }
1245 }
1246 catch(SQLException sqle) {
1247
1248 switch(sqle.getErrorCode()) {
1249 case DBHelper.X_ORACLE_INVALID_LR :
1250 throw new PersistenceException("invalid LR supplied: no such document: ["+
1251 sqle.getMessage()+"]");
1252 default:
1253 throw new PersistenceException("can't change document data: ["+
1254 sqle.getMessage()+"]");
1255 }
1256 }
1257 finally {
1258 DBHelper.cleanup(pstmt);
1259 }
1260
1261 }
1262
1263 /**
1264 * adds document to corpus in the database
1265 * if the document is already part of the corpus nothing
1266 * changes
1267 */
1268 protected void addDocumentToCorpus(Long docID,Long corpID)
1269 throws PersistenceException,SecurityException {
1270
1271 //0. preconditions
1272 Assert.assertNotNull(docID);
1273 Assert.assertNotNull(corpID);
1274
1275 //1. check session
1276 if (null == this.session) {
1277 throw new SecurityException("session not set");
1278 }
1279
1280 if (false == this.ac.isValidSession(this.session)) {
1281 throw new SecurityException("invalid session supplied");
1282 }
1283
1284 //2. check permissions
1285 if (false == canWriteLR(corpID)) {
1286 throw new SecurityException("no write access granted to the user");
1287 }
1288
1289 if (false == canWriteLR(docID)) {
1290 throw new SecurityException("no write access granted to the user");
1291 }
1292
1293 //3. database
1294 PreparedStatement pstmt = null;
1295
1296 try {
1297 pstmt = this.jdbcConn.prepareStatement("select persist_add_document_to_corpus(?,?) ");
1298 pstmt.setLong(1,docID.longValue());
1299 pstmt.setLong(2,corpID.longValue());
1300 pstmt.execute();
1301 }
1302 catch(SQLException sqle) {
1303
1304 switch(sqle.getErrorCode()) {
1305 case DBHelper.X_ORACLE_INVALID_LR:
1306 throw new PersistenceException("invalid LR ID supplied ["+sqle.getMessage()+"]");
1307 default:
1308 throw new PersistenceException(
1309 "can't add document to corpus : ["+ sqle.getMessage()+"]");
1310 }
1311 }
1312 finally {
1313 DBHelper.cleanup(pstmt);
1314 }
1315 }
1316
1317
1318 }
|