/*
* $Id: Brain.java,v 1.4 2002/09/16 08:05:02 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.brain;
import java.io.IOException;
import java.util.Enumeration;
import java.util.ArrayList;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.sql.ResultSet;
import java.sql.DriverManager;
import anvil.core.Any;
import anvil.java.util.Hashlist;
import anvil.java.util.BindingEnumeration;
import anvil.server.Zone;
import anvil.server.OperationFailedException;
import anvil.database.ConnectionManager;
import anvil.database.PooledConnection;
import anvil.database.NoConnectionPoolException;
/**
* class Brain
*
* @author: Jani Lehtim�ki
*/
public class Brain
{
protected Zone _zone;
protected String _poolname;
protected int _cachesize;
protected Hashlist _cache;
public Brain(Zone zone, String poolname, int cachesize)
{
_zone = zone;
_poolname = poolname;
_cachesize = cachesize;
_cache = new Hashlist();
}
protected PooledConnection getConnection() throws SQLException
{
ConnectionManager manager = _zone.getManagerFor(_poolname);
if (manager != null) {
return manager.acquire(_poolname);
} else {
throw new NoConnectionPoolException(_poolname);
}
}
protected void cache(Long id, Synapse synapse) throws OperationFailedException
{
if (_cache.size()>_cachesize) {
Synapse syn = (Synapse)_cache.removeAt(0);
if (syn != null && syn.isChanged()) {
syn.commit();
}
}
_cache.put(id, synapse);
}
protected Synapse getCached(Long id)
{
return (Synapse)_cache.get(id);
}
public synchronized void commit() throws OperationFailedException
{
Enumeration e = _cache.elements();
while(e.hasMoreElements()) {
Synapse synapse = (Synapse)e.nextElement();
if (synapse.isChanged()) {
synapse.commit();
}
}
}
public synchronized Synapse get(long id) throws OperationFailedException
{
Long ident = new Long(id);
synchronized(this) {
try {
Synapse synapse = getCached(ident);
if (synapse == null) {
synapse = new Synapse(load(id));
}
cache(ident, synapse);
return synapse;
} catch (SQLException e) {
throw new OperationFailedException(e);
}
}
}
public synchronized Synapse get(long id, String type, String name) throws OperationFailedException
{
Long ident = new Long(id);
Synapse synapse = getCached(ident);
if (synapse != null) {
return synapse;
}
synapse = new Synapse(this, id, type, name);
cache(ident, synapse);
return synapse;
}
public Synapse[] find(String type, String name) throws OperationFailedException
{
if (type == null && name == null) {
return new Synapse[0];
}
PooledConnection impl = null;
Connection conn = null;
try {
impl = getConnection();
conn = (Connection)impl.getConnection();
PreparedStatement stmt;
if (type != null && name != null) {
stmt = conn.prepareStatement("select id, type, name from synapse where type=? and name=?");
stmt.setString(1, type);
stmt.setString(2, name);
} else if (type != null) {
stmt = conn.prepareStatement("select id, type, name from synapse where type=?");
stmt.setString(1, type);
} else {
stmt = conn.prepareStatement("select id, type, name from synapse where name=?");
stmt.setString(1, name);
}
ArrayList list = new ArrayList();
ResultSet result = stmt.executeQuery();
while(result.next()) {
Synapse synapse = get(result.getLong(1), result.getString(2), result.getString(3));
list.add(synapse);
}
result.close();
stmt.close();
return (Synapse[])list.toArray(new Synapse[list.size()]);
} catch (SQLException e) {
cleanup(conn);
e.fillInStackTrace();
throw new OperationFailedException(e);
} finally {
release(impl);
}
}
private static long _id = -1;
public synchronized long getNextSequence() throws SQLException
{
if (_id == -1) {
PooledConnection impl = null;
Connection conn = null;
try {
impl = getConnection();
conn = (Connection)impl.getConnection();
Statement stmt = conn.createStatement();
ResultSet result = stmt.executeQuery("select max(id) from synapse");
if (result.next()) {
_id = result.getLong(1);
}
stmt.close();
} catch (SQLException e) {
cleanup(conn);
e.fillInStackTrace();
throw e;
} finally {
release(impl);
}
}
return ++_id;
}
public Synapse create(String type, String name) throws OperationFailedException
{
try {
Synapse syn = new Synapse(new SynapseImpl(this, getNextSequence(), type, name));
cache(new Long(syn.getId()), syn);
return syn;
} catch (SQLException e) {
throw new OperationFailedException(e);
}
}
protected Any createAny(String type, String value)
{
if (type.equals("string")) {
return Any.create(value);
}
if (type.equals("int")) {
try {
return Any.create(Long.parseLong(value));
} catch (NumberFormatException e) {
return Any.ZERO;
}
}
if (type.equals("float")) {
try {
return Any.create(Double.parseDouble(value));
} catch (NumberFormatException e) {
return Any.DOUBLE_ZERO;
}
}
if (type.equals("boolean")) {
return value.equals("true") ? Any.TRUE : Any.FALSE;
}
if (type.equals("null")) {
return Any.NULL;
}
if (type.equals("undefined")) {
return Any.UNDEFINED;
}
if (type.equals("serialized")) {
try {
return anvil.core.Serialization.unserialize(null, value);
} catch (anvil.core.UnserializationException e) {
}
}
return Any.create(value);
}
protected SynapseImpl load(long id) throws OperationFailedException, SQLException
{
PooledConnection impl = null;
Connection conn = null;
SynapseImpl synapse = null;
try {
impl = getConnection();
conn = (Connection)impl.getConnection();
Statement stmt = conn.createStatement();
ResultSet result = stmt.executeQuery("select type, name from synapse where id="+id);
if (result.next()) {
String type = result.getString(1);
String name = result.getString(2);
synapse = new SynapseImpl(this, id, type, name);
result.close();
result = stmt.executeQuery("select name, type, value from data where id="+id);
while(result.next()) {
synapse.setVariable(result.getString(1),
createAny(result.getString(2), result.getString(3)));
}
result.close();
result = stmt.executeQuery(
"select " +
"dimension.dim, dimension.target, synapse.type, synapse.name " +
"from " +
"dimension, synapse " +
"where " +
"source="+id+" and " +
"(isnull(target) or target=synapse.id) " +
"order by " +
"dimension.dim, dimension.position ");
Dimension dim = null;
while(result.next()) {
String dim_name = result.getString(1);
long syn_id = result.getLong(2);
boolean do_insert = !result.wasNull();
String syn_type = result.getString(3);
String syn_name = result.getString(4);
if (dim == null || !dim.getName().equals(dim_name)) {
dim = new Dimension(synapse, dim_name, false);
synapse.addDimension(dim);
}
if (do_insert) {
dim.add(get(syn_id, syn_type, syn_name));
}
}
result.close();
}
result.close();
} catch (SQLException e) {
cleanup(conn);
e.fillInStackTrace();
throw e;
} finally {
release(impl);
}
if (synapse != null) {
return synapse;
}
throw new OperationFailedException("Synapse #"+id+" not found");
}
void save(Connection conn, SynapseImpl synapse, Dimension dim) throws SQLException
{
if (!dim.isChanged()) {
return;
}
long id = synapse.getId();
PreparedStatement stmt = conn.prepareStatement("delete from dimension where source="+id+" and dim=?");
stmt.setString(1, dim.getName());
stmt.execute();
stmt.close();
stmt = conn.prepareStatement("replace into dimension (dim,source,target,position) values (?, "+id+", ?, ?)");
stmt.setString(1, dim.getName());
int size = dim.size();
if (size == 0) {
stmt.setNull(2, Types.INTEGER);
stmt.setLong(3, 0);
stmt.execute();
} else {
for(int i=0; i<size; i++) {
stmt.setLong(2, dim.get(i).getId());
stmt.setInt(3, i);
stmt.execute();
stmt.execute();
}
}
stmt.close();
}
void save(Connection conn, SynapseImpl synapse) throws SQLException
{
long id = synapse.getId();
PreparedStatement stmt = conn.prepareStatement("replace into synapse (id,name,type) values ("+id+", ?, ?)");
stmt.setString(1, synapse.getName());
stmt.setString(2, synapse.getType());
stmt.execute();
stmt.close();
Statement st = conn.createStatement();
st.execute("delete from data where id="+id);
st.close();
BindingEnumeration enum = synapse.getVariables();
while (enum.hasMoreElements()) {
stmt = conn.prepareStatement("insert into data (id,name,type,value) values ("+id+", ?, ?, ?)");
stmt.setString(1, enum.nextKey().toString());
Any value = (Any)enum.nextElement();
switch(value.typeOf()) {
case Any.IS_NULL:
stmt.setString(2, value.isDefined() ? "null" : "undefined");
stmt.setString(3, "");
break;
case Any.IS_BOOLEAN:
stmt.setString(2, "boolean");
stmt.setString(3, value.toBoolean() ? "true" : "false");
break;
case Any.IS_INT:
stmt.setString(2, "int");
stmt.setInt(3, value.toInt());
break;
case Any.IS_DOUBLE:
stmt.setString(2, "double");
stmt.setDouble(3, value.toDouble());
break;
case Any.IS_STRING:
stmt.setString(2, "string");
stmt.setString(3, value.toString());
break;
default:
try {
stmt.setString(3, anvil.core.Serialization.serialize(null, value));
stmt.setString(2, "serialized");
} catch (IOException e) {
stmt.setString(2, "null");
stmt.setString(3, "");
}
}
stmt.execute();
}
stmt.close();
Enumeration e = synapse.getDimensions();
while(e.hasMoreElements()) {
Dimension dim = (Dimension)e.nextElement();
dim.commit(conn);
}
}
void remove(long id) throws SQLException
{
_cache.remove(new Long(id));
PooledConnection impl = null;
Connection conn = null;
try {
impl = getConnection();
conn = (Connection)impl.getConnection();
Statement stmt = conn.createStatement();
stmt.execute("delete from synapse where id="+id);
stmt.execute("delete from data where id="+id);
stmt.execute("delete from dimension where source="+id+" or target="+id);
stmt.close();
//conn.commit();
} catch (SQLException e) {
cleanup(conn);
e.fillInStackTrace();
throw e;
} finally {
release(impl);
}
}
void save(SynapseImpl synapse) throws SQLException
{
PooledConnection impl = null;
Connection conn = null;
try {
impl = getConnection();
conn = (Connection)impl.getConnection();
save(conn, synapse);
//conn.commit();
} catch (SQLException e) {
cleanup(conn);
e.fillInStackTrace();
throw e;
} finally {
release(impl);
}
}
void save(Dimension dimension) throws SQLException
{
PooledConnection impl = null;
Connection conn = null;
try {
impl = getConnection();
conn = (Connection)impl.getConnection();
save(conn, dimension.getSynapseImpl(), dimension);
//conn.commit();
} catch (SQLException e) {
cleanup(conn);
e.fillInStackTrace();
throw e;
} finally {
release(impl);
}
}
protected void cleanup(Connection conn)
{
if (conn != null) {
try {
conn.close();
} catch (Throwable t) {
}
}
}
protected void release(PooledConnection conn)
{
if (conn != null) {
conn.release();
}
}
}