/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.core.kam;
import static org.openbel.framework.common.BELUtilities.hasItems;
import static org.openbel.framework.common.BELUtilities.quoteParameter;
import static org.openbel.framework.common.BELUtilities.sizedHashSet;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.enums.AnnotationType;
import org.openbel.framework.common.enums.FunctionEnum;
import org.openbel.framework.common.enums.RelationshipType;
import org.openbel.framework.common.model.Statement;
import org.openbel.framework.common.protonetwork.model.AnnotationDefinitionTable;
import org.openbel.framework.common.protonetwork.model.AnnotationDefinitionTable.TableAnnotationDefinition;
import org.openbel.framework.common.protonetwork.model.AnnotationValueTable;
import org.openbel.framework.common.protonetwork.model.AnnotationValueTable.TableAnnotationValue;
import org.openbel.framework.common.protonetwork.model.DocumentTable.DocumentHeader;
import org.openbel.framework.common.protonetwork.model.NamespaceTable;
import org.openbel.framework.common.protonetwork.model.NamespaceTable.TableNamespace;
import org.openbel.framework.common.protonetwork.model.ParameterTable;
import org.openbel.framework.common.protonetwork.model.ParameterTable.TableParameter;
import org.openbel.framework.common.protonetwork.model.ProtoEdgeTable;
import org.openbel.framework.common.protonetwork.model.ProtoEdgeTable.TableProtoEdge;
import org.openbel.framework.common.protonetwork.model.ProtoNodeTable;
import org.openbel.framework.common.protonetwork.model.SkinnyUUID;
import org.openbel.framework.common.protonetwork.model.StatementAnnotationMapTable;
import org.openbel.framework.common.protonetwork.model.StatementAnnotationMapTable.AnnotationPair;
import org.openbel.framework.common.protonetwork.model.StatementTable;
import org.openbel.framework.common.protonetwork.model.StatementTable.TableStatement;
import org.openbel.framework.common.protonetwork.model.TermParameterMapTable;
import org.openbel.framework.common.protonetwork.model.TermTable;
import org.openbel.framework.core.df.AbstractJdbcDAO;
import org.openbel.framework.core.df.DBConnection;
/**
* JdbcKAMLoaderImpl implements a {@link KAMLoader} to load a KAM into the
* KAMstore schema using Jdbc.
* <p>
* The {@link PreparedStatement} resources are managed in
* {@link AbstractJdbcDAO} so one must take care in calling
* {@link AbstractJdbcDAO#terminate()} after the KAMLoader DAO is used.
* </p>
*
* @author Anthony Bargnesi {@code <abargnesi@selventa.com>}
*/
public class JdbcKAMLoaderImpl extends AbstractJdbcDAO implements KAMLoader {
// max varchar length, anything longer than this length will be stored as
// text
private static final int MAX_VARCHAR_LENGTH = 4000;
private static final int MAX_MEDIUM_VARCHAR_LENGTH = 255;
private static final String FUNCTION_TYPE_SQL =
"insert into @.function_type(function_type_id,name) values(?,?)";
private static final String OBJECT_TYPE_SQL =
"insert into @.objects_type(objects_type_id,name) values(?,?)";
private static final String RELATIONSHIP_TYPE_SQL =
"insert into @.relationship_type(relationship_type_id,name) " +
"values(?, ?)";
private static final String ANNOTATION_DEFINITION_TYPE_SQL =
"insert into @.annotation_definition_type" +
"(annotation_definition_type_id,name) " +
"values(?, ?)";
private static final String DOCUMENT_HEADER_INFORMATION_SQL =
"insert into @.document_header_information(document_id,name,description,"
+ "version,copyright,disclaimer,contact_information,authors,license_information) "
+ "values(?,?,?,?,?,?,?,?,?)";
private static final String OBJECTS_SQL =
"insert into @.objects(type_id,varchar_value,objects_text_id) values(?,?,?)";
private static final String OBJECTS_ID_COLUMN = "OBJECTS_ID";
private static final String OBJECTS_ID_COLUMN_POSTGRESQL = "objects_id";
private static final String OBJECTS_TEXT_SQL =
"insert into @.objects_text(text_value) values(?)";
private static final String OBJECTS_TEXT_COLUMN = "OBJECTS_TEXT_ID";
private static final String OBJECTS_TEXT_COLUMN_POSTGRESQL =
"objects_text_id";
private static final String NAMESPACE_SQL =
"insert into @.namespace(namespace_id,prefix,resource_location_oid) "
+
"values(?,?,?)";
private static final String DOCUMENT_NAMESPACE_SQL =
"insert into @.document_namespace_map(document_id,namespace_id) " +
"values(?,?)";
private static final String TERM_PARAMETER_SQL =
"insert into @.term_parameter(term_parameter_id,kam_global_parameter_id,"
+
"term_id,namespace_id,parameter_value_oid,ordinal) values(?,?,?,?,?,?)";
private static final String TERM_SQL =
"insert into @.term(term_id,kam_node_id,term_label_oid) " +
"values(?,?,?)";
private static final String KAM_NODE_SQL =
"insert into @.kam_node(kam_node_id,function_type_id,node_label_oid) "
+
"values(?,?,?)";
private static final String KAM_NODE_PARAMETER_SQL =
"insert into @.kam_node_parameter(kam_global_parameter_id,kam_node_id,"
+
"ordinal) values(?,?,?)";
private static final String KAM_EDGE_SQL =
"insert into @.kam_edge(kam_edge_id,kam_source_node_id," +
"kam_target_node_id,relationship_type_id) values(?,?,?,?)";
private static final String KAM_PARAMETER_UUID_SQL =
"insert into @.kam_parameter_uuid(kam_global_parameter_id,most_significant_bits,"
+ "least_significant_bits) values(?,?,?)";
private static final String STATEMENT_SQL =
"insert into @.statement(" +
"statement_id,document_id,subject_term_id," +
"relationship_type_id,object_term_id,nested_subject_id," +
"nested_relationship_type_id,nested_object_id," +
"bel_statement) values(?,?,?,?,?,?,?,?,?)";
private static final String KAM_EDGE_STATEMENT_SQL =
"insert into @.kam_edge_statement_map(kam_edge_id,statement_id) values(?,?)";
private static final String ANNOTATION_DEFINITION_SQL =
"insert into @.annotation_definition(annotation_definition_id," +
"name,description,annotation_usage,domain_value_oid," +
"annotation_definition_type_id) values(?,?,?,?,?,?)";
private static final String DOCUMENT_ANNOTATION_DEFINITION_MAP_SQL =
"insert into @.document_annotation_def_map(document_id," +
"annotation_definition_id) values(?,?)";
private static final String ANNOTATION_SQL =
"insert into @.annotation(annotation_id,value_oid," +
"annotation_definition_id) values(?,?,?)";
private static final String STATEMENT_ANNOTATION_SQL =
"insert into @.statement_annotation_map(statement_id,annotation_id) "
+
"values(?,?)";
private static final String SIMPLE_SELECT_SQL =
"select 1 from @.annotation_definition_type";
private Map<String, Integer> valueIndexMap =
new HashMap<String, Integer>();
/**
* Creates a JdbcKAMLoaderImpl from the Jdbc {@link Connection} that will be
* used to load the KAM.
*
* @param dbc {@link Connection}, the database connection which must be
* non-null and already open for sql execution.
* @param schemaName {@link String}, the schema name for the KAM which must
* be non-null
* @throws InvalidArgument - Thrown if <tt>dbc</tt> is null,
* <tt>schemaName</tt> is null, or the SQL connection is already closed.
* @throws SQLException - Thrown if a SQL error occurred while loading the
* KAM.
*/
public JdbcKAMLoaderImpl(DBConnection dbc, String schemaName)
throws SQLException {
super(dbc, schemaName);
}
/**
* {@inheritDoc}
*/
@Override
public boolean schemaExists() {
PreparedStatement ps = null;
try {
ps = getPreparedStatement(SIMPLE_SELECT_SQL);
ps.executeQuery();
return true;
} catch (SQLException e) {
return false;
} finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
// Ignore it
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Map<String, Integer> loadFunctionTypes() throws SQLException {
PreparedStatement ps = getPreparedStatement(FUNCTION_TYPE_SQL);
Map<String, Integer> functionTypeIdMap =
new HashMap<String, Integer>();
int ftid = 0;
for (FunctionEnum f : FunctionEnum.values()) {
String functionName = f.getDisplayValue();
ps.setInt(1, ftid);
ps.setString(2, functionName);
ps.addBatch();
functionTypeIdMap.put(functionName, ftid);
ftid++;
}
ps.executeBatch();
return functionTypeIdMap;
}
/**
* {@inheritDoc}
*/
@Override
public Map<String, Integer> loadObjectTypes() throws SQLException {
int otid = 0;
PreparedStatement ps = getPreparedStatement(OBJECT_TYPE_SQL);
Map<String, Integer> objectTypeIdMap = new HashMap<String, Integer>();
ps.setInt(1, otid);
ps.setString(2, "number");
ps.addBatch();
objectTypeIdMap.put("number", otid);
otid++;
ps.setInt(1, otid);
ps.setString(2, "varchar");
ps.addBatch();
objectTypeIdMap.put("varchar", otid);
otid++;
ps.setInt(1, otid);
ps.setString(2, "clob");
ps.addBatch();
objectTypeIdMap.put("clob", otid);
ps.executeBatch();
return objectTypeIdMap;
}
/**
* {@inheritDoc}
*/
@Override
public void loadRelationshipTypes() throws SQLException {
PreparedStatement ps = getPreparedStatement(RELATIONSHIP_TYPE_SQL);
for (RelationshipType r : RelationshipType.values()) {
String relationshipName = r.getDisplayValue();
ps.setInt(1, r.getValue());
ps.setString(2, relationshipName);
ps.addBatch();
}
ps.executeBatch();
}
/**
* {@inheritDoc}
*/
@Override
public void loadAnnotationDefinitionTypes()
throws SQLException {
int adtid = 0;
PreparedStatement ps =
getPreparedStatement(ANNOTATION_DEFINITION_TYPE_SQL);
for (AnnotationType at : AnnotationType.values()) {
String annotationTypeName = at.getDisplayValue();
ps.setInt(1, adtid);
ps.setString(2, annotationTypeName);
ps.addBatch();
adtid++;
}
// FIXME [Hack] add URL annotation type
ps.setInt(1, AnnotationDefinitionTable.URL_ANNOTATION_TYPE_ID);
ps.setString(2, AnnotationDefinitionTable.URL_ANNOTATION_TYPE);
ps.addBatch();
ps.executeBatch();
}
/**
* {@inheritDoc}
*/
@Override
public void loadDocuments(List<DocumentHeader> documents)
throws SQLException {
PreparedStatement ps =
getPreparedStatement(DOCUMENT_HEADER_INFORMATION_SQL);
for (int i = 0; i < documents.size(); i++) {
DocumentHeader dh = documents.get(i);
ps.setInt(1, (i + 1));
ps.setString(2, StringUtils.left(dh.getName(), 255));
ps.setString(3, StringUtils.left(dh.getDescription(), 255));
ps.setString(4, StringUtils.left(dh.getVersion(), 64));
ps.setString(5, StringUtils.left(dh.getCopyright(), 4000));
ps.setString(6, StringUtils.left(dh.getDisclaimer(), 4000));
ps.setString(7, StringUtils.left(dh.getContactInfo(), 4000));
ps.setString(8, StringUtils.left(dh.getAuthors(), 4000));
ps.setString(9, StringUtils.left(dh.getLicenses(), 4000));
ps.execute();
}
}
/**
* {@inheritDoc}
*/
@Override
public void loadNamespace(int i, TableNamespace ns) throws SQLException {
PreparedStatement ps;
int rloid = saveObject(1, ns.getResourceLocation());
ps = getPreparedStatement(NAMESPACE_SQL);
ps.setInt(1, (i + 1));
ps.setString(2, ns.getPrefix());
ps.setInt(3, rloid);
ps.execute();
}
@Override
public void loadDocumentNamespaceMap(Map<Integer, List<Integer>> dnsm)
throws SQLException {
PreparedStatement ps = getPreparedStatement(DOCUMENT_NAMESPACE_SQL);
Set<Entry<Integer, List<Integer>>> entries = dnsm.entrySet();
for (final Entry<Integer, List<Integer>> entry : entries) {
final Integer key = entry.getKey();
for (final Integer nsi : entry.getValue()) {
ps.setInt(1, (key + 1));
ps.setInt(2, (nsi + 1));
ps.addBatch();
}
}
ps.executeBatch();
}
/**
* {@inheritDoc}
*/
@Override
public void loadNodes(NamespaceTable nt, ParameterTable pt, TermTable tt,
TermParameterMapTable tpmt, ProtoNodeTable pnt) throws SQLException {
List<String> terms = tt.getTermValues();
Map<Integer, List<Integer>> tpmtidx = tpmt.getTermParameterIndex();
Map<Integer, Integer> node2term = pnt.getNodeTermIndex();
PreparedStatement knps = getPreparedStatement(KAM_NODE_SQL);
// load kam nodes
final List<String> nodes = pnt.getProtoNodes();
final Map<Integer, Integer> eqn = pnt.getEquivalences();
final Set<Integer> added = new HashSet<Integer>();
for (int i = 0, n = nodes.size(); i < n; i++) {
final Integer eqId = eqn.get(i);
// continue if we have already seen this equivalent proto node
if (added.contains(eqId)) {
continue;
}
added.add(eqId);
// build BEL kam node label
Integer tid = node2term.get(i);
String nl = terms.get(tid);
List<Integer> pids = tpmtidx.get(tid);
for (Integer pid : pids) {
TableParameter param = pt.getTableParameter(pid);
TableNamespace ns = param.getNamespace();
nl = nl.replaceFirst("#", ns == null ?
quoteParameter(param.getValue()) :
ns.getPrefix() + ":" + quoteParameter(param.getValue()));
}
Integer knl = valueIndexMap.get(nl);
if (knl == null) {
knl = saveObject(1, nl);
valueIndexMap.put(nl, knl);
}
String tf = nl.substring(0, nl.indexOf('('));
int fv = FunctionEnum.getFunctionEnum(tf).getValue();
// XXX offset
knps.setInt(1, eqId + 1);
knps.setInt(2, fv);
knps.setInt(3, knl);
knps.addBatch();
}
knps.executeBatch();
PreparedStatement knpps = getPreparedStatement(KAM_NODE_PARAMETER_SQL);
PreparedStatement knups = getPreparedStatement(KAM_PARAMETER_UUID_SQL);
final Map<Integer, Integer> gpi = pt.getGlobalIndex();
final Map<Integer, SkinnyUUID> guu = pt.getGlobalUUIDs();
final Set<Integer> seenKamNodes = sizedHashSet(nodes.size());
final Set<Integer> seenGlobalIds = sizedHashSet(gpi.size());
// load kam node parameters
final Map<Integer, Integer> nti = pnt.getNodeTermIndex();
for (int i = 0, n = nodes.size(); i < n; i++) {
final Integer ti = nti.get(i);
// XXX offset
final Integer eqId = eqn.get(i) + 1;
// don't add kam node parameters if we have already seen the
// equivalent node.
if (seenKamNodes.contains(eqId)) {
continue;
}
List<Integer> gtpl = tpmtidx.get(ti);
if (hasItems(gtpl)) {
for (int j = 0; j < gtpl.size(); j++) {
// get parameter index, retrieve global parameter, and set
Integer parameterIndex = gtpl.get(j);
final Integer gid = gpi.get(parameterIndex);
// XXX offset
knpps.setInt(1, gid + 1);
knpps.setInt(2, eqId);
knpps.setInt(3, j);
knpps.addBatch();
if (seenGlobalIds.contains(gid)) {
continue;
}
SkinnyUUID uuid = guu.get(gid);
if (uuid != null) {
// XXX offset
knups.setInt(1, gid + 1);
knups.setLong(2, uuid.getMostSignificantBits());
knups.setLong(3, uuid.getLeastSignificantBits());
knups.addBatch();
}
seenGlobalIds.add(gid);
}
}
// track equivalent kam node
seenKamNodes.add(eqId);
}
knpps.executeBatch();
PreparedStatement pps = getPreparedStatement(TERM_PARAMETER_SQL);
PreparedStatement tps = getPreparedStatement(TERM_SQL);
final Map<Integer, Integer> termNodes = pnt.getTermNodeIndex();
// load term parameters and terms
int tpindex = 0;
for (int ti = 0; ti < terms.size(); ti++) {
String t = terms.get(ti);
// find node equivalence
Integer nodeId = termNodes.get(ti);
// XXX offset
final Integer eqId = eqn.get(nodeId) + 1;
Integer ctl = valueIndexMap.get(t);
if (ctl == null) {
ctl = saveObject(1, t);
valueIndexMap.put(t, ctl);
}
// XXX offset
tps.setInt(1, ti + 1);
// XXX offset
tps.setInt(2, eqId);
tps.setInt(3, ctl);
tps.addBatch();
int ord = 0;
List<Integer> pl = tpmtidx.get(ti);
if (hasItems(pl)) {
for (Integer pi : pl) {
TableParameter p = pt.getIndexTableParameter().get(pi);
Integer cpv = valueIndexMap.get(p.getValue());
if (cpv == null) {
cpv = saveObject(1, p.getValue());
valueIndexMap.put(p.getValue(), cpv);
}
final Integer gid = gpi.get(pi);
// XXX offset
pps.setInt(1, tpindex + 1);
// XXX offset
pps.setInt(2, gid + 1);
// XXX offset
pps.setInt(3, ti + 1);
// find index for the parameter's namespace
TableNamespace tn = p.getNamespace();
Integer ni = null;
if (tn != null) {
ni = nt.getNamespaceIndex().get(tn);
}
if (ni == null) {
pps.setNull(4, Types.INTEGER);
} else {
// XXX offset
pps.setInt(4, ni + 1);
}
pps.setInt(5, cpv);
pps.setInt(6, ord);
pps.addBatch();
ord++;
tpindex++;
if (seenGlobalIds.contains(gid)) {
continue;
}
SkinnyUUID uuid = guu.get(gid);
if (uuid != null) {
// XXX offset
knups.setInt(1, gid + 1);
knups.setLong(2, uuid.getMostSignificantBits());
knups.setLong(3, uuid.getLeastSignificantBits());
knups.addBatch();
}
seenGlobalIds.add(gid);
}
}
}
tps.executeBatch();
pps.executeBatch();
knups.executeBatch();
}
/**
* {@inheritDoc}
*/
@Override
public void loadEdges(StatementTable st, TermTable tt, ProtoNodeTable pnt,
ProtoEdgeTable pet)
throws SQLException {
// load kam edges and associate to kam nodes (global terms)
PreparedStatement keps = getPreparedStatement(KAM_EDGE_SQL);
final Map<Integer, Integer> eqn = pnt.getEquivalences();
final Map<Integer, Integer> eqs = pet.getEquivalences();
final List<TableProtoEdge> edges = pet.getProtoEdges();
Set<Integer> added = new HashSet<Integer>();
for (int i = 0, n = edges.size(); i < n; i++) {
final Integer eqId = eqs.get(i);
// continue if we have already seen this equivalent proto edge
if (added.contains(eqId)) {
continue;
}
added.add(eqId);
final TableProtoEdge edge = edges.get(i);
// XXX offset
keps.setInt(1, eqId + 1);
// XXX offset
keps.setInt(2, eqn.get(edge.getSource()) + 1);
// XXX offset
keps.setInt(3, eqn.get(edge.getTarget()) + 1);
RelationshipType r = RelationshipType.getRelationshipType(edge
.getRel());
keps.setInt(4, r.getValue());
keps.addBatch();
}
added.clear();
keps.executeBatch();
// load statements
final List<StatementTable.TableStatement> ts = st.getStatements();
final Map<Integer, Integer> sdm = st.getStatementDocument();
final Map<Integer, Statement> _stmts = st.getIndexedStatements();
PreparedStatement sps = getPreparedStatement(STATEMENT_SQL);
for (int i = 0, n = ts.size(); i < n; i++) {
final TableStatement stmt = ts.get(i);
// XXX offset
sps.setInt(1, i + 1);
// XXX offset
sps.setInt(2, sdm.get(i) + 1);
// XXX offset
sps.setInt(3, stmt.getSubjectTermId() + 1);
if (stmt.getRelationshipName() == null) {
// load definitional statement
sps.setNull(4, Types.INTEGER);
sps.setNull(5, Types.INTEGER);
sps.setNull(6, Types.INTEGER);
sps.setNull(7, Types.INTEGER);
sps.setNull(8, Types.INTEGER);
} else if (stmt.getObjectTermId() != null) {
// load simple statement
RelationshipType r = RelationshipType.getRelationshipType(stmt
.getRelationshipName());
sps.setInt(4, r.getValue());
// XXX offset
sps.setInt(5, stmt.getObjectTermId() + 1);
sps.setNull(6, Types.INTEGER);
sps.setNull(7, Types.INTEGER);
sps.setNull(8, Types.INTEGER);
} else {
// load nested statement
RelationshipType r = RelationshipType.getRelationshipType(stmt
.getRelationshipName());
sps.setInt(4, r.getValue());
// set null for object term since this is a nested statement
sps.setNull(5, Types.INTEGER);
// XXX offset
sps.setInt(6, stmt.getNestedSubject() + 1);
RelationshipType nr = RelationshipType.getRelationshipType(stmt
.getNestedRelationship());
sps.setInt(7, nr.getValue());
// XXX offset
sps.setInt(8, stmt.getNestedObject() + 1);
}
// set bel statement text
Statement s = _stmts.get(i);
sps.setString(9, s.toBELShortForm());
sps.addBatch();
}
sps.executeBatch();
// load many-to-many association of edges to statements
PreparedStatement skes = getPreparedStatement(KAM_EDGE_STATEMENT_SQL);
final Map<Integer, Set<Integer>> edgeStmts = pet.getEdgeStatements();
// collect all non-unique kam edge / statement combinations
final Map<Integer, Set<Integer>> edgeMap =
new HashMap<Integer, Set<Integer>>();
for (int i = 0, n = edges.size(); i < n; i++) {
// lookup individual edge statements and the equivalent edge id
final Integer edgeId = i;
Set<Integer> es = edgeStmts.get(edgeId);
final Integer eqEdgeId = pet.getEquivalences().get(edgeId);
// create statement set for equivalent edge
Set<Integer> stmts = edgeMap.get(eqEdgeId);
if (stmts == null) {
stmts = new HashSet<Integer>();
edgeMap.put(eqEdgeId, stmts);
}
// map statements (from individual edges) to the equivalent
if (hasItems(es)) {
stmts.addAll(es);
}
}
// iterate kam edges, insert all unique edge / stmt mappings
Set<Entry<Integer, Set<Integer>>> edgeMapEntries = edgeMap.entrySet();
for (Map.Entry<Integer, Set<Integer>> e : edgeMapEntries) {
// XXX offset
int edgeId = e.getKey() + 1;
Set<Integer> stmts = e.getValue();
for (final Integer stmt : stmts) {
skes.setInt(1, edgeId);
// XXX offset
skes.setInt(2, stmt + 1);
skes.addBatch();
}
}
skes.executeBatch();
}
/**
* {@inheritDoc}
*/
@Override
public void loadAnnotationDefinitions(AnnotationDefinitionTable adt)
throws SQLException {
PreparedStatement adps =
getPreparedStatement(ANNOTATION_DEFINITION_SQL);
for (Map.Entry<Integer, TableAnnotationDefinition> ade : adt
.getIndexDefinition().entrySet()) {
TableAnnotationDefinition ad = ade.getValue();
adps.setInt(1, (ade.getKey() + 1));
adps.setString(2, ad.getName());
if (AnnotationDefinitionTable.URL_ANNOTATION_TYPE_ID == ad
.getAnnotationType()) {
adps.setNull(3, Types.VARCHAR);
adps.setNull(4, Types.VARCHAR);
} else {
adps.setString(3, StringUtils.abbreviate(ad.getDescription(),
MAX_MEDIUM_VARCHAR_LENGTH));
adps.setString(4, StringUtils.abbreviate(ad.getUsage(),
MAX_MEDIUM_VARCHAR_LENGTH));
}
final int oid;
final String domain = ad.getAnnotationDomain();
final Integer objectId = valueIndexMap.get(domain);
if (objectId != null) {
oid = objectId;
} else {
oid = saveObject(1, domain);
valueIndexMap.put(domain, oid);
}
adps.setInt(5, oid);
adps.setInt(6, ad.getAnnotationType());
adps.addBatch();
}
adps.executeBatch();
// associate annotate definitions to documents
PreparedStatement dadmps =
getPreparedStatement(DOCUMENT_ANNOTATION_DEFINITION_MAP_SQL);
Map<Integer, Set<Integer>> dadm = adt
.getDocumentAnnotationDefinitions();
Set<Entry<Integer, Set<Integer>>> entries = dadm.entrySet();
for (final Entry<Integer, Set<Integer>> entry : entries) {
final Integer key = entry.getKey();
for (final Integer adid : entry.getValue()) {
dadmps.setInt(1, (key + 1));
dadmps.setInt(2, (adid + 1));
dadmps.addBatch();
}
dadmps.executeBatch();
}
}
/**
* {@inheritDoc}
*/
@Override
public void loadAnnotationValues(AnnotationValueTable avt)
throws SQLException {
PreparedStatement aps = getPreparedStatement(ANNOTATION_SQL);
Set<Entry<Integer, TableAnnotationValue>> annotationEntries = avt
.getIndexValue().entrySet();
for (Entry<Integer, TableAnnotationValue> annotationEntry : annotationEntries) {
aps.setInt(1, (annotationEntry.getKey() + 1));
TableAnnotationValue tableValue = annotationEntry.getValue();
String value = tableValue.getAnnotationValue();
int oid;
Integer objectId = valueIndexMap.get(value);
if (objectId != null) {
oid = objectId;
} else {
oid = saveObject(1, value);
valueIndexMap.put(value, oid);
}
aps.setInt(2, oid);
aps.setInt(3, (tableValue.getAnnotationDefinitionId() + 1));
aps.addBatch();
}
aps.executeBatch();
}
/**
* {@inheritDoc}
*/
@Override
public void loadStatementAnnotationMap(StatementAnnotationMapTable samt)
throws SQLException {
Map<Integer, Set<AnnotationPair>> sidAnnotationIndex =
samt.getStatementAnnotationPairsIndex();
PreparedStatement saps = getPreparedStatement(STATEMENT_ANNOTATION_SQL);
final Set<Entry<Integer, Set<AnnotationPair>>> entries =
sidAnnotationIndex.entrySet();
for (final Entry<Integer, Set<AnnotationPair>> entry : entries) {
final Integer sid = entry.getKey();
for (final AnnotationPair annotation : entry.getValue()) {
// XXX offset
saps.setInt(1, sid + 1);
// XXX offset
saps.setInt(2, annotation.getAnnotationValueId() + 1);
saps.addBatch();
}
}
saps.executeBatch();
}
/**
* Saves an entry to the object table.
*
* @param tid {@code int}, the object type id
* @param v {@link String}, the non-null object value
* @return {@code int}, the object primary key
* @throws SQLException - Thrown if a sql error occurred saving an entry to
* the object table
*/
protected int saveObject(int tid, String v) throws SQLException {
final String objectsIdColumn = (dbConnection.isPostgresql() ?
OBJECTS_ID_COLUMN_POSTGRESQL : OBJECTS_ID_COLUMN);
PreparedStatement ps = getPreparedStatement(OBJECTS_SQL,
new String[] { objectsIdColumn });
ResultSet rs = null;
if (v == null) {
throw new InvalidArgument("object value cannot be null");
}
try {
v = new String(v.getBytes(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("utf-8 unsupported", e);
}
try {
// Insert into objects_text if we are over MAX_VARCHAR_LENGTH
Integer objectsTextId = null;
if (v.length() > MAX_VARCHAR_LENGTH) {
final String objectsTextColumn = (dbConnection.isPostgresql() ?
OBJECTS_TEXT_COLUMN_POSTGRESQL : OBJECTS_TEXT_COLUMN);
PreparedStatement otps = getPreparedStatement(OBJECTS_TEXT_SQL,
new String[] { objectsTextColumn });
ResultSet otrs = null;
StringReader sr = null;
try {
sr = new StringReader(v);
otps.setClob(1, sr, v.length());
otps.execute();
otrs = otps.getGeneratedKeys();
if (otrs.next()) {
objectsTextId = otrs.getInt(1);
}
} finally {
close(otrs);
if (sr != null) {
sr.close();
}
}
}
// FIXME Hardcoding objects_type to 1?
ps.setInt(1, 1);
if (objectsTextId == null) {
// insert value into objects table
ps.setString(2, v);
ps.setNull(3, Types.INTEGER);
} else {
ps.setNull(2, Types.VARCHAR);
ps.setInt(3, objectsTextId);
}
ps.execute();
rs = ps.getGeneratedKeys();
int oid;
if (rs.next()) {
oid = rs.getInt(1);
} else {
throw new IllegalStateException("object insert failed.");
}
return oid;
} finally {
close(rs);
}
}
}