-
Jérôme Euzenat authoredJérôme Euzenat authored
CacheImpl.java 37.64 KiB
/*
* $Id$
*
* Copyright (C) Seungkeun Lee, 2006
* Copyright (C) INRIA, 2006-2013
*
* 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 2.1
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package fr.inrialpes.exmo.align.service;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
import java.util.Date;
import java.util.Random;
import java.util.Properties;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.inrialpes.exmo.align.impl.BasicAlignment;
import fr.inrialpes.exmo.align.impl.BasicRelation;
import fr.inrialpes.exmo.align.impl.Annotations;
import fr.inrialpes.exmo.align.impl.Namespace;
import fr.inrialpes.exmo.align.impl.URIAlignment;
import fr.inrialpes.exmo.align.impl.URICell;
import fr.inrialpes.exmo.align.impl.Namespace;
import fr.inrialpes.exmo.ontowrap.Ontology;
import org.semanticweb.owl.align.Alignment;
import org.semanticweb.owl.align.AlignmentException;
import org.semanticweb.owl.align.Cell;
import java.io.PrintStream;
import java.io.EOFException;
/**
* This class caches the content of the alignment database. I.e.,
* It loads the metadata in the hash table
* It stores the alignment when requested
* It
*/
public class CacheImpl {
final static Logger logger = LoggerFactory.getLogger( CacheImpl.class );
Hashtable<String,Alignment> alignmentTable = null;
Hashtable<URI,Set<Alignment>> ontologyTable = null;
String host = null;
String port = null;
int rights = 1; // writing rights in the database (default is 1)
String idprefix = null;
final int VERSION = 450; // Version of the API to be stored in the database
/* 300: initial database format
301: ADDED alignment id as primary key
302: ALTERd cached/stored/ouri tag forms
310: ALTERd extension table with added URIs and method -> val
340: ALTERd size of relation in cell table (5 -> 25)
400: ALTERd size of relation in cell table (5 -> 255 because of URIs)
ALTERd all URI size to 255
ALTERd level size to 25
ADDED cell_id as keys?
450: ADDED ontology database / reduced alignment database
ADDED prefix in server
ADDED dependency database (no action)
*/
DBService service = null;
Connection conn = null;
final int CONNECTION_ERROR = 1;
final int SUCCESS = 2;
final int INIT_ERROR = 3;
static private final String SVCNS = Namespace.ALIGNSVC.getUriPrefix();
static private final String CACHED = "cached";
static private final String STORED = "stored";
static private final String ALID = "alid/";
static private final String OURI1 = "ouri1";
static private final String OURI2 = "ouri2";
//**********************************************************************
public CacheImpl( DBService serv ) {
service = serv;
try {
conn = service.getConnection();
} catch( Exception e ) {
logger.warn( "Cannot connect to DB", e );
}
alignmentTable = new Hashtable<String,Alignment>();
ontologyTable = new Hashtable<URI,Set<Alignment>>();
}
public void reset() throws SQLException {
alignmentTable = new Hashtable<String,Alignment>();
ontologyTable = new Hashtable<URI,Set<Alignment>>();
// reload alignment descriptions
loadAlignments( true );
}
/**
* loads the alignment descriptions from the database and put them in the
* alignmentTable hashtable
*/
public void init( Properties p, String prefix ) throws SQLException, AlignmentException {
logger.debug( "Initializing Database cache" );
port = p.getProperty("http"); // bad idea
host = p.getProperty("host");
idprefix = prefix;
Statement st = createStatement();
// test if a database is here, otherwise create it
ResultSet rs = conn.getMetaData().getTables(null,null, "server", new String[]{"TABLE"});
if ( !rs.next() ) {
initDatabase();
} else {
updateDatabase(); // in case it is necessary to upgrade
}
String pref = p.getProperty("prefix");
if ( pref == null || pref.equals("") ) {
rs = st.executeQuery( "SELECT prefix FROM server WHERE port='port'" );
while( rs.next() ) {
idprefix = rs.getString("prefix");
}
}
st.close();
// register by the database
registerServer( host, port, rights==1, idprefix );
// load alignment descriptions
loadAlignments( true );
}
public void close() throws SQLException {
Statement st = createStatement();
// unregister by the database
st.executeUpdate( "DELETE FROM server WHERE host='"+host+"' AND port='"+port+"'" );
st.close();
conn.close();
}
public Statement createStatement() throws SQLException {
conn = service.getConnection();
return conn.createStatement();
}
// **********************************************************************
// LOADING FROM DATABASE
/**
* loads the alignment descriptions from the database and put them in the
* alignmentTable hashtable
* index them under the ontology URIs
*/
private void loadAlignments( boolean force ) throws SQLException {
logger.debug( "Loading alignments..." );
String id = null;
Alignment alignment = null;
Vector<String> idInfo = new Vector<String>();
Statement st = createStatement();
if (force) {
// Retrieve the alignment ids
ResultSet rs = st.executeQuery("SELECT id FROM alignment");
while(rs.next()) {
id = rs.getString("id");
idInfo.add(id);
}
// For each alignment id store metadata
for( int i = 0; i < idInfo.size(); i ++ ) {
id = idInfo.get(i);
alignment = retrieveDescription( id );
recordAlignment( recoverAlignmentUri( id ), alignment, true );
}
}
st.close();
}
protected Enumeration<Alignment> listAlignments() {
return alignmentTable.elements();
}
protected Collection<Alignment> alignments() {
return alignmentTable.values();
}
protected Collection<URI> ontologies() {
return ontologyTable.keySet();
}
protected Collection<Alignment> alignments( URI u1, URI u2 ) {
Collection<Alignment> results = new HashSet<Alignment>();
if ( u1 != null ) {
for ( Alignment al : ontologyTable.get( u1 ) ) {
try {
// if ( al.getOntology1URI().equals( u1 ) ) {
if ( u2 == null ) results.add( al );
else if ( al.getOntology2URI().equals( u2 )
|| al.getOntology1URI().equals( u2 )) results.add( al );
// }
} catch (AlignmentException alex) {
logger.debug( "IGNORED Exception", alex );
}
}
} else if ( u2 != null ) {
for ( Alignment al : ontologyTable.get( u2 ) ) {
results.add( al );
}
} else { results = alignmentTable.values(); }
return results;
}
protected void flushCache() {// throws AlignmentException
for ( Alignment al : alignmentTable.values() ){
if ( al.getExtension(SVCNS, CACHED ) != null &&
!al.getExtension( SVCNS, CACHED ).equals("") &&
al.getExtension(SVCNS, STORED ) != null &&
!al.getExtension( SVCNS, STORED ).equals("") ) flushAlignment( al );
};
}
/**
* loads the description of alignments from the database and set them
* in an alignment object
*/
protected Alignment retrieveDescription( String id ){
ResultSet rs;
String tag;
String value;
logger.debug( "Loading alignment {}", id );
URIAlignment result = new URIAlignment();
Statement st = null;
try {
st = createStatement();
// Get basic ontology metadata
rs = st.executeQuery( "SELECT * FROM alignment WHERE id = '" + id +"'" );
while( rs.next() ) {
result.setLevel(rs.getString("level"));
result.setType(rs.getString("type"));
}
// Get ontologies
rs = st.executeQuery( "SELECT * FROM ontology WHERE id = '" + id +"'" );
while(rs.next()) {
if ( rs.getBoolean("source") ) {
result.getOntologyObject1().setURI( new URI(rs.getString("uri")) );
if ( rs.getString("file") != null )
result.setFile1( new URI( rs.getString("file") ) );
if ( rs.getString("formuri") != null )
result.getOntologyObject1().setFormURI( new URI(rs.getString("formuri")) );
if ( rs.getString("formname") != null )
result.getOntologyObject1().setFormalism( rs.getString("formname") );
result.setExtension( SVCNS, OURI1, rs.getString("uri") );
} else {
result.getOntologyObject2().setURI( new URI(rs.getString("uri")) );
if ( rs.getString("file") != null )
result.setFile2( new URI( rs.getString("file") ) );
if ( rs.getString("formuri") != null )
result.getOntologyObject2().setFormURI( new URI(rs.getString("formuri")) );
if ( rs.getString("formname") != null )
result.getOntologyObject2().setFormalism( rs.getString("formname") );
result.setExtension( SVCNS, OURI2, rs.getString("uri") );
}
}
// Get dependencies if necessary
// Get extension metadata
rs = st.executeQuery( "SELECT * FROM extension WHERE id = '" + id + "'" );
while(rs.next()) {
tag = rs.getString("tag");
value = rs.getString("val");
result.setExtension( rs.getString("uri"), tag, value);
}
} catch (Exception e) { // URI exception that should not occur
logger.debug( "IGNORED unlikely URI exception", e);
return null;
} finally {
try { st.close(); } catch (Exception ex) {};
}
// has been extracted from the database
//result.setExtension( SVCNS, STORED, "DATE");
// not yet cached (this instruction should be useless)
result.setExtension( SVCNS, CACHED, (String)null );
return result;
}
/**
* loads the full alignment from the database and put it in the
* alignmentTable hastable
*
* should be invoked when:
* ( result.getExtension(CACHED) == ""
* && result.getExtension(STORED) != "") {
*/
protected Alignment retrieveAlignment( String uri, Alignment alignment ) throws SQLException, AlignmentException, URISyntaxException {
String id = stripAlignmentUri( uri );
URI ent1 = null, ent2 = null;
alignment.setOntology1( new URI( alignment.getExtension( SVCNS, OURI1 ) ) );
alignment.setOntology2( new URI( alignment.getExtension( SVCNS, OURI2 ) ) );
// Get cells
Statement st = createStatement();
Statement st2 = createStatement();
ResultSet rs = st.executeQuery( "SELECT * FROM cell WHERE id = '" + id + "'" );
while( rs.next() ) {
ent1 = new URI( rs.getString("uri1") );
ent2 = new URI( rs.getString("uri2") );
if ( ent1 == null || ent2 == null ) break;
Cell cell = alignment.addAlignCell(ent1, ent2, rs.getString("relation"), Double.parseDouble(rs.getString("measure")));
String cid = rs.getString( "cell_id" );
if ( cid != null && !cid.equals("") ) {
if ( !cid.startsWith("##") ) {
cell.setId( cid );
}
ResultSet rse2 = st2.executeQuery("SELECT * FROM extension WHERE id = '" + cid + "'");
while ( rse2.next() ){
cell.setExtension( rse2.getString("uri"),
rse2.getString("tag"),
rse2.getString("val") );
}
}
cell.setSemantics( rs.getString( "semantics" ) );
}
// reset
resetCacheStamp(alignment);
st.close();
return alignment;
}
/**
* unload the cells of an alignment...
* This should help retrieving some space
*
* should be invoked when:
* ( result.getExtension(CACHED) != ""
* && obviously result.getExtension(STORED) != ""
*/
protected void flushAlignment( Alignment alignment ) {// throws AlignmentException
//alignment.removeAllCells();
// reset
//alignment.setExtension( SVCNS, CACHED, "" );
}
//**********************************************************************
// DEALING WITH URIs
// Public because this is now used by AServProtocolManager
public String generateAlignmentUri() {
// Generate an id based on a URI prefix + Date + random number
return recoverAlignmentUri( generateId() );
}
public String recoverAlignmentUri( String id ) {
// Recreate Alignment URI from its id
return idprefix + "/" + ALID + id;
}
public String stripAlignmentUri( String alid ) {
return alid.substring( alid.indexOf( ALID )+5 );
}
/*
* Rules for cell ids:
* (1) if users set cell_id uses them (check them for URI)
* (2) if not, generate a *local* cell id if necessary and add ##
* (3) use these cell-id in the extension part...
* STORE:
* if cell has extension && no id, create cell id, store it in db, not in setId
* if cell has extension && id, us it with getId/setId
* UNSTORE:
* suppress those extensions with the cell_id if exists
* LOAD-FROM-DB:
* if there is a cell id, use it for loading extensions
* At alignment store time, use getCellId -> store it
* At alignment load-from-db time, get the id and all the
*/
private String generateCellId() {
return "##"+generateId();
}
private String generateId() {
// Generate an id based on Date + random number
return new Date().getTime() + "/" + randomNum();
}
private int randomNum() {
Random rand = new Random(System.currentTimeMillis());
return Math.abs(rand.nextInt(1000));
}
//**********************************************************************
// FETCHING FROM CACHE
/**
* retrieve alignment metadata from id
* This is more difficult because we return the alignment we have
* disreagarding if it is complete o only metadata
*/
public Alignment getMetadata( String uri ) throws AlignmentException {
Alignment result = alignmentTable.get( uri );
if ( result == null )
throw new AlignmentException("getMetadata: Cannot find alignment");
return result;
}
/**
* retrieve full alignment from id (and cache it)
*/
public Alignment getAlignment( String uri ) throws AlignmentException, SQLException {
Alignment result = null;
try {
result = alignmentTable.get( uri );
} catch( Exception ex ) {
//logger.trace( "Unknown exception with Id = {}", uri );
logger.debug( "IGNORED: Unknown exception", ex );
}
if ( result == null ) {
//logger.trace( "Cache: Id ={} is not found.", uri );
throw new AlignmentException( "getAlignment: Cannot find alignment "+uri );
}
// If not cached, retrieve it now
if ( ( result.getExtension( SVCNS, CACHED ) == null || result.getExtension( SVCNS, CACHED ).equals("") )
&& result.getExtension(SVCNS, STORED ) != null
&& !result.getExtension(SVCNS, STORED ).equals("") ) {
try { retrieveAlignment( uri, result ); }
catch ( URISyntaxException urisex ) {
logger.trace( "Cache: cannot read from DB", urisex );
throw new AlignmentException( "getAlignment: Cannot find alignment", urisex );
};
}
return result;
}
public Set<Alignment> getAlignments( URI uri ) {
return ontologyTable.get( uri );
}
/**
* returns the alignments between two ontologies
* if one of the ontologies is null, then return them all
*/
public Set<Alignment> getAlignments( URI uri1, URI uri2 ) {
Set<Alignment> result;
Set<Alignment> potential = new HashSet<Alignment>();
if ( uri2 != null ){
String uri2String = uri2.toString();
Set<Alignment> found = ontologyTable.get( uri2 );
if ( found != null ) {
for( Alignment al : found ) {
if ( al.getExtension(SVCNS, OURI2).equals( uri2String ) ) {
potential.add( al );
}
}
}
}
if ( uri1 != null ) {
if ( potential.isEmpty() ) {
Set<Alignment> found = ontologyTable.get( uri1 );
if ( found != null ) {
potential = found;
} else return potential;
}
result = new HashSet<Alignment>();
String uri1String = uri1.toString();
for( Alignment al : potential ) {
// This is not the best because URI are not resolved here...
if ( al.getExtension(SVCNS, OURI1).equals( uri1String ) ) {
result.add( al );
}
}
} else { result = potential; }
return result;
}
//**********************************************************************
// RECORDING ALIGNMENTS
/**
* records newly created alignment
*/
public String recordNewAlignment( Alignment alignment, boolean force ) {
try { return recordNewAlignment( generateAlignmentUri(), alignment, force );
} catch (AlignmentException ae) { return (String)null; }
}
/**
* records alignment identified by id
*/
public String recordNewAlignment( String uri, Alignment al, boolean force ) throws AlignmentException {
Alignment alignment = al;
alignment.setExtension(SVCNS, OURI1, alignment.getOntology1URI().toString());
alignment.setExtension(SVCNS, OURI2, alignment.getOntology2URI().toString());
// Index
recordAlignment( uri, alignment, force );
// Not yet stored
alignment.setExtension(SVCNS, STORED, (String)null);
// Cached now
resetCacheStamp(alignment);
return uri;
}
/**
* records alignment identified by id
*/
public String recordAlignment( String uri, Alignment alignment, boolean force ) {
// record the Alignment at the corresponding Uri in tables!
alignment.setExtension( Namespace.ALIGNMENT.uri, Annotations.ID, uri );
// Store it
try {
URI ouri1 = new URI( alignment.getExtension( SVCNS, OURI1) );
URI ouri2 = new URI( alignment.getExtension( SVCNS, OURI2) );
if ( force || alignmentTable.get( uri ) == null ) {
Set<Alignment> s1 = ontologyTable.get( ouri1 );
if ( s1 == null ) {
s1 = new HashSet<Alignment>();
ontologyTable.put( ouri1, s1 );
}
s1.add( alignment );
Set<Alignment> s2 = ontologyTable.get( ouri2 );
if ( s2 == null ) {
s2 = new HashSet<Alignment>();
ontologyTable.put( ouri2, s2 );
}
s2.add( alignment );
alignmentTable.put( uri, alignment );
}
return uri;
} catch ( Exception e ) {
logger.debug( "IGNORED: Unlikely URI exception", e );
return null;
}
}
/**
* suppresses the record for an alignment
*/
public void unRecordAlignment( Alignment alignment ) {
String id = alignment.getExtension( Namespace.ALIGNMENT.uri, Annotations.ID );
try {
Set<Alignment> s1 = ontologyTable.get( new URI( alignment.getExtension( SVCNS, OURI1) ) );
if ( s1 != null ) s1.remove( alignment );
Set<Alignment> s2 = ontologyTable.get( new URI( alignment.getExtension( SVCNS, OURI2) ) );
if ( s2 != null ) s2.remove( alignment );
} catch ( URISyntaxException uriex ) {
logger.debug( "IGNORED: Unlikely URI exception", uriex );
}
alignmentTable.remove( id );
}
//**********************************************************************
// STORING IN DATABASE
/**
* quote:
* Prepare a string to be used in SQL queries by preceeding occurences of
* "'", """, and "\" by a "\".
* This should be implemented at a lower level within Java itself
* (or the sql package).
* This function is used here for protecting everything to be entered in
* the database
*/
public String quote( String s ) {
if ( s == null ) return "NULL";
String result = "'";
char[] chars = s.toCharArray();
int j = 0;
int i = 0;
char c;
for ( ; i < chars.length; i++ ){
c = chars[i];
if ( c == '\'' || c == '"' || c == '\\' ) {
result += new String( chars, j, i-j ) + "\\" + c;
j = i+1;
};
}
return result + new String( chars, j, i-j ) + "'";
}
public boolean isAlignmentStored( Alignment alignment ) {
return ( alignment.getExtension( SVCNS, STORED ) != null &&
!alignment.getExtension( SVCNS, STORED ).equals("") );
}
/**
* Non publicised class
*/
public void eraseAlignment( String uri, boolean eraseFromDB ) throws SQLException, AlignmentException {
Alignment alignment = getAlignment( uri );
if ( alignment != null ) {
if ( eraseFromDB ) unstoreAlignment( uri, alignment );
// Suppress it from the cache...
unRecordAlignment( alignment );
}
}
/**
* Non publicised class
*/
public void unstoreAlignment( String uri ) throws SQLException, AlignmentException {
Alignment alignment = getAlignment( uri );
if ( alignment != null ) {
unstoreAlignment( uri, alignment );
}
}
public void unstoreAlignment( String uri, Alignment alignment ) throws SQLException, AlignmentException {
Statement st = createStatement();
String id = stripAlignmentUri( uri );
try {
conn.setAutoCommit( false );
// Delete cell's extensions
ResultSet rs = st.executeQuery( "SELECT cell_id FROM cell WHERE id='"+id+"'" );
while ( rs.next() ){
String cid = rs.getString("cell_id");
if ( cid != null && !cid.equals("") ) {
st.executeUpdate( "DELETE FROM extension WHERE id='"+cid+"'" );
}
}
st.executeUpdate("DELETE FROM cell WHERE id='"+id+"'");
st.executeUpdate("DELETE FROM extension WHERE id='"+id+"'");
st.executeUpdate("DELETE FROM ontology WHERE id='"+id+"'");
st.executeUpdate("DELETE FROM dependency WHERE id='"+id+"'");
st.executeUpdate("DELETE FROM alignment WHERE id='"+id+"'");
alignment.setExtension( SVCNS, STORED, (String)null);
} catch ( SQLException sex ) {
conn.rollback();
logger.warn( "SQLError", sex );
throw sex;
} finally {
conn.setAutoCommit( false );
st.close();
}
}
public void storeAlignment( String uri ) throws AlignmentException, SQLException {
String query = null;
BasicAlignment alignment = (BasicAlignment)getAlignment( uri );
String id = stripAlignmentUri( uri );
Statement st = null;
// We store stored date
alignment.setExtension( SVCNS, STORED, new Date().toString());
// We empty cached date
alignment.setExtension( SVCNS, CACHED, (String)null );
// Try to store at most 3 times.
// Otherwise, an exception EOFException will be thrown (relation with Jetty???)
// [JE2013: Can we check this?]
for( int i=0; i < 3 ; i++ ) {
st = createStatement();
try {
logger.debug( "Storing alignment {}as {}", uri, id );
conn.setAutoCommit( false );
query = "INSERT INTO alignment " +
"(id, type, level) " +
"VALUES (" +quote(id)+","+quote(alignment.getType())+","+quote(alignment.getLevel()) +")";
st.executeUpdate(query);
recordOntology( st, id, true,
alignment.getOntology1URI(),
alignment.getFile1(),
alignment.getOntologyObject1() );
recordOntology( st, id, false,
alignment.getOntology2URI(),
alignment.getFile2(),
alignment.getOntologyObject2() );
// store dependencies
for ( String[] ext : alignment.getExtensions() ) {
String turi = ext[0];
String tag = ext[1];
String val = ext[2];
query = "INSERT INTO extension " +
"(id, uri, tag, val) " +
"VALUES (" + quote(id) + "," + quote(turi) + "," + quote(tag) + "," + quote(val) + ")";
st.executeUpdate(query);
}
for( Cell c : alignment ) {
String cellid = null;
if ( c.getObject1() != null && c.getObject2() != null ){
cellid = c.getId();
if ( cellid != null ){
if ( cellid.startsWith("#") ) {
cellid = alignment.getExtension( Namespace.ALIGNMENT.uri, Annotations.ID ) + cellid;
}
} else if ( c.getExtensions() != null ) {
// JE: In case of extensions create an ID
cellid = generateCellId();
}
else cellid = "";
String uri1 = c.getObject1AsURI(alignment).toString();
String uri2 = c.getObject2AsURI(alignment).toString();
String strength = c.getStrength() + ""; // crazy Java
String sem;
if ( !c.getSemantics().equals("first-order") )
sem = c.getSemantics();
else sem = "";
String rel = ((BasicRelation)c.getRelation()).getRelation();
query = "INSERT INTO cell " +
"(id, cell_id, uri1, uri2, measure, semantics, relation) " +
"VALUES (" + quote(id) + "," + quote(cellid) + "," + quote(uri1) + "," + quote(uri2) + "," + quote(strength) + "," + quote(sem) + "," + quote(rel) + ")";
st.executeUpdate(query);
}
if ( cellid != null && !cellid.equals("") && c.getExtensions() != null ) {
// Store extensions
for ( String[] ext : c.getExtensions() ) {
String turi = ext[0];
String tag = ext[1];
String val = ext[2];
query = "INSERT INTO extension " +
"(id, uri, tag, val) " +
"VALUES (" + quote(cellid) + "," + quote(turi) + "," + quote(tag) + "," + quote(val) + ")";
st.executeUpdate(query);
}
}
}
} catch ( SQLException sex ) {
logger.warn( "SQLError", sex );
conn.rollback();
throw sex;
} finally {
conn.setAutoCommit( true );
}
break;
}
st.close();
// We reset cached date
resetCacheStamp(alignment);
}
// Do not add transaction here: this is handled by caller
public void recordOntology( Statement st, String id, boolean source, URI uri, URI file, Ontology onto ) throws SQLException {
String sfile = "";
String suri = "";
if ( file != null ) sfile = file.toString();
if ( uri != null ) suri = uri.toString();
String query = null;
logger.debug( "Recording ontology {} with file {}", suri, sfile );
if ( onto != null ) {
query = "INSERT INTO ontology " +
"(id, uri, file, source, formname, formuri) " +
"VALUES ("+quote(id)+","+ quote(suri)+","+quote(sfile)+"," +(source?'1':'0')+","+quote(onto.getFormalism())+","+quote(onto.getFormURI().toString())+")";
} else {
query = "INSERT INTO ontology " +
"(id, uri, file, source) " +
"VALUES ("+quote(id)+","+ quote(suri)+","+quote(sfile)+"," +(source?'1':'0')+")";
}
st.executeUpdate(query);
}
//**********************************************************************
// CACHE MANAGEMENT (Not implemented yet)
public void resetCacheStamp( Alignment result ){
result.setExtension(SVCNS, CACHED, new Date().toString() );
}
public void cleanUpCache() {
// for each alignment in the table
// set currentDate = Date();
// if ( DateFormat.parse( result.getExtension(SVCNS, CACHED) ).before( ) ) {
// - for each ontology if no other alignment => unload
// - clean up cells
// }
}
// **********************************************************************
// DATABASE CREATION AND UPDATING
/*
# server info
create table server (
host varchar(50),
port varchar(5),
prefix varchar(50),
edit varchar(5)
);
# alignment info
create table alignment (
id varchar(100),
type varchar(5),
level varchar(25),
primary key (id));
# ontology info
create table ontology (
id varchar(255),
uri varchar(255),
file varchar(255),
source boolean,
formname varchar(50),
formuri varchar(255)
);
# dependencies info
create table dependency (
id varchar(255),
dependsOn varchar(255)
);
# cell info
create table cell(
id varchar(100),
cell_id varchar(255),
uri1 varchar(255),
uri2 varchar(255),
semantics varchar(30),
measure varchar(20),
relation varchar(255));
# extension info
create table extension(
id varchar(100),
uri varchar(200),
tag varchar(50),
val varchar(500));
*/
public void initDatabase() throws SQLException {
logger.info( "Initialising database" );
Statement st = createStatement();
try {
conn.setAutoCommit( false );
// Create tables
st.executeUpdate("CREATE TABLE alignment (id VARCHAR(100), type VARCHAR(5), level VARCHAR(25), primary key (id))");
st.executeUpdate("CREATE TABLE ontology (id VARCHAR(255), source BOOLEAN, uri VARCHAR(255), formname VARCHAR(50), formuri VARCHAR(255), file VARCHAR(255), primary key (id, source))");
st.executeUpdate("CREATE TABLE dependency (id VARCHAR(255), dependsOn VARCHAR(255))");
st.executeUpdate("CREATE TABLE cell(id VARCHAR(100), cell_id VARCHAR(255), uri1 VARCHAR(255), uri2 VARCHAR(255), semantics VARCHAR(30), measure VARCHAR(20), relation VARCHAR(255))");
st.executeUpdate("CREATE TABLE extension(id VARCHAR(100), uri VARCHAR(200), tag VARCHAR(50), val VARCHAR(500))");
st.executeUpdate("CREATE TABLE server (host VARCHAR(50), port VARCHAR(5), prefix VARCHAR (50), edit BOOLEAN, version VARCHAR(5))");
st.close();
// Register *DATABASE* Because of the values (that some do not like), this is a special statement
registerServer( "dbms", "port", false, idprefix );
} catch ( SQLException sex ) {
logger.warn( "SQLError", sex );
conn.rollback();
throw sex;
} finally {
conn.setAutoCommit( true );
}
}
public void resetDatabase( boolean force ) throws SQLException, AlignmentException {
Statement st = createStatement();
try {
conn.setAutoCommit( false );
// Check that no one else is connected...
if ( force != true ){
ResultSet rs = st.executeQuery("SELECT COUNT(*) AS rowcount FROM server WHERE edit=1");
rs.next();
int count = rs.getInt("rowcount") ;
rs.close() ;
if ( count > 1 ) {
throw new AlignmentException("Cannot init database: other processes use it");
}
}
// Suppress old database if exists
st.executeUpdate("DROP TABLE IF EXISTS server");
st.executeUpdate("DROP TABLE IF EXISTS alignment");
st.executeUpdate("DROP TABLE IF EXISTS ontology");
st.executeUpdate("DROP TABLE IF EXISTS dependency");
st.executeUpdate("DROP TABLE IF EXISTS cell");
st.executeUpdate("DROP TABLE IF EXISTS extension");
// Redo it
initDatabase();
// Register *THIS* server, etc. characteristics (incl. version name)
registerServer( host, port, rights==1, idprefix );
} catch ( SQLException sex ) {
logger.warn( "SQLError", sex );
conn.rollback();
throw sex;
} finally {
st.close();
conn.setAutoCommit( true );
}
}
private void registerServer( String host, String port, Boolean writeable, String prefix ) throws SQLException {
// Register *THIS* server, etc. characteristics (incl. version name)
PreparedStatement pst = conn.prepareStatement("INSERT INTO server (host, port, edit, version, prefix) VALUES (?,?,?,?,?)");
pst.setString(1,host);
pst.setString(2,port);
pst.setBoolean(3,writeable);
pst.setString(4,VERSION+"");
pst.setString(5,idprefix);
pst.executeUpdate();
pst.close();
}
/*
* A dummy method, since it exists just ALTER TABLE ... DROP and ALTER TABLE ... ADD in SQL Language.
* each dbms has its own language for manipulating table columns....
*/
public void renameColumn(Statement st, String tableName, String oldName, String newName, String newType) throws SQLException {
try {
conn.setAutoCommit( false );
st.executeUpdate("ALTER TABLE "+tableName+" ADD "+newName+" "+newType);
st.executeUpdate("UPDATE "+tableName+" SET "+newName+"="+oldName);
st.executeUpdate("ALTER TABLE "+tableName+" DROP "+oldName);
} catch ( SQLException sex ) {
logger.warn( "SQLError", sex );
conn.rollback();
throw sex;
} finally {
conn.setAutoCommit( true );
}
}
/*
* Another dummy method, since it exists just ALTER TABLE ... DROP and ALTER TABLE ... ADD in SQL Language.
* each dbms has its own language for manipulating table columns....
*/
public void changeColumnType(Statement st, String tableName, String columnName, String newType) throws SQLException {
try {
conn.setAutoCommit( false );
String tempName = columnName+"temp";
renameColumn(st,tableName,columnName,tempName,newType);
renameColumn(st,tableName,tempName,columnName,newType);
} catch ( SQLException sex ) {
logger.warn( "SQLError", sex );
conn.rollback();
throw sex;
} finally {
conn.setAutoCommit( true );
}
}
public void updateDatabase() throws SQLException, AlignmentException {
Statement st = createStatement();
// get the version number (port is the entry which is always here)
ResultSet rs = st.executeQuery("SELECT version FROM server WHERE port='port'");
rs.next();
int version = rs.getInt("version") ;
if ( version < VERSION ) {
if ( version >= 302 ) {
if ( version < 310 ) {
logger.info( "Upgrading to version 3.1" );
// ALTER database
renameColumn(st,"extension","method","val","VARCHAR(500)");
// case mysql
//st.executeUpdate("ALTER TABLE extension CHANGE method val VARCHAR(500)");
st.executeUpdate("ALTER TABLE extension ADD uri VARCHAR(200);");
// Modify extensions
ResultSet rse = st.executeQuery("SELECT * FROM extension");
Statement st2 = createStatement();
while ( rse.next() ){
String tag = rse.getString("tag");
//logger.trace(" Treating tag {} of {}", tag, rse.getString("id"));
if ( !tag.equals("") ){
int pos;
String ns;
String name;
if ( (pos = tag.lastIndexOf('#')) != -1 ) {
ns = tag.substring( 0, pos );
name = tag.substring( pos+1 );
} else if ( (pos = tag.lastIndexOf(':')) != -1 && pos > 5 ) {
ns = tag.substring( 0, pos )+"#";
name = tag.substring( pos+1 );
} else if ( (pos = tag.lastIndexOf('/')) != -1 ) {
ns = tag.substring( 0, pos+1 );
name = tag.substring( pos+1 );
} else {
ns = Namespace.ALIGNMENT.uri;
name = tag;
}
//logger.trace(" >> {} : {}", ns, name);
st2.executeUpdate("UPDATE extension SET tag='"+name+"', uri='"+ns+"' WHERE id='"+rse.getString("id")+"' AND tag='"+tag+"'");
}
}
}
// Nothing to do with 340: subsumed by 400
if ( version < 400 ) {
logger.info("Upgrading to version 4.0");
// ALTER database
changeColumnType(st,"cell","relation", "VARCHAR(255)");
changeColumnType(st,"cell","uri1", "VARCHAR(255)");
changeColumnType(st,"cell","uri2", "VARCHAR(255)");
changeColumnType(st,"alignment","level", "VARCHAR(255)");
changeColumnType(st,"alignment","uri1", "VARCHAR(255)");
changeColumnType(st,"alignment","uri2", "VARCHAR(255)");
changeColumnType(st,"alignment","file1", "VARCHAR(255)");
changeColumnType(st,"alignment","file2", "VARCHAR(255)");
renameColumn(st,"alignment","owlontology1","ontology1", "VARCHAR(255)");
renameColumn(st,"alignment","owlontology2","ontology2", "VARCHAR(255)");
}
if ( version < 450 ) {
logger.info("Upgrading to version 4.5");
logger.info("Creating Ontology table");
st.executeUpdate("CREATE TABLE ontology (id VARCHAR(255), uri VARCHAR(255), source BOOLEAN, file VARCHAR(255), formname VARCHAR(50), formuri VARCHAR(255), primary key (id, source))");
ResultSet rse = st.executeQuery("SELECT * FROM alignment");
while ( rse.next() ){
Statement st2 = createStatement();
// No Ontology _type_ available then
st2.executeUpdate("INSERT INTO ontology (id, uri, source, file) VALUES ('"+rse.getString("id")+"','"+rse.getString("uri1")+"','1','"+rse.getString("file1")+"')");
st2.executeUpdate("INSERT INTO ontology (id, uri, source, file) VALUES ('"+rse.getString("id")+"','"+rse.getString("uri2")+"','0','"+rse.getString("file2")+"')");
}
logger.info("Cleaning up Alignment table");
st.executeUpdate("ALTER TABLE alignment DROP ontology1");
st.executeUpdate("ALTER TABLE alignment DROP ontology2");
st.executeUpdate("ALTER TABLE alignment DROP uri1");
st.executeUpdate("ALTER TABLE alignment DROP uri2");
st.executeUpdate("ALTER TABLE alignment DROP file1");
st.executeUpdate("ALTER TABLE alignment DROP file2");
logger.debug("Altering server table");
st.executeUpdate("ALTER TABLE server ADD prefix VARCHAR(50);");
st.executeUpdate("UPDATE server SET prefix='"+idprefix+"'");
logger.debug("Updating server with prefix");
Statement stmt = null;
try { // In all alignment
conn.setAutoCommit( false );
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet uprs = stmt.executeQuery( "SELECT id FROM alignment" );
while ( uprs.next() ) {
String oldid = uprs.getString("id");
String newid = stripAlignmentUri( oldid );
//logger.trace("Updating {} to {}", oldid, newid );
uprs.updateString( "id", newid );
uprs.updateRow();
// In all cell (for id and cell_id)
st.executeUpdate("UPDATE cell SET id='"+newid+"' WHERE id='"+oldid+"'" );
// In all extension
st.executeUpdate("UPDATE extension SET id='"+newid+"' WHERE id='"+oldid+"'" );
// In all ontology
st.executeUpdate("UPDATE ontology SET id='"+newid+"' WHERE id='"+oldid+"'" );
}
// Now, for each cell, with an id,
// either recast the id ... or not
conn.commit();
} catch ( SQLException e ) {
logger.warn( "IGNORED Failed to update", e );
} finally {
if ( stmt != null ) { stmt.close(); }
conn.setAutoCommit( true );
}
logger.info("Creating dependency table");
st.executeUpdate("CREATE TABLE dependency (id VARCHAR(255), dependsOn VARCHAR(255))");
logger.info("Fixing legacy errors in cached/stored");
st.executeUpdate( "UPDATE extension SET val=( SELECT e2.val FROM extension e2 WHERE e2.tag='cached' AND e2.id=extension.id ) WHERE tag='stored' AND val=''" );
// We should also implement a clean up (suppress all starting with http://)
}
// ALTER version
st.executeUpdate("UPDATE server SET version='"+VERSION+"'");
} else {
throw new AlignmentException( "Database must be upgraded ("+version+" -> "+VERSION+")" );
}
}
st.close();
}
}