/*******************************************************************************
* Copyright 2014 Miami-Dade County
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.sharegov.cirm.rdb;
import static org.sharegov.cirm.OWL.fullIri;
import static org.sharegov.cirm.OWL.hash;
import static org.sharegov.cirm.OWL.individual;
import static org.sharegov.cirm.OWL.objectProperty;
import static org.sharegov.cirm.OWL.ontology;
import static org.sharegov.cirm.OWL.reasoner;
import static org.sharegov.cirm.rdb.Concepts.CLOB;
import static org.sharegov.cirm.rdb.Concepts.DOUBLE;
import static org.sharegov.cirm.rdb.Concepts.INTEGER;
import static org.sharegov.cirm.rdb.Concepts.TIMESTAMP;
import static org.sharegov.cirm.rdb.Concepts.VARCHAR;
import static org.sharegov.cirm.rdb.Sql.DELETE_FROM;
import static org.sharegov.cirm.rdb.Sql.INSERT_INTO;
import static org.sharegov.cirm.rdb.Sql.UPDATE;
import static org.sharegov.cirm.utils.GenUtils.dbg;
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import mjson.Json;
import oracle.net.aso.a;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.EntityType;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyExpression;
import org.semanticweb.owlapi.model.OWLDataPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLDataRange;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLProperty;
import org.semanticweb.owlapi.model.OWLPropertyAssertionAxiom;
import org.semanticweb.owlapi.vocab.OWL2Datatype;
import org.sharegov.cirm.CirmTransaction;
import org.sharegov.cirm.OWL;
import org.sharegov.cirm.utils.GenUtils;
import org.sharegov.cirm.utils.ThreadLocalStopwatch;
/**
* RelationalStore(Base) provides methods to query and persist Business
* Ontologies in a SQL Database.
*
* There are two schemas: GENERIC and MAPPED. The GENERIC schema (aka vertical
* schema) consists of CIRM_IRI CIRM_CLASSIFICATION CIRM_OWL_OBJECT_PROPERTY
* CIRM_OWL_DATA_PROPERTY CIRM_OWL_DATA_VALUE
*
* For some owlclasses class specific tables exist, the MAPPED schema (aka
* horizontal schema). These classes are precisely defined in the county
* ontology (http://www.miamidade.goc/ontology) under:
* /Tangible/Software_Object/DBObject and subclasses. As of 2012.04.18 the
* schema has the following tables: CIRM_SR_ACTIVITY, CIRM_SR_REQUESTS,
* CIRM_SRREQ_SRACTOR, CIRM_SR_ACTOR, CIRM_MDC_ADDRESS, CIRM_SERVICE_ACTION,
* CIRM_SERVICE_CALL
*
*
*
* TODO Change CIRM_SR_REQUESTS to singular CIRM_SR_REQUEST !!
*
*
* @see org.sharegov.cirm.rdb.RelationalOWLMapper
*
* Search for hilpoldQ to find questions tom has.
*
* @author Syed Abbas, Thomas Hilpold
*/
public class RelationalStoreImpl implements RelationalStore
{
public static boolean DBG = true;
public static boolean DBGX = false;
public static boolean DBGLOCK = true;
public static boolean DBG_ALL_TRANSACTIONS_LOCK = false;
public static boolean DBG_PRE_RETRY_SLEEP = true;
public static boolean DBG_NO_CLASSIFICATION = true;
/**
* Causes the toplevel transaction to retry at least twice each time.
* Only for testing txn.
* Must never be true in production!
*/
public static boolean TEST_TXN_ALWAYS_RETRY_TWICE = false;
public static boolean TXN_CHECK_CONNECTION = true;
/**
* Absolute time limit on retries for one transaction independent of the
* number of attempted retries.
*/
public final static int TXN_MAX_RETRY_MINUTES = 60;
/**
* Pre retry sleep is calculated after 3 unsuccessful executions (2 retries)
* based on many factors before the 3rd and later retries.
* (total concurrency, execution time, et.c).
* This sets a maximum limit, imposed after calculation.
*/
public final static int TXN_MAX_PRE_RETRY_SLEEP_SECS = 10;
private static final boolean USE_SEQUENCE_FOR_IDS = true;
// private static final int AVG_WAIT_BEFORE_RETRY_MS = 500;
public static final int POOL_SIZE_INITIAL = 5;
public static final int POOL_SIZE_MAX = 50; //150 processes limit on server
public static final int POOL_CONNECTION_REUSE_COUNT_MAX = 1000;
public static final int POOL_CONNECTION_STATEMENTS_MAX = 40;
public static final boolean POOL_CONNECTION_VALIDATE_ON_BORROW = true;
public static final int POOL_CONNECTION_WAIT_TIMEOUT_SECS = 120;
public static final int POOL_CONNECTION_INACTIVE_TIMEOUT_SECS = 8 * 3600; //before it is removed from pool
public static final int POOL_CONNECTION_PREFETCH_ROWS = 50; //single db roundtrip
public static final int POOL_CONNECTION_BATCH_ROWS = 50; //single db roundtrip
/**
* Oracle supports snaphot isolation when set to serializable mode.
*/
public static int TRANSACTION_ISOLATION_LEVEL = Connection.TRANSACTION_SERIALIZABLE;
private static Logger logger = Logger.getLogger("org.sharegov.cirm.rdb");
public static final String TABLE_IRI = "CIRM_IRI";
public static final String TABLE_IRI_TYPE = "CIRM_IRI_TYPE";
public static final String VIEW_IRI = "CIRM_IRI_VIEW"; // includes IRI_TYPE
public static final String TABLE_CLASSIFICATION = "CIRM_CLASSIFICATION";
public static final String SEQUENCE = "CIRM_SEQUENCE";
public static final String USER_FRIENDLY_SEQUENCE = "CIRM_USER_FRIENDLY_SEQUENCE";
public static final String TABLE_OBJECT_PROPERTY = "CIRM_OWL_OBJECT_PROPERTY";
public static final String TABLE_DATA_PROPERTY = "CIRM_OWL_DATA_PROPERTY";
public static final String TABLE_DATA_VALUE_CLOB = "CIRM_OWL_DATA_VAL_CLOB";
public static final String TABLE_DATA_VALUE_DATE = "CIRM_OWL_DATA_VAL_DATE";
public static final String TABLE_DATA_VALUE_DOUBLE = "CIRM_OWL_DATA_VAL_DOUBLE";
public static final String TABLE_DATA_VALUE_INTEGER = "CIRM_OWL_DATA_VAL_INTEGER";
public static final String TABLE_DATA_VALUE_STRING = "CIRM_OWL_DATA_VAL_STRING";
public static final String VIEW_DATA_PROPERTY = "CIRM_DATA_PROPERTY_VIEW";
public static final String VIEW_DATA_PROPERTY_VALUE = "CIRM_DATA_PROP_VALUE_VIEW";
public static final int MAX_VARCHAR_SIZE = 4000;
public static final int VALUE_VARCHAR_SIZE = 255;
// public static final int MAX_INCLAUSE_SIZE = 1000; // oracle limits sql
// in() list to 1000 entries, see ORA-01795, so paging technique used.
// private String url;
// private String username;
// private String password;
private DataSourceRef dataSourceRef = null;
//private volatile DataSource dataSource;
private volatile DBLockStrategy lockingStrategy;
private DatatypeFactory xmlDatatypeFactory;
// private NumberFormat doubleFormat = NumberFormat.getNumberInstance();
// private NumberFormat integerFormat = NumberFormat.getIntegerInstance();
private Map<String, Long> iriTypes = null;
private int currentLocalID = 1000; // Used if USE_SEQUENCE IS OFF
public RelationalStoreImpl()
{
// this("jdbc:oracle:thin:@10.9.25.27:1521:xe",
// "oracle.jdbc.OracleDriver", "cirmschm", "cirmschm");
try
{
xmlDatatypeFactory = DatatypeFactory.newInstance();
}
catch (DatatypeConfigurationException e)
{
throw new RuntimeException("Failed to create xmlDataFactory", e);
}
lockingStrategy = new SimpleDBLockStrategy();
}
// public RelationalStoreImpl(String url, String driverClassName, String username,
// String password)
// {
// this.url = url;
// this.username = username;
// this.password = password;
// }
public RelationalStoreImpl(DataSourceRef dataSourceRef)
{
this();
this.dataSourceRef = dataSourceRef;
}
public Connection createNewDatabaseConnection()
{
try
{
return dataSourceRef.resolve().getConnection();
// if (dataSource == null)
// {
// synchronized (RelationalStoreImpl.class)
// {
// if (dataSource == null)
// {
// if (USE_CONNECTION_POOL)
// {
// dataSource = createPoolDatasource();
// } else
// {
// dataSource = createDatasource();
// }
// System.out
// .println("Connection transaction isolation level: "
// + TRANSACTION_ISOLATION_LEVEL);
// }
//
// }
// }
// return dataSource.getConnection();
}
catch (SQLException ex)
{
throw new RuntimeException(ex);
}
}
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#getConnection()
*/
//@Override
public ThreadLocalConnection getConnection()
{
if(CirmTransaction.get() == null)
{
System.err.println("RelationalStore: Error: getConnection was called outside of any transaction !");
//TODO throw this after detecting all problems in existing code.
new Exception().printStackTrace();
}
ThreadLocalConnection conn = ThreadLocalConnection.getThreadLocalConnection();
if (conn == null)
{
try
{
// if (dataSource == null)
// {
// synchronized (this)
// {
// if (dataSource == null)
// {
// if (USE_CONNECTION_POOL)
// {
// dataSource = createPoolDatasource();
// System.out.println("Data source acquired: " + dataSource);
// } else
// {
// dataSource = createDatasource();
// }
// System.out
// .println("Connection transaction isolation level: "
// + TRANSACTION_ISOLATION_LEVEL);
// }
//
// }
// }
Connection toBeWrapped = dataSourceRef.resolve().getConnection();
// if (dataSource instanceof PoolDataSource)
// {
// PoolDataSource pds = (PoolDataSource) dataSource;
// if ((POOL_SIZE_MAX - pds.getBorrowedConnectionsCount()) < 5)
// {
// System.err.println("PoolDataSource - LESS THAN 5 CONNECTIONS AVAILABLE");
// //DBGUtils.printPoolDataSourceInfo(pds);
// }
// }
if (toBeWrapped.getHoldability() == ResultSet.HOLD_CURSORS_OVER_COMMIT)
{
// System.out.println("HOLD CURSORS ON COMMIT WAS DEFAULT. CHANGING TO CLOSE ON COMMIT.");
toBeWrapped.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
}
// Snapshot Isolation MVCC for Oracle?
if (toBeWrapped.getTransactionIsolation() != TRANSACTION_ISOLATION_LEVEL)
{
toBeWrapped.setTransactionIsolation(TRANSACTION_ISOLATION_LEVEL);
}
if (toBeWrapped.getAutoCommit())
{ // TODO THIS COMMITS THE TRANSACTION !!!!! THINK OF THE POOL!
toBeWrapped.setAutoCommit(false);
}
// create a full functioning war
conn = ThreadLocalConnection.createThreadLocalConnectionTopLevel(toBeWrapped);
} catch (SQLException sex)
{
System.err.println(sex.toString());
sex.printStackTrace();
throw new RuntimeException(sex);
}
}
try
{
if (conn.isClosed())
throw new IllegalStateException();
} catch (SQLException e)
{
e.printStackTrace();
}
return conn;
}
/**
*
* @throws SQLException
*/
// private PoolDataSource createPoolDatasource() throws SQLException
// {
// String poolName = "Cirm UCP Pool for " + this.getClass().getSimpleName();
// PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
// pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
// pds.setURL(url);
// pds.setUser(username);
// pds.setPassword(password);
// pds.setConnectionPoolName(poolName);
// pds.setInitialPoolSize(POOL_SIZE_INITIAL);
// pds.setMinPoolSize(POOL_SIZE_INITIAL);
// pds.setMaxPoolSize(POOL_SIZE_MAX);
// pds.setMaxConnectionReuseCount(POOL_CONNECTION_REUSE_COUNT_MAX);
// //Sets implicit statement cache on all pooled connections
// pds.setMaxStatements(POOL_CONNECTION_STATEMENTS_MAX);
// pds.setValidateConnectionOnBorrow(POOL_CONNECTION_VALIDATE_ON_BORROW);
// //How long to wait if a conn is not available
// pds.setConnectionWaitTimeout(POOL_CONNECTION_WAIT_TIMEOUT_SECS);
// //How many secs to wait until a pooled and unused connection is removed from pool
// // 8 h
// pds.setInactiveConnectionTimeout(POOL_CONNECTION_INACTIVE_TIMEOUT_SECS);
// Properties connectionProperties = new Properties();
// connectionProperties.setProperty("defaultRowPrefetch", "" + POOL_CONNECTION_PREFETCH_ROWS);
// connectionProperties.setProperty("defaultBatchValue", "" + POOL_CONNECTION_BATCH_ROWS);
// pds.setConnectionProperties(connectionProperties);
// System.out.println("ORACLE POOL DATA SOURCE : ");
// System.out.println("DB URL : " + url);
// try {
// Connection testConn = pds.getConnection();
// testConn.close();
// } catch (Exception e)
// {
// ThreadLocalStopwatch.getWatch().time("POOL DATA SOURCE: FAILED TO GET A TEST CONNECTION FROM POOL!\r\n Exception was: ");
// e.printStackTrace();
// System.err.print("Attemting to destroy the failing pool \"" + poolName + "\"...");
// try
// {
// UniversalConnectionPoolManager pm = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();
// pm.destroyConnectionPool(poolName);
// System.err.println("Succeeded.");
// } catch (UniversalConnectionPoolException e1)
// {
// System.err.println("Failed. Exception on failing to destroy pool was:");
// e1.printStackTrace();
// }
// throw new RuntimeException(e);
// }
// DBGUtils.printPoolDataSourceInfo(pds);
// return pds;
// }
//
// /**
// * Gets a pooled connection with auto commit disabled.
// *
// * @return
// * @throws SQLException
// */
// private OracleDataSource createDatasource() throws SQLException
// {
// OracleDataSource ods = new OracleDataSource();
// ods.setURL(url);
// ods.setUser(username);
// ods.setPassword(password);
// // FOR DEBUGGING DB ods.setLogWriter(new PrintWriter(System.out));
// // hilpold maybe use: ods.setConnectionCachingEnabled(arg0);
// // ods.setExplicitCachingEnabled(arg0);
// // ods.setConnectionCacheProperties(arg0);;
// // ods.setImplicitCachingEnabled(arg0);
// // ods.setConnectionProperties(arg0);
// System.out.println("Oracle Datasource created : ");
// System.out.println("ConnectionCachingEnabled : "
// + ods.getConnectionCachingEnabled());
// System.out.println("ConnectionCacheProperties : "
// + ods.getConnectionCacheProperties());
// System.out.println("ImplicitCachingEnabled : "
// + ods.getImplicitCachingEnabled());
// System.out.println("ExplicitCachingEnabled : "
// + ods.getExplicitCachingEnabled());
// System.out.println("MaxStatements : "
// + ods.getMaxStatements());
// return ods;
// }
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#nextSequenceNumber()
*/
//@Override
public long nextSequenceNumber()
{
return txn(new CirmTransaction<Long>() {
public Long call()
{
Connection conn = getConnection();
try
{
long nextId = dataSourceRef.getHook().nextSequence(conn, SEQUENCE);
conn.commit();
return nextId;
}
catch (SQLException e)
{
rollback(conn);
e.printStackTrace();
throw new RuntimeException(e);
}
finally
{
DBU.close(conn, null, null);
}
}});
}
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#nextUserFriendlySequenceNumber()
*/
//@Override
public long nextUserFriendlySequenceNumber()
{
Connection conn = getConnection();
try
{
long nextId = dataSourceRef.getHook().nextSequence(conn, USER_FRIENDLY_SEQUENCE);
conn.commit();
return nextId;
}
catch (SQLException e)
{
rollback(conn);
e.printStackTrace();
throw new RuntimeException(e);
}
finally
{
DBU.close(conn, null, null);
}
}
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#nextUserFriendlySequenceNumber()
*/
//@Override
public void resetUserFriendlySequenceNumber()
{
Connection conn = getConnection();
try
{
dataSourceRef.getHook().resetSequence(conn, USER_FRIENDLY_SEQUENCE);
conn.commit();
}
catch (SQLException e)
{
rollback(conn);
e.printStackTrace();
throw new RuntimeException(e);
}
finally
{
DBU.close(conn, null, null);
}
}
// -------------------------------------------------------------------------
// VERTICAL SCHEMA TIP METHODS
//
/**
* Returns all IDs and relevant Entities from the given ontology. This
* includes: A) Classes, Individuals, ObjectProperties, DataProperties in
* the Signature of the given ontology. B) Datatypes in the signature or
* importclosure of the ontology.
*
* @throws a
* RuntimeException, with any occuring SQLException as cause.
*/
public Map<OWLEntity, DbId> selectIDsAndEntitiesByIRIs(OWLOntology ontology,
DbId boObj,
boolean insertIfMissing)
{
Map<OWLEntity, DbId> result;
Set<OWLEntity> entities = new HashSet<OWLEntity>();
entities.addAll(ontology.getClassesInSignature());
// Do not try to load id or insert already known boObj
Set<OWLNamedIndividual> namedIndividuals = ontology.getIndividualsInSignature();
if (boObj != null)
namedIndividuals.remove(boObj.getSecond());
entities.addAll(namedIndividuals);
entities.addAll(ontology.getObjectPropertiesInSignature());
entities.addAll(ontology.getDataPropertiesInSignature());
// 2013.01.24 hilpold OLD:
// entities.addAll(ontology.getDatatypesInSignature(true));
entities.addAll(ontology.getDatatypesInSignature(false));
result = selectInsertIDsAndEntitiesByIRIs(entities, insertIfMissing);
// Add already known and guaranteed to be inserted boObj
if (boObj != null)
result.put(boObj.getSecond(), boObj);
return result;
}
/**
* @throws a
* RuntimeException, with any occuring SQLException as cause.
*/
public Map<OWLEntity, DbId> selectInsertIDsAndEntitiesByIRIs(Set<? extends OWLEntity> objects, boolean insertIfMissing)
{
Connection conn = getConnection();
Map<OWLEntity, DbId> result;
// long iriCount = selectIRICount(conn);
try
{
if (dbg())
ThreadLocalStopwatch.getWatch().reset("selectInsertIDsAndEntitiesByIRIs() - start");
result = selectIDsAndEntitiesByIRIs(objects, conn, false);
if (dbg())
ThreadLocalStopwatch.getWatch().time("selectInsertIDsAndEntitiesByIRIs() - DB select to find existing IRIs");
if ((result.size() < objects.size() /* || !result.keySet().equals(objects) */) && insertIfMissing)
{
Set<OWLEntity> entitiesToInsert = new HashSet<OWLEntity>(objects);
// o.addAll(objects);
entitiesToInsert.removeAll(result.keySet());
Map<OWLEntity, DbId> insertedIDsNew = insertNewEntities(entitiesToInsert, conn);
if (dbg())
ThreadLocalStopwatch.getWatch().time("selectInsertIDsAndEntitiesByIRIs() - DB insert new IRIs");
// long iriCountPostInsert = selectIRICount(conn);
// if (iriCount + entitiesToInsert.size() != iriCountPostInsert)
// {
// System.err.println("Oracle bug detected in selectIDsAndEntitiesByIRIs: After Inserting : "
// + iriCount + entitiesToInsert.size() +
// " a select only returned: " + iriCountPostInsert);
// throw new RuntimeException(new
// SQLException("Oracle Select after Insert bug detected. Emulating cannot serialize to cause retry of whole transaction.",
// "Should close connection and retry", 8177));
// }
if (entitiesToInsert.size() != insertedIDsNew.size())
{
System.err.println("selectIDsAndEntitiesByIRIs: entitiesToInsert.size() != insertedIDsNew.size()"
+ entitiesToInsert.size()
+ " inserted(NEW): "
+ insertedIDsNew.size());
throw new IllegalStateException("Deep trouble. See log.");
}
if (dbg())
ThreadLocalStopwatch
.getWatch()
.time("selectInsertIDsAndEntitiesByIRIs() - DB select to find all IRIs (newly inserted + existing) IRIs");
// Error handling:
if (DBGX)
{
Map<OWLEntity, DbId> insertedIDs = selectIDsAndEntitiesByIRIs(entitiesToInsert, conn, true);
if (entitiesToInsert.size() != insertedIDs.size())
{
System.err
.println("selectIDsAndEntitiesByIRIs: After insert query must match size of entitiesToInsert; insert failed otherwise. To insert: "
+ entitiesToInsert.size()
+ " inserted: " + insertedIDs.size());
entitiesToInsert.removeAll(insertedIDs.keySet());
for (OWLEntity e : entitiesToInsert)
{
if (insertedIDs.keySet().contains(e))
{
System.err.print("FOUND : ");
} else
{
System.err.print("NOT FOUND: ");
}
System.err.println(" IRI: " + e.getIRI().toString()
+ " type: " + e.getEntityType());
}
}
}
result.putAll(insertedIDsNew);
}
conn.commit();
return result;
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(conn);
}
}
// /**
// * This method acquires and closes a db connection. In most situations one
// * wants to pass the connection as parameter.
// *
// * @param entitiesWithIRIs
// * @return
// */
// @Deprecated
// public Map<OWLEntity, Long> selectIDsAndEntitiesByIRIs(Set<? extends
// OWLEntity> entitiesWithIRIs)
// {
// Connection conn = getConnection();
// try
// {
// return selectIDsAndEntitiesByIRIs(entitiesWithIRIs, conn);
// }
// catch (SQLException e)
// {
// throw new RuntimeException(e);
// }
// finally
// {
// close(conn);
// }
// }
public Map<OWLEntity, DbId> selectIDsAndEntitiesByIRIs(OWLEntity entityWithIRI)
{
return selectIDsAndEntitiesByIRIs(Collections.singleton(entityWithIRI));
}
public Map<OWLEntity, DbId> selectIDsAndEntitiesByIRIs(final Set<? extends OWLEntity> entitiesWithIRIs)
{
return txn(new CirmTransaction<Map<OWLEntity, DbId>>()
{
@Override
public Map<OWLEntity, DbId> call() throws Exception
{
return selectIDsAndEntitiesByIRIsInt(entitiesWithIRIs);
}
});
}
public Map<OWLEntity, DbId> selectIDsAndEntitiesByIRIsInt(Set<? extends OWLEntity> entitiesWithIRIs)
{
Connection conn = getConnection();
try
{
Map<OWLEntity, DbId> ret = selectIDsAndEntitiesByIRIs(entitiesWithIRIs, conn);
try
{
conn.commit();
}
catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
}
return ret;
} finally
{
close(conn);
}
}
public Map<OWLEntity, DbId> selectIDsAndEntitiesByIRIs(
Set<? extends OWLEntity> entitiesWithIRIs, Connection conn)
{
return selectIDsAndEntitiesByIRIs(entitiesWithIRIs, conn, false);
}
public Map<OWLEntity, DbId> selectIDsAndEntitiesByIRIs(Set<? extends OWLEntity> entitiesWithIRIs, Connection conn, boolean shouldFindAll)
{
Map<OWLEntity, DbId> result = new HashMap<OWLEntity, DbId>(entitiesWithIRIs.size() * 2 + 1);
StringBuilder select = new StringBuilder();
select.append("SELECT ID FROM ").append(TABLE_IRI).append(" WHERE ")
.append("IRI = ? AND IRI_TYPE_ID = ? ");
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = conn.prepareStatement(select.toString());
for (OWLEntity e : entitiesWithIRIs)
{
long entityTypeID = selectIDByEntityType(e.getEntityType());
String iriStr = e.getIRI().toString();
pstmt.setString(1, iriStr);
pstmt.setLong(2, entityTypeID);
rs = pstmt.executeQuery();
if (rs.next())
{
result.put(e, new DbId(rs.getLong(1), e, true));
}
rs.close();
}
}
catch (SQLException e)
{
if (!canRetrySQL(e))
{
System.err.println("selectIDsAndEntitiesByIRIs exception " + e);
}
throw new RuntimeException(e);
}
finally
{
close(rs, pstmt);
}
if (shouldFindAll && entitiesWithIRIs.size() != result.size())
System.err.println("Not all entities found - missing were " + (entitiesWithIRIs.size() - result.size()) + " of " + entitiesWithIRIs.size());
return result;
}
// /**
// * This will find all entities of all types that match the given entities'
// IRIs.
// * e.g. if one individual x is given, it would find individual x,
// dataproperty x, class x, if it's in the Db and the IRI matches.
// * @param entitiesWithIRIs
// * @param conn
// * @param shouldFindAll
// * @return
// * @deprecated
// */
// private Map<OWLEntity, Long> selectIDsAndEntitiesByIRIsOld(Set<? extends
// OWLEntity> entitiesWithIRIs, Connection conn, boolean shouldFindAll,
// OWLDataFactory df)
// {
// Map<OWLEntity, Long> result = new LinkedHashMap<OWLEntity, Long>();
// java.sql.Statement stmt = null;
// ResultSet rs = null;
// StringBuilder select = new StringBuilder();
// //OWLDataFactory dataFactory = OWL.dataFactory();
// if (entitiesWithIRIs == null || entitiesWithIRIs.size() == 0)
// return result;
// int pageSize = 1000; // oracle limits sql in() list to 1000 entries, see
// // ORA-01795, so paging technique used.
// int pageCount = 1;
// if (entitiesWithIRIs.size() > 1000)
// pageCount = (entitiesWithIRIs.size() + pageSize - 1) / pageSize;
// try
// {
// List<OWLEntity> set = new ArrayList<OWLEntity>(entitiesWithIRIs);
// for (int g = 0; g < pageCount; g++)
// {
// select.delete(0, select.length());
// //TODO query by IRI AANNDD type
// select.append("SELECT ID, IRI, IRI_TYPE FROM ").append(VIEW_IRI).append(" WHERE ").append("IRI IN (");
// //for (int i = (g * pageSize); i < (g + 1) * pageSize && i <
// entitiesWithIRIs.size(); i++)
// // select.append("?,");
// for (int i = (g * pageSize); i < (g + 1) * pageSize && i <
// entitiesWithIRIs.size(); i++)
// select.append("'" + set.get(i).getIRI().toString() + "',");
// select.deleteCharAt(select.lastIndexOf(",")).append(")");
// stmt = conn.createStatement(); // prepareStatement(select.toString());
// if(DBG)
// {
// System.out.println(select.toString());
// }
// rs = stmt.executeQuery(select.toString());
// if (stmt.getWarnings() != null) {
// throw new IllegalStateException("" + stmt.getWarnings());
// }
// int i = 0;
// while (rs.next())
// {
// i++;
// //String iriStr =
// OWLEntity o = df.getOWLEntity(typeOf(rs.getString("IRI_TYPE")),
// IRI.create(rs.getString("IRI")));
//
// long id = rs.getLong("ID");
// if (rs.wasNull()) throw new IllegalStateException("ID was null!");
// //2012.11.08 commenting out check, because after optimization, we have 2
// with same IRI and different types:
// //if (!entitiesWithIRIs.contains(o)) {
// // throw new
// IllegalArgumentException("selectIDsAndEntitiesByIRIs: created element that's not contained in entitiesWithIRIs : "
// + o);
// //}
// //assert end
// if (result.put(o, id) != null) {
// throw new
// IllegalArgumentException("selectIDsAndEntitiesByIRIs: Inserted already existing entity into result map. Entity: "
// + o + " Id: " + id);
// }
// if (rs.getWarnings() != null) {
// System.err.println("RS warnings: " + rs.getWarnings());
// }
// }
// //2012.05.03 hilpold rs and statement need to be closed here!!
// close(rs, stmt);
// }
// if (shouldFindAll
// && entitiesWithIRIs.size() > result.size() ) {
// System.err.print("Oracle Bug detected. selectIDsAndEntitiesByIRIs NOT ALL FOUND: ");
// //System.err.println("Statement was: " + select.toString());
// System.err.println("entitiesWithIRIs.size() was: " +
// entitiesWithIRIs.size() + " result.size() was " + result.size());
// throw new
// SQLException("Oracle Select after Insert bug detected. Emulating cannot serialize exc to cause retry of whole transaction.",
// "Should close connection and retry", 8177);
// //System.err.println("Resultset had Rows: " + i);
// }
// }
// catch (SQLException e)
// {
// if (!isCannotSerializeException(e)) {
// System.err.println("selectIDsAndEntitiesByIRIs exception " + e);
// }
// throw new RuntimeException(e);
// } finally {
// close(rs, stmt);
// }
// return result;
// }
// /**
// * Inserts entities (IRI and IRIType) into IRI table generating a new ID
// for
// * each. No duplicate check is performed in this method. Caller needs to
// * make sure that entities don't have an ID assigned yet.
// *
// * Commit the connection after calling this method.
// *
// * @param entities
// * @return
// * @throws SQLException
// */
// public Map<OWLEntity, Long> insertNewEntitiesNoBatch(Set<? extends
// OWLEntity> entities, Connection conn) throws SQLException
// {
// PreparedStatement stmt = null;
// Map<OWLEntity, Long> result = new HashMap<OWLEntity,
// Long>(entities.size() * 2);
// // Connection conn = null;
// // int[] result = {};
// StringBuffer insert = new StringBuffer();
// //
// insert.append("INSERT INTO ").append(TABLE_IRI).append("(").append("ID").append(",IRI").append(", IRI_TYPE_ID")
// //
// .append(")").append("VALUES").append("(").append(SEQUENCE).append(".NEXTVAL").append(",?,?")
// // .append(")");
// insert.append("INSERT INTO ").append(TABLE_IRI).append("(").append("ID").append(",IRI").append(", IRI_TYPE_ID")
// .append(")").append("VALUES").append("(?,?,?)");
// OWLEntity curEntity = null;
// try
// {
// // conn = getConnection();
// // conn.setAutoCommit(false);
// stmt = conn.prepareStatement(insert.toString());
// Map<String,Long> iriTypes = selectIriTypesCached();
// for (OWLEntity entity : entities)
// {
// curEntity = entity;
// long entityId;
// if (USE_SEQUENCE_FOR_IDS) {
// entityId = nextSequenceNumber();
// } else {
// entityId = getNextLocalID();
// }
// stmt.setLong(1, entityId);
// String entityIRIStr = entity.getIRI().toString();
// if (entityIRIStr.isEmpty()) throw new
// IllegalArgumentException("Empty IRI String");
// stmt.setString(2, entityIRIStr);
// //This will throw an NPE if iriType not found.
// long iriTypeId = iriTypes.get(entity.getEntityType().getName());
// stmt.setLong(3, iriTypeId);
// int insertedRows = stmt.executeUpdate();
// if (insertedRows != 1) throw new
// IllegalStateException("insertedRows != 1");
// stmt.clearParameters();
// if (result.put(entity, entityId) != null) {
// throw new
// IllegalStateException("Inserting an entity that already existed.");
// }
// }
// //int[] batchResult = stmt.executeBatch();
// // for (int i = 0; i < batchResult.length; i ++) {
// // if (batchResult[i] == java.sql.Statement.EXECUTE_FAILED) {
// // throw new SQLException("Execution of batch update no: " + i + " of :"
// + batchResult.length + " failed.");
// // }
// // }
// return result;
// }
// catch (SQLException e)
// {
// // System.err.println("SQLException on executing: " + insert.toString() +
// " for entity: param 1 "
// // + curEntity.getIRI() + " param 2 " + curEntity.getEntityType());
// //e.printStackTrace();
// throw e;
// // try
// // {
// // conn.rollback();
// // }
// // catch (SQLException f)
// // {
// // f.printStackTrace();
// // }
// }
// finally
// {
// close(stmt);
// }
// }
/**
* Inserts entities (IRI and IRIType) into IRI table generating a new ID for
* each. No duplicate check is performed in this method. Caller needs to
* make sure that entities don't have an ID assigned yet.
*
* Commit the connection after calling this method.
*
* @param entities
* @return
* @throws SQLException
*/
public Map<OWLEntity, DbId> insertNewEntities(Set<? extends OWLEntity> entities, Connection conn)
throws SQLException
{
PreparedStatement stmt = null;
Map<OWLEntity, DbId> result = new HashMap<OWLEntity, DbId>(entities.size() * 2);
StringBuffer insert = new StringBuffer();
insert.append("INSERT INTO ").append(TABLE_IRI).append("(")
.append("ID").append(",IRI").append(", IRI_TYPE_ID")
.append(")").append("VALUES").append("(?,?,?)");
OWLEntity curEntity = null;
try
{
// conn = getConnection();
// conn.setAutoCommit(false);
stmt = conn.prepareStatement(insert.toString());
Map<String, Long> iriTypes = selectIriTypesCached();
for (OWLEntity entity : entities)
{
curEntity = entity;
long entityId;
if (USE_SEQUENCE_FOR_IDS)
{
entityId = nextSequenceNumber();
}
else
{
entityId = getNextLocalID();
}
stmt.setLong(1, entityId);
String entityIRIStr = entity.getIRI().toString();
if (entityIRIStr.isEmpty())
throw new IllegalArgumentException("Empty IRI String");
stmt.setString(2, entityIRIStr);
// This will throw an NPE if iriType not found.
long iriTypeId = iriTypes.get(entity.getEntityType().getName());
stmt.setLong(3, iriTypeId);
stmt.addBatch();
if (result.put(entity, new DbId(entityId, entity, false)) != null)
{
throw new IllegalStateException(
"Inserting an entity that already existed.");
}
}
int[] batchResult = stmt.executeBatch();
for (int i = 0; i < batchResult.length; i++)
{
if (batchResult[i] == java.sql.Statement.EXECUTE_FAILED)
{
throw new SQLException("Execution of batch update no: " + i
+ " of :" + batchResult.length + " failed.");
}
}
return result;
}
catch (SQLException e)
{
if (!canRetrySQL(e))
{
System.err
.println("insertNewEntities: SQLException on executing: "
+ insert.toString()
+ " for entity: param 1 "
+ curEntity.getIRI()
+ " param 2 "
+ curEntity.getEntityType());
e.printStackTrace();
//hilpold check for NPE here:
e.getNextException().printStackTrace();
}
throw e;
} finally
{
close(stmt);
}
}
public Map<OWLEntity, Long> insertNewEntitiesBatch(
Set<? extends OWLEntity> entities, Connection conn)
throws SQLException
{
PreparedStatement stmt = null;
Map<OWLEntity, Long> result = new HashMap<OWLEntity, Long>(
entities.size() * 2);
StringBuffer insert = new StringBuffer();
insert.append("INSERT INTO ").append(TABLE_IRI).append("(")
.append("ID").append(",IRI").append(", IRI_TYPE_ID")
.append(")").append("VALUES").append("(?,?,?)");
OWLEntity curEntity = null;
try
{
// conn = getConnection();
// conn.setAutoCommit(false);
stmt = conn.prepareStatement(insert.toString());
Map<String, Long> iriTypes = selectIriTypesCached();
for (OWLEntity entity : entities)
{
curEntity = entity;
long entityId;
if (USE_SEQUENCE_FOR_IDS)
{
entityId = nextSequenceNumber();
} else
{
entityId = getNextLocalID();
}
stmt.setLong(1, entityId);
String entityIRIStr = entity.getIRI().toString();
if (entityIRIStr.isEmpty())
throw new IllegalArgumentException("Empty IRI String");
stmt.setString(2, entityIRIStr);
// This will throw an NPE if iriType not found.
long iriTypeId = iriTypes.get(entity.getEntityType().getName());
stmt.setLong(3, iriTypeId);
stmt.addBatch();
if (result.put(entity, entityId) != null)
{
throw new IllegalStateException(
"Inserting an entity that already existed.");
}
}
int[] batchResult = stmt.executeBatch();
for (int i = 0; i < batchResult.length; i++)
{
if (batchResult[i] == java.sql.Statement.EXECUTE_FAILED)
{
throw new SQLException("Execution of batch update no: " + i
+ " of :" + batchResult.length + " failed.");
}
}
return result;
} catch (SQLException e)
{
if (!canRetrySQL(e))
{
System.err
.println("insertNewEntities: SQLException on executing: "
+ insert.toString()
+ " for entity: param 1 "
+ curEntity.getIRI()
+ " param 2 "
+ curEntity.getEntityType());
e.printStackTrace();
}
throw e;
} finally
{
close(stmt);
}
}
private long getNextLocalID()
{
return currentLocalID++;
}
/**
*
* @param subject
* @param identifiers
* @return
*/
public Map<OWLObjectPropertyExpression, Set<OWLIndividual>> selectObjectProperties(
OWLIndividual subject, Map<OWLEntity, DbId> identifiers,
OWLDataFactory df)
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
Map<OWLObjectPropertyExpression, Set<OWLIndividual>> result = null;
StringBuilder select = new StringBuilder();
select.append("SELECT B.IRI as PREDICATE, C.IRI as OBJECT FROM ")
.append(TABLE_OBJECT_PROPERTY)
.append(" A,")
.append(TABLE_IRI)
.append(" B,")
.append(TABLE_IRI)
.append(" C")
.append(" WHERE ")
.append("SUBJECT =")
.append("? AND A.PREDICATE = B.ID AND A.OBJECT = C.ID AND TO_DATE IS NULL ORDER BY A.PREDICATE");
DbId s = identifiers.get(subject.asOWLNamedIndividual());
if (s == null)
{
throw new IllegalArgumentException(
"Subject not contained in identifiers' map : " + subject);
}
conn = getConnection();
try
{
stmt = conn.prepareStatement(select.toString());
stmt.setLong(1, s.getFirst());
rs = stmt.executeQuery();
// OWLDataFactory factory = OWL.dataFactory();
result = new HashMap<OWLObjectPropertyExpression, Set<OWLIndividual>>();
while (rs.next())
{
OWLObjectProperty predicate = df.getOWLObjectProperty(IRI
.create(rs.getString("PREDICATE")));
OWLIndividual object = df.getOWLNamedIndividual(IRI.create(rs
.getString("OBJECT")));
if (result.containsKey(predicate))
result.get(predicate).add(object);
else
{
Set<OWLIndividual> v = new HashSet<OWLIndividual>();
v.add(object);
result.put(predicate, v);
}
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
return result;
}
// //Used by MessageManager only
// public Map<OWLDataPropertyExpression, Set<OWLLiteral>>
// selectDataProperties(OWLIndividual subject)
// {
// Set<OWLEntity> s = new HashSet<OWLEntity>();
// s.add(subject.asOWLNamedIndividual());
// Map<OWLEntity, Long> identifiers = selectIDsAndEntitiesByIRIs(s, true);
// return selectDataProperties(subject, identifiers);
// }
public Map<OWLDataPropertyExpression, Set<OWLLiteral>> selectDataProperties(
OWLIndividual subject,
Map<OWLEntity, DbId> identifiers,
OWLDataFactory df)
{
return selectDataProperties(subject, null, identifiers, df);
}
/**
*
* @param subject
* @param version
* may be null, would return most current.
* @param identifiers
* @return
*/
public Map<OWLDataPropertyExpression, Set<OWLLiteral>> selectDataProperties(
OWLIndividual subject, Date version,
Map<OWLEntity, DbId> identifiers, OWLDataFactory df)
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
Map<OWLDataPropertyExpression, Set<OWLLiteral>> result = null;
StringBuffer select = new StringBuffer();
select.append("SELECT PREDICATE_IRI, DATATYPE_IRI")
.append(",VALUE_VARCHAR").append(",VALUE_CLOB")
.append(",VALUE_DATE").append(",VALUE_DOUBLE")
.append(",VALUE_INTEGER").append(",VALUE_VARCHAR_LONG")
.append(" FROM ").append("").append(VIEW_DATA_PROPERTY_VALUE)
.append(" WHERE ").append(" SUBJECT =").append("? "); // / ORDER
// BY
// A.PREDICATE;
if (version != null)
{
select.append(" AND FROM_DATE <= ? ").append(
"AND (TO_DATE >= ? or TO_DATE is null) ");
}
else
{
select.append("AND TO_DATE is null");
}
try
{
Long s = identifiers.get(subject.asOWLNamedIndividual()).getFirst();
if (s == null)
{
throw new IllegalArgumentException(
"Subject not contained in identifiers: " + subject);
}
conn = getConnection();
stmt = conn.prepareStatement(select.toString());
// System.out.println(select.toString());
stmt.setLong(1, s);
if (version != null)
{
Timestamp t = new Timestamp(version.getTime());
stmt.setTimestamp(2, t);
stmt.setTimestamp(3, t);
}
rs = stmt.executeQuery();
// OWLDataFactory factory = OWL.dataFactory();
result = new HashMap<OWLDataPropertyExpression, Set<OWLLiteral>>();
while (rs.next())
{
OWLDataProperty predicate = df.getOWLDataProperty(IRI.create(rs
.getString(1)));
String datatypeIRI = rs.getString("DATATYPE_IRI");
// String lang = rs.getString("LANG");
OWL2Datatype datatype = OWL2Datatype.getDatatype(IRI
.create(datatypeIRI));
OWLLiteral literal = literal(df, rs, datatype);
Set<OWLLiteral> predicateLiterals = result.get(predicate);
if (predicateLiterals == null)
{
predicateLiterals = new HashSet<OWLLiteral>();
result.put(predicate, predicateLiterals);
}
predicateLiterals.add(literal);
}
conn.commit();
}
catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
}
finally
{
close(rs, stmt, conn);
}
return result;
}
public Set<OWLClass> selectClass(OWLIndividual subject,
Map<OWLEntity, DbId> identifiers,
OWLDataFactory df)
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
Set<OWLClass> result = null;
StringBuffer select = new StringBuffer();
select.append("SELECT B.IRI as CLASSIRI FROM ")
.append(TABLE_CLASSIFICATION).append(" A,").append(TABLE_IRI)
.append(" B").append(" WHERE ").append("SUBJECT =")
// .append("? AND A.OWLCLASS = B.ID AND TO_DATE IS NULL ORDER BY A.OWLCLASS");
.append("? AND A.OWLCLASS = B.ID AND TO_DATE IS NULL ");
try
{
Long s = identifiers.get(subject.asOWLNamedIndividual()).getFirst();
if (s == null)
{
if (DBG_NO_CLASSIFICATION) ThreadLocalStopwatch.getWatch().time("RelationalStoreImpl::selectClass null identifier for " + subject + " empty set returned");
return Collections.emptySet();
}
conn = getConnection();
stmt = conn.prepareStatement(select.toString());
stmt.setLong(1, s);
rs = stmt.executeQuery();
// OWLDataFactory factory = OWL.dataFactory();
result = new HashSet<OWLClass>();
while (rs.next())
{
OWLClass cl = df.getOWLClass(IRI.create(rs
.getString("CLASSIRI")));
result.add(cl);
}
conn.commit();
}
catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
}
finally
{
close(rs, stmt, conn);
}
return result;
}
// -------------------------------------------------------------------------
// SELECT FROM VERTICAL SCHEMA HISTORY METHODS
//
public Map<OWLObjectPropertyExpression, Set<OWLIndividual>> selectObjectProperties(
OWLIndividual subject, Date version,
Map<OWLEntity, DbId> identifiers, OWLDataFactory df)
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
Map<OWLObjectPropertyExpression, Set<OWLIndividual>> result = null;
StringBuffer select = new StringBuffer();
select.append("SELECT B.IRI as PREDICATE, C.IRI as OBJECT FROM ")
.append(TABLE_OBJECT_PROPERTY).append(" A, ").append(TABLE_IRI)
.append(" B, ").append(TABLE_IRI).append(" C ")
.append(" WHERE ")
.append("SUBJECT = ? ")
.append("AND A.FROM_DATE <= ? ")
// hilpoldQ could this return two rows? if [t1 <= t <= t2]
.append("AND (A.TO_DATE >= ? or A.TO_DATE is null) ")
.append("AND A.PREDICATE = B.ID ")
.append("AND A.OBJECT = C.ID");
try
{
Long s = identifiers.get(subject.asOWLNamedIndividual()).getFirst();
conn = getConnection();
stmt = conn.prepareStatement(select.toString());
stmt.setLong(1, s);
Timestamp t = new Timestamp(version.getTime());
stmt.setTimestamp(2, t);
stmt.setTimestamp(3, t);
rs = stmt.executeQuery();
// OWLDataFactory factory = OWL.dataFactory();
result = new HashMap<OWLObjectPropertyExpression, Set<OWLIndividual>>();
while (rs.next())
{
OWLObjectProperty predicate = df.getOWLObjectProperty(IRI
.create(rs.getString("PREDICATE")));
OWLIndividual object = df.getOWLNamedIndividual(IRI.create(rs
.getString("OBJECT")));
if (result.containsKey(predicate))
result.get(predicate).add(object);
else
{
Set<OWLIndividual> v = new HashSet<OWLIndividual>();
v.add(object);
result.put(predicate, v);
}
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
return result;
}
public Set<OWLClass> selectClass(OWLIndividual subject, Date version,
Map<OWLEntity, DbId> identifiers, OWLDataFactory df)
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
Set<OWLClass> result = null;
StringBuffer select = new StringBuffer();
select.append("SELECT B.IRI as CLASSIRI ").append("FROM ")
.append(TABLE_CLASSIFICATION).append(" A, ").append(TABLE_IRI)
.append(" B ").append("WHERE ").append("SUBJECT = ? ")
.append("AND A.FROM_DATE <= ? ")
.append("AND (A.TO_DATE >= ? or A.TO_DATE is null) ")
.append("AND A.OWLCLASS = B.ID");
try
{
Long s = identifiers.get(subject.asOWLNamedIndividual()).getFirst();
if (s == null)
{
if (DBG_NO_CLASSIFICATION) ThreadLocalStopwatch.getWatch().time("RelationalStoreImpl::selectClassV null identifier for " + subject + " empty set returned");
return Collections.emptySet();
}
conn = getConnection();
stmt = conn.prepareStatement(select.toString());
stmt.setLong(1, s);
Timestamp t = new Timestamp(version.getTime());
stmt.setTimestamp(2, t);
stmt.setTimestamp(3, t);
rs = stmt.executeQuery();
// OWLDataFactory factory = OWL.dataFactory();
result = new HashSet<OWLClass>();
while (rs.next())
{
OWLClass cl = df.getOWLClass(IRI.create(rs
.getString("CLASSIRI")));
result.add(cl);
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
return result;
}
/**
* Searches all 3 tables - CIRM_OWL_DATA_PROPERTY, CIRM_OWL_OBJECT_PROPERTY,
* CIRM_CLASSIFICATION and returns the list of unique FROM_DATEs for a given
* individual.
*/
public List<Date> selectIndividualHistory(long subject)
{
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
StringBuilder select = new StringBuilder();
select.append("select distinct(FROM_DATE) from CIRM_OWL_DATA_PROPERTY where SUBJECT = ? union "
+ "select distinct(FROM_DATE) from CIRM_OWL_OBJECT_PROPERTY where SUBJECT = ? union "
+ "select distinct(FROM_DATE) from CIRM_CLASSIFICATION where SUBJECT = ? ");
List<Date> dates = new ArrayList<Date>();
try
{
conn = getConnection();
stmt = conn.prepareStatement(select.toString());
stmt.setLong(1, subject);
stmt.setLong(2, subject);
stmt.setLong(3, subject);
rs = stmt.executeQuery();
while (rs.next())
{
dates.add(rs.getTimestamp(1));
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
return dates;
}
public List<Long> getServiceRequestList()
{
List<Long> result = new ArrayList<Long>();
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
StringBuilder select = new StringBuilder(
"SELECT SR_REQUEST_ID FROM CIRM_SR_REQUESTS");
try
{
conn = getConnection();
stmt = conn.prepareStatement(select.toString());
rs = stmt.executeQuery();
while (rs.next())
{
result.add(rs.getLong(1));
}
conn.commit();
} catch (Exception e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
return result;
}
// -------------------------------------------------------------------------
// DELETE FROM VERTICAL SCHEMA
//
/**
* Expires the given OWLClassAssertionAxioms without removing their history.
*
* @param set
* @param individuals
* @param identifiers
* @throws SQLException
*/
public void deleteClassification(Set<OWLClassAssertionAxiom> set,
Set<OWLNamedIndividual> individuals,
Map<OWLEntity, DbId> identifiers) throws SQLException
{
// TODO hilpold: set is not used????
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
StringBuffer update = new StringBuffer();
update.append("UPDATE ").append(TABLE_CLASSIFICATION)
.append(" SET TO_DATE= ? ")
.append("WHERE SUBJECT = ? AND TO_DATE IS NULL");
try
{
conn = getConnection();
Timestamp now = new Timestamp(getStoreTimeInt().getTime());
stmt = conn.prepareStatement(update.toString());
for (OWLNamedIndividual i : individuals)
{
Long s = identifiers.get(i).getFirst();
stmt.setTimestamp(1, now);
stmt.setLong(2, s);
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
}
public void deleteClassificationWithHistory(
Set<OWLClassAssertionAxiom> axioms, Map<OWLEntity, Long> identifiers)
throws SQLException
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
StringBuffer deleteH = new StringBuffer();
deleteH.append("DELETE FROM ").append(TABLE_CLASSIFICATION)
.append(" WHERE SUBJECT = ? ");
try
{
conn = getConnection();
stmt = conn.prepareStatement(deleteH.toString());
for (OWLClassAssertionAxiom axiom : axioms)
{
OWLNamedIndividual subject = axiom.getIndividual()
.asOWLNamedIndividual();
Long subjectId = identifiers.get(subject);
if (subjectId == null)
throw new IllegalArgumentException(
"Subject from ClassAssertionAxiom " + axiom
+ " was not found in identifiers (size: "
+ identifiers.size());
stmt.setLong(1, subjectId);
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
}
/**
* Expires the given OWLDataPropertyAssertionAxiom without removing their
* history.
*
* @param axioms
* @param individuals
* @param identifiers
* @throws SQLException
*/
public void deleteDataProperties(Set<OWLDataPropertyAssertionAxiom> axioms,
Set<OWLNamedIndividual> individuals,
Map<OWLEntity, DbId> identifiers) throws SQLException
{
PreparedStatement stmt = null;
Connection conn = null;
StringBuffer update = new StringBuffer();
update.append("UPDATE ").append(TABLE_DATA_PROPERTY)
.append(" SET TO_DATE= ? ")
.append("WHERE SUBJECT = ? AND TO_DATE IS NULL");
try
{
conn = getConnection();
Timestamp now = new Timestamp(getStoreTimeInt().getTime());
stmt = conn.prepareStatement(update.toString());
for (OWLNamedIndividual i : individuals)
{
Long s = identifiers.get(i).getFirst();
stmt.setTimestamp(1, now);
stmt.setLong(2, s);
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(stmt, conn);
}
}
public void deleteDataPropertiesWithHistory(
Set<OWLDataPropertyAssertionAxiom> axioms,
Map<OWLEntity, Long> identifiers) throws SQLException
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
StringBuffer deleteH = new StringBuffer();
deleteH.append("DELETE FROM ").append(TABLE_DATA_PROPERTY)
.append(" WHERE SUBJECT = ? ");
try
{
conn = getConnection();
stmt = conn.prepareStatement(deleteH.toString());
for (OWLDataPropertyAssertionAxiom axiom : axioms)
{
OWLNamedIndividual subject = axiom.getSubject()
.asOWLNamedIndividual();
// get allrows for subject
Long subjectId = identifiers.get(subject);
if (subjectId == null)
throw new IllegalArgumentException(
"Subject from OWLDataPropertyAssertionAxiom "
+ axiom
+ " was not found in identifiers (size: "
+ identifiers.size());
stmt.setLong(1, subjectId);
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
}
/**
* Expires the given OWLObjectPropertyAssertionAxiom without removing their
* history.
*
* @param axioms
* @param individuals
* @param identifiers
* @throws SQLException
*/
public void deleteObjectProperties(
Set<OWLObjectPropertyAssertionAxiom> axioms,
Set<OWLNamedIndividual> individuals,
Map<OWLEntity, DbId> identifiers) throws SQLException
{
PreparedStatement stmt = null;
ResultSet rs = null;
Connection conn = getConnection();
// sets all active object properties as expired, including those outside
// the map.
StringBuffer update = new StringBuffer();
update.append("UPDATE ").append(TABLE_OBJECT_PROPERTY)
.append(" SET TO_DATE= ? ")
.append("WHERE SUBJECT = ? AND TO_DATE IS NULL");
try
{
Timestamp now = new Timestamp(getStoreTimeInt().getTime());
stmt = conn.prepareStatement(update.toString());
for (OWLNamedIndividual i : individuals)
{
Long s = identifiers.get(i).getFirst();
stmt.setTimestamp(1, now);
stmt.setLong(2, s);
stmt.addBatch();
}
stmt.executeBatch();
}
catch (SQLException e)
{
rollback(conn);
throw e;
}
finally
{
close(rs, stmt, conn);
}
}
public void deleteObjectPropertiesWithHistory(
Set<OWLObjectPropertyAssertionAxiom> axioms,
Map<OWLEntity, Long> identifiers) throws SQLException
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
StringBuffer deleteH = new StringBuffer();
deleteH.append("DELETE FROM ").append(TABLE_OBJECT_PROPERTY)
.append(" WHERE SUBJECT = ? ");
try
{
conn = getConnection();
stmt = conn.prepareStatement(deleteH.toString());
for (OWLObjectPropertyAssertionAxiom axiom : axioms)
{
OWLNamedIndividual subject = axiom.getSubject()
.asOWLNamedIndividual();
// get allrows for subject
Long subjectId = identifiers.get(subject);
if (subjectId == null)
throw new IllegalArgumentException(
"Subject from OWLObjectPropertyAssertionAxiom "
+ axiom
+ " was not found in identifiers (size: "
+ identifiers.size());
stmt.setLong(1, subjectId);
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
}
// @Deprecated
// public Set<OWLNamedIndividual>
// deleteMappedOntologyIndividuals(OWLOntology ontology,
// Map<OWLEntity, Long> identifiers)
// {
// Connection conn = getConnection();
// try
// {
// Set<OWLNamedIndividual> result =
// deleteMappedOntologyIndividuals(ontology, identifiers, conn);
// conn.commit();
// return result;
// }
// catch (SQLException e)
// {
// try
// {
// conn.rollback();
// }
// catch (SQLException e1)
// {
// e1.printStackTrace();
// }
// throw new RuntimeException(e);
// }
// finally
// {
// close(conn);
// }
// }
/**
* DELETE MAPPED. This is currently not working because of foreign key
* constraints. The individuals need at least be ordered by type.
*
* @param ontology
* @param identifiers
* @return
* @throws SQLException
*/
public Set<OWLNamedIndividual> deleteMappedOntologyIndividuals(
OWLOntology ontology, Map<OWLEntity, DbId> identifiers)
throws SQLException
{
Connection conn = getConnection();
Set<OWLNamedIndividual> done = new HashSet<OWLNamedIndividual>();
List<Statement> statements = new ArrayList<Statement>(
ontology.getAxiomCount());
for (OWLNamedIndividual i : ontology.getIndividualsInSignature())
{
if (!done.contains(i)
&& RelationalOWLMapper.isMapped(i.getTypes(ontology)))
{
addDeleteStatementsForMappedIndividualRecursive(statements,
ontology, i, identifiers, done);
}
}
try
{
execute(statements, identifiers, conn);
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(conn);
}
return done;
}
/**
* Will be called recursively.
*
* @param statements
* a list to add delete statements to.
* @param o
* @param ind
* @param identifiers
* @param done
*/
private void addDeleteStatementsForMappedIndividualRecursive(
List<Statement> statements, OWLOntology o, OWLIndividual ind,
Map<OWLEntity, DbId> identifiers, Set<OWLNamedIndividual> done)
{
Statement s = new Statement();
OWLNamedIndividual table = RelationalOWLMapper.table(ind.getTypes(o));
if (table != null)
{
Sql sql = DELETE_FROM(table.getIRI().getFragment());
// add mapped properties
Set<OWLNamedIndividual> columnIRI = RelationalOWLMapper
.columnIriPK(table);
// add iri value
OWLNamedIndividual column = null;
if (!columnIRI.isEmpty())
{
column = columnIRI.iterator().next();
sql.WHERE(column.getIRI().getFragment()).EQUALS("?");
s.getParameters().add(identifiers.get(ind));
Set<OWLIndividual> columnType = column.getObjectPropertyValues(
objectProperty(fullIri(Concepts.hasColumnType)),
ontology());
s.getTypes().add(
columnType.iterator().next().asOWLNamedIndividual());
}
Map<OWLObjectPropertyExpression, Set<OWLIndividual>> objectPropertyValues = ind
.getObjectPropertyValues(o);
// hasMany
Map<OWLObjectProperty, OWLClass> hasMany = RelationalOWLMapper
.hasMany(objectPropertyValues.keySet());
for (OWLObjectProperty mappedProperty : hasMany.keySet())
{
OWLClass hasManyMappedClass = hasMany.get(mappedProperty);
boolean deleted = false;
for (OWLIndividual prop : objectPropertyValues
.get(mappedProperty))
{
OWLNamedIndividual manyTable = RelationalOWLMapper
.table(hasManyMappedClass);
OWLNamedIndividual joinTable = RelationalOWLMapper.join(
table, manyTable);
OWLNamedIndividual manyObject = prop.asOWLNamedIndividual();
if (joinTable == null)
continue;
boolean manyToMany = !joinTable.equals(manyTable);
if (manyToMany)
{
OWLNamedIndividual joinColumnIRI = RelationalOWLMapper
.foreignKeyByjoinColumnAndTable(column,
joinTable);
// delete from junction table
if (!deleted)
{
Statement delete = new Statement();
delete.setSql(DELETE_FROM(
joinTable.getIRI().getFragment()).WHERE(
joinColumnIRI.getIRI().getFragment())
.EQUALS("?"));
delete.getParameters().add(identifiers.get(ind));
Set<OWLIndividual> columnType = column
.getObjectPropertyValues(
objectProperty(fullIri(Concepts.hasColumnType)),
ontology());
delete.getTypes().add(
columnType.iterator().next()
.asOWLNamedIndividual());
statements.add(delete);
deleted = true;
}
// Recursive!
addDeleteStatementsForMappedIndividualRecursive(
statements, o, manyObject, identifiers, done);
} else
{
// TODO : many-to-one
}
}
}
s.setSql(sql);
statements.add(s);
for (Map.Entry<OWLObjectPropertyExpression, Set<OWLIndividual>> mappedProperty : objectPropertyValues
.entrySet())
{
OWLObjectPropertyExpression ex = mappedProperty.getKey();
if (ex instanceof OWLObjectProperty)
{
OWLObjectProperty prop = (OWLObjectProperty) ex;
Set<OWLIndividual> set = objectPropertyValues.get(prop);
if (set.size() > 0)
{
OWLNamedIndividual entity = set.iterator().next()
.asOWLNamedIndividual();
addDeleteStatementsForMappedIndividualRecursive(
statements, o, entity, identifiers, done);
}
}
}
}
}
//
// Helper for delete only.
//
protected void execute(List<Statement> statements,
Map<OWLEntity, DbId> identifiers,
Connection conn)
throws SQLException
{
PreparedStatement stmt = null;
for (Statement s : statements)
{
stmt = prepareStatement(conn, s, identifiers);
try
{
stmt.executeUpdate();
}
catch (SQLException e)
{
if (!canRetrySQL(e))
{
System.err.println("Error executing update: " + e.toString());
printStatement(s);
System.err.println("Other Statements: ");
int i = 0;
for (Statement x : statements)
{
System.err.print("Statements: " + i);
if (x.equals(s))
{
System.err.print("This is the failing statement: " + i);
}
printStatement(x);
i ++;
}
}
throw e;
}
finally
{
close(stmt);
}
}
}
void printStatement(Statement s)
{
String sql = s.getSql().SQL();
System.out.println(sql);
int i = 0;
for (Object param : s.getParameters())
{
System.out.print("" + i + ": " + param + "|");
i++;
}
System.out.println();
i = 0;
for (OWLNamedIndividual type : s.getTypes())
{
System.out.print("" + i + ": " + type.getIRI().getFragment() + "|");
i++;
}
System.out.println();
}
//
// public long selectIRICount(Connection conn) {
// ResultSet rs = null;
// java.sql.Statement stmt = null;
// try {
// stmt = conn.createStatement();
// rs = stmt.executeQuery("SELECT COUNT(*) FROM " + VIEW_IRI);
// rs.next();
// return rs.getLong(1);
// } catch (SQLException e) {
// throw new RuntimeException(e);
// } finally {
// close(rs, stmt);
// }
//
//
// }
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#insertIri(long, java.lang.String, java.lang.String, java.sql.Connection)
*/
//@Override
public void insertIri(long n, String iri, String type, Connection conn)
throws SQLException
{
PreparedStatement stmt = null;
// Connection conn = null;
StringBuffer insert = new StringBuffer();
insert.append("INSERT INTO ").append(TABLE_IRI).append("(")
.append("ID").append(",IRI").append(", IRI_TYPE_ID")
.append(")").append("VALUES").append("(").append("?,?,?")
.append(")");
try
{
Map<String, Long> iriTypes = selectIriTypesCached();
stmt = conn.prepareStatement(insert.toString());
stmt.setLong(1, n);
stmt.setString(2, iri);
stmt.setLong(3, iriTypes.get(type));
stmt.execute();
} catch (SQLException e)
{
throw e;
} finally
{
close(stmt);
}
}
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#updateIri(long, java.lang.String, java.sql.Connection)
*/
//Override
public void updateIri(long id, String iri, Connection conn)
throws SQLException
{
PreparedStatement stmt = null;
if (iri == null)
throw new NullPointerException("new iri null for id: " + id);
StringBuffer update = new StringBuffer();
update.append("UPDATE ").append(TABLE_IRI).append(" SET IRI = ?")
.append(" WHERE ID = ?");
try
{
stmt = conn.prepareStatement(update.toString());
stmt.setString(1, iri);
stmt.setLong(2, id);
stmt.execute();
} catch (SQLException e)
{
throw e;
} finally
{
close(stmt);
}
}
public Long selectIDByEntityType(EntityType<? extends OWLEntity> et)
{
return selectIriTypesCached().get(et.getName());
}
/**
* Select the iri type from instance variable, if null looks up iri types
* from RDB.
*
* @return
*/
public Map<String, Long> selectIriTypesCached()
{
if (iriTypes == null)
{
synchronized (this)
{
if (iriTypes == null)
iriTypes = selectIriTypes();
}
}
return iriTypes;
}
public synchronized Map<String, Long> selectIriTypes()
{
boolean shouldRepeat = false;
Map<String, Long> result = null;
do
{
Connection conn = getConnection();
try
{
result = selectIriTypesInternal(conn);
if (result.size() < EntityType.values().size())
{
insertIriTypes(conn);
conn.commit();
shouldRepeat = false;
}
result = selectIriTypesInternal(conn);
if (result.size() < EntityType.values().size())
{
throw new IllegalStateException(
"Failed to insert Iri types into RDB.");
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
if (canRetrySQL(e))
shouldRepeat = true;
else
throw new RuntimeException(e);
} finally
{
close(conn);
}
} while (shouldRepeat);
return result;
}
private Map<String, Long> selectIriTypesInternal(Connection conn)
throws SQLException
{
Map<String, Long> result = new ConcurrentHashMap<String, Long>();
PreparedStatement stmt = null;
ResultSet rs = null;
StringBuffer select = new StringBuffer(100);
select.append("SELECT ID, IRI FROM ").append(TABLE_IRI_TYPE);
try
{
stmt = conn.prepareStatement(select.toString());
rs = stmt.executeQuery();
while (rs.next())
{
result.put(rs.getString("IRI"), rs.getLong("ID"));
}
} catch (SQLException e)
{
throw e;
} finally
{
close(rs, stmt);
}
return result;
}
private void insertIriTypes(Connection conn) throws SQLException
{
PreparedStatement stmt = null;
StringBuffer insert = new StringBuffer();
insert.append("INSERT INTO ").append(TABLE_IRI_TYPE).append("(")
.append("ID").append(",IRI").append(")").append("VALUES")
.append("(").append("?,?").append(")");
try
{
stmt = conn.prepareStatement(insert.toString());
stmt.setLong(1, 1);
stmt.setString(2, EntityType.CLASS.getName());
stmt.addBatch();
stmt.setLong(1, 2);
stmt.setString(2, EntityType.DATA_PROPERTY.getName());
stmt.addBatch();
stmt.setLong(1, 3);
stmt.setString(2, EntityType.DATATYPE.getName());
stmt.addBatch();
stmt.setLong(1, 4);
stmt.setString(2, EntityType.NAMED_INDIVIDUAL.getName());
stmt.addBatch();
stmt.setLong(1, 5);
stmt.setString(2, EntityType.OBJECT_PROPERTY.getName());
stmt.addBatch();
stmt.setLong(1, 6);
stmt.setString(2, EntityType.ANNOTATION_PROPERTY.getName());
stmt.addBatch();
stmt.executeBatch();
} catch (SQLException e)
{
throw e;
} finally
{
close(stmt);
}
}
// -------------------------------------------------------------------------
// VERTICAL SCHEMA AND MAPPED SCHEMA METHODS
//
/**
* Returns a set with all individuals for whom a mapping exists. The
* ontology is used. This method should be part of RelationalOWLMapper.
*/
private Set<OWLNamedIndividual> getMappedIndividualsFrom(
final OWLOntology ontology,
final Set<OWLNamedIndividual> individuals)
{
Set<OWLNamedIndividual> result = new HashSet<OWLNamedIndividual>(
individuals.size());
for (OWLNamedIndividual curIndividual : individuals)
{
if (RelationalOWLMapper.isMapped(curIndividual.getTypes(ontology)))
{
result.add(curIndividual);
}
}
return result;
}
/**
* Merge ontology into DB.
*
* @param o
* @param ind
* @param identifiers
*/
public void merge(OWLOntology ontology, DbId boObj)
{
if (dbg())
{
ThreadLocalStopwatch.getWatch().reset(
"Start merge ontology "
+ ontology.getOntologyID().getOntologyIRI());
// System.out.println("MERGING ONTOLOGY: " + ontology);
// DBGUtils.printOntologyFunctional(ontology);
}
// 0. Save time
Timestamp time = new Timestamp(getStoreTimeInt().getTime());
// 1. Get all IDs, insert if missing
Map<OWLEntity, DbId> identifiers = selectIDsAndEntitiesByIRIs(ontology, boObj, true);
if (dbg())
ThreadLocalStopwatch.getWatch().time("Done get IRIs ");
// 2. Determine mapped and unmapped individuals
Set<OWLNamedIndividual> allIndividuals = ontology.getIndividualsInSignature();
Set<OWLNamedIndividual> mappedIndividuals = getMappedIndividualsFrom(ontology, allIndividuals);
Set<OWLNamedIndividual> unmappedIndividuals = new HashSet<OWLNamedIndividual>(allIndividuals);
unmappedIndividuals.removeAll(mappedIndividuals);
// 3. Get and use only axioms, that are not mapped in the mapped schema.
Set<OWLDataPropertyAssertionAxiom> notMappedDataPropertyAssertionAxioms = getNotMappedDataPropertyAxioms(ontology);
Set<OWLObjectPropertyAssertionAxiom> notMappedObjectPropertyAssertionAxioms = getNotMappedObjectPropertyAxioms(ontology);
// 4. All class assertions will be stored (including for mapped classes)
Set<OWLClassAssertionAxiom> allClassAssertionAxioms = ontology.getAxioms(AxiomType.CLASS_ASSERTION);
// ensure all non mapped literals inserted
// Map<String, Long> literalHashToIDsNotMapped =
// selectLiterals(notMappedDataPropertyAssertionAxioms, true);
Map<Object, Long> literalValueToIDsNotMapped = selectLiteralValueIDsFromAxioms(notMappedDataPropertyAssertionAxioms, true);// Literals(notMappedDataPropertyAssertionAxioms,
// true);
if (dbg())
ThreadLocalStopwatch.getWatch().time("Done get Literal IDs ");
// TABLE: This affexets CIRM_OWL_DATA_VALU
// System.out.println(new BOntology(ontology).toJSON());
Connection conn = null;
try
{
conn = getConnection();
// conn.setAutoCommit(false);
// MERGE VERTICAL SCHEMA (Should be unmapped individuals, object and
// dataproperties only)
Map<List<Statement>, List<Statement>> mergeStatements = new LinkedHashMap<List<Statement>, List<Statement>>();
mergeStatements.putAll(mergeClassAssertions(allClassAssertionAxioms, allIndividuals, identifiers, time));
// mergeStatements.putAll(mergeClassAssertions(ontology.getAxioms(AxiomType.CLASS_ASSERTION),
// allIndividuals, identifiers));
mergeStatements.putAll(mergeDataProperties(notMappedDataPropertyAssertionAxioms,
allIndividuals,
identifiers,
literalValueToIDsNotMapped,
time));
mergeStatements.putAll(mergeObjectProperties(notMappedObjectPropertyAssertionAxioms,
allIndividuals,
identifiers,
time));
// triple store merge
for (Map.Entry<List<Statement>, List<Statement>> merge : mergeStatements.entrySet())
{
List<Statement> updates = merge.getKey();
List<Statement> inserts = merge.getValue();
if (!updates.isEmpty())
{
executeBatch(updates, identifiers, conn);
}
if (!inserts.isEmpty())
{
executeBatch(inserts, identifiers, conn);
}
}
if (dbg())
ThreadLocalStopwatch.getWatch().time("Done batch statements ");
//
// mapped tables merge
// Merge mapped will use only axioms, for which a column mapping
// exists.
// the class assertion axioms for mapped individuals don't need to
// be stores,
// as classes for mapped individuals can be derived from table and
// county ontology.
for (Map.Entry<OWLNamedIndividual, List<Statement>> entry : mergeMappedIndividuals(
ontology, identifiers).entrySet())
{
if (dbg())
logger.info("executing Statements for individual:"
+ entry.getKey());
execute(entry.getValue(), identifiers, conn);
}
if (dbg())
ThreadLocalStopwatch.getWatch().time("Done mapped statements ");
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(conn);
if (dbg())
{
ThreadLocalStopwatch.getWatch().time(
"End merge "
+ ontology.getOntologyID().getOntologyIRI());
}
}
}
/**
* Merge of all mapped individuals. hilpold this is the only method
* preparing mapped merge.
*
* @param o
* @param identifiers
*/
private Map<OWLNamedIndividual, List<Statement>> mergeMappedIndividuals(
OWLOntology ontology, Map<OWLEntity, DbId> identifiers)
{
Map<OWLNamedIndividual, List<Statement>> done = new LinkedHashMap<OWLNamedIndividual, List<Statement>>();
for (OWLNamedIndividual curIndividual : ontology.getIndividualsInSignature())
{
if (!done.containsKey(curIndividual) &&
RelationalOWLMapper.isMapped(curIndividual.getTypes(ontology)))
{
mergeMappedIndividual(ontology, curIndividual, identifiers, null, done);
}
}
return done;
}
// -------------------------------------------------------------------------
// READ MAPPED INDIVIDUAL AND ALL REFERRED INDIVIDUALS
//
// -------------------------------------------------------------------------
/**
* Reads an individual's and it's by objectproperty related individuals'
* data by reading the unmapped and -if mapped- the mapped schema and create
* axioms. It keeps track of already visited individuals for both schemas.
*
* Call this within a transaction only.
*/
void readIndividualDataRecursive(OWLOntology on, OWLNamedIndividual ind)
{
Set<OWLNamedIndividual> doneNotMapped = new HashSet<OWLNamedIndividual>();
Set<OWLNamedIndividual> doneMapped = new HashSet<OWLNamedIndividual>();
readIndividualDataNotMappedRecursive(on, ind, doneNotMapped);
readIndividualDataMappedRecursive(on, ind, doneMapped);
// Now visit those who were found during notMapped, but not during
// mapped and vice versa.
boolean hasSymmetricDifference;
do
{
Set<OWLNamedIndividual> doneNotMappedMinusMapped = new HashSet<OWLNamedIndividual>(
doneNotMapped);
Set<OWLNamedIndividual> doneMappedMinusNonMapped = new HashSet<OWLNamedIndividual>(
doneMapped);
doneNotMappedMinusMapped.removeAll(doneMapped);
doneMappedMinusNonMapped.removeAll(doneNotMapped);
hasSymmetricDifference = !(doneNotMappedMinusMapped.isEmpty() && doneMappedMinusNonMapped
.isEmpty());
if (dbg())
System.out.println("DoneNotMappedMinusMapped = "
+ doneNotMappedMinusMapped.size()
+ "; DoneMappedMinusNonMapped = "
+ doneMappedMinusNonMapped.size());
// read all axioms for individuals found during mapped, but missed
// during not mapped. (some properties might not be mapped)
for (OWLNamedIndividual stillNeedsNotMapped : doneMappedMinusNonMapped)
{
if (!doneNotMapped.contains(stillNeedsNotMapped))
{
readIndividualDataNotMappedRecursive(on,
stillNeedsNotMapped, doneNotMapped);
}
}
// read all axioms for individuals found during notMapped, but
// missed during mapped. (some properties might be mapped)
for (OWLNamedIndividual stillNeedsMapped : doneNotMappedMinusMapped)
{
if (!doneMapped.contains(stillNeedsMapped))
{
readIndividualDataMappedRecursive(on, stillNeedsMapped,
doneMapped);
}
}
} while (hasSymmetricDifference);
}
/**
* Recursively reads all axioms from the not mapped schema for all
* individuals that can be reached starting with and including the given
* individiual. doneMapped will contain every individual that was visited or
* referenced during NON mapped traversal.
*
* @param on
* an ontology to add axioms too.
* @param ind
* the start individual
* @param doneNotMapped
* will contain all individuals that were visited or referenced
* (!) after this method returns.
*/
void readIndividualDataNotMappedRecursive(OWLOntology on,
OWLNamedIndividual ind, Set<OWLNamedIndividual> doneNotMapped)
{
Set<OWLNamedIndividual> referencedIndividuals = Collections.emptySet();
if (!doneNotMapped.contains(ind))
{
doneNotMapped.add(ind);
referencedIndividuals = readIndividualDataNotMapped(on, ind);
for (OWLNamedIndividual needed : referencedIndividuals)
{
readIndividualDataNotMappedRecursive(on, needed, doneNotMapped);
}
}
}
/**
* Recursively reads all axioms from the mapped schema for all individuals
* that can be reached starting with and including the given individiual.
* 1:1, 1:*, *:* relationships will be resolved. doneMapped will contain
* every individual that was visited or referenced during mapped traversal.
*
* @param on
* @param ind
* @param doneMapped
* will contain all individuals that were visited or referenced
* (!) after this method returns.
*/
void readIndividualDataMappedRecursive(OWLOntology on,
OWLNamedIndividual ind, Set<OWLNamedIndividual> doneMapped)
{
Set<OWLNamedIndividual> referencedIndividuals = Collections.emptySet();
if (!doneMapped.contains(ind))
{
doneMapped.add(ind);
referencedIndividuals = readIndividualDataMapped(on, ind,
doneMapped);
for (OWLNamedIndividual needed : referencedIndividuals)
{
readIndividualDataMappedRecursive(on, needed, doneMapped);
}
}
}
/**
* Searches for all entities by the IRI of the given individual and adds
* OWLObjectPropertyAssertionAxioms, OWLDataPropertyAssertionAxioms,
* OWLClassAssertionAxiom the ontology with
*
* @param on
* an ontology to add axioms too.
* @param ind
* @return a set of dependent referenced individuals, which should be loaded
* next or the empty set.
*/
Set<OWLNamedIndividual> readIndividualDataNotMapped(OWLOntology on, OWLNamedIndividual ind)
{
OWLDataFactory df = on.getOWLOntologyManager().getOWLDataFactory();
// TODO hilpold THREAD SAFE DATA FACTORY needed if not onto exclusive
// and not hgdb
OWLOntologyManager manager = on.getOWLOntologyManager(); // OWL.manager();
ArrayList<OWLOntologyChange> changes = new ArrayList<OWLOntologyChange>();
Set<OWLNamedIndividual> referencedIndividuals = Collections.emptySet();
// TRANSACTION START
ThreadLocalConnection conn = getConnection();
try
{
Map<OWLEntity, DbId> identifiers = selectIDsAndEntitiesByIRIs(Collections.singleton(ind));
if (identifiers.isEmpty())
return referencedIndividuals;
Map<OWLObjectPropertyExpression, Set<OWLIndividual>> objProps =
selectObjectProperties(ind, identifiers, df);
for (Map.Entry<OWLObjectPropertyExpression, Set<OWLIndividual>> e : objProps.entrySet())
{
for (OWLIndividual propValue : e.getValue())
{
changes.add(new AddAxiom(on,
manager.getOWLDataFactory()
.getOWLObjectPropertyAssertionAxiom(e.getKey(), ind, propValue)));
if (referencedIndividuals.isEmpty())
{
referencedIndividuals = new HashSet<OWLNamedIndividual>();
}
referencedIndividuals.add((OWLNamedIndividual) propValue);
}
}
Map<OWLDataPropertyExpression, Set<OWLLiteral>> dataProps =
selectDataProperties(ind, identifiers, df);
for (Map.Entry<OWLDataPropertyExpression, Set<OWLLiteral>> e : dataProps
.entrySet())
{
for (OWLLiteral propValue : e.getValue())
changes.add(new AddAxiom(on, manager.getOWLDataFactory()
.getOWLDataPropertyAssertionAxiom(e.getKey(), ind,
propValue)));
}
Set<OWLClass> classes = selectClass(ind, identifiers, df);
for (OWLClass c : classes)
{
changes.add(new AddAxiom(on,
manager.getOWLDataFactory().getOWLClassAssertionAxiom(c, ind)));
}
manager.applyChanges(changes);
conn.commit();
return referencedIndividuals;
} catch (Exception e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(conn);
}
}
/**
* Reads the given mapped named individual and resolves all 1:1, 1:* and *:*
* relationships in which the named individual takes part.
*
* @param on
* @param ind
* @return a set of referenced individuals that have not been loaded yet or
* the empty set.
*/
public Set<OWLNamedIndividual> readIndividualDataMapped(OWLOntology onto,
OWLNamedIndividual ind, Set<OWLNamedIndividual> doneMapped)
{
Set<OWLNamedIndividual> referencedIndividuals = Collections.emptySet();
OWLClass classFromIRI = findClassInLoadedOntologiesFor(ind);
if (!RelationalOWLMapper.isMapped(classFromIRI))
{
if (dbg())
{
System.out
.println("readIndividualData called with non mapped individual: "
+ ind + "");
}
doneMapped.add(ind);
return referencedIndividuals;
}
// Assert class here? No, already done in loadunmapped.
// OWLClassAssertionAxiom clsAssAxiom =
// factory.getOWLClassAssertionAxiom(classFromIRI, ind);
// manager.applyChange(new AddAxiom(onto, clsAssAxiom));
// Find Table and read as much as possible from row
OWLNamedIndividual indTable = RelationalOWLMapper.table(classFromIRI);
Set<OWLNamedIndividual> columnIRIPKs = RelationalOWLMapper
.columnIriPK(indTable);
OWLNamedIndividual primaryKeyColumn = columnIRIPKs.iterator().next();
Map<OWLEntity, DbId> identifiers = selectIDsAndEntitiesByIRIs(ind);
long primaryKeyValue = identifiers.get(ind).getFirst();
Set<OWLNamedIndividual> referenced = readMappedIndividualSql(onto, ind,
primaryKeyValue, classFromIRI, indTable, primaryKeyColumn);
if (!referenced.isEmpty())
{
if (referencedIndividuals.isEmpty())
{
referencedIndividuals = new HashSet<OWLNamedIndividual>();
}
referencedIndividuals.addAll(referenced);
}
// onto now has all directly read axioms. referencedIndividuals need to
// be dealt with by caller, who needs to make sure
// that unmapped schema was already tried for those individuals.
// TRAVERESE RELATIONSHIPS 1:1, 1:*, *:*.
Set<Map<OWLNamedIndividual, OWLNamedIndividual>> joinTableToOtherTableMaps = RelationalOWLMapper
.joinsByTable(indTable);
if (joinTableToOtherTableMaps == null)
joinTableToOtherTableMaps = Collections.emptySet();
// for SR_Request: SR_ACTIVITY->SR_ACTIVITY, SRREQ_SRACTOR->SRACTOR, ??
for (Map<OWLNamedIndividual, OWLNamedIndividual> joinTableToOtherTable : joinTableToOtherTableMaps)
{
// Assert map exactly one entry.
Map.Entry<OWLNamedIndividual, OWLNamedIndividual> joinTableToOtherTableEntry = joinTableToOtherTable
.entrySet().iterator().next();
// 1) Get objectProperty for current relationship
// 2) Distinguish 1:1, 1:* or *:*
// 3) 1:1 -> load one row
// 3b) 1:* -> ind is one, load many (property, ind, manyTable,
// onto,)
// 3c) *:* -> SELECT * (-<JOIN>.LEFT) FROM <JOIN>, <MANY> WHERE
// <JOIN>.LEFT = indKey and
// <JOIN>.RIGHT = <MANY>.PK
// with those rows, call readMappedIndividualRow(Resultset)
OWLNamedIndividual joinTable = joinTableToOtherTableEntry.getKey();
OWLNamedIndividual otherTable = joinTableToOtherTableEntry
.getValue();
// e.g. hasServiceActivity -> (ServiceActivity, SR_ACTIVITY)
// e.g. hasServiceCaseActor-> (ServiceCaseActor, SR_ACTOR)
Set<OWLClass> classesForTable = RelationalOWLMapper
.classesByTable(otherTable);
int manyPropertiesFound = 0;
for (OWLClass otherTableMappedClass : classesForTable)
{
// 2013.02.03 abbas domain and range restriction on hasMany
// OWLObjectProperty manyProperty =
// RelationalOWLMapper.hasManyByClass(otherTableMappedClass);
Map<OWLObjectProperty, OWLClass> propertyAndDomain = RelationalOWLMapper
.hasManyByRange(otherTableMappedClass);
if (propertyAndDomain != null)
{
if (propertyAndDomain.size() > 1)
throw new IllegalStateException(
"Exception hasMany property and domain size exception. Only one property and domain can be defined for a hasMany relationship.");
Map.Entry<OWLObjectProperty, OWLClass> entry = propertyAndDomain
.entrySet().iterator().next();
OWLObjectProperty manyProperty = entry.getKey();
OWLClass domainClass = entry.getValue();
// 1:1 or 1:* or *:*
// add domainClass check by way of its mapped table
if (manyProperty != null
&& indTable.equals(RelationalOWLMapper
.table(domainClass)))
{
manyPropertiesFound++;
Set<OWLNamedIndividual> curReferenced = readMappedRelationshipSql(
onto, ind, primaryKeyValue, primaryKeyColumn,
manyProperty, joinTable, otherTable,
otherTableMappedClass, doneMapped);
if (referencedIndividuals.isEmpty()
&& !curReferenced.isEmpty())
{
referencedIndividuals = new HashSet<OWLNamedIndividual>();
}
referencedIndividuals.addAll(curReferenced);
}
}
}
if (dbg())
{
System.out.println("Many Properties found for ind: " + indTable
+ " joinT " + joinTable + " other " + otherTable
+ " Classes " + manyPropertiesFound);
}
}
return referencedIndividuals;
}
/**
* Adds all axioms to the ontology by loading individuals from all rows on
* the right hand side of a 1:1, 1:* or *:* relationship.
*
* @param onto
* @param mappedIndividual
* the left hand side of the relationship.
* @param primaryKeyValue
* of the mappedIndividual's table
* @param primaryKeyColumn
* of the mappedIndividual's table
* @param manyProperty
* @param joinTable
* the jointable in a many to many relationship or equal to
* othertable in 1:1, 1:*, never null
* @param otherTable
* the right hand side table of the relationship, never null
* @param otherTableMappedClass
* @return a set of individuals that were referenced but not yet read.
*/
private Set<OWLNamedIndividual> readMappedRelationshipSql(OWLOntology onto,
OWLNamedIndividual mappedIndividual, long primaryKeyValue,
OWLNamedIndividual primaryKeyColumn,
OWLObjectProperty manyProperty, OWLNamedIndividual joinTable,
OWLNamedIndividual otherTable, OWLClass otherTableMappedClass,
Set<OWLNamedIndividual> doneMapped)
{
OWLDataFactory df = onto.getOWLOntologyManager().getOWLDataFactory();
Set<OWLNamedIndividual> referencedIndividuals = Collections.emptySet();
Connection conn = getConnection();
// Determinne foreign key based on PK and otherTable.
OWLNamedIndividual primaryKeyColOtherTable;
Set<OWLNamedIndividual> primaryKeyCols = RelationalOWLMapper
.columnIriPK(otherTable);
boolean nonIRIPrimaryKeyColOtherTable = primaryKeyCols == null
|| primaryKeyCols.isEmpty();
if (!nonIRIPrimaryKeyColOtherTable)
{
primaryKeyColOtherTable = primaryKeyCols.iterator().next();
} else
{
primaryKeyColOtherTable = null;
}
OWLNamedIndividual foreignKeyColAJoinTable = RelationalOWLMapper
.foreignKeyByjoinColumnAndTable(primaryKeyColumn, joinTable);
String foreignKeyColAJoinTableStr = getColumnNameSQL(foreignKeyColAJoinTable);
String sql;
if (otherTable.equals(joinTable))
{
// assert joinTable equals otherTable
// 1:1 or 1:*
// in this case the jointable equals the othertable, therefore we
// can use the foreignKeyColAJoinTableStr
sql = "SELECT * FROM " + otherTable.getIRI().getFragment()
+ " WHERE " + foreignKeyColAJoinTableStr + " = "
+ primaryKeyValue;
} else
{
// many to many, not implemented for nonIRIPK yet.
String primaryKeyColOtherTableStr = getColumnNameSQL(primaryKeyColOtherTable);
OWLNamedIndividual foreignKeyColBJoinTable = RelationalOWLMapper
.foreignKeyByjoinColumnAndTable(primaryKeyColOtherTable,
joinTable);
String foreignKeyColBJoinTableStr = getColumnNameSQL(foreignKeyColBJoinTable);
sql = "SELECT * FROM " + joinTable.getIRI().getFragment() + " A, "
+ otherTable.getIRI().getFragment() + " B WHERE " + "A."
+ foreignKeyColAJoinTableStr + " = " + primaryKeyValue
+ " AND A." + foreignKeyColBJoinTableStr + " = B."
+ primaryKeyColOtherTableStr;
}
java.sql.Statement stmt = null;
ResultSet rs = null;
try
{
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
int anonId = 1;
while (rs.next())
{
// OWLNamedIndividual primaryKeyColumnOther =
// RelationalOWLMapper.columnIriPK(otherTable).iterator().next();
OWLIndividual otherIndividual;
if (!nonIRIPrimaryKeyColOtherTable)
{
// Named Individual
otherIndividual = (OWLNamedIndividual) selectEntityByID(
rs.getLong(getColumnNameSQL(primaryKeyColOtherTable)),
df);
} else
{
// Anonymous individual for nonIRIPrimaryKeyColOtherTable
// (e.g. ServiceAction)
// TODO THREAD SAFE OWL DATA FACTORY NEEDED if not onto
// exclusive
otherIndividual = onto.getOWLOntologyManager()
.getOWLDataFactory()
.getOWLAnonymousIndividual("Anon:" + anonId);
anonId++;
}
if (!doneMapped.contains(otherIndividual) /*
* || otherIndividual
* instanceof
* OWLAnonymousIndividual
*/)
{
if (otherIndividual instanceof OWLNamedIndividual)
{
doneMapped.add((OWLNamedIndividual) otherIndividual);
}
Set<OWLNamedIndividual> referenced = readMappedIndividualRow(
onto, otherIndividual, otherTable, rs);
if (!referenced.isEmpty())
{
if (referencedIndividuals.isEmpty())
{
referencedIndividuals = new HashSet<OWLNamedIndividual>();
}
referencedIndividuals.addAll(referenced);
}
}
// TODO shall we always add axioms here, even though we already
// visited otherIndividual -> yes, but
// we need to make sure that we don't traverse the relationship
// twice e.g. from both ends, if we want to avoid
// duplicate axiom creation.
// add axiom (objectprop(manyProperty, mappedInd, subject)
OWLOntologyManager man = onto.getOWLOntologyManager();
// TODO THREAD SAFE OWL DATA FACTORY NEEDED if not onto
// exclusive
OWLDataFactory factory = man.getOWLDataFactory();
// we could look at the actual changes here
man.addAxiom(onto, factory.getOWLObjectPropertyAssertionAxiom(
manyProperty, mappedIndividual, otherIndividual));
man.addAxiom(onto, factory.getOWLClassAssertionAxiom(
otherTableMappedClass, otherIndividual));
}
conn.commit();
return referencedIndividuals;
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
}
/**
* Submits a sql statement to read one mapped individual.
*
* @param onto
* @param individualAndID
* the individual to read. Guaranteed to be convertible to ID.
* @return a set of individuals that were referenced but not yet read.
*/
public Set<OWLNamedIndividual> readMappedIndividualSql(OWLOntology onto,
OWLNamedIndividual mappedIndividual, long primaryKeyValue,
OWLClass mappedIndividualClass, OWLNamedIndividual table,
OWLNamedIndividual primaryKeyColumn)
{
Connection conn = getConnection();
String primaryKeyColumnStr = getColumnNameSQL(primaryKeyColumn);
String sql = "SELECT * FROM " + table.getIRI().getFragment()
+ " WHERE " + primaryKeyColumnStr + " = " + primaryKeyValue;
Set<OWLNamedIndividual> ret;
java.sql.Statement stmt = null;
ResultSet rs = null;
try
{
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
if (!rs.next())
{
throw new IllegalStateException("Expected to find "
+ mappedIndividual + " in table " + table
+ " using pk col " + primaryKeyColumn
+ " and pk value " + primaryKeyValue
+ " but no row was returned.");
}
ret = readMappedIndividualRow(onto, mappedIndividual, table, rs);
conn.commit();
return ret;
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
}
/**
* Reads all mapped properties from a given resultset row that represents
* the mappedIndiviual and creates axioms.
*
* @param onto
* @param individualAndID
* the individual to read. Guaranteed to be convertible to ID.
* @param mappedIndividual
* may be a named or anonymous individual (anonymous see
* Cirm_Service_Action)
* @param rsAtCurRow
* a resultset with a cursor positioned at the row that
* represents the mappedIndividual
* @return a set of foreign key values ordered by name of foreign key
* column. TODO should also return the foreign key values that were
* read.
*/
public Set<OWLNamedIndividual> readMappedIndividualRow(OWLOntology onto,
OWLIndividual mappedIndividual, OWLNamedIndividual table,
ResultSet rsAtCurRow) throws SQLException
{
Set<OWLNamedIndividual> referencedIndividuals = new HashSet<OWLNamedIndividual>();
// OWLNamedIndividual table =
// RelationalOWLMapper.table(mappedIndividualClass);
// Set<OWLNamedIndividual> columnIRIPKs =
// RelationalOWLMapper.columnIriPK(table);
Map<OWLProperty<?, ?>, OWLNamedIndividual> propertyToColumn = RelationalOWLMapper
.columnMapping(table);
Set<Map<OWLObjectProperty, OWLNamedIndividual>> hasOnePropertyToFKColumn = RelationalOWLMapper
.hasOneByTable(table);
// Set<OWLNamedIndividual> columnPKs =
// RelationalOWLMapper.columnPK(table);
// READ mapped properties for the individual
for (Map.Entry<OWLProperty<?, ?>, OWLNamedIndividual> mappedProperty : propertyToColumn
.entrySet())
{
// String columnSQLName = getColumnNameSQL();
//System.out.println("Reading " + mappedProperty.getKey());
OWLNamedIndividual referenced = readOWLPropertyFromMappedColumn(
onto, mappedIndividual, mappedProperty.getKey(),
mappedProperty.getValue(), false, rsAtCurRow);
if (referenced != null)
{
referencedIndividuals.add(referenced);
}
}
// Read FK values, create axioms and recursively load referred
// individuals
// 1:1
if (hasOnePropertyToFKColumn != null)
{
for (Map<OWLObjectProperty, OWLNamedIndividual> hasOneMap : hasOnePropertyToFKColumn)
{
// Assuming Singletons
Map.Entry<OWLObjectProperty, OWLNamedIndividual> hasOneEntry = hasOneMap
.entrySet().iterator().next();
OWLNamedIndividual referenced = readOWLPropertyFromMappedColumn(
onto, mappedIndividual, hasOneEntry.getKey(),
hasOneEntry.getValue(), true, rsAtCurRow);
if (referenced != null)
{
referencedIndividuals.add(referenced);
}
}
}
return referencedIndividuals;
}
/**
* Reads a Data- or ObjectProperty from the Resultset and adds one axiom to
* the given ontology.
*
* @return null or an individual that was referenced by an object property
* and should be visited.
*/
@SuppressWarnings("rawtypes")
private OWLNamedIndividual readOWLPropertyFromMappedColumn(
OWLOntology onto, OWLIndividual mappedIndividual,
OWLProperty property, OWLNamedIndividual column,
boolean isFKColumn, ResultSet rs) throws SQLException
{
OWLNamedIndividual referenced = null;
// TODO THREAD SAFE OWL DATA FACTORY NEEDED if not onto exclusive
OWLOntologyManager manager = onto.getOWLOntologyManager();
OWLDataFactory df = manager.getOWLDataFactory();
String columnNameSql = getColumnNameSQL(column);
OWLPropertyAssertionAxiom<?, ?> newAxiom;
// e.g. VARCHAR,
OWLNamedIndividual typeSQL = getColumnType(column);
if (property instanceof OWLDataProperty)
{
OWLDataProperty dataProp = (OWLDataProperty) property;
OWLDatatype typeOWL = getPropertyRangeAsDatatype(dataProp);
Object value;
try
{
value = rs.getObject(columnNameSql);
} catch (SQLException e)
{
System.err
.println("SqlException during accessing column: "
+ columnNameSql + " for individual "
+ mappedIndividual);
throw e;
}
if (value instanceof oracle.sql.Datum)
{
value = getJDBCValueFromOracleValue((oracle.sql.Datum) value);
}
// hilpold 2012.08.14 if (value != null || (typeOWL != null &&
// typeOWL.isString())) {
if (value != null)
{
OWLLiteral literal = createLiteral(df, typeOWL, typeSQL, value);
newAxiom = df.getOWLDataPropertyAssertionAxiom(dataProp, mappedIndividual, literal);
manager.addAxiom(onto, newAxiom);
}
else
{
if (dbg())
System.out
.println("Info: Null value for non xsd:String mapped Column "
+ columnNameSql
+ " in "
+ mappedIndividual
+ " ignored.");
}
} else if (property instanceof OWLObjectProperty)
{
if (isFKColumn)
{
// Resolving 1:1 or *:1 on * side. Refers to owlnamedobject in
// the business ontology that needs to be loaded also.
OWLObjectProperty objectProp = (OWLObjectProperty) property;
long value = rs.getLong(columnNameSql);
if (!rs.wasNull())
{
OWLNamedIndividual object = (OWLNamedIndividual) selectEntityByID(
value, df);
if (object != null)
{
newAxiom = df.getOWLObjectPropertyAssertionAxiom(
objectProp, mappedIndividual, object);
manager.addAxiom(onto, newAxiom);
// rs holdability might be an issue, if we would use
// recursion here.
// 2012.05.29 hilpold: invalid, ind could be partially
// loaded nonmapped: if
// (!onto.containsEntityInSignature(object, false)) {
referenced = object;
} else
{
if (dbg())
System.out
.println("Info: Entity for id not found. Id was: "
+ value
+ " objprop was "
+ objectProp
+ " in "
+ mappedIndividual + " ignored.");
// throw new
// IllegalStateException("Entity for id not found. Id was: "
// + value);
}
} // else ignore null col value
} else
{
// A storeFragment -> create an IRI, assuming fragment unique
// or B long -> refers to entity (e.g. see emailAddress)
// or C other -> is a full IRI, create named Individual
OWLIndividual object;
String value = rs.getString(columnNameSql);
// NEED To add emailAddress Case.
// normal property
// This property will refer to legacy or county ontology.
OWLObjectProperty objectProp = (OWLObjectProperty) property;
if (value != null)
{
if (RelationalOWLMapper.isStoreFragment(objectProp))
{
object = OWL
.findNamedIndividualByFragment((String) value);
} else
{
// probe for long
Long valueAsLong = null;
if (value.length() > 0
&& Character.isDigit(value.charAt(value
.length() - 1)))
{
try
{
valueAsLong = Long.parseLong(value);
} catch (NumberFormatException e)
{
valueAsLong = null;
}
}
if (valueAsLong != null)
{
// we have an ID, refers to a named individual in
// IRI table.
referenced = (OWLNamedIndividual) selectEntityByID(
valueAsLong, df);
// we report it as referenced, there might be more
// axioms for it that need to be loaded later.
object = referenced;
} else
{
object = df.getOWLNamedIndividual(IRI
.create((String) value));
}
}
newAxiom = df.getOWLObjectPropertyAssertionAxiom(
objectProp, mappedIndividual, object);
try
{
manager.addAxiom(onto, newAxiom);
}
catch (Exception ex)
{
System.out.println("oops!");
}
} // else no axiom created for a null value
}
} else
{
throw new IllegalArgumentException("property type unknown "
+ property + " class: " + property.getClass());
}
return referenced;
}
/**
* Converts an oracle specific value from a resultset to a Java value. This
* first became necessary when we received a oracle.sql.TimeStamp instead of
* a java.sql.TimeStamp from a rs.
*
* @param valueORA
* @return
* @throws IllegalArgumentException
* if conversion fails with SQL problem.
* @throws IllegalStateException
* if conversion fails due to ora implementation.
*/
public Object getJDBCValueFromOracleValue(oracle.sql.Datum valueORA)
{
try
{
Object nonORAValue = valueORA.toJdbc();
if (nonORAValue instanceof oracle.sql.Datum)
{
throw new IllegalStateException(
"Conversion resulted in another ORACLE specific value");
}
return nonORAValue;
} catch (SQLException e)
{
throw new IllegalArgumentException("Conversion of value "
+ valueORA + " failed with SQLException.", e);
}
}
public OWLEntity selectEntityByID(final long id, final OWLDataFactory df)
{
return txn(new CirmTransaction<OWLEntity>()
{
@Override
public OWLEntity call() throws Exception
{
return selectEntityByIDInt(id, df);
}
});
}
/**
* Selects one entity by id.
*
* @param id
* @return the entity or null, if id not found in IRI table.
*/
public OWLEntity selectEntityByIDInt(long id, OWLDataFactory df)
{
Map<Long, OWLEntity> result = selectEntitiesByIDs(
Collections.singleton(id), df);
return (result == null || result.isEmpty()) ? null : result.entrySet()
.iterator().next().getValue();
}
/**
* Creates a literal for the given value. Allows null for Strings, but for
* no other types. For Timestamp conversion to lexical value, system has to
* operate in the same timezone!
*
* If typeSQL is VarChar and typeOwl is null, a String literal will be
* created.
*
* @param factory
* @param typeOWL
* @param typeSQL
* @param value
* @return
*/
private OWLLiteral createLiteral(OWLDataFactory factory,
OWLDatatype typeOWL,
OWLNamedIndividual typeSQL,
Object value)
{
OWLLiteral result;
String typeSQLAsStr = typeSQL.getIRI().toString();
if (typeSQLAsStr.equals(Concepts.VARCHAR))
{
if (typeOWL == null)
{
// Assuming string on VARCHAR; this should be defined in the
// ontology as datatype range.
typeOWL = factory.getOWLDatatype(OWL2Datatype.XSD_STRING
.getIRI());
}
if (value == null && typeOWL.isString())
{
value = "";
}
result = factory.getOWLLiteral((String) value, typeOWL);
}
else if (typeSQLAsStr.equals(Concepts.INTEGER))
{
// this will throw NPE if value null.
int valueInt;
if (value instanceof BigInteger)
{
valueInt = ((BigInteger) value).intValue();
}
else if (value instanceof BigDecimal)
{
valueInt = ((BigDecimal) value).intValue();
}
else if (value != null)
{
valueInt = ((Number) value).intValue();
}
else
{
System.err
.println("Creating empty string literal for null value in INTEGER SQL column. This indicates a mapping problem from Integer SQL to String Onto.");
return factory.getOWLLiteral("");
}
if (value != null && typeOWL.isBuiltIn()
&& typeOWL.getBuiltInDatatype() == OWL2Datatype.XSD_BOOLEAN)
{
boolean valueBool = valueInt == 0 ? false : true;
result = factory.getOWLLiteral(valueBool);
} else
{
result = factory.getOWLLiteral(valueInt);
}
}
else if (typeSQLAsStr.equals(Concepts.DOUBLE))
{
if (value instanceof BigDecimal)
{
BigDecimal valueBigDec = (BigDecimal) value;
result = factory.getOWLLiteral(valueBigDec.toPlainString(),
typeOWL);
} else if (value != null)
{
double valueDouble = (Double) value;
result = factory.getOWLLiteral(valueDouble);
} else
{
System.err
.println("Creating empty string literal for null value in DOUBLE SQL column. This indicates a mapping problem from DOUBLE SQL to String Onto.");
result = factory.getOWLLiteral("");
}
}
else if (typeSQLAsStr.equals(Concepts.TIMESTAMP))
{
String lexicalValue;
Timestamp valueST;
// hilpold unfortunately we have to deal with a potential oracle
// timstamp here.
if (value instanceof oracle.sql.TIMESTAMP)
{
oracle.sql.TIMESTAMP valueAsOrclTimeStamp = (oracle.sql.TIMESTAMP) value;
try
{
valueST = (Timestamp) valueAsOrclTimeStamp.timestampValue();
} catch (SQLException e)
{
throw new RuntimeException(
"Could not convert oracle specific timestamp to java.sql.Timestamp.",
e);
}
} else
{
valueST = (Timestamp) value;
}
// TODO default (!!!) timezone, we should use only one timezone to
// interpret timestamps during conversion lexi -> long, long ->
// lexi.
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(valueST);
// lexical ISO 8601 date
synchronized (xmlDatatypeFactory)
{
lexicalValue = xmlDatatypeFactory.newXMLGregorianCalendar(cal)
.toXMLFormat();
}
if (typeOWL == null)
{
System.out.println("Type was null for timestamp: "
+ lexicalValue + " assuming "
+ OWL2Datatype.XSD_DATE_TIME_STAMP.getIRI());
typeOWL = factory
.getOWLDatatype(OWL2Datatype.XSD_DATE_TIME_STAMP
.getIRI());
}
result = factory.getOWLLiteral(lexicalValue, typeOWL);
}
else if (typeSQLAsStr.equals(Concepts.CLOB))
{
Clob valueClob = (Clob) value;
try
{
result = factory.getOWLLiteral(valueClob.getSubString(0L,
(int) valueClob.length()));
} catch (SQLException e)
{
throw new RuntimeException("Could not read Clob: " + value
+ " for " + typeOWL, e);
}
}
else
{
throw new IllegalArgumentException("TypeSQL not recognized : "
+ typeSQL + " asStr: " + typeSQLAsStr);
}
return result;
}
/**
* Checks hasColumnType ObjectProperty to get the type of the column.
*
* @param column
* @return
*/
private OWLNamedIndividual getColumnType(OWLNamedIndividual column)
{
Set<OWLNamedIndividual> columnTypes = reasoner()
.getObjectPropertyValues(column,
objectProperty(fullIri(Concepts.hasColumnType)))
.getFlattened();
if (columnTypes.size() > 1)
{
System.err.println("More than one columntype for col: " + column
+ ". using first.");
for (OWLNamedIndividual coltype : columnTypes)
{
System.err.println("type: " + coltype);
}
}
return columnTypes.iterator().next();
}
/**
* Finds an OWLDataType, which is a range for the given property by
* iterating over the OWLDataPropertyRangeAxioms.
*
* @param property
* @return the DataType or null, if non found.
*/
private OWLDatatype getPropertyRangeAsDatatype(OWLDataProperty property)
{
Set<OWLOntology> ontos = OWL.ontologies();// MetaService.get().
// ontology().getImportsClosure()
Set<OWLDataPropertyRangeAxiom> rangeAxioms = new HashSet<OWLDataPropertyRangeAxiom>();
for (OWLOntology onto : ontos)
{
rangeAxioms.addAll(onto.getDataPropertyRangeAxioms(property));
}
// find first range that is a datatype
for (OWLDataPropertyRangeAxiom rax : rangeAxioms)
{
OWLDataRange range = rax.getRange();
if (range instanceof OWLDatatype)
{
return (OWLDatatype) range;
}
}
// System.err.println("getPropertyRange: No datatype Range found, returning null for data property: "
// + property);
return null;
}
/**
* Returns the COLUMN from
* <TABLE>
* .<COLUMN>.
*
* @param column
* @return
*/
public String getColumnNameSQL(OWLNamedIndividual column)
{
return column.getIRI().getFragment().split("\\.")[1];
}
/**
* Finds an OWLClass (with fully qualified IRI) to a mapped individuals IRI,
* by extracting a short class name from the individual's IRI and searching
* in all classes of all loaded Ontologies.
*
* The algorithm assumes that IRI-contained short classnames are unique
* within the loaded Ontologies, but does not check this condition.
*
* @see getMainClassNameFromIRI
* @param mappedInd
* @return an OWLClass with a fully qualified IRI.
*/
public OWLClass findClassInLoadedOntologiesFor(
OWLNamedIndividual mappedIndividual)
{
String className = getMainClassNameFromIRI(mappedIndividual.getIRI());
if (className != null)
{
for (OWLOntology o : OWL.ontologies())
{
for (OWLClass c : o.getClassesInSignature())
{
if (c.getIRI().getFragment().equals(className))
{
return c;
}
}
}
}
return null;
}
/**
* Reads the classname from IRIs given in two formats:
* http://www.miamidade.gov/bo/{Main_Type_IRI_Short}/67#bo <br/>
* or <br/>
* http://www.miamidade.gov/ontology#Street_Address2972 <br/>
*
*
* @param individualIRI
* an iri representing a bo or another individual.
* @return a short string representation of the class without a base IRI.
* e.g. BULKYTRA, Street_Address or NULL.
*/
public String getMainClassNameFromIRI(IRI individualIRI)
{
String className = null;
if (OWL.isBusinessObject(individualIRI))
{
className = individualIRI.toURI().getPath().split("/")[2];
} else
{
String fragment = individualIRI.getFragment();
// Split off the tailing number consisting of more than one digit.
if (fragment != null
&& fragment.length() > 0
&& Character
.isDigit(fragment.charAt(fragment.length() - 1)))
{
String[] split = fragment.split("\\d+");
if (split.length == 1 && split[0].length() > 0)
{
// we found valid className
className = split[0];
}
}
}
return className;
}
/**
*
* Builds a SQL Merge statement for an individual.
*
* @param o
* @param ind
* @param tableMapping
* @param columnMapping
* @param identifiers
* @param statements
* @param done
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private void mergeMappedIndividual(OWLOntology o, OWLNamedIndividual ind,
Map<OWLEntity, DbId> identifiers,
Map<OWLNamedIndividual, DbId> foreignKeys,
Map<OWLNamedIndividual, List<Statement>> done)
{
// logger.info("Merging individual" + ind.getIRI());
if (done.containsKey(ind))
return;
if (dbg())
{
System.out.println("Merging mapped ind: " + ind.getIRI()
+ " Foreign keys: " + foreignKeys);
}
boolean put = true;
List<Statement> statements = new ArrayList<Statement>();
Statement statement = new Statement();
OWLNamedIndividual table = RelationalOWLMapper.table(ind.getTypes(o));
if (table == null)
{
System.err.println("No table for individual: " + ind + " types were: ");
int i = 0;
for (OWLClassExpression cle : ind.getTypes(o))
{
System.err.println("Class: " + i + " is " + cle);
i++;
}
throw new IllegalStateException("No table for individual " + ind + " mapped. Cannot continue.");
}
Map<OWLProperty, OWLNamedIndividual> columns = (Map) RelationalOWLMapper.columnMapping(table);
Sql update = UPDATE(table.getIRI().getFragment());// + " as A");
List<OWLNamedIndividual> updateTypes = new ArrayList<OWLNamedIndividual>();
List<Object> updateParameters = new ArrayList<Object>();
Sql insert = INSERT_INTO(table.getIRI().getFragment());
List<OWLNamedIndividual> insertTypes = new ArrayList<OWLNamedIndividual>();
List<Object> insertParameters = new ArrayList<Object>();
// add mapped properties
for (Map.Entry<OWLProperty, OWLNamedIndividual> mappedProperty2Col : columns.entrySet())
{
OWLNamedIndividual column = mappedProperty2Col.getValue();
String columnName = mappedProperty2Col.getValue().getIRI().getFragment();
Set<OWLNamedIndividual> columnType =
reasoner().getObjectPropertyValues(column,objectProperty(fullIri(Concepts.hasColumnType))).getFlattened();
if (mappedProperty2Col.getKey() instanceof OWLDataProperty)
{
OWLLiteral value;
Iterator<OWLLiteral> valueIterator = ind.getDataPropertyValues(
mappedProperty2Col.getKey().asOWLDataProperty(), o).iterator();
value = valueIterator.hasNext() ? valueIterator.next() : null;
OWLNamedIndividual type = columnType.iterator().next().asOWLNamedIndividual();
insert.VALUES(columnName.replace(table.getIRI().getFragment() + ".", ""), "?");
insertParameters.add(value);
insertTypes.add(type);
Set<OWLNamedIndividual> pk = RelationalOWLMapper.columnPK(table);
//if the column is not a primary key then add it to the update stmt.
if (pk == null || !pk.contains(column))
{
update.SET(columnName.replace(table.getIRI().getFragment() + ".", ""), "?");
updateParameters.add(value);
updateTypes.add(type);
}
}
else if (mappedProperty2Col.getKey() instanceof OWLObjectProperty)
{
OWLObjectProperty property = mappedProperty2Col.getKey().asOWLObjectProperty();
Iterator<OWLIndividual> valueIterator = ind.getObjectPropertyValues(property, o).iterator();
OWLNamedIndividual value;
value = valueIterator.hasNext() ? valueIterator.next().asOWLNamedIndividual() : null;
// store value, check if fragment only
OWLNamedIndividual type = columnType.iterator().next().asOWLNamedIndividual();
update.SET(columnName.replace(table.getIRI().getFragment() + ".", ""), "?");
updateTypes.add(type);
insert.VALUES(columnName.replace(table.getIRI().getFragment() + ".", ""), "?");
insertTypes.add(type);
if (value == null)
{
updateParameters.add(null);
insertParameters.add(null);
}
else if (RelationalOWLMapper.isStoreFragment(property))
{
// check if IRI is in one of managed ontologies.
IRI valueAsIRI = value.getIRI();
if (ontology().containsIndividualInSignature(valueAsIRI,
true))
{
updateParameters.add(valueAsIRI.getFragment());
insertParameters.add(valueAsIRI.getFragment());
}
else
{
updateParameters.add(valueAsIRI.getFragment());
insertParameters.add(valueAsIRI.getFragment());
// 2013.02.11 Exception restored after room discussion
String msg = "Tried to store value: "
+ valueAsIRI
+ " for property: "
+ property
+ ". The value represents an individual that is not contained in the import closure of meta ontology. \r\n"
+ "StoreFragment must only be used for properties that are defined in meta.";
throw new IllegalStateException(msg);
}
}
else
{
updateParameters.add(identifiers.get(value));
insertParameters.add(identifiers.get(value));
}
}
else
{
throw new IllegalArgumentException(
"property neither Data- nor ObjectProperty: "
+ mappedProperty2Col);
}
} // end foreach
// MAP FOREIGNKEYS START
if (foreignKeys != null && !foreignKeys.isEmpty())
{
Set<OWLNamedIndividual> pk = RelationalOWLMapper.columnPK(table);
for (Map.Entry<OWLNamedIndividual, DbId> foreignKey : foreignKeys.entrySet())
{
String foreignKeyColumn = foreignKey.getKey().getIRI().getFragment();
// TODO hilpoldQ Can RelationalOWLMapper be used here?
Set<OWLNamedIndividual> fkType = reasoner()
.getObjectPropertyValues(foreignKey.getKey(),objectProperty(fullIri(Concepts.hasColumnType)))
.getFlattened();
OWLNamedIndividual type = fkType.iterator().next().asOWLNamedIndividual();
insert.VALUES(foreignKeyColumn.replace(table.getIRI().getFragment() + ".", ""), "?");
insertTypes.add(type);
insertParameters.add(foreignKey.getValue());
//if the column is not a primary key then add it to the update stmt.
if (pk == null || !pk.contains(foreignKey.getKey()))
{
update.SET(foreignKeyColumn.replace(table.getIRI().getFragment() + ".", ""), "?");
updateTypes.add(type);
updateParameters.add(foreignKey.getValue());
}
}
}
// hasOne
Map<OWLObjectPropertyExpression, Set<OWLIndividual>> objectPropertyValues = ind.getObjectPropertyValues(o);
for (Map.Entry<OWLObjectPropertyExpression, Set<OWLIndividual>> mappedProperty : objectPropertyValues.entrySet())
{
OWLObjectPropertyExpression ex = mappedProperty.getKey();
if (ex instanceof OWLObjectProperty)
{
OWLObjectProperty prop = (OWLObjectProperty) ex;
OWLNamedIndividual column = RelationalOWLMapper.hasOne(prop,table);
if (column != null)
{
Set<OWLIndividual> set = objectPropertyValues.get(prop);
if (set.size() > 0)
{
OWLNamedIndividual entity = set.iterator().next().asOWLNamedIndividual();
Set<OWLNamedIndividual> columnType =
reasoner().getObjectPropertyValues(column,
objectProperty(fullIri(Concepts.hasColumnType))).getFlattened();
String columnName = column.getIRI().getFragment();
// RECURSION ALONG HASONE RELATIONSHIP
mergeMappedIndividual(o, entity, identifiers, null, done);
OWLNamedIndividual type = columnType.iterator().next().asOWLNamedIndividual();
update.SET(columnName.replace(table.getIRI().getFragment() + ".", ""), "?");
updateTypes.add(type);
updateParameters.add(identifiers.get(entity));
insert.VALUES(columnName.replace(table.getIRI().getFragment() + ".", ""), "?");
insertTypes.add(type);
insertParameters.add(identifiers.get(entity));
}
}
}
}
// remove relationship hasOne properties by setting the foregin key
// column to null when the property is not provided.
Set<Map<OWLObjectProperty, OWLNamedIndividual>> hasOnePropsByTable = RelationalOWLMapper.hasOneByTable(table);
if (hasOnePropsByTable != null)
{
for (Map<OWLObjectProperty, OWLNamedIndividual> prop2Columns : hasOnePropsByTable)
{
for (Map.Entry<OWLObjectProperty, OWLNamedIndividual> prop2Column : prop2Columns.entrySet())
{
OWLObjectProperty prop = prop2Column.getKey();
OWLNamedIndividual column = prop2Column.getValue();
String columnName = column.getIRI().getFragment();
String columnAlias = columnName.replace(table.getIRI().getFragment() + ".", "");
// If the hasOne column has already been provided
// then do nothing.
if (insert.COLUMNS().contains(columnAlias) || update.COLUMNS().contains(columnAlias))
{
continue;
}
if (!objectPropertyValues.containsKey(prop))
{
Set<OWLNamedIndividual> columnType = reasoner()
.getObjectPropertyValues(
column,
objectProperty(fullIri(Concepts.hasColumnType)))
.getFlattened();
OWLNamedIndividual type = columnType.iterator().next().asOWLNamedIndividual();
update.SET(columnAlias, "?");
updateTypes.add(type);
updateParameters.add(null);
insert.VALUES(columnAlias, "?");
insertTypes.add(type);
insertParameters.add(null);
}
}
}
}
// end hasOne
Set<OWLNamedIndividual> columnIRI = RelationalOWLMapper.columnIriPK(table);
OWLNamedIndividual column = null;
// add iri value
// THIS IS THE PRIMARY KEY FOR SELECT
if (columnIRI != null && !columnIRI.isEmpty())
{
column = columnIRI.iterator().next();
OWLNamedIndividual columnType = reasoner()
.getObjectPropertyValues(column, objectProperty(fullIri(Concepts.hasColumnType))).getFlattened().iterator().next();
update.WHERE(column.getIRI().getFragment().replace(table.getIRI().getFragment() + ".", "")).EQUALS("?");
updateParameters.add(identifiers.get(ind));
updateTypes.add(columnType);
insert.VALUES(column.getIRI().getFragment().replace(table.getIRI().getFragment() + ".", ""), "?");
insertParameters.add(identifiers.get(ind));
insertTypes.add(columnType);
}
if (identifiers.get(ind).isExisting())
{
statement.setSql(update);
statement.getParameters().addAll(updateParameters);
statement.getTypes().addAll(updateTypes);
}
else
{
statement.setSql(insert);
statement.getParameters().addAll(insertParameters);
statement.getTypes().addAll(insertTypes);
}
statements.add(statement);
// At this point the statement to add a row has been constructed. Now
// resolve
// hasMany RelationShips
// hasMany
Map<OWLObjectProperty, OWLClass> hasMany = RelationalOWLMapper.hasMany(objectPropertyValues.keySet());
for (OWLObjectProperty mappedProperty : hasMany.keySet())
{
OWLClass hasManyMappedClass = hasMany.get(mappedProperty);
OWLNamedIndividual manyTable = RelationalOWLMapper.table(hasManyMappedClass);
OWLNamedIndividual joinTable = RelationalOWLMapper.join(table, manyTable);
if (joinTable == null)
continue;
boolean manyToMany = !joinTable.equals(manyTable);
OWLNamedIndividual joinColumnIRI = RelationalOWLMapper.foreignKeyByjoinColumnAndTable(column, joinTable);
Set<OWLNamedIndividual> manyColumnIRI = RelationalOWLMapper.columnIriPK(manyTable);
String joinTableFragment = joinTable.getIRI().getFragment();
String joinColumnIRIFragment = joinColumnIRI.getIRI().getFragment().replace(joinTableFragment + ".", "");
OWLNamedIndividual joinColumnIRIType =
reasoner().getObjectPropertyValues(joinColumnIRI,objectProperty(fullIri(Concepts.hasColumnType))).getFlattened().iterator().next();
OWLNamedIndividual foreignKeyColumnManyToMany = null;
OWLNamedIndividual foreignKeyColumnManyToManyType = null;
// Create delete statement first, but only if its an existing entity.
if (identifiers.get(ind).isExisting())
{
Statement delete = null;
if(manyToMany)
{
delete = buildManyToManyDelete(ind, identifiers, joinTableFragment, joinColumnIRIFragment, joinColumnIRIType);
}
else
{
delete = buildOneToManyDelete(ind, identifiers, objectPropertyValues, mappedProperty, manyColumnIRI,
joinTableFragment, joinColumnIRIFragment, joinColumnIRIType);
}
statements.add(delete);
}
//end create delete statement
// Loop through all manyObjects merging one by one.
for (OWLIndividual propValue : objectPropertyValues.get(mappedProperty))
{
OWLNamedIndividual manyObject = propValue.asOWLNamedIndividual();
if (manyToMany)
{
OWLNamedIndividual manyColumn = manyColumnIRI.iterator().next();
if (manyColumnIRI != null)
{
// RECURSION
mergeMappedIndividual(o, manyObject, identifiers, null, done);
if (foreignKeyColumnManyToMany == null)
foreignKeyColumnManyToMany =
RelationalOWLMapper.foreignKeyByjoinColumnAndTable(manyColumn, joinTable);
if (foreignKeyColumnManyToManyType == null)
foreignKeyColumnManyToManyType = reasoner()
.getObjectPropertyValues(
foreignKeyColumnManyToMany,
objectProperty(fullIri(Concepts.hasColumnType)))
.getFlattened().iterator().next();
String foreignColumn = foreignKeyColumnManyToMany.getIRI().getFragment().replace(joinTableFragment + ".", "");
Statement ins = new Statement();
ins.setSql(INSERT_INTO(joinTableFragment).VALUES(joinColumnIRIFragment, "?").VALUES(foreignColumn, "?"));
ins.getParameters().add(identifiers.get(ind));
ins.getParameters().add(identifiers.get(manyObject));
ins.getTypes().add(joinColumnIRIType);
ins.getTypes().add(foreignKeyColumnManyToManyType);
statements.add(ins);
}
}
else
{
// ONE TO MANY
if (done.containsKey(manyObject))
{
//logger.info("removing and re-merging many-to-one: "
// + manyObject.getIRI());
done.remove(manyObject);
//logger.info("join Object" + ind.getIRI().toString());
}
done.put(ind, statements);
put = false;
mergeMappedIndividual(
o,
manyObject,
identifiers,
Collections.singletonMap(joinColumnIRI,
identifiers.get(ind)), done);
}
}
}
if (put)
done.put(ind, statements);
}
private Statement buildOneToManyDelete(
OWLNamedIndividual ind,
Map<OWLEntity, DbId> identifiers,
Map<OWLObjectPropertyExpression, Set<OWLIndividual>> objectPropertyValues,
OWLObjectProperty mappedProperty,
Set<OWLNamedIndividual> manyColumnIRI, String joinTableFragment,
String joinColumnIRIFragment, OWLNamedIndividual joinColumnIRIType)
{
if (ind == null) throw new NullPointerException("ind param was null");
//next line expensive - maybe do check later in the code
if (identifiers.get(ind) == null) throw new IllegalStateException("no identifier found for ind " + ind);
if (objectPropertyValues == null) throw new NullPointerException("null objectPropertyValues for ind " + ind);
if (mappedProperty == null) throw new NullPointerException("null mappedProperty for ind " + ind);
if (manyColumnIRI == null) throw new NullPointerException("null manyColumnIRI for ind " + ind);
if (joinTableFragment == null) throw new NullPointerException("null joinTableFragment for ind " + ind);
if (joinColumnIRIFragment == null) throw new NullPointerException("null joinColumnIRIFragment for ind " + ind);
if (joinColumnIRIType == null) throw new NullPointerException("null joinColumnIRIType for ind " + ind);
Statement delete = new Statement();
Sql deleteSql = DELETE_FROM(joinTableFragment).WHERE(joinColumnIRIFragment).EQUALS("?");
delete.getParameters().add(identifiers.get(ind));
delete.getTypes().add(joinColumnIRIType);
if(!objectPropertyValues.get(mappedProperty).isEmpty())
{
OWLNamedIndividual manyColumnInd = manyColumnIRI.iterator().next();
String manyColumn = manyColumnInd.getIRI().getFragment().replace(joinTableFragment + ".", "");
OWLNamedIndividual manyColumnIRIType =
reasoner().getObjectPropertyValues(manyColumnInd,objectProperty(fullIri(Concepts.hasColumnType))).getFlattened().iterator().next();
deleteSql.AND().WHERE(manyColumn);
List<String> values = new ArrayList<String>(objectPropertyValues.get(mappedProperty).size());
for (OWLIndividual propValue : objectPropertyValues.get(mappedProperty))
{
OWLNamedIndividual manyObject = propValue.asOWLNamedIndividual();
values.add("?");
delete.getParameters().add(identifiers.get(manyObject));
delete.getTypes().add(manyColumnIRIType);
}
deleteSql.NOT_IN(values.toArray(new String[values.size()]));
}
delete.setSql(deleteSql);
if(DBGX)
{
printStatement(delete);
}
return delete;
}
private Statement buildManyToManyDelete(
OWLNamedIndividual ind,
Map<OWLEntity, DbId> identifiers,
String joinTableFragment,
String joinColumnIRIFragment, OWLNamedIndividual joinColumnIRIType )
{
if (ind == null) throw new NullPointerException("ind param was null");
//next line expensive - maybe do check later in the code
if (identifiers.get(ind) == null) throw new IllegalStateException("no identifier found for ind " + ind);
if (joinTableFragment == null) throw new NullPointerException("null joinTableFragment for ind " + ind);
if (joinColumnIRIFragment == null) throw new NullPointerException("null joinColumnIRIFragment for ind " + ind);
if (joinColumnIRIType == null) throw new NullPointerException("null joinColumnIRIType for ind " + ind);
Statement delete = new Statement();
Sql deleteSql = DELETE_FROM(joinTableFragment).WHERE(joinColumnIRIFragment).EQUALS("?");
delete.getParameters().add(identifiers.get(ind));
delete.getTypes().add(joinColumnIRIType);
delete.setSql(deleteSql);
if(DBGX)
{
printStatement(delete);
}
return delete;
}
/**
* Creates update and insert statements for CIRM_CLASSIFICATION
*
* @param set
* @param individuals
* @param identifiers
* @return a singleton map containing as key the list of updates and as
* value the list of inserts.
*/
private Map<List<Statement>, List<Statement>> mergeClassAssertions(
Set<OWLClassAssertionAxiom> set,
Set<OWLNamedIndividual> individuals,
Map<OWLEntity, DbId> identifiers, Timestamp time)
{
List<Statement> updates = new ArrayList<Statement>();
List<Statement> inserts = new ArrayList<Statement>();
Sql update = UPDATE(TABLE_CLASSIFICATION).SET("TO_DATE", "?")
.WHERE("SUBJECT").EQUALS("?").AND().WHERE("TO_DATE IS NULL");
// Timestamp now = new Timestamp(getStoreTime().getTime());
List<OWLNamedIndividual> updateParamTypes = new ArrayList<OWLNamedIndividual>();
updateParamTypes.add(individual(Concepts.TIMESTAMP));
updateParamTypes.add(individual(Concepts.INTEGER));
Sql insert = INSERT_INTO(TABLE_CLASSIFICATION).VALUES("SUBJECT", "?")
.VALUES("OWLCLASS", "?").VALUES("FROM_DATE", "?");
List<OWLNamedIndividual> insertParamTypes = new ArrayList<OWLNamedIndividual>();
insertParamTypes.add(individual(Concepts.INTEGER));
insertParamTypes.add(individual(Concepts.INTEGER));
insertParamTypes.add(individual(Concepts.TIMESTAMP));
for (OWLNamedIndividual i : individuals)
{
List<Object> parameters = new ArrayList<Object>();
parameters.add(time);
Long individualID = identifiers.get(i).getFirst();
if (individualID == null)
{
throw new IllegalArgumentException(
"Individual ID not found in identifiers for: " + i);
}
parameters.add(individualID);
Statement statement = new Statement();
statement.setSql(update);
statement.setParameters(parameters);
statement.setTypes(updateParamTypes);
updates.add(statement);
}
for (OWLClassAssertionAxiom axiom : set)
{
OWLClassExpression expr = axiom.getClassExpression();
if (expr instanceof OWLClass)
{
List<Object> parameters = new ArrayList<Object>();
Long individualID = identifiers.get(axiom.getIndividual()).getFirst();
if (individualID == null)
{
throw new IllegalArgumentException(
"Individual ID not found in identifiers for: "
+ axiom.getIndividual() + " in axiom : "
+ axiom);
}
parameters.add(individualID);
//
// Long s = identifiers.get(axiom.getIndividual());
// parameters.add(s);
Long c = identifiers.get((OWLClass) expr).getFirst();
parameters.add(c);
parameters.add(time);
Statement statement = new Statement();
statement.setSql(insert);
statement.setParameters(parameters);
statement.setTypes(insertParamTypes);
inserts.add(statement);
}
}
return Collections.singletonMap(updates, inserts);
}
private Map<List<Statement>, List<Statement>> mergeDataProperties(
Set<OWLDataPropertyAssertionAxiom> axioms,
Set<OWLNamedIndividual> individuals,
Map<OWLEntity, DbId> identifiers,
Map<Object, Long> literalValueIdentifiers, Timestamp time)
{
List<Statement> updates = new ArrayList<Statement>();
List<Statement> inserts = new ArrayList<Statement>();
// 1 : set all TO_DATES for all Properties of the Subject to end their
// history
Sql update = UPDATE(TABLE_DATA_PROPERTY).SET("TO_DATE", "?")
.WHERE("SUBJECT").EQUALS("?").AND().WHERE("TO_DATE IS NULL");
// Timestamp now = new Timestamp(getStoreTime().getTime());
List<OWLNamedIndividual> types = new ArrayList<OWLNamedIndividual>();
types.add(individual(Concepts.TIMESTAMP));
types.add(individual(Concepts.INTEGER));
// 2: insert all new
Sql insert = INSERT_INTO(TABLE_DATA_PROPERTY).VALUES("SUBJECT", "?")
.VALUES("PREDICATE", "?").VALUES("DATATYPE_ID", "?")
// .VALUES("LANG", "?")
.VALUES("VALUE_ID", "?").VALUES("FROM_DATE", "?");
// .VALUES("VALUE_HASH", "?");
List<OWLNamedIndividual> types2 = new ArrayList<OWLNamedIndividual>();
types2.add(individual(Concepts.INTEGER));
types2.add(individual(Concepts.INTEGER));
types2.add(individual(Concepts.INTEGER));
types2.add(individual(Concepts.INTEGER));
types2.add(individual(Concepts.TIMESTAMP));
for (OWLNamedIndividual i : individuals)
{
Long s = identifiers.get(i).getFirst();
List<Object> parameters = new ArrayList<Object>();
parameters.add(time);
parameters.add(s);
Statement statement = new Statement();
statement.setSql(update);
statement.setParameters(parameters);
statement.setTypes(types);
updates.add(statement);
}
for (OWLDataPropertyAssertionAxiom axiom : axioms)
{
Long subjectID = identifiers.get(axiom.getSubject()).getFirst();
OWLDataProperty dataproperty = (OWLDataProperty) axiom
.getProperty();
Long predicateID = identifiers.get(dataproperty).getFirst();
OWLLiteral literal = axiom.getObject();
Long datatypeID = identifiers.get(literal.getDatatype()).getFirst();
Object value = getLiteralSqlValue(literal);
// System.out.println(literal);
Long valueID = literalValueIdentifiers.get(value);
if (subjectID == null)
throw new IllegalStateException(
"Subject's Id not found in identifiers. Subject was: "
+ axiom.getSubject() + " Axiom was: " + axiom);
if (predicateID == null)
throw new IllegalStateException(
"Predicate's Id/Property not found in identifiers. Property was: "
+ axiom.getProperty() + " Axiom was: " + axiom);
if (datatypeID == null)
throw new IllegalStateException(
"Dataype's Id not found in identifiers. Datatype was: "
+ literal.getDatatype() + " Literal was: "
+ literal + " Axiom was: " + axiom);
if (valueID == null)
throw new IllegalStateException(
"Value's Id not found in identifiers. Value was: "
+ value + " Literal was: " + literal
+ " Axiom was: " + axiom);
// String hash = hash(value);
List<Object> parameters = new ArrayList<Object>();
parameters.add(subjectID);
parameters.add(predicateID);
parameters.add(datatypeID);
parameters.add(valueID);
parameters.add(time);
Statement statement = new Statement();
statement.setSql(insert);
statement.setParameters(parameters);
statement.setTypes(types2);
inserts.add(statement);
}
return Collections.singletonMap(updates, inserts);
}
private Map<List<Statement>, List<Statement>> mergeObjectProperties(
Set<OWLObjectPropertyAssertionAxiom> axioms,
Set<OWLNamedIndividual> individuals,
Map<OWLEntity, DbId> identifiers,
Timestamp time)
{
List<Statement> updates = new ArrayList<Statement>();
List<Statement> inserts = new ArrayList<Statement>();
Sql update = UPDATE(TABLE_OBJECT_PROPERTY).SET("TO_DATE", "?")
.WHERE("SUBJECT").EQUALS("?").AND().WHERE("TO_DATE IS NULL");
// Timestamp now = new Timestamp(getStoreTime().getTime());
List<OWLNamedIndividual> types = new ArrayList<OWLNamedIndividual>();
types.add(individual(Concepts.TIMESTAMP));
types.add(individual(Concepts.INTEGER));
Sql insert = INSERT_INTO(TABLE_OBJECT_PROPERTY).VALUES("SUBJECT", "?")
.VALUES("PREDICATE", "?").VALUES("OBJECT", "?")
.VALUES("FROM_DATE", "?");
List<OWLNamedIndividual> types2 = new ArrayList<OWLNamedIndividual>();
types2.add(individual(Concepts.INTEGER));
types2.add(individual(Concepts.INTEGER));
types2.add(individual(Concepts.INTEGER));
types2.add(individual(Concepts.TIMESTAMP));
for (OWLNamedIndividual i : individuals)
{
Long s = identifiers.get(i).getFirst();
List<Object> parameters = new ArrayList<Object>();
parameters.add(time);
parameters.add(s);
Statement statement = new Statement();
statement.setSql(update);
statement.setParameters(parameters);
statement.setTypes(types);
updates.add(statement);
}
for (OWLObjectPropertyAssertionAxiom axiom : axioms)
{
Long s = identifiers.get(axiom.getSubject()).getFirst();
OWLObjectPropertyExpression expr = axiom.getProperty();
if (expr instanceof OWLObjectProperty)
{
Long p = identifiers.get((OWLObjectProperty) expr).getFirst();
Long o = identifiers.get(axiom.getObject()).getFirst();
List<Object> parameters = new ArrayList<Object>();
parameters.add(s);
parameters.add(p);
parameters.add(o);
parameters.add(time);
Statement statement = new Statement();
statement.setSql(insert);
statement.setParameters(parameters);
statement.setTypes(types2);
inserts.add(statement);
}
}
return Collections.singletonMap(updates, inserts);
}
// -------------------------------------------------------------------------
// HELPERS FOR MERGE ONLY
//
/**
* Returns all DataPropertyAssertionAxioms, who do no have a mapped column
* in the MAPPED schema for their literal objects. This is determined, by
* first looking, if the subject is mapped and if it does, checking for a
* column mapping. TODO this method should be moved to another class.
*/
public Set<OWLDataPropertyAssertionAxiom> getNotMappedDataPropertyAxioms(
OWLOntology ontology)
{
Set<OWLDataPropertyAssertionAxiom> allAxioms = new HashSet<OWLDataPropertyAssertionAxiom>(
ontology.getAxioms(AxiomType.DATA_PROPERTY_ASSERTION));
Iterator<OWLDataPropertyAssertionAxiom> it = allAxioms.iterator();
while (it.hasNext())
{
OWLDataPropertyAssertionAxiom curAxiom = it.next();
OWLNamedIndividual subject = (OWLNamedIndividual) curAxiom
.getSubject();
OWLNamedIndividual table = RelationalOWLMapper.table(subject
.getTypes(ontology));
if (table != null)
{
Map<OWLProperty<?, ?>, OWLNamedIndividual> columnMapping = RelationalOWLMapper
.columnMapping(table);
if (columnMapping.containsKey(curAxiom.getProperty()))
{
it.remove();
} else
{
OWLLiteral axiomLiteral = curAxiom.getObject();
if (axiomLiteral.getLiteral() == null
|| axiomLiteral.getLiteral().isEmpty())
{
System.err
.println("getNotMappedDataPropertyAxioms: Ignoring not mapped axiom with null or empty literal: "
+ curAxiom);
it.remove();
}
}
}
}
return allAxioms;
}
/**
* Returns all ObjectPropertyAxioms, for whose ObjectProperty no
* columnMapping, and no hasOne and no hasMany exists.
*
* @param ontology
* @return
*/
public Set<OWLObjectPropertyAssertionAxiom> getNotMappedObjectPropertyAxioms(
OWLOntology ontology)
{
Set<OWLObjectPropertyAssertionAxiom> allAxioms = new HashSet<OWLObjectPropertyAssertionAxiom>(
ontology.getAxioms(AxiomType.OBJECT_PROPERTY_ASSERTION));
Iterator<OWLObjectPropertyAssertionAxiom> it = allAxioms.iterator();
while (it.hasNext())
{
OWLObjectPropertyAssertionAxiom curAxiom = it.next();
OWLNamedIndividual subject = (OWLNamedIndividual) curAxiom
.getSubject();
OWLObjectPropertyExpression propertyExpression = curAxiom
.getProperty();
Set<OWLClassExpression> subjectClasses = subject.getTypes(ontology);
OWLNamedIndividual table = RelationalOWLMapper
.table(subjectClasses);
if (table != null)
{
Map<OWLProperty<?, ?>, OWLNamedIndividual> columnMapping = RelationalOWLMapper
.columnMapping(table);
Set<OWLNamedIndividual> hasOneTables = null;
OWLClass hasManyMapping = null;
if (propertyExpression instanceof OWLObjectProperty)
{
OWLObjectProperty property = propertyExpression
.asOWLObjectProperty();
hasOneTables = RelationalOWLMapper
.hasOne2TablesByProperty(property);
hasManyMapping = RelationalOWLMapper.hasMany(property);
}
if (columnMapping.containsKey(curAxiom.getProperty())
|| hasOneTables != null || hasManyMapping != null)
{
it.remove();
}
}
}
return allAxioms;
}
// /**
// * Returns all ClassAssertionAxioms, for whose individuals no tableMapping
// exists.
// *
// * @param ontology
// * @return
// */
// public Set<OWLClassAssertionAxiom>
// getNotMappedClassAssertionAxioms(OWLOntology ontology)
// {
// Set<OWLClassAssertionAxiom> allAxioms =
// ontology.getAxioms(AxiomType.CLASS_ASSERTION);
// Iterator<OWLClassAssertionAxiom> it = allAxioms.iterator();
// while (it.hasNext()) {
// OWLClassAssertionAxiom curAxiom = it.next();
// OWLNamedIndividual individual =
// (OWLNamedIndividual)curAxiom.getIndividual();
// OWLNamedIndividual table =
// RelationalOWLMapper.table(individual.getTypes(ontology));
// if (table != null) {
// it.remove();
// }
// }
// return allAxioms;
// }
/**
* Returns a map of literal-->ID entries for all given DataPropertyAxiom.
*
* @param literalAxioms
* @param insertIfMissing
* @return A map of OWLLiteral to value ID (Datatype ID is selected earlier)
*/
public Map<Object, Long> selectLiteralValueIDsFromAxioms(
Set<OWLDataPropertyAssertionAxiom> literalAxioms,
boolean insertIfMissing)
{
Set<OWLLiteral> literals = new HashSet<OWLLiteral>();
for (OWLDataPropertyAssertionAxiom axiom : literalAxioms)
{
OWLLiteral literal = axiom.getObject();
if (literal.getLiteral() == null || literal.getLiteral().isEmpty())
{
System.err
.println("selectLiteralValueIDsFromAxioms: Ignoring null or empty literal in axiom: "
+ axiom);
continue;
}
literals.add(literal);
}
return selectLiteralValueIDs(literals, insertIfMissing);
}
public Map<Object, Long> selectLiteralValueIDs(Set<OWLLiteral> literals,
boolean insertIfMissing)
{
Map<Object, Long> resultAllTables = new HashMap<Object, Long>();
Map<String, Set<Object>> tableToLiteralValues = classifyLiteralValuesToTables(literals);
for (Map.Entry<String, Set<Object>> tableToLiteralEntry : tableToLiteralValues
.entrySet())
{
String table = tableToLiteralEntry.getKey();
Set<Object> values = tableToLiteralEntry.getValue();
Map<Object, Long> resultOneTable = selectLiteralValueIDsInternal(
table, values);
resultAllTables.putAll(resultOneTable);
if (resultOneTable.size() < values.size() && insertIfMissing)
{
Set<Object> valuesToInsert = new HashSet<Object>(values);
valuesToInsert.removeAll(resultOneTable.keySet());
insertLiteralValues(table, valuesToInsert);
Map<Object, Long> selectInserted = selectLiteralValueIDsInternal(
table, valuesToInsert);
if (selectInserted.size() != valuesToInsert.size())
{
System.err
.println("Oracle bug inconsistency in selectLiteralValueIDs. Will retry. Inserted "
+ valuesToInsert.size()
+ " literal values. "
+ " But on select only "
+ selectInserted.size() + " were found. ");
throw new RuntimeException(
new SQLException(
"Oracle Select after Insert bug detected. Emulating cannot serialize to cause retry of whole transaction.",
"Should close connection and retry", 8177));
}
resultAllTables.putAll(selectInserted);
}
}
return resultAllTables;
}
/**
* Returns the data value table (e.g. DATA_VAL_CLOB) for a sql type.
*
* @param type
* as defined in Concepts.
* @return
*/
private String getTableForSqlType(OWLNamedIndividual type)
{
String table;
if (type.getIRI().toString().equals(Concepts.CLOB))
{
table = TABLE_DATA_VALUE_CLOB;
} else if (type.getIRI().toString().equals(Concepts.TIMESTAMP))
{
table = TABLE_DATA_VALUE_DATE;
} else if (type.getIRI().toString().equals(Concepts.DOUBLE))
{
table = TABLE_DATA_VALUE_DOUBLE;
} else if (type.getIRI().toString().equals(Concepts.INTEGER))
{
table = TABLE_DATA_VALUE_INTEGER;
} else if (type.getIRI().toString().equals(Concepts.VARCHAR))
{
table = TABLE_DATA_VALUE_STRING;
} else
{
throw new IllegalArgumentException("Not recognized: " + type);
}
return table;
}
/**
* Maps Indiviual sql values of literals to tables.
*
* @param literals
* @return
*/
private Map<String, Set<Object>> classifyLiteralValuesToTables(
Set<OWLLiteral> literals)
{
Map<String, Set<Object>> tablesToLiteralValues = new HashMap<String, Set<Object>>();
for (OWLLiteral curLiteral : literals)
{
String table = getTableForLiteral(curLiteral);
Set<Object> literalValuesByTableSet = tablesToLiteralValues
.get(table);
if (literalValuesByTableSet == null)
{
literalValuesByTableSet = new HashSet<Object>(
literals.size() * 2);
tablesToLiteralValues.put(table, literalValuesByTableSet);
}
if (curLiteral.getLiteral() == null
|| curLiteral.getLiteral().isEmpty())
{
System.err
.println("classifyLiteralValuesToTables: ignoring null or empty literal "
+ curLiteral + " table was: " + table);
} else
{
literalValuesByTableSet.add(getLiteralSqlValue(table,
curLiteral));
}
}
return tablesToLiteralValues;
}
/**
* returns the table as mapped by looking at the literals datatype and in
* case of a String, the length of the String.
*
* @param literal
* @return
*/
private String getTableForLiteral(OWLLiteral literal)
{
OWL2Datatype o2dt = literal.getDatatype().getBuiltInDatatype();
OWLNamedIndividual type = RelationalOWLMapper.hasTypeMapping(o2dt);
if (type == null)
{
throw new IllegalArgumentException(
"No TypeMapping found in Meta for datatype: "
+ literal.getDatatype() + " Literal was: "
+ literal);
}
if (type.getIRI().toString().equals(Concepts.VARCHAR)
&& literal.getLiteral().length() >= VALUE_VARCHAR_SIZE)
{
type = Concepts.CLOB_Individual;
}
return getTableForSqlType(type);
}
// private Map<Object, Long> selectLiteralValueIDsInternal(Map<String,
// Set<Object>> tableToValues)
// {
// Map<Object, Long> result = new HashMap<Object, Long>(100);
// for (Map.Entry<String, Set<Object>> tableEntry: tableToValues.entrySet())
// {
// String table = tableEntry.getKey();
// Set<Object> values = tableEntry.getValue();
// result.putAll(selectLiteralValueIDsInternal(table,values));
// }
// return result;
// }
//
// /**
// * Creates a Map categorizing all literals of equal value.
// * @param table
// * @param literals
// * @return a map from value -> set of literals with equal value
// */
// private Map<Object, Set<OWLLiteral>> getLiteralsByValue(String table,
// Set<OWLLiteral> literals) {
// Map<Object, Set<OWLLiteral>> valueToLiterals = new HashMap<Object,
// Set<OWLLiteral>>(literals.size() + 13);
// for (OWLLiteral literal : literals) {
// Object value = getLiteralSqlValue(table, literal);
// Set<OWLLiteral> literalsEqualValue = valueToLiterals.get(value);
// if (literalsEqualValue == null) {
// literalsEqualValue = new HashSet<OWLLiteral>();
// valueToLiterals.put(value, literalsEqualValue);
// }
// literalsEqualValue.add(literal);
// }
// return valueToLiterals;
// }
/**
* returns the value that is needed to find a literal in the database. This
* is equal to the storage value, except for CLOBs, where a hash value is
* returned.
*
* @param literal
* @return
*/
private Object getLiteralSqlValue(OWLLiteral literal)
{
String table = getTableForLiteral(literal);
return getLiteralSqlValue(table, literal);
}
/**
* Here the allowed java value TYPES are defined: {String[2], String,
* sql.TimeStamp, Double, Integer (includes Boolean 1 or 0) }
*
* @param table
* @param literal
* @return a String[2] {hashcode, String} for CLOB table, a String, a
* TimeStamp a Double or an Integer Object.
*/
private Object getLiteralSqlValue(String table, OWLLiteral literal)
{
if (table.equals(TABLE_DATA_VALUE_CLOB))
{
return Collections
.singletonMap(hash(literal), literal.getLiteral());
} else if (table.equals(TABLE_DATA_VALUE_STRING))
{
return literal.getLiteral();
} else if (table.equals(TABLE_DATA_VALUE_DATE))
{
return new Timestamp(parseDate(literal).getTime());
} else if (table.equals(TABLE_DATA_VALUE_DOUBLE))
{
// TODO float might be needed too.
return literal.parseDouble();
} else if (table.equals(TABLE_DATA_VALUE_INTEGER))
{
long intValue;
if (literal.isBoolean())
{
intValue = literal.parseBoolean() ? 1 : 0;
} else
{
intValue = Long.parseLong(literal.getLiteral());
}
return intValue;
} else
{
throw new IllegalArgumentException("Table not recognized: " + table);
}
}
/**
* Loads
*
* @param table
* @param valueToLiterals
* a map from individual values to literals.
* @return
*/
private Map<Object, Long> selectLiteralValueIDsInternal(String table,
Set<Object> values)
{
if (values.size() == 0)
return Collections.emptyMap();
Map<Object, Long> result = new HashMap<Object, Long>(
values.size() * 2 + 1);
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
StringBuilder select = new StringBuilder(250);
select.append("SELECT ID");
if (table.equals(TABLE_DATA_VALUE_CLOB))
{
// select.append(",VALUE_HASH AS CVALUE");
select.append(" FROM ").append(table)
.append(" WHERE VALUE_HASH = ? ");
} else if (table.equals(TABLE_DATA_VALUE_STRING))
{
// select.append(",VALUE_VARCHAR AS CVALUE");
select.append(" FROM ").append(table)
.append(" WHERE VALUE_VARCHAR = ?");
} else if (table.equals(TABLE_DATA_VALUE_DATE))
{
// select.append(",VALUE_DATE AS CVALUE");
select.append(" FROM ").append(table)
.append(" WHERE VALUE_DATE = ? ");
} else if (table.equals(TABLE_DATA_VALUE_DOUBLE))
{
// select.append(",VALUE_DOUBLE AS CVALUE");
select.append(" FROM ").append(table)
.append(" WHERE VALUE_DOUBLE = ? ");
} else if (table.equals(TABLE_DATA_VALUE_INTEGER))
{
// select.append(",VALUE_INTEGER AS CVALUE");
select.append(" FROM ").append(table)
.append(" WHERE VALUE_INTEGER = ? ");
} else
{
throw new IllegalArgumentException("Table " + table
+ " not a valid data value table");
}
// 1. Prepare Statement Parameters for current page
StringBuilder sql = new StringBuilder(select);
// whereClause.deleteCharAt(select.lastIndexOf(",")).append(")");
try
{
conn = getConnection();
stmt = conn.prepareStatement(sql.toString());
for (Object value : values)
{
if (value instanceof Map)
{
// CLOB case, hash value is index 0
@SuppressWarnings("unchecked")
Map.Entry<String, String> hashToValueStr = ((Map<String, String>) value)
.entrySet().iterator().next();
stmt.setObject(1, (hashToValueStr.getKey()));
} else
{
stmt.setObject(1, value);
}
rs = stmt.executeQuery();
// 2. Execute Statement and load value IDs.
if (rs.next())
result.put(value, rs.getLong(1));
if (rs.next())
System.err
.println(" new IllegalStateException(Found more than one IDs for Value: "
+ value
+ " one id is: "
+ rs.getLong(1)
+ " table was: " + table);
}
close(rs, stmt);
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
return result;
}
// /**
// *
// * @param table
// * @param values
// * @return
// * @deprecated
// */
// private Map<Object, Long> selectLiteralValueIDsInternalOlD(String table,
// Set<Object> values)
// {
// if (values.size() == 0)
// return Collections.emptyMap();
// Map<Object, Long> result = new HashMap<Object, Long>((100));
// PreparedStatement stmt = null;
// Connection conn = null;
// ResultSet rs = null;
// StringBuilder select = new StringBuilder(100);
// //OWLDataFactory factory = MetaService.get().getDataFactory();
// //int pageSize = 1000;
// //Map<Object, Set<OWLLiteral>> valueToLiterals =
// getLiteralsByValue(table, literals);
// int pageCount = 1;
// if (values.size() > MAX_INCLAUSE_SIZE)
// pageCount = (values.size() + MAX_INCLAUSE_SIZE - 1) / MAX_INCLAUSE_SIZE;
// try
// {
// conn = getConnection();
// select.append("SELECT ID");
// if(table.equals(TABLE_DATA_VALUE_CLOB)){
// select.append(",VALUE_HASH AS CVALUE");
// select.append(" FROM ").append(table).append(" WHERE VALUE_HASH IN (");
// }else if(table.equals(TABLE_DATA_VALUE_STRING)){
// select.append(",VALUE_VARCHAR AS CVALUE");
// select.append(" FROM ").append(table).append(" WHERE VALUE_VARCHAR IN (");
// }else if(table.equals(TABLE_DATA_VALUE_DATE)){
// select.append(",VALUE_DATE AS CVALUE");
// select.append(" FROM ").append(table).append(" WHERE VALUE_DATE IN (");
// }else if(table.equals(TABLE_DATA_VALUE_DOUBLE)){
// select.append(",VALUE_DOUBLE AS CVALUE");
// select.append(" FROM ").append(table).append(" WHERE VALUE_DOUBLE IN (");
// }else if(table.equals(TABLE_DATA_VALUE_INTEGER)){
// select.append(",VALUE_INTEGER AS CVALUE");
// select.append(" FROM ").append(table).append(" WHERE VALUE_INTEGER IN (");
// }else{
// throw new IllegalArgumentException("Table " + table +
// " not a valid data value table");
// }
// Iterator<Object> valueIterator = values.iterator();
// for (int g = 0; g < pageCount; g++)
// {
// // 1. Prepare Statement Parameters for current page
// StringBuilder sql = new StringBuilder(select);
// for (int i = (g * MAX_INCLAUSE_SIZE); i < ((g + 1) * MAX_INCLAUSE_SIZE) -
// 1 && i < values.size() - 1; i++)
// sql.append("?,");
// sql.append("?)");
// //whereClause.deleteCharAt(select.lastIndexOf(",")).append(")");
// stmt = conn.prepareStatement(sql.toString());
// int j = 1;
// for (int i = (g * MAX_INCLAUSE_SIZE); i < (g + 1) * MAX_INCLAUSE_SIZE &&
// i < values.size(); i++)
// {
// Object value = valueIterator.next();
// if (value instanceof Map) {
// //CLOB case, hash value is index 0
// Map.Entry<String,String> hashToValueStr = ((Map<String,
// String>)value).entrySet().iterator().next();
// stmt.setObject(j, (hashToValueStr.getKey()));
// } else {
// //TODO hilpold WITH SYED: make sure, that a value date will be found:
// //TODO test precision, et.c. we seem to have problems with not finding,
// but running into constraint violations on insert!
// //TODO test targetSqlType, et.c. we seem to have problems with not
// finding timestamps, but running into constraint violations on insert!
// stmt.setObject(j, value);
// }
// j++;
// }
// // 2. Execute Statement and load value IDs.
// rs = stmt.executeQuery();
// while (rs.next())
// {
// readLiteralValueIDInto(table, rs, result, values);
// }
// close(rs, stmt);
// conn.commit();
// }
// }
// catch (SQLException e)
// {
// rollback(conn);
// throw new RuntimeException(e);
// }
// finally
// {
// close(rs, stmt, conn);
// }
// return result;
// }
// /**
// *
// * @param table
// * @param rs
// * @param result
// * @param values
// * @throws SQLException
// * @deprecated
// */
// private void readLiteralValueIDInto(String table, ResultSet rs,
// Map<Object, Long> result, Set<Object> values) throws SQLException
// {
// long id = rs.getLong("ID");
// Object value;
// if(table.equals(TABLE_DATA_VALUE_CLOB)){
// String hashValue = rs.getString("CVALUE");
// Map<String,String> clobStringValueMap = findClobStringMap(values,
// hashValue);
// // Insert the lookup String[] consisting of hashCode and original already
// in memory string
// // instead of the loaded value. We need the String[] comparison later to
// determine, which clob values
// // needs to be inserted. See callers of this method.
// if (clobStringValueMap == null) {
// throw new IllegalStateException("Could not find a CLOB value for hash: "
// + hashValue + " in given values. Size: " + values.size());
// }
// value = clobStringValueMap;
// }else if(table.equals(TABLE_DATA_VALUE_STRING)){
// value = rs.getString("CVALUE");
// }else if(table.equals(TABLE_DATA_VALUE_DATE)){
// value = rs.getTimestamp("CVALUE");
// }else if(table.equals(TABLE_DATA_VALUE_DOUBLE)){
// value = rs.getDouble("CVALUE");
// }else if(table.equals(TABLE_DATA_VALUE_INTEGER)){
// value = rs.getLong("CVALUE");
// } else {
// throw new IllegalArgumentException("Table not recognized: " + table);
// }
// if (rs.wasNull()) {
// throw new
// IllegalStateException("Resultset returned a null value for a Literal Value. Value ID: "
// + id + " Table: " + table);
// }
// result.put(value, id);
// }
/**
* Assumes the values to contain String[2] (clobValues) elements and looks
* for a match on value[0].equals(hashCode).
*
* @param values
* @param
* @return a singleton Map{hashCode -> value} or null if not found
*/
public Map<String, String> findClobStringMap(Set<Object> values,
String hashCode)
{
for (Object value : values)
{
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) value;
Map.Entry<String, String> clobValue = map.entrySet().iterator()
.next();
if (clobValue.getKey() == null
|| clobValue.getValue().length() <= VALUE_VARCHAR_SIZE)
{
throw new IllegalStateException(
"Found bad clobValue array in values: " + clobValue);
}
if (clobValue.getKey().equals(hashCode))
{
return map;
}
}
return null;
}
/**
*
* @param table
* @param values
* if table = CLOB, String[2] are expected
* @return
*/
public int[] insertLiteralValues(String table, Set<Object> values)
{
PreparedStatement stmt = null;
Connection conn = null;
int[] result = {};
StringBuffer insert = new StringBuffer();
insert.append("INSERT INTO ").append(table).append("(").append("ID");
if (table.equals(TABLE_DATA_VALUE_CLOB))
{
insert.append(",VALUE_HASH, VALUE_VARCHAR, VALUE_CLOB ");
} else if (table.equals(TABLE_DATA_VALUE_STRING))
{
insert.append(",VALUE_VARCHAR ");
} else if (table.equals(TABLE_DATA_VALUE_DATE))
{
insert.append(",VALUE_DATE ");
} else if (table.equals(TABLE_DATA_VALUE_DOUBLE))
{
insert.append(",VALUE_DOUBLE ");
} else if (table.equals(TABLE_DATA_VALUE_INTEGER))
{
insert.append(",VALUE_INTEGER ");
} else
{
throw new IllegalArgumentException("Table " + table
+ " not a valid data value table");
}
insert.append(") VALUES ( ").append(dataSourceRef.getHook().nextSequenceClause(SEQUENCE)).append(",");
if (table.equals(TABLE_DATA_VALUE_CLOB))
{
// for _VARCHAR AND _CLOB
insert.append("?,?,?)");
} else
{
insert.append("?)");
}
try
{
conn = getConnection();
stmt = conn.prepareStatement(insert.toString());
for (Object value : values)
{
if (value == null
|| (value instanceof String && ((String) value)
.isEmpty()))
{
System.err
.println("insertLiteralValues: Not inserting illegal null value or empty string for table "
+ table);
continue;
}
if (table.equals(TABLE_DATA_VALUE_CLOB))
{
@SuppressWarnings("unchecked")
Map<String, String> clobValueMap = (Map<String, String>) value;
Map.Entry<String, String> clobValueMapEntry = clobValueMap
.entrySet().iterator().next();
String hashValue = clobValueMapEntry.getKey(); //TODO check if hash exists!!! and how hash is calculated -> has collision is normal.
String longStringValue = clobValueMapEntry.getValue();
stmt.setString(1, hashValue);
if (longStringValue.length() > MAX_VARCHAR_SIZE)
{
// Clob case
stmt.setNull(2, Types.VARCHAR);
stmt.setClob(3, new StringReader(longStringValue));
} else
{
stmt.setString(2, longStringValue);//TODO check if select method is correct for string
stmt.setNull(3, Types.CLOB);
}
} else if (table.equals(TABLE_DATA_VALUE_STRING))
{
stmt.setString(1, (String) value); //TODO check if select method is correct for string
} else if (table.equals(TABLE_DATA_VALUE_DATE))
{
stmt.setTimestamp(1, (Timestamp) value);
} else if (table.equals(TABLE_DATA_VALUE_DOUBLE))
{
stmt.setDouble(1, (Double) value);
} else if (table.equals(TABLE_DATA_VALUE_INTEGER))
{
stmt.setLong(1, (Long) value);
} else
{
throw new IllegalArgumentException("Table " + table
+ " not a valid data value table");
}
stmt.addBatch();
}
result = stmt.executeBatch();
conn.commit();
} catch (Exception e)
{
rollback(conn); //TODO print values!
System.err.println("Error: RelationalStoreImpl::insertLiteralValues table was " + table + " values: ");
print(values);
throw new RuntimeException(e);
} finally
{
close(stmt, conn);
}
return result;
}
private void print(Set<Object> objects)
{
if (objects == null)
{
System.err.println("objects set was null");
return;
}
int i = 0;
for (Object o : objects)
{
System.err.print("" + i + " : ");
if (o == null)
{
System.err.println("null");
} else
{
System.err.println("Class: " + o.getClass().getSimpleName() + " Object: " + "'" + o.toString() + "'");
}
i++;
}
}
/**
* Deletes objects from CIRM_IRI table including full history. Make sure, no
* other foreign keys refer to it before calling this method.
*
* @param objects
* @return
*/
public int[] deleteIRIsWithHistory(Map<OWLEntity, Long> objects)
{
PreparedStatement stmt = null;
Connection conn = null;
int[] result = {};
StringBuffer insert = new StringBuffer();
insert.append("DELETE FROM ").append(TABLE_IRI).append(" WHERE ID = ?");
try
{
conn = getConnection();
conn.setAutoCommit(false);
stmt = conn.prepareStatement(insert.toString());
for (Map.Entry<OWLEntity, Long> object : objects.entrySet())
{
stmt.setLong(1, object.getValue());
stmt.addBatch();
}
result = stmt.executeBatch();
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(stmt, conn);
}
return result;
}
//
// DB HELPERS MERGE ONLY
//
private void executeBatch(List<Statement> statements,
Map<OWLEntity, DbId> identifiers,
Connection conn)
throws SQLException
{
PreparedStatement stmt = null;
String lastSqlStr = null;
int lastParameterSize = -1;
try
{
if (dbg())
{
System.out.println("executeBatch()");
System.out.println(statements.get(0).getSql().SQL());
}
for (Statement s : statements)
{
if (stmt == null)
{
// will add parameters to first statement.
stmt = prepareStatement(conn, s, identifiers);
}
else
{
for (int i = 0; i < s.getParameters().size(); i++)
{
addParameter(stmt, s.getParameters().get(i), s
.getTypes().get(i), i + 1, identifiers);
}
}
stmt.addBatch();
// Checking Assertions:
String curSql = s.getSql().toString();
if (lastSqlStr == null)
{
lastSqlStr = curSql;
} else
{
if (!curSql.equals(lastSqlStr))
{
throw new IllegalStateException(
"SQL in batch statement list does not match: last SQL: "
+ lastSqlStr + " current SQL: "
+ curSql);
}
}
int curParameterSize = s.getParameters().size();
if (lastParameterSize == -1)
{
lastParameterSize = curParameterSize;
} else
{
if (curParameterSize != lastParameterSize)
{
throw new IllegalStateException(
"Cur Parameter size in statement is different from last: last #: "
+ lastParameterSize + " current #: "
+ curParameterSize);
}
}
if (curParameterSize != s.getTypes().size())
{
throw new IllegalStateException(
"SQL Parameter size did not match types size: param #: "
+ curParameterSize + " types #: "
+ s.getTypes().size());
}
}
stmt.executeBatch();
} catch (SQLException e)
{
if (!canRetrySQL(e))
{
System.err.println("executeBatch Exception " + e.toString()
+ "executing following statements: ");
int i = 0;
for (Statement s : statements)
{
System.err.println("" + i + " " + s.getSql().SQL());
int j = 1;
for (Object param : s.getParameters())
{
System.err.print("(" + j + "=" + param + ")");
j++;
}
System.err.println();
i++;
}
}
throw e;
} finally
{
// 2012.07.25 close was missing!!!
close(stmt);
}
}
// private void execute(List<Statement> statements, Map<OWLEntity, Long>
// identifiers, Connection conn) throws SQLException
// {
// PreparedStatement stmt = null;
// for (Statement s : statements)
// {
// stmt = prepareStatement(conn, s, identifiers);
// stmt.executeUpdate();
// }
// }
public Date getStoreTime()
{
return txn(new CirmTransaction<Date>()
{
@Override
public Date call() throws Exception
{
return getStoreTimeInt();
}
});
}
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#getStoreTime()
*/
//@Override
Date getStoreTimeInt()
{
Connection conn = null;
Date result;
try
{
conn = getConnection();
result = dataSourceRef.getHook().timeStamp(conn);
conn.commit();
}
catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
}
finally
{
DBU.close(conn, null, null);
}
return result;
}
//
// GENERIC QUERY AND DEPENDENT METHODS
//
public Map<Long, OWLEntity> queryGetEntities(final Query query, final OWLDataFactory df)
throws SQLException
{
return txn(new CirmTransaction<Map<Long, OWLEntity>>()
{
@Override
public Map<Long, OWLEntity> call() throws Exception
{
return queryGetEntitiesInt(query, df);
}
});
}
public Map<Long, OWLEntity> queryGetEntitiesInt(Query query, OWLDataFactory df)
throws SQLException
{
Connection conn = getConnection();
Map<Long, OWLEntity> result;
try
{
result = selectEntitiesByIDs(query(query, df), df);
conn.commit();
return result;
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(conn);
}
}
@Override
public Json customSearch(final Query query) throws SQLException
{
return txn(new CirmTransaction<Json>()
{
@Override
public Json call() throws Exception
{
return customSearchInt(query);
}
});
}
public Json customSearchInt(Query query) throws SQLException
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
Json results = Json.array();
try
{
conn = getConnection();
stmt = prepareStatement(conn, query.getStatement(), null);
rs = stmt.executeQuery();
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
ResultSetMetaData rsmd = rs.getMetaData();
Json metaInfo = Json.object();
for (int i = 1; i <= rsmd.getColumnCount(); i++)
{
metaInfo.set(rsmd.getColumnName(i), rsmd.getColumnType(i));
}
while (rs.next())
{
Json eachRow = Json.object();
for (Entry<String, Json> property : metaInfo.asJsonMap()
.entrySet())
{
String columnName = property.getKey();
int columnType = property.getValue().asInteger();
if (columnType == Types.VARCHAR)
eachRow.set(columnName, rs.getString(columnName));
if (columnType == Types.LONGVARCHAR)
eachRow.set(columnName, rs.getString(columnName));
if (columnType == Types.CLOB)
eachRow.set(columnName, rs.getString(columnName));
if (columnType == Types.NUMERIC)
{
int i = rs.getInt(columnName);
eachRow.set(columnName, i != 0 ? Integer.toString(i) : "");
}
if (columnType == Types.TIMESTAMP)
{
Timestamp dts = rs.getTimestamp(columnName);
eachRow.set(columnName, (dts != null) ? df.format(dts)
: "");
}
}
results.add(eachRow);
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
return results;
}
@Override
public Json advancedSearch(final Query query) throws SQLException
{
return txn(new CirmTransaction<Json>()
{
@Override
public Json call() throws Exception
{
return advancedSearchInt(query);
}
});
}
public Json advancedSearchInt(Query query) throws SQLException
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
Json results = Json.array();
try
{
conn = getConnection();
stmt = conn.prepareStatement(query.getStatement().getSql().SQL());
rs = stmt.executeQuery();
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
ResultSetMetaData rsmd = rs.getMetaData();
while (rs.next())
{
int boid = rs.getInt(1);
String type = rs.getString(2);
String fullAddress = rs.getString(3);
int zip = rs.getInt(4);
String city = rs.getString(5);
String hasStatus = rs.getString(6);
Timestamp lastActDate = rs.getTimestamp(7);
Timestamp createdDate = rs.getTimestamp(8);
//String hasUserFriendlyID = rs.getString(9);
String hasCaseNumber = rs.getString(9);
String unit = rs.getString(10);
String gisColumn = null;
if (rsmd.getColumnCount() == 11)
gisColumn = rs.getString(11);
Json single = Json.object();
single.set("boid", boid);
single.set("type", (type != null) ? fullIri(type).getFragment()
: "");
single.set("fullAddress", (fullAddress != null) ? fullAddress
: "");
if(unit != null)
single.set("fullAddress",
single.at("fullAddress").asString()+" #"+unit);
single.set("Zip_Code", (zip != 0) ? zip : "");
single.set("Street_Address_City", (city != null) ? city : "");
single.set("hasStatus", (hasStatus != null) ? hasStatus : "");
single.set("lastActivityUpdatedDate",
(lastActDate != null) ? df.format(lastActDate) : "");
single.set("hasDateCreated",
(createdDate != null) ? df.format(createdDate) : "");
//single.set("hasUserFriendlyID",
//(hasUserFriendlyID != null) ? hasUserFriendlyID : "");
single.set("hasCaseNumber",
(hasCaseNumber != null) ? hasCaseNumber : "");
single.set("gisColumn", (gisColumn != null) ? gisColumn : "");
results.add(single);
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
return results;
}
@Override
public LinkedHashSet<Long> query(final Query query, final OWLDataFactory df)
{
return txn(new CirmTransaction<LinkedHashSet<Long>>()
{
@Override
public LinkedHashSet<Long>call() throws Exception
{
return queryInt(query, df);
}
});
}
public LinkedHashSet<Long> queryInt(Query query, OWLDataFactory df)
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
LinkedHashSet<Long> result = new LinkedHashSet<Long>(300);
try
{
conn = getConnection();
Set<? extends OWLEntity> queryEntities = query.getEntities();
if (queryEntities == null)
{
queryEntities = Collections.emptySet();
}
stmt = prepareStatement(conn, query.getStatement(), selectIDsAndEntitiesByIRIs(queryEntities));
rs = stmt.executeQuery();
while (rs.next())
{
result.add(rs.getLong(1));
}
conn.commit();
}
catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
return result;
}
/**
* Selects all OWLEntities
*
* @param ids
* @return
*/
public Map<Long, OWLEntity> selectEntitiesByIDs(Set<Long> ids,
OWLDataFactory df)
{
Map<Long, OWLEntity> result = new LinkedHashMap<Long, OWLEntity>();
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
StringBuilder select = new StringBuilder();
// OWLDataFactory dataFactory = OWL.dataFactory();
if (ids == null || ids.size() == 0)
return result;
int pageSize = 1000; // oracle limits sql in() list to 1000 entries, see
// ORA-01795, so paging technique used.
int pageCount = 1;
List<Long> idsAsList = new ArrayList<Long>(ids);
// We expect sorting the ids to improve query processing by db.
Collections.sort(idsAsList);
if (idsAsList.size() > 1000)
pageCount = (idsAsList.size() + pageSize - 1) / pageSize;
try
{
conn = getConnection();
for (int g = 0; g < pageCount; g++)
{
select.delete(0, select.length());
// TODO maybe use IRI TABLE!!! FASTER?
select.append("SELECT ID, IRI, IRI_TYPE FROM ")
.append(VIEW_IRI).append(" WHERE ").append("ID IN (");
for (int i = (g * pageSize); i < (g + 1) * pageSize
&& i < idsAsList.size(); i++)
select.append("?,");
select.deleteCharAt(select.lastIndexOf(",")).append(")");
stmt = conn.prepareStatement(select.toString());
int j = 1;
for (int i = (g * pageSize); i < (g + 1) * pageSize
&& i < idsAsList.size(); i++)
stmt.setLong(j++, idsAsList.get(i));
rs = stmt.executeQuery();
while (rs.next())
{
OWLEntity o = df.getOWLEntity(
typeOf(rs.getString("IRI_TYPE")),
IRI.create(rs.getString("IRI")));
result.put(rs.getLong("ID"), o);
}
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw new RuntimeException(e);
} finally
{
close(rs, stmt, conn);
}
// >1 here just to avoid a log entry for the SR BO check.
if (result.size() != ids.size() && ids.size() > 1)
{
System.err
.println("selectEntitiesByIDs did not find all ids.size: "
+ ids.size() + " result.size: " + result.size());
}
return result;
}
protected PreparedStatement prepareStatement(Connection conn,
Statement s,
Map<OWLEntity, DbId> identifiers) throws SQLException
{
if (dbg())
System.out.println(s.getSql().SQL());
PreparedStatement ps = conn.prepareStatement(s.getSql().SQL());
for (int i = 0; i < s.getParameters().size(); i++)
{
addParameter(ps, s.getParameters().get(i), s.getTypes().get(i), i + 1, identifiers);
}
if (dbg())
System.out.println();
return ps;
}
protected void addParameter(PreparedStatement ps,
Object value,
OWLNamedIndividual type,
int index,
Map<OWLEntity, DbId> identifiers)
throws SQLException
{
String t = type.getIRI().toString();
Long id = null;
if (value == null)
{
// This might not work for all database systems.
ps.setObject(index, null);
}
else if (value instanceof DbId)
{
Long lvalue = ((DbId)value).getFirst();
if (t.equals(Concepts.VARCHAR))
ps.setString(index, lvalue.toString());
else if (t.equals(Concepts.INTEGER))
ps.setLong(index, lvalue);
}
else if (value instanceof OWLLiteral)
{
// Needed for mapped schema only
if (t.equals(Concepts.VARCHAR))
ps.setString(index, ((OWLLiteral) value).getLiteral());
else if (t.equals(Concepts.INTEGER))
{
OWLLiteral literal = (OWLLiteral) value;
if (literal.isBoolean())
ps.setLong(index, literal.parseBoolean() ? 1 : 0);
else
ps.setLong(index, literal.parseInteger());
} else if (t.equals(Concepts.DOUBLE))
ps.setDouble(index, ((OWLLiteral) value).parseDouble());
else if (t.equals(Concepts.TIMESTAMP))
ps.setTimestamp(index,
new Timestamp(parseDate((OWLLiteral) value).getTime()));
else if (t.equals(Concepts.CLOB))
ps.setClob(index,
new StringReader(((OWLLiteral) value).getLiteral()));
}
else if (value instanceof Long)
{
if (t.equals(Concepts.VARCHAR))
ps.setString(index, ((Long) value).toString());
else if (t.equals(Concepts.INTEGER))
ps.setLong(index, (Long) value);
}
else if (value instanceof String)
{
if (t.equals(Concepts.VARCHAR))
ps.setString(index, (String) value);
else if (t.equals(Concepts.CLOB))
ps.setClob(index, new StringReader((String) value));
else if (t.equals(Concepts.TIMESTAMP))
ps.setTimestamp(index, new Timestamp(parseDate((String) value)
.getTime()));
else if (t.equals(Concepts.DOUBLE))
// TODO test this: ps.setBigDecimal(index, new
// BigDecimal(((String) value)));
ps.setDouble(index, Double.parseDouble((String) value));
else if (t.equals(Concepts.INTEGER))
ps.setLong(index, Long.parseLong((String) value));
} else if (value instanceof Timestamp)
{
ps.setTimestamp(index, (Timestamp) value);
} else if (value instanceof OWLEntity)
{
if (t.equals(Concepts.INTEGER))
{
id = identifiers.get(value).getFirst();
ps.setLong(index, id);
}
} else
{
throw new IllegalArgumentException("Value Type not recognized"
+ value + " class: " + value.getClass());
}
if (dbg())
{
System.out.println("[" + index + " = "
+ ((id == null) ? value : id + "(" + value + ")") + "] ");
}
}
// protected int getParameterSQLType(OWLNamedIndividual t) {
// if (t.equals(Concepts.VARCHAR))
// ps.setString(index, ((OWLLiteral) value).getLiteral());
// else if (t.equals(Concepts.INTEGER))
// {
// OWLLiteral literal = (OWLLiteral) value;
// if (literal.isBoolean())
// ps.setLong(index, literal.parseBoolean() ? 1 : 0);
// else
// ps.setLong(index, literal.parseInteger());
// }
// else if (t.equals(Concepts.DOUBLE))
// ps.setBigDecimal(index, new BigDecimal(((OWLLiteral)
// value).getLiteral()));
// else if (t.equals(Concepts.TIMESTAMP))
// ps.setTimestamp(index, new Timestamp(parseDate((OWLLiteral)
// value).getTime()));
// else if (t.equals(Concepts.CLOB))
// ps.setClob(index, new StringReader(((OWLLiteral) value).getLiteral()));
// }
private Date parseDate(OWLLiteral value)
{
return parseDate(value.getLiteral());
}
private Date parseDate(String value)
{
Date result = new Date();
try
{
// parse ISO 8601 date
synchronized (xmlDatatypeFactory)
{
try
{
result = xmlDatatypeFactory.newXMLGregorianCalendar(value)
.toGregorianCalendar().getTime();
} catch (IllegalArgumentException t)
{
result = GenUtils.parseDate(value);
}
}
} catch (Exception e)
{
logger.info("Could not parse date " + value + " as ISO 8601");
throw new RuntimeException(e);
}
return result;
}
// -------------------------------------------------------------------------
// OWL RELATED HELPERS
//
protected EntityType<?> typeOf(String s)
{
for (EntityType<?> type : EntityType.values())
if (type.toString().equals(s))
return type;
throw new IllegalArgumentException("EntityType not recognized: " + s);
}
protected OWLLiteral literal(OWLDataFactory factory, ResultSet rs,
OWL2Datatype d) throws SQLException
{
// TODO
// here we could have the rs on a "0" varchar, a "0"integer or a "0"
// double,
// even though d == Boolean. This would break the algorithm.
// There might be other cases, such as d == integer, rs on varchar or
// double or others.
//
OWLNamedIndividual type = objectProperty(individual(d.getIRI()
.getFragment()), "hasTypeMapping");
if (type == null)
{
throw new IllegalStateException(
"Exception while attempting to extract literal from ResultSet. Check if there is a hasTypeMapping for owl type "
+ d.getIRI());
}
OWLLiteral result;
if (VARCHAR.equals(type.getIRI().toString()))
{
String varcharValue = rs.getString("VALUE_VARCHAR");
if (varcharValue == null)
{
varcharValue = rs.getString("VALUE_VARCHAR_LONG");
if (varcharValue == null)
{
Clob clob = rs.getClob("VALUE_CLOB");
if (rs.wasNull())
throw new IllegalStateException(
"Could read neither varchar or clob from the resultset for datatype "
+ d);
result = clobLiteral(factory, clob, d);
} else
{
result = factory.getOWLLiteral(varcharValue, d);
}
} else
{
result = factory.getOWLLiteral(varcharValue, d);
}
} else if (CLOB.equals(type.getIRI().toString()))
{
Clob clob = rs.getClob("VALUE_CLOB");
if (rs.wasNull())
throw new IllegalStateException(
"Could not read clob from the resultset for datatype "
+ d);
result = clobLiteral(factory, clob, d);
} else if (TIMESTAMP.equals(type.getIRI().toString()))
{
result = dateLiteral(factory, rs.getTimestamp("VALUE_DATE"), d);
} else if (DOUBLE.equals(type.getIRI().toString()))
{
double valueDouble = rs.getDouble("VALUE_DOUBLE");
if (rs.wasNull())
throw new IllegalStateException(
"Null decimal from the resultset for datatype " + d);
result = factory.getOWLLiteral("" + valueDouble, d);
} else if (INTEGER.equals(type.getIRI().toString()))
{
long l = rs.getLong("VALUE_INTEGER");
if (rs.wasNull())
throw new IllegalStateException(
"Null integer from the resultset for datatype " + d);
if (d.equals(OWL2Datatype.XSD_BOOLEAN))
{
boolean value = (l == 1);
if (!value && l != 0)
throw new IllegalArgumentException(
"Expected 0 for false, but read " + l
+ " from the resultset. Datatype was: "
+ d);
result = factory.getOWLLiteral(value);
} else
result = factory.getOWLLiteral("" + l, d);
} else
{
// logger.warning("New type found but not yet implemented: OWL2Datatype "
// + d + " type: " + type);
throw new IllegalStateException(
"New type found but not yet implemented: OWL2Datatype " + d
+ " type: " + type);
}
return result;
}
// protected OWLLiteral literalTheOldWay(OWLDataFactory factory, ResultSet
// rs, OWL2Datatype d)
// {
// //TODO
// // here we could have the rs on a "0" varchar, a "0"integer or a "0"
// double,
// // even though d == Boolean. This would break the algorithm.
// // There might be other cases, such as d == integer, rs on varchar or
// double or others.
// //
// OWLNamedIndividual type =
// objectProperty(individual(d.getIRI().getFragment()), "hasTypeMapping");
// OWLLiteral result = null;
// try
// {
// if (VARCHAR.equals(type.getIRI().toString()))
// {
// if (rs.getString("VALUE_AS_VARCHAR") == null)
// result = clobLiteral(factory, rs.getClob("VALUE_AS_CLOB"), d);
// else
// result = factory.getOWLLiteral(rs.getString("VALUE_AS_VARCHAR"), d);
// }
// else if (CLOB.equals(type.getIRI().toString()))
// {
// result = clobLiteral(factory, rs.getClob("VALUE_AS_CLOB"), d);
// }
// else if (TIMESTAMP.equals(type.getIRI().toString()))
// {
// result = dateLiteral(factory, rs.getTimestamp("VALUE_AS_DATE"), d);
// }
// else if (DOUBLE.equals(type.getIRI().toString()))
// {
// String s = "";
// if (rs.getBigDecimal("VALUE_AS_DOUBLE") != null)
// s = rs.getBigDecimal("VALUE_AS_DOUBLE").toPlainString();
// result = factory.getOWLLiteral(s, d);
// }
// else if (INTEGER.equals(type.getIRI().toString()))
// {
// long l = rs.getLong("VALUE_AS_INTEGER");
// if (rs.wasNull()) {/* BIG TROUBLE */ };
// if (d.equals(OWL2Datatype.XSD_BOOLEAN))
// result = factory.getOWLLiteral(l == 1 ? true : false);
// else
// result = factory.getOWLLiteral(new Long(l).toString(), d);
// }
// else
// {
// result = factory.getOWLLiteral(
// rs.getString("VALUE_AS_VARCHAR") == null ? "" :
// rs.getString("VALUE_AS_VARCHAR"), d);
// }
// }
// catch (Exception e)
// {
// e.printStackTrace();
// System.out
// .println("Exception while attempting to extract literal from ResultSet. Check if there is a hasTypeMapping for owl type "
// + d.getIRI());
// }
// return result;
// }
private OWLLiteral clobLiteral(OWLDataFactory factory, Clob clob,
OWL2Datatype d) throws SQLException
{
OWLLiteral result = factory.getOWLLiteral("", d);
long len = clob.length();
if (len < 1)
throw new IllegalArgumentException(
"Empty Clob read, database should not contain empty clob. Dataype was: "
+ d);
result = factory.getOWLLiteral(clob.getSubString(1, (int) len), d);
return result;
}
/**
* Creates a literal for OWL2 XSD type DATE_TIME or DATE_TIME_STAMP
*
* @param factory
* @param timestamp
* must not be null/
* @param d
* @return
* @throws IllegalArgumentException
* if timestamp
*/
protected OWLLiteral dateLiteral(OWLDataFactory factory,
Timestamp timestamp, OWL2Datatype d)
{
OWLLiteral result;
if (timestamp == null)
throw new IllegalArgumentException(
"Timestamp was null for datatype " + d);
synchronized (xmlDatatypeFactory)
{
GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
cal.setTime(timestamp);
result = factory.getOWLLiteral(xmlDatatypeFactory
.newXMLGregorianCalendar(cal).toXMLFormat(), d);
}
return result;
}
// -------------------------------------------------------------------------
// JDBC RELATED HELPERS
//
/**
* Tries to rollback the given connection. Null allowed. Exception printed.
*/
protected void rollback(Connection conn)
{
if (conn != null)
{
try
{
conn.rollback();
} catch (SQLException e)
{
System.err.println("Exception while rolling back connection : "
+ conn);
e.printStackTrace(System.err);
}
}
}
protected void close(java.sql.Statement stmt)
{
close(null, stmt, null);
}
protected void close(Connection conn)
{
close(null, null, conn);
}
/**
* Tries to call close on each given database object.
*/
protected void close(java.sql.Statement stmt, Connection conn)
{
close(null, stmt, conn);
}
/**
* Tries to call close on each given database object.
*/
protected void close(ResultSet rs, java.sql.Statement stmt)
{
close(rs, stmt, null);
}
/**
* Tries to call close on each given database object. Prints a stacktrace,
* if a throwable is thrown, but continues closing others.
*
* @param rs
* null allowed.
* @param stmt
* null allowed.
* @param conn
* null allowed.
*/
protected void close(ResultSet rs, java.sql.Statement stmt, Connection conn)
{
if (rs != null)
try
{
rs.close();
} catch (Throwable t)
{
t.printStackTrace();
}
if (stmt != null)
try
{
stmt.close();
} catch (Throwable t)
{
t.printStackTrace();
}
if (conn != null)
try
{
conn.close();
} catch (Throwable t)
{
t.printStackTrace();
}
}
/**
* Checks if a retry was already detected (RetryDetectedException) or
* if the exception is a retriable SQL exception.
* @param t
* @return
*/
static boolean shouldRetry(Throwable t)
{
if (RetryDetectedException.isRetryDetectedOrCausedBy(t))
return true;
else
return canRetrySQL(t);
}
/**
* Checks if a throwable is or contains a retriable SQL exception
*
* @param t
* @return
*/
static boolean canRetrySQL(Throwable t)
{
do
{
if (t instanceof SQLException)
{
SQLException sqe = (SQLException)t;
do
{
int c = sqe.getErrorCode();
if (c == 8177 || c == 8006)
return true;
sqe = sqe.getNextException();
} while (sqe != null);
}
t = t.getCause();
} while (t != null);
return false;
}
/**
* Checks for ORACLE 8177 error.
* "ORA-08177: can't serialize access for this transaction"
*
* @param e
* @return
*/
// private static boolean isCannotSerializeException(Throwable t)
// {
// do
// {
// if (t instanceof SQLException)
// {
// if (((SQLException) t).getErrorCode() == 8177)
// return true;
// }
// t = t.getCause();
// } while (t != null);
// return false;
// }
// //
// // Latest incoming changes from Phani and Syed
// //
// private boolean isDateDatatype(OWL2Datatype builtInDatatype)
// {
// return (builtInDatatype.equals(OWL2Datatype.XSD_DATE_TIME)
// || builtInDatatype.equals(OWL2Datatype.XSD_DATE_TIME_STAMP));
// }
public List<Map<String, Object>> query(final Statement statement, final OWLDataFactory df) throws Exception // ,TODO:Create decorator/or
// renderer argument//)
{
return txn(new CirmTransaction<List<Map<String, Object>>>()
{
@Override
public List<Map<String, Object>> call() throws Exception
{
return queryInt(statement, df);
}
});
}
public List<Map<String, Object>> queryInt(Statement statement,
OWLDataFactory df) throws Exception // ,TODO:Create decorator/or
// renderer argument//)
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
Set<OWLEntity> entities = new HashSet<OWLEntity>();
try
{
for (Object parameter : statement.getParameters())
{
if (parameter instanceof OWLEntity)
entities.add((OWLEntity) parameter);
}
conn = getConnection();
stmt = prepareStatement(conn,
statement,
selectInsertIDsAndEntitiesByIRIs(entities, true));
rs = stmt.executeQuery();
while (rs.next())
{
Map<String, Object> columns = new HashMap<String, Object>();
ResultSetMetaData rsmd = rs.getMetaData();
for (int i = 1; i <= rsmd.getColumnCount(); i++)
{
Object obj = null;
if (rsmd.getColumnType(i) == Types.TIMESTAMP)
{
Timestamp ts = rs.getTimestamp(i);
if (ts != null)
obj = ts.getTime();
} else
obj = rs.getObject(i);
columns.put(rsmd.getColumnLabel(i), obj);
}
result.add(columns);
}
conn.commit();
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
return result;
}
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#executeStatement(org.sharegov.cirm.rdb.Statement)
*/
//@Override
public int executeStatement(final Statement statement) throws Exception // ,TODO:Create decorator/or
// renderer argument//)
{
final Set<OWLEntity> entities = new HashSet<OWLEntity>();
for (Object parameter : statement.getParameters())
{
if (parameter instanceof OWLEntity)
entities.add((OWLEntity) parameter);
}
return txn(new CirmTransaction<Integer>() {
public Integer call() throws Exception
{
PreparedStatement stmt = null;
Connection conn = null;
ResultSet rs = null;
try
{
conn = getConnection();
stmt = prepareStatement(conn, statement,
selectInsertIDsAndEntitiesByIRIs(entities, true));
//int i = 0;
int i = stmt.executeUpdate();
conn.commit();
return i;
} catch (SQLException e)
{
rollback(conn);
throw e;
} finally
{
close(rs, stmt, conn);
}
}
});
}
/* (non-Javadoc)
* @see org.sharegov.cirm.rdb.RelationalStore#txn(org.sharegov.cirm.CirmTransaction)
*/
@Override
public <T> T txn(CirmTransaction<T> transaction)
{
//ThreadLocalConnection.hasThreadLocalConnection()
T result;
if (CirmTransaction.isExecutingOnThisThread())
{ // toplevel txn already executing
// check if the connection for the call is sublevel, if not a close was missed on a toplevel:
if (TXN_CHECK_CONNECTION) checkNextConnectionToBeSublevel();
CirmTransaction<?> toplevel = CirmTransaction.get();
try
{
//Another top level transaction exist, use call() (and not execute()) to inherit blocking behaviour from top level
// and not replace the toplevel trans bound to the thread.
// Check retry flag before and after execution of the subtransaction.
// This will throw a RetryDetectedException to cease subtransaction execution up the stack
// if it's already set.
toplevel.checkRetryRequested();
result = (T) transaction.call();
toplevel.checkRetryRequested();
return result;
} catch (Exception e)
{
if (shouldRetry(e) && !toplevel.isRequestingRetry())
{
toplevel.requestRetry();
}
throw new RuntimeException(e);
}
}
else
{
return (T) txnPrivate(transaction);
}
}
private <T> T txnPrivate(CirmTransaction<T> transaction)
{
T result = null;
int retryCount = 0;
transaction.begin();
try {
do
{
ThreadLocalConnection conn = getConnection();
if (!conn.isTopLevelMode()) {
throw new RuntimeException("txnPrivate: Connection must be in toplevel mode. Commit/Close will fail on" + conn.getDirectConnection());
}
//This has to be a top level connection
try
{
if (lockingStrategy.isLockRequired(transaction) || DBG_ALL_TRANSACTIONS_LOCK)
{
transaction.setAllowDBLock(true);
if(DBGLOCK) ThreadLocalStopwatch.getWatch().time("LOCKS USED FOR " + transaction);
}
result = transaction.execute();
if (TEST_TXN_ALWAYS_RETRY_TWICE && retryCount < 2)
throw new RetryDetectedException("Test retry: " + retryCount);
conn.commit();
transaction.end(true);
}
catch (Exception e)
{
rollback(conn);
if (!shouldRetry(e))
{
transaction.end(false);
throw new RuntimeException(e);
}
}
finally
{
transaction.setAllowDBLock(false);
close(conn);
}
if (!transaction.isSucceeded())
{
retryCount ++;
ThreadLocalStopwatch.getWatch().time("RETRY Transaction " + retryCount + ". time");
ThreadLocalStopwatch.getWatch().time("Transaction info: "
+ "Live(Concurrently executing): " + CirmTransaction.getNrOfExecutingTransactions()
+ " Total: " + CirmTransaction.getNrOfTotalTransactions()
+ " Failed: " + CirmTransaction.getNrOfFailedTransactions()
+ " Cur executions: " + transaction.getExecutionCount());
if (transaction.getTotalExecutionTimeSecs() > TXN_MAX_RETRY_MINUTES * 60)
throw new RuntimeException("TXN: Maximum retry time reached for transaction "
+ "(" + TXN_MAX_RETRY_MINUTES + " minutes). Giving up after " + retryCount + " retries. ");
//Sleep to avoid next collision
preRetrySleep(transaction);
}
}
while (!transaction.isSucceeded());
//Fire top level transaction event while transaction is still associated with thread.
transaction.getTransactionEventSupport().fireEvent(transaction);
return result;
}
finally
{
if (!transaction.isEnded())
{
//Retry giving up -> FAIL
transaction.end(false);
}
}
}
/**
* Calculates a randomized sleeptime from 0-10sec dependend on factors in the transaction framework after 2 retries.
*
* @param t
* @return
*/
public long preRetrySleep(CirmTransaction<?> t)
{
int executions = t.getExecutionCount();
if (executions <= 3) return 0;
//Time of current execution until failure
double exSecs = t.getCurrentExecutionTimeSecs();
if (exSecs == -1) exSecs = 0.01;
//How many transacionts are currently executing in parallel?
int concurrency = CirmTransaction.getNrOfExecutingTransactions();
double random = Math.random();
long sleepTimeMs = (long) (1000 * exSecs * concurrency * (executions - 3.0) * random / 2.0);
if (sleepTimeMs > TXN_MAX_PRE_RETRY_SLEEP_SECS * 1000)
sleepTimeMs = 1000 * (TXN_MAX_PRE_RETRY_SLEEP_SECS - 1) + (long)(2000 * random);
try
{
Thread.sleep(sleepTimeMs);
} catch (InterruptedException e) {}
if (DBG_PRE_RETRY_SLEEP)
{
System.out.println("Pre Retry Sleep " + sleepTimeMs + " ms");
}
return sleepTimeMs;
}
/**
* Tests the next connection for this thread is an inactive sublevel connection and fixes a stale toplevel connection by committing and closing it if necessary.
* If it is not, the toplevel connection will be committed and closed.
*/
private boolean checkNextConnectionToBeSublevel()
{
boolean isTopLevel;
//Ensure connection not in toplevel mode:
ThreadLocalConnection testConn = getConnection();
isTopLevel = testConn.isTopLevelMode();
if (isTopLevel)
{
System.err.println("TXN Problem: A pooled TL connection had a threadlocal and is toplevel. FIX codebase soon to close the connection properly.");
System.err.println("We'll commit and close it now as a temporary fix.");
System.err.println("FIX codebase soon! (We're committing unknown changes and repeatable exceptions will not be repeated.");
try
{
testConn.commit();
} catch (SQLException e)
{
e.printStackTrace();
}
}
try
{
testConn.close();
} catch (SQLException e1)
{
System.err.println("testConnectionToBeSublevel: ignored problem on close" + e1);
//throw new RuntimeException(e1);
}
return !isTopLevel;
}
}