From 223580579a78d9301641980ef68878662172cfef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Euzenat?= <Jerome.Euzenat@inria.fr>
Date: Mon, 28 Apr 2014 20:50:44 +0000
Subject: [PATCH] - separated VolatilCache from SQLCache

---
 html/relnotes.html                            |   6 +-
 .../exmo/align/service/SQLCache.java          | 565 ++++++------------
 .../exmo/align/service/VolatilCache.java      | 434 ++++++++++++++
 3 files changed, 624 insertions(+), 381 deletions(-)
 create mode 100644 src/fr/inrialpes/exmo/align/service/VolatilCache.java

diff --git a/html/relnotes.html b/html/relnotes.html
index 7c79777b..9345eaf9 100644
--- a/html/relnotes.html
+++ b/html/relnotes.html
@@ -70,12 +70,13 @@ with a warning:
 
 <!--h2>Version 4.9 (1xxx): ??/??/201X - Al pesto</h2-->
 <!--h2>Version 4.8 (1xxx): ??/??/201x - Antésine</h2-->
-<!--h2>Version 4.7 (1xxx): ??/0?/2014 - Letraset</h2-->
+<!--h2>Version 4.7 (19xx): ??/0?/2014 - Letraset</h2-->
 <p><ul compact="1">
 <li><span style="color: red;">Deprecated</span> <tt>BasicAlignment.removeAlignCell()</tt>, use <tt>remCell()</tt> instead (impl)</tt>
 <li><span style="color: red;">Moved</span> <tt>QueryMediator</tt>, from <tt>service</tt> to <tt>queryprocessor</tt> (impl)</tt>
 <li>Fixed a bug in <tt>QueryMediator</tt> which doubled '#' (serv)</li>
 <li>Fixed a few mistakes in <tt>SilkRendererVisitor</tt> (impl)</li>
+<li>Fixed several bugs in <tt>GraphPatternRendererVisitor</tt> (impl)</li>
 <li>Implemented <tt>translateMessage()</tt> and <tt>rewriteQuery()</tt> in <tt>BasicAlignment</tt> (impl)</li>
 <li>Reorganised AlignmentServices into transport (HTTP) and service (HTML/Web service) (serv)</li>
 <li>Enabled query translation in interface (serv)</li>
@@ -83,7 +84,8 @@ with a warning:
 <li>Added a command-line utility for query translation (cli)</li>
 <li>Added a guard forbiding to create a <tt>BasicCell</tt> with null objects (impl)</li>
 <li>Added httpcore library necessary for tutorial4 (tutorial/lib)</li>
-<li>Genericised storage <tt>Cache</tt> (serv)</li>
+<li>Added extensions to BasicOntologyNetwork (impl)</li>
+<li>Genericised storage <tt>Cache</tt> and implemented <tt>VolatilCache</tt> (serv)</li>
 </ul></p>
 
 <h2>Version 4.6 (1875): 22/01/2014 - Da lec'h all</h2>
diff --git a/src/fr/inrialpes/exmo/align/service/SQLCache.java b/src/fr/inrialpes/exmo/align/service/SQLCache.java
index dacbeea6..72702036 100644
--- a/src/fr/inrialpes/exmo/align/service/SQLCache.java
+++ b/src/fr/inrialpes/exmo/align/service/SQLCache.java
@@ -21,19 +21,14 @@
 
 package fr.inrialpes.exmo.align.service;
 
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.Hashtable;
+//import java.util.Iterator;
+//import java.util.Map.Entry;
 import java.util.Vector;
-import java.util.Collection;
-import java.util.Set;
-import java.util.HashSet;
+//import java.util.Set;
 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;
@@ -45,43 +40,35 @@ import org.slf4j.LoggerFactory;
 
 import fr.inrialpes.exmo.align.impl.BasicAlignment;
 import fr.inrialpes.exmo.align.impl.BasicRelation;
+import fr.inrialpes.exmo.align.impl.BasicOntologyNetwork;
 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.OntologyNetwork;
 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;
 
 /**
- * JE: This class and Cache should never return SQLException but AlignmentException
- * JE: Maybe some methods are common with RDF storage, the rest would rather be DBService...
+ * This class implements, in addition to VolatilCache,
+ * the persistent storage of Alignments and networks
+ * In a SQL database.
  *
- * 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 
+ * It loads Alignments and network from the database
+ * It stores them in the database on demand
  */
 
-public class SQLCache implements Cache {
+public class SQLCache extends VolatilCache implements Cache {
     final static Logger logger = LoggerFactory.getLogger( SQLCache.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
+    final int VERSION = 461; // 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
@@ -94,6 +81,7 @@ public class SQLCache implements Cache {
        450: ADDED ontology database / reduced alignment database
 	    ADDED prefix in server
             ADDED dependency database (no action)
+       461: CHANGED THE STICKER BECAUSE OF IMPLEMENTATION
      */
 
     DBService service = null;
@@ -103,13 +91,6 @@ public class SQLCache implements Cache {
     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 SQLCache( DBService serv ) {
@@ -119,16 +100,14 @@ public class SQLCache implements Cache {
 	} catch( Exception e ) {
 	    logger.warn( "Cannot connect to DB", e );
 	}
-	alignmentTable = new Hashtable<String,Alignment>();
-	ontologyTable = new Hashtable<URI,Set<Alignment>>();
+	resetTables();
     }
 
     public void reset() throws AlignmentException {
-	alignmentTable = new Hashtable<String,Alignment>();
-	ontologyTable = new Hashtable<URI,Set<Alignment>>();
+	resetTables();
 	// reload alignment descriptions
 	try {
-	    loadAlignments( true );
+	    load( true );
 	} catch ( SQLException sqlex ) {
 	    throw new AlignmentException( "SQL exception", sqlex );
 	}
@@ -140,10 +119,9 @@ public class SQLCache implements Cache {
      * alignmentTable hashtable
      */
     public void init( Properties p, String prefix ) throws AlignmentException {
-	logger.debug( "Initializing Database cache" );
+	super.init( p, prefix );
 	port = p.getProperty("http"); // bad idea
 	host = p.getProperty("host");
-	idprefix = prefix;
 	try {
 	    Statement st = createStatement();
 	    // test if a database is here, otherwise create it
@@ -163,7 +141,7 @@ public class SQLCache implements Cache {
 	    // register by the database
 	    registerServer( host, port, rights==1, idprefix );
 	    // load alignment descriptions
-	    loadAlignments( true );
+	    load( true );
 	    st.close();
 	} catch (SQLException sqlex) {
 	    throw new AlignmentException( "SQLException", sqlex );
@@ -194,7 +172,7 @@ public class SQLCache implements Cache {
      * alignmentTable hashtable
      * index them under the ontology URIs
      */
-    private void loadAlignments( boolean force ) throws SQLException {
+    private void load( boolean force ) throws SQLException {
 	logger.debug( "Loading alignments..." );
 	String id = null;
 	Alignment alignment = null;
@@ -218,50 +196,7 @@ public class SQLCache implements Cache {
 	}
 	st.close();
     }
-
-    protected Enumeration<Alignment> listAlignments() {
-	return alignmentTable.elements();
-    }
-
-    public Collection<Alignment> alignments() {
-	return alignmentTable.values();
-    }
-
-    public Collection<URI> ontologies() {
-	return ontologyTable.keySet();
-    }
-
-    public 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;
-    }
-
-    public 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
@@ -375,232 +310,23 @@ public class SQLCache implements Cache {
 	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 {
-	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 ( SQLException sqlex ) {
-		throw new AlignmentException( "getAlignment: SQL exception", sqlex );
-	    } catch ( URISyntaxException urisex ) {
-		logger.trace( "Cache: cannot read from DB", urisex );
-		throw new AlignmentException( "getAlignment: Cannot find alignment", urisex );
-	    };
+    protected Alignment fetchAlignment( String uri, Alignment result ) throws AlignmentException {
+	try { 
+	    return retrieveAlignment( uri, result );
+	} catch ( SQLException sqlex ) {
+	    throw new AlignmentException( "getAlignment: SQL exception", sqlex );
+	} 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
     /**
@@ -629,76 +355,50 @@ public class SQLCache implements Cache {
 	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 AlignmentException {
-        Alignment alignment = getAlignment( uri );
-        if ( alignment != null ) {
-	    try {
-		if ( eraseFromDB ) unstoreAlignment( uri, alignment );
-		// Suppress it from the cache...
-	    } catch (SQLException sqlex) {
-		throw new AlignmentException( "SQL Exception", sqlex );
-	    }
-	    unRecordAlignment( alignment );
-        }
-    }
-
     /**
      * Non publicised class
      */
-    public void unstoreAlignment( String uri ) throws SQLException, AlignmentException {
+    public void unstoreAlignment( String uri ) throws 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 );
+    // Suppress it from the cache...
+    public void unstoreAlignment( String uri, Alignment alignment ) throws AlignmentException {
 	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+"'" );
+	    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 new AlignmentException( "SQL Exception", sex );
+	    } finally {
+		conn.setAutoCommit( false );
+		st.close();
 	    }
-	    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();
+	    throw new AlignmentException( "Cannot establish SQL Connexion", sex );
 	}
     }
 
-    /*
-	    try {
-		if ( eraseFromDB ) unstoreAlignment( uri, alignment );
-		// Suppress it from the cache...
-	    } catch (SQLException sqlex) {
-		throw new AlignmentException( "SQL Exception", sqlex );
-	    }
-	    unRecordAlignment( alignment );
-        }
-    */
     public void storeAlignment( String uri ) throws AlignmentException {
 	String query = null;
 	BasicAlignment alignment = (BasicAlignment)getAlignment( uri );
@@ -716,7 +416,7 @@ public class SQLCache implements Cache {
 	    for( int i=0; i < 3 ; i++ ) {
 		try {
 		    st = createStatement();
-		    logger.debug( "Storing alignment {} as {}", uri, id );
+		    logger.debug( "Storing alignment {}�as {}", uri, id );
 		    conn.setAutoCommit( false );
 		    query = "INSERT INTO alignment " + 
 			"(id, type, level) " +
@@ -820,21 +520,6 @@ public class SQLCache implements Cache {
 	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
     /*
@@ -892,6 +577,24 @@ public class SQLCache implements Cache {
       uri varchar(200),
       tag varchar(50),
       val varchar(500));
+      
+      # ontologies info 
+      
+      create table  (
+      id varchar(255),
+      idonet varchar(255),
+      uri varchar(255),
+      name varchar(50),
+      file varchar(255));
+
+      # ontologynetwork info 
+      
+      create table ontologynetwork(
+      id varchar(255),
+      uri varchar(255),
+      name varchar(50),
+      type varchar(50),
+      file varchar(255));
 
     */
 
@@ -906,7 +609,9 @@ public class SQLCache implements Cache {
 	    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.executeUpdate("CREATE TABLE ontologies (id VARCHAR(255), idonet VARCHAR(255), uri VARCHAR(255), name VARCHAR(50), file VARCHAR(255), primary key (id,idonet))");
+     // st.executeUpdate("CREATE TABLE ontologynetwork (id VARCHAR(255), uri VARCHAR(255), name VARCHAR(50), type VARCHAR(50), file VARCHAR(255), primary key (id,uri))");
+	    st.executeUpdate("CREATE TABLE server (host VARCHAR(50), port VARCHAR(5), prefix VARCHAR (50), edit BOOLEAN, version VARCHAR(5))");	    
 
 	    /*
 	    // EDOAL
@@ -920,14 +625,8 @@ public class SQLCache implements Cache {
 	    // type\in classrest: joinid = id in classrest
 	    st.executeUpdate("CREATE TABLE classlist (joinid VARCHAR(50), intid VARCHAR(250))"); //intid in classexpr
 	    st.executeUpdate("CREATE TABLE classrest (joinid VARCHAR(50), arg1 VARCHAR(250), arg2 VARCHAR(250))");
-	    
-
 	    */
 
-
-
-
-
 	    st.close();
 
 	    // Register *DATABASE* Because of the values (that some do not like), this is a special statement
@@ -962,6 +661,8 @@ public class SQLCache implements Cache {
 	    st.executeUpdate("DROP TABLE IF EXISTS dependency");
 	    st.executeUpdate("DROP TABLE IF EXISTS cell");
 	    st.executeUpdate("DROP TABLE IF EXISTS extension");
+	    //st.executeUpdate("DROP TABLE IF EXISTS ontologies");
+	    //st.executeUpdate("DROP TABLE IF EXISTS ontologynetwork");
 	    // Redo it
 	    initDatabase();
 	  
@@ -1144,6 +845,16 @@ public class SQLCache implements Cache {
 		    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://)
 		}
+		if ( version < 461 ) {
+		    logger.info("Upgrading to version 4.7");
+		    // Nothing to be done so far
+		    // 462:
+		    // Ontology tables (modified ex tables)
+		    // 463:
+		    // Ontology networks (+3 tables)
+		    // 464:
+		    // EDOAL
+		}
 		// ALTER version
 		st.executeUpdate("UPDATE server SET version='"+VERSION+"'");
 	    } else {
@@ -1152,5 +863,101 @@ public class SQLCache implements Cache {
 	}
 	st.close();
     }
+    
+    //**********************************************************************
+    // ONTOLOGY NETWORKS
+    /*
+     * 
+     * 
+     */
+  
+    /*
+      // JE: This adds an Ontology in THE NETWORK
+    // put the meta data of the ontology network
+    // - structure json/html
+    // - type=
+    public void putOntologyNetwork( URI onuri, String structure, String type ) throws AlignmentException {
+	onetwork = new BasicOntologyNetwork();
+	onetwork.onName = structure; 
+	onetwork.onType = type;
+	onetwork.onFile = null;
+	onetworkTable.put(onuri,onetwork);
+	//TODO handle error in put
+    }
+    */
+    
+    /*
+    // fetch all the ontologies of the network
+    // TODO where should be placed?
+    // To put in LOVAService.java
+import fr.inrialpes.exmo.ontowrap.onetparser.JSONFetcher;  //TODO it shouldn't be here?
 
+    public void fetchLOVOntologyNetwork( URI onuri, String structure, String type ) throws AlignmentException {
+	oonetworkTable = JSONFetcher.TypeFetcher(onuri, structure, type);
+    }
+    */
+    
+    /*
+    // JE: This code was for storing ontologies...
+    // And still relying on a global variable
+    // Apparently, this should work with ONE NETWORK...
+    public void	recordOntologyNetwork( String id ) throws SQLException {
+    	Statement st = null;
+    	id = stripNetworkUri( id );
+    	st = createStatement();
+    	Set<URI> keys = onetworkTable.keySet();
+        for(URI key: keys)
+	    if ( key != null ) {
+    		String uri = key.toString();
+    		String query = null;
+    		logger.debug( "Recording ontology {} with file {}", onetworkTable.keys() );
+		query = "INSERT INTO ontologynetwork " + 
+		    "(id, uri, name, type, file) " +
+		    "VALUES ("+
+		    quote(id)+","+
+		    quote(uri)+","+
+		    quote(onetwork.onName)+","+
+		    quote(onetwork.onType)+","+
+		    quote(onetwork.onFile)+")";
+		System.out.println("El query:  "+ query);
+		st.executeUpdate(query);
+	    }
+    	//recordOONetwork(id);
+    	//TODO add START TRANSACTION; (Insert into ontologynetwork and ontologies) .. COMMIT;
+    }
+    */
+    
+    /*
+    public void	recordOONetwork(String idonet) throws SQLException {
+        int totOnto = 0;
+    	Statement st = null;
+    	st = createStatement();
+    	Set<Entry<URI, OONetwork>> set = oonetworkTable.entrySet();
+        Iterator<Entry<URI, OONetwork>> it = set.iterator();
+        while (it.hasNext()) {
+	    Map.Entry<URI, OONetwork> entry = (Map.Entry<URI, OONetwork>) it.next();
+	    URI uri = entry.getKey();
+	    String urionto = uri.toString();
+	    OONetwork oonetwork = entry.getValue();
+	    String id = generateId()+totOnto;
+	    
+	    if ( urionto != null ) {
+		String query = null;
+		logger.debug( "Recording ontology {} with file {}", urionto );
+		query = "INSERT INTO ontologies " + 
+		    "(id, idonet, uri, name, file) " +
+		    "VALUES ("+
+		    quote(id)+","+
+		    quote(idonet)+","+
+		    quote(urionto)+","+
+		    quote(oonetwork.oonName)+","+
+		    quote(oonetwork.oonFile)+")";
+		System.out.println("El query:  "+ query);
+		totOnto++;
+	    	st.executeUpdate(query);
+	    }
+        }
+    	st.close();
+    }*/
+    
 }
diff --git a/src/fr/inrialpes/exmo/align/service/VolatilCache.java b/src/fr/inrialpes/exmo/align/service/VolatilCache.java
new file mode 100644
index 00000000..65ef5c96
--- /dev/null
+++ b/src/fr/inrialpes/exmo/align/service/VolatilCache.java
@@ -0,0 +1,434 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) INRIA, 2006-2014
+ *
+ * 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.Hashtable;
+import java.util.Map;
+import java.util.Map.Entry;
+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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import fr.inrialpes.exmo.align.impl.Annotations;
+import fr.inrialpes.exmo.align.impl.Namespace;
+
+import org.semanticweb.owl.align.OntologyNetwork;
+import org.semanticweb.owl.align.Alignment;
+import org.semanticweb.owl.align.AlignmentException;
+
+/**
+ * This class implements the Alignment store of the server in
+ * a non persistent way.
+ * It can be subclassed by for implementing persistent storage.
+ *
+ * It indexes all entities in specific tables
+ * Allocate them URIs
+ */
+
+public class VolatilCache implements Cache {
+    final static Logger logger = LoggerFactory.getLogger( VolatilCache.class );
+
+    Hashtable<String,Alignment> alignmentTable = null;
+    Hashtable<URI,Set<Alignment>> ontologyTable = null;
+    Hashtable<URI,OntologyNetwork> onetworkTable = null;
+
+    String idprefix = null;
+
+    static protected final String SVCNS = Namespace.ALIGNSVC.getUriPrefix();
+    static protected final String CACHED = "cached";
+    static protected final String STORED = "stored";
+    static protected final String ALID = "alid/";
+    static protected final String OURI1 = "ouri1";
+    static protected final String OURI2 = "ouri2";
+    static protected final String ONID = "onid/";
+	
+    //**********************************************************************
+
+    public VolatilCache() {
+	resetTables();
+    }
+
+    public void resetTables() {
+	alignmentTable = new Hashtable<String,Alignment>();
+	ontologyTable = new Hashtable<URI,Set<Alignment>>();
+	onetworkTable = new Hashtable<URI,OntologyNetwork>();
+    }
+
+    public void reset() throws AlignmentException {
+	resetTables();
+    }
+
+    /**
+     * loads the alignment descriptions from the database and put them in the
+     * alignmentTable hashtable
+     */
+    public void init( Properties p, String prefix ) throws AlignmentException {
+	logger.debug( "Initializing Database cache" );
+	idprefix = prefix;
+    }
+
+    public void close() throws AlignmentException {
+    }
+
+    // **********************************************************************
+    // LOADING FROM DATABASE
+
+    protected Enumeration<Alignment> listAlignments() {
+	return alignmentTable.elements();
+    }
+
+    public Collection<Alignment> alignments() {
+	return alignmentTable.values();
+    }
+
+    public Collection<URI> ontologies() {
+	return ontologyTable.keySet();
+    }
+    
+    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;
+    }
+
+    public Collection<URI> ontologynetworks() {
+    	return onetworkTable.keySet();
+    }
+    
+    public Collection<OntologyNetwork> ontologyNetworks() {
+    	return onetworkTable.values();
+    }
+    
+    public 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;
+    }
+
+    //**********************************************************************
+    // 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() );
+    }
+    
+    protected String recoverAlignmentUri( String id ) {
+	// Recreate Alignment URI from its id
+	return idprefix + "/" + ALID + id;
+    }
+    
+    protected String stripAlignmentUri( String alid ) {
+	return alid.substring( alid.indexOf( ALID )+5 );
+    }
+
+    public String generateNetworkUri() { //For Ontology and Ontology Networks
+	// Generate an id based on a URI prefix + Date + random number
+	return recoverNetworkUri( generateId() );
+    }
+    
+    protected String recoverNetworkUri( String id ) {
+	// Recreate Ontology Network URI from its id
+	return idprefix + "/" + ONID + id;
+    }
+    
+    protected String stripNetworkUri( String onetid ) {
+	return onetid.substring( onetid.indexOf( ONID )+5 ); 
+    }
+    
+    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)); 
+    }
+
+    /*
+     * 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 
+     */
+
+    protected String generateCellId() {
+	return "##"+generateId();
+    }
+
+    //**********************************************************************
+    // 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 {
+	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, persistent implementation has to get it
+	if ( ( result.getExtension( SVCNS, CACHED ) == null || result.getExtension( SVCNS, CACHED ).equals("") )
+	     && result.getExtension(SVCNS, STORED ) != null 
+	     && !result.getExtension(SVCNS, STORED ).equals("") ) {
+	    return fetchAlignment( uri, result );
+	}
+	return result;
+    }
+
+    protected Alignment fetchAlignment( String uri, Alignment result ) throws AlignmentException {
+	return result;
+    }
+	
+    public 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 );
+	};
+    }
+
+    /**
+     * unload the cells of an alignment...
+     * This should help releasing 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, "" );
+    }
+    
+    //**********************************************************************
+    // 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 ( URISyntaxException 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
+
+    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 AlignmentException {
+        Alignment alignment = getAlignment( uri );
+        if ( alignment != null ) {
+	    if ( eraseFromDB ) unstoreAlignment( uri, alignment );
+	    unRecordAlignment( alignment );
+        }
+    }
+
+    public void unstoreAlignment( String uri, Alignment alignment ) throws AlignmentException {
+    }
+
+    public void storeAlignment( String uri ) throws AlignmentException {
+    }
+
+    //**********************************************************************
+    // 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
+	// }
+    }
+
+}
-- 
GitLab