User: fleury
Date: 00/07/06 00:52:16
Modified: src/main/org/jboss/ejb/plugins/jaws
JAWSPersistenceManager.java
Log:
typos corrected
The tuned sql creation was spooky. The if statement in particular.
Revision Changes Path
1.17 +1417 -1
jboss/src/main/org/jboss/ejb/plugins/jaws/JAWSPersistenceManager.java
Index: JAWSPersistenceManager.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/jaws/JAWSPersistenceManager.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- JAWSPersistenceManager.java 2000/06/21 11:51:32 1.16
+++ JAWSPersistenceManager.java 2000/07/06 07:52:14 1.17
@@ -1 +1,1417 @@
-/*
* jBoss, the OpenSource EJB server
*
* Distributable under GPL license.
*
See terms of license at gnu.org.
*/
package org.jboss.ejb.plugins.jaws;
import
java.beans.Beans;
import java.beans.beancontext.BeanContextServicesSupport;
import
java.lang.reflect.Method;
import java.lang.reflect.Field;
import
java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import
java.rmi.NoSuchObjectException;
import java.rmi.ServerException;
import
java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
import
java.util.StringTokenizer;
import java.util.HashMap;
import java.sql.Types;
import
java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Connection;
import
java.text.MessageFormat;
import javax.ejb.EJBObject;
import javax.ejb.EntityBean;
import javax.ejb.CreateException;
import javax.ejb.DuplicateKeyException;
import
javax.ejb.FinderException;
import javax!
.ejb.RemoveException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import org.jboss.ejb.Container;
import
org.jboss.ejb.EntityContainer;
import org.jboss.ejb.EntityPersistenceManager;
import
org.jboss.ejb.EntityEnterpriseContext;
import org.jboss.logging.Log;
import
com.dreambean.ejx.ejb.EjbReference;
import
org.jboss.ejb.plugins.jaws.deployment.JawsFileManager;
import
org.jboss.ejb.plugins.jaws.deployment.JawsFileManagerFactory;
import
org.jboss.ejb.plugins.jaws.deployment.JawsEjbJar;
import
org.jboss.ejb.plugins.jaws.deployment.JawsEnterpriseBeans;
import
org.jboss.ejb.plugins.jaws.deployment.JawsEjbReference;
import
org.jboss.ejb.plugins.jaws.deployment.JawsEntity;
import
org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
import
org.jboss.ejb.plugins.jaws.deployment.Finder;
/**
* Just Another Web Store - an O/R
mapper
*
*
* Note: This is a really long class, but I thought that splitting it up
* would only make t!
hings more confusing. To compensate for the size
* I have tried to make many helper
methods to keep each method small.
*
* @see <related>
* @author <a
href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
* @author <a
href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
* @author <a
href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
* @author <a
href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
* @version $Revision: 1.16 $
*/
public class JAWSPersistenceManager
implements EntityPersistenceManager
{
//
Constants -----------------------------------------------------
// Attributes
----------------------------------------------------
EntityContainer container;
Method ejbStore;
Method ejbLoad;
Method ejbActivate;
Method ejbPassivate;
Method ejbRemove;
// Pre-calculated fields to speed things up
ArrayList
pkFields = new ArrayList(); // Field's in entity class
ArrayList pkClassFields =
new ArrayList(); // Field!
's in pk class
ArrayList pkColumns = new ArrayList(); // String's
String
pkColumnList; // Comma-separated list of column names
String pkColumnWhereList; //
Comma-separated list of column names (for WHERE clauses)
ArrayList cmpFields = new
ArrayList(); // The fields from the actual Bean
ArrayList CMPFields = new
ArrayList(); // The JawsCMPField representation
ArrayList jdbcTypes = new
ArrayList(); // Integer's
ArrayList pkJdbcTypes = new ArrayList(); // Integer's
describing pk
ArrayList ejbRefs = new ArrayList(); // EJB-references
HashMap definedFinders = new HashMap();
boolean compoundKey;
Class
primaryKeyClass;
JawsEntity entity;
String dbName;
String tableName;
String createSql;
String insertSql;
String existSql;
// String updateSql;
Calculated dynamically (=tuned updates)
String selectSql;
String removeSql;
String dropSql;
Context javaCtx;
Log log = new Log("JAWS");
DataSource!
ds;
String url;
boolean readOnly;
long readOnlyTimeOut;
// Static
--------------------------------------------------------
// Constructors
--------------------------------------------------
// Public
--------------------------------------------------------
public void
setContainer(Container c)
{
container = (EntityContainer)c;
}
public void init()
throws Exception
{
log.debug("Initializing JAWS
plugin for "+container.getMetaData().getEjbName());
javaCtx =
(Context)new InitialContext().lookup("java:comp/env");
JawsFileManager
jfm = (JawsFileManager)new JawsFileManagerFactory().createFileManager();
// Setup beancontext
BeanContextServicesSupport beanCtx = new
BeanContextServicesSupport();
beanCtx.add(Beans.instantiate(getClass().getClassLoader(),
"com.dreambean.ejx.xml.ProjectX"));
beanCtx.add(jfm);
// Load XML,
if the URL doesn't have def!
ault information the filemanager uses defaults
JawsEjbJar jar =
jfm.load(container.getApplication().getURL());
// Extract meta-info
entity =
(JawsEntity)jar.getEnterpriseBeans().getEjb(container.getMetaData().getEjbName());
Iterator fields = entity.getCMPFields();
while (fields.hasNext())
{
JawsCMPField field = (JawsCMPField)fields.next();
CMPFields.add(field);
cmpFields.add(container.getBeanClass().getField(field.getFieldName()));
//
Identify JDBC-type
jdbcTypes.add(new
Integer(getJDBCType(field.getJdbcType())));
// EJB-reference
if (field.getJdbcType().equals("REF"))
{
ejbRefs.add(getPkColumns(field));
}
}
// Read-only?
readOnly = entity.getReadOnly();
readOnlyTimeOut = entity.getTimeOut();
// Identify pk
pkColumnList = "";
pkColumnWhereList = "";
compoun!
dKey = entity.getPrimaryKeyField().equals("");
if (compoundKey)
{
// Compound key
Field[] pkClassFieldList =
container.getClassLoader().loadClass(entity.getPrimaryKeyClass()).getFields();
// Build pk field list and SQL-pk string
for (int i = 0; i <
pkClassFieldList.length; i++)
{
pkClassFields.add(pkClassFieldList[i]);
Field field =
container.getBeanClass().getField(pkClassFieldList[i].getName());
pkFields.add(field);
for (int j = 0; j < CMPFields.size(); j++)
{
JawsCMPField cmpField = (JawsCMPField)CMPFields.get(j);
if (cmpField.getFieldName().equals(field.getName()))
{
pkColumnList += ((i == 0)?"":",") + cmpField.getColumnName();
pkColumnWhereList += ((i == 0)?"":" AND ") + cmpField.getColumnName()+"=?";
pkJdbcTypes.add(new Integer(getJDBCType(cmpField.!
getJdbcType())));
pkColumns.add(cmpFields.get(j));
break;
}
}
}
// Get compound
key class
primaryKeyClass =
container.getClassLoader().loadClass(entity.getPrimaryKeyClass());
} else
{
// Primitive key
pkFields.add(container.getBeanClass().getField(entity.getPrimaryKeyField()));
for (int j = 0; j < CMPFields.size(); j++)
{
JawsCMPField
cmpField = (JawsCMPField)CMPFields.get(j);
if
(cmpField.getFieldName().equals(entity.getPrimaryKeyField()))
{
pkColumnList = cmpField.getColumnName();
pkColumnWhereList =
cmpField.getColumnName()+"=?";
pkJdbcTypes.add(new
Integer(getJDBCType(cmpField.getJdbcType())));
pkColumns.add(cmpFields.get(j));
break;
}
}
}
// Create SQL commands
makeSql();
!
// Find EJB-methods
ejbStore =
EntityBean.class.getMethod("ejbStore", new Class[0]);
ejbLoad =
EntityBean.class.getMethod("ejbLoad", new Class[0]);
ejbActivate =
EntityBean.class.getMethod("ejbActivate", new Class[0]);
ejbPassivate =
EntityBean.class.getMethod("ejbPassivate", new Class[0]);
ejbRemove =
EntityBean.class.getMethod("ejbRemove", new Class[0]);
}
public void start()
throws Exception
{
// Find datasource
url =
((JawsEjbJar)entity.getBeanContext().getBeanContext()).getDataSource();
if
(!url.startsWith("jdbc:"))
{
ds = (DataSource)new
InitialContext().lookup(((JawsEjbJar)entity.getBeanContext().getBeanContext()).getDataSource());
}
// Create table if necessary
if (entity.getCreateTable())
{
// Try to create it
Connection con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
!
{
con = getConnection();
stmt =
con.prepareStatement(createSql);
stmt.executeQuery();
log.debug("Table "+tableName+" created");
} catch (SQLException e)
{
// For debug only
// e.printStackTrace();
log.debug("Table
"+tableName+" exists");
} finally
{
if (rs != null) try
{ rs.close(); } catch (Exception e) { e.printStackTrace(); }
if (stmt !=
null) try { stmt.close(); } catch (Exception e) { e.printStackTrace(); }
if (con != null) try { con.close(); } catch (Exception e) { e.printStackTrace(); }
}
}
}
public void stop()
{
}
public void destroy()
{
if (entity.getRemoveTable())
{
// Remove it!
Connection
con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
con = getConnection();
stmt = co!
n.prepareStatement(dropSql);
stmt.executeUpdate();
log.debug("Table "+tableName+" removed");
} catch (SQLException e)
{
log.debug("Table "+tableName+" could not be removed");
} finally
{
if (rs != null) try { rs.close(); } catch (Exception e) {
e.printStackTrace(); }
if (stmt != null) try { stmt.close(); } catch
(Exception e) { e.printStackTrace(); }
if (con != null) try { con.close();
} catch (Exception e) { e.printStackTrace(); }
}
}
}
public
void createEntity(Method m, Object[] args, EntityEnterpriseContext ctx)
throws
RemoteException, CreateException
{
// Get methods
try
{
Method createMethod = container.getBeanClass().getMethod("ejbCreate",
m.getParameterTypes());
Method postCreateMethod =
container.getBeanClass().getMethod("ejbPostCreate", m.getParameterTypes());
// Call ejbCreate!
createMethod.invoke(ctx.getInstance(), args);
// Extract
pk
Object id = null;
if (compoundKey)
{
try
{
id = primaryKeyClass.newInstance();
} catch
(InstantiationException e)
{
throw new
ServerException("Could not create primary key",e);
}
for (int i = 0; i < pkFields.size(); i++)
{
Field from =
(Field)pkFields.get(i);
Field to = (Field)pkClassFields.get(i);
to.set(id,from.get(ctx.getInstance()));
}
} else
{
id = ((Field)pkFields.get(0)).get(ctx.getInstance());
}
log.debug("Create, id is "+id);
// Check duplicate
if (beanExists(id)) {
// it exists, we need the DuplicateKey
thingy
throw new DuplicateKeyException("Entity with key !
"+id+" already exists");
}
// We know we are OK and can proceed
with the insert
// Set id
ctx.setId(id);
// Lock instance
in cache
((EntityContainer)container).getInstanceCache().insert(ctx);
// Create EJBObject
ctx.setEJBObject(container.getContainerInvoker().getEntityEJBObject(id));
//
Insert in db
log.debug("Insert");
Connection con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
con = getConnection();
log.debug("SQL:"+insertSql);
stmt = con.prepareStatement(insertSql);
int idx = 1; //
Parameter-index
int refIdx = 0; // EJB-reference index, into ejbRefs
for (int i = 0; i < cmpFields.size(); i++)
{
int
jdbcType = getCMPFieldJDBCType(i);
Object value =
getCMPFieldValue(ctx.getInstance()!
, i);
if (jdbcType == Types.REF)
{
idx
= setForeignKey(stmt, idx, refIdx++, value);
} else
{
setParameter(stmt, idx++, jdbcType, value);
}
}
stmt.executeUpdate();
} catch (SQLException e)
{
log.exception(e);
throw new CreateException("Could not
create entity:"+e);
} finally
{
if (rs != null) try {
rs.close(); } catch (Exception e) { e.printStackTrace(); }
if (stmt !=
null) try { stmt.close(); } catch (Exception e) { e.printStackTrace(); }
if (con != null) try { con.close(); } catch (Exception e) { e.printStackTrace(); }
}
// Store state to be able to do tuned updates
PersistenceContext pCtx = new PersistenceContext();
// If
read-only, set last read to now
if (readOnly) pCtx.l!
astRead = System.currentTimeMillis();
// Save initial state for
tuned updates
pCtx.state = getState(ctx);
ctx.setPersistenceContext(pCtx);
// Invoke postCreate
postCreateMethod.invoke(ctx.getInstance(), args);
} catch
(InvocationTargetException e)
{
throw new
CreateException("Create failed:"+e);
} catch (NoSuchMethodException e)
{
throw new CreateException("Create methods not found:"+e);
} catch
(IllegalAccessException e)
{
throw new CreateException("Could not
create entity:"+e);
}
}
/*
* beanExists
*
* Checks in the
database that the backend already holds the entity
*
*/
public boolean
beanExists(EntityEnterpriseContext ctx)
{
return
beanExists(ctx.getId());
}
public boolean beanExists(Object id)
{
Connection con = null;
PreparedStatement stmt !
= null;
ResultSet rs = null;
boolean exists = false;
try
{
//Get the connection
con =
getConnection();
stmt = con.prepareStatement(existSql);
log.debug("SQL:"+existSql);
// Primary key in WHERE-clause
if (compoundKey)
{
// Compound key
for (int i = 0; i < pkClassFields.size(); i++)
{
int jdbcType = getPkFieldJDBCType(i);
Object value =
getPkFieldValue(id, i);
// Set this field of the key
setParameter(stmt, i+1, jdbcType, value);
}
} else
// We have a Field key
{
// So just set that field
int jdbcType = getPkFieldJDBCType(0);
setParameter(stmt, 1,
jdbcType, id);
}
rs = stmt.executeQuery();
// Unlikely we'll fall into the next if statement, as th!
e
// COUNT(*) should always return a value, unless something dubious occurs
if ( !rs.next() ) {
stmt.close();
throw new
SQLException("Unable to check for EJB in database");
}
int total = rs.getInt("Total");
log.debug("Object count:"+total);
if ( total >= 1 )
exists = true;
else
exists = false;
stmt.close();
}
catch (Exception e ) {
log.exception(e);
// An exception means something erroneous has
occurred, either
// the table doesn't exist or something else. Either way,
indicate
// we failed to find the bean
exists = false;
}
finally {
// Ensure our database connection is
released
try {
if ( con != null ) con.close();
}
catch ( SQLException se ) {
!
log.exception(se);
}
return exists;
}
}
public Object findByPrimaryKey(Object id) throws FinderException
{
if (beanExists(id))
{
return id;
}
else
{
throw new FinderException ("Object with
primary key "+
id+
" not found in storage");
}
}
public Object
findEntity(Method finderMethod, Object[] args, EntityEnterpriseContext ctx)
throws RemoteException, FinderException
{
if
(finderMethod.getName().equals("findByPrimaryKey"))
{
return
findByPrimaryKey(args[0]);
}
else
{
ArrayList result =
(ArrayList)findEntities(finderMethod, args, ctx);
if (result.size() == 0)
throw new FinderException("No such entity!");
else
return
result.get(0);
}
}
public Collection findEntities(Method
finderMethod, Object[] args, EntityEnterpriseCon!
text ctx)
throws RemoteException, FinderException
{
Connection con =
null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
// Try defined finders
DefinedFinder df =
(DefinedFinder)definedFinders.get(finderMethod.getName());
if (df != null)
{
con = getConnection();
log.debug("SQL:"+df.sql);
stmt = con.prepareStatement(df.sql);
// Set parameters
for (int i =
0; i < df.parameters.length; i++)
{
stmt.setObject(i+1, args[df.parameters[i]]);
}
}
else
{
if
(finderMethod.getName().equals("findAll"))
{
// Try findAll
con = getConnection();
stmt =
con.prepareStatement("SELECT "+pkColumnList+" FROM "+tableName);
} else if
(finderMethod.getName().startsWith("findBy"))
{
// Try
findByX
String cmpFieldName = finderMethod!
.getName().substring(6).toLowerCase();
System.out.println("Finder:"+cmpFieldName);
for (int i
= 0; i < CMPFields.size(); i++)
{
JawsCMPField
cmpField = (JawsCMPField)CMPFields.get(i);
//
Find field
if
(cmpFieldName.equals(cmpField.getFieldName().toLowerCase()))
{
int jdbcType = getCMPFieldJDBCType(i);
// Is reference?
if (jdbcType == Types.REF)
{
// TODO: Precompute SQL
String sql = "SELECT "+pkColumnList+" FROM "+tableName+ " WHERE ";
// TODO: Fix this.. I mean it's already been computed
once..
JawsCMPField[] cmpFields = getPkColumns(cmpField);
for (int j = 0; j < cmpFields.leng!
th; j++)
{
sql += (j==0?"":" AND ")
+ cmpField.getColumnName()+"_"+cmpFields[j].getColumnName()+"=?";
}
con = getConnection();
log.debug("SQL:"+sql);
stmt =
con.prepareStatement(sql);
// Set
parameters
setForeignKey(stmt, 1, 0, args[0]);
} else
{
// Find in db
// TODO: Precompute SQL
String sql = "SELECT
"+pkColumnList+" FROM "+tableName+ " WHERE "+cmpField.getColumnName()+"=?";
con = getConnection();
log.debug("SQL:"+sql);
stmt = con.prepareStatement(sql);
// Set parameters
!
setParameter(stmt, 1, jdbcType, args[0]);
}
}
}
} else
{
log.warning("No finder for this method:"+finderMethod.getName());
return new java.util.ArrayList();
}
}
// Compute
result
rs = stmt.executeQuery();
ArrayList result = new ArrayList();
if (compoundKey)
{
// Compound key
try
{
while (rs.next())
{
Object pk
= primaryKeyClass.newInstance();
for (int i = 0; i <
pkClassFields.size(); i++)
{
Field field =
(Field)pkClassFields.get(i);
field.set(pk, rs.getObject(i+1));
}
result.add(pk);
}
}
catch (Exception e)
{
throw new ServerException!
("Finder failed",e);
}
} else
{
// Primitive
key
while (rs.next())
{
result.add(rs.getObject(1));
}
}
return
result;
} catch (SQLException e)
{
log.exception(e);
throw new FinderException("Find failed");
} finally
{
if (rs !=
null) try { rs.close(); } catch (Exception e) { e.printStackTrace(); }
if
(stmt != null) try { stmt.close(); } catch (Exception e) { e.printStackTrace(); }
if (con != null) try { con.close(); } catch (Exception e) { e.printStackTrace(); }
}
}
public void activateEntity(EntityEnterpriseContext ctx)
throws
RemoteException
{
// Call bean
try
{
ejbActivate.invoke(ctx.getInstance(), new Object[0]);
} catch (Exception e)
{
throw new ServerException("Activation failed", e);
}
//
Set new p!
ersistence context
ctx.setPersistenceContext(new PersistenceContext());
}
public void loadEntity(EntityEnterpriseContext ctx)
throws RemoteException
{
// Check read only
if (readOnly)
{
PersistenceContext
pCtx = (PersistenceContext)ctx.getPersistenceContext();
// Timeout
has expired for this entity?
if ((pCtx.lastRead + readOnlyTimeOut) >
System.currentTimeMillis())
return; // State is still "up to date"
}
Connection con = null;
PreparedStatement stmt = null;
ResultSet
rs = null;
try
{
// Load from db
con =
getConnection();
stmt = con.prepareStatement(selectSql);
log.debug("Load SQL:"+selectSql);
// Primary key in WHERE-clause
if (compoundKey)
{
// Compound key
for (int i =
0; i < pkClassFields.size(); i++)
{
!
int jdbcType = getPkFieldJDBCType(i);
Object value =
getPkFieldValue(ctx.getId(), i);
setParameter(stmt, i+1, jdbcType,
value);
}
} else
{
// Primitive key
Object value = ctx.getId();
int jdbcType = getPkFieldJDBCType(0);
setParameter(stmt, 1, jdbcType, value);
}
rs =
stmt.executeQuery();
if (!rs.next())
throw new
NoSuchObjectException("Entity "+ctx.getId()+" not found");
// Set
values
int idx = 1;
int refIdx = 0;
for (int i = 0; i <
CMPFields.size(); i++)
{
JawsCMPField cmpField =
(JawsCMPField)CMPFields.get(i);
if (((Integer)jdbcTypes.get(i)).intValue()
== Types.REF)
{
// Create pk
JawsCMPField[]
pkFields = (JawsCMPField[])ejbRefs.get(refIdx++);
JawsEntity
referencedEntity = (!
JawsEntity)pkFields[0].getBeanContext();
Object pk;
if
(referencedEntity.getPrimaryKeyField().equals(""))
{
// Compound key
pk =
container.getClassLoader().loadClass(referencedEntity.getPrimaryKeyClass()).newInstance();
Field[] fields = pk.getClass().getFields();
for(int j = 0; j < fields.length; j++)
{
Object val = rs.getObject(idx++);
fields[j].set(pk, val);
log.debug("Referenced pk field:"+val);
}
} else
{
// Primitive
key
pk = rs.getObject(idx++);
log.debug("Referenced pk:"+pk);
}
// Find referenced entity
try
{
Object
home = javaCtx.lookup(cmpField.getSqlType());
Method[] homeMethods =
home.getC!
lass().getMethods();
Method finder = null;
// We have to locate fBPK iteratively since we don't really know the
pk-class
for (int j = 0; j < homeMethods.length; j++)
if (homeMethods[j].getName().equals("findByPrimaryKey"))
{
finder = homeMethods[j];
break;
}
if (finder == null)
throw new NoSuchMethodException("FindByPrimaryKey method not found in home
interface");
log.debug("PK="+pk);
Object ref = finder.invoke(home, new
Object[] { pk });
// Set found entity
((Field)cmpFields.get(i)).set(ctx.getInstance(), ref);
} catch
(Exception e)
{
throw new ServerException("Could not
restore reference", !
e);
}
} else
{
// Load primitive
// TODO: this probably needs to be fixed for BLOB's
etc.
((Field)cmpFields.get(i)).set(ctx.getInstance(),
rs.getObject(idx++));
}
}
// Store state to be
able to do tuned updates
PersistenceContext pCtx =
(PersistenceContext)ctx.getPersistenceContext();
if (readOnly) pCtx.lastRead
= System.currentTimeMillis();
// Call ejbLoad on bean instance
ejbLoad.invoke(ctx.getInstance(), new Object[0]);
// Done
} catch (Exception e)
{
throw new ServerException("Load failed", e);
} finally
{
if (rs != null) try { rs.close(); } catch (Exception e)
{ e.printStackTrace(); }
if (stmt != null) try { stmt.close(); } catch
(Exception e) { e.printStackTrace(); }
if (con != null) try { con.close(); }
catch !
(Exception e) { e.printStackTrace(); }
}
}
/*
*
storeEntity(EntityEnterpriseContext ctx)
*
* if the readOnly flag is
specified in the xml file this won't store.
* if not a tuned update is issued.
*
*/
public void storeEntity(EntityEnterpriseContext ctx)
throws
RemoteException
{
// Check for read-only
if (readOnly)
return;
Connection con = null;
PreparedStatement stmt = null;
try
{
// Call bean
ejbStore.invoke(ctx.getInstance(), new Object[0]);
// Create tuned update
String updateSql = "UPDATE
"+tableName+" SET ";
Object[] currentState = getState(ctx);
boolean[] dirtyField = new boolean[currentState.length];
Object[] oldState =
((PersistenceContext)ctx.getPersistenceContext()).state;
boolean dirty =
false;
int refIdx = 0;
System.out.println("THE
CURRENTSTATE "+getSt!
ate(ctx));
for (int i = 0;i < currentState.length; i++)
{
if (((Integer)jdbcTypes.get(i)).intValue() == Types.REF) {
if
(((currentState[i] != null) &&
(oldState[i] == null ||
!currentState[i].equals(oldState[i]))) ||
(oldState[i] != null))
{
JawsCMPField[] pkFields =
(JawsCMPField[])ejbRefs.get(refIdx);
for (int j = 0; j <
pkFields.length; j++)
{
updateSql +=
(dirty?",":"") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].getColumnName()+"=?";
dirty = true;
}
dirtyField[i]
= true;
}
refIdx++;
} else
{
if (((currentState[i] != null) &&
(oldState[i] ==
null || !currentState[i].equals(oldState[i]))) ||
(oldState[i] !=
null))
!
{
updateSql += (dirty?",":"") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"=?";
dirty = true;
dirtyField[i] = true;
}
}
}
if (!dirty)
{
return;
} else
{
updateSql += " WHERE "+pkColumnWhereList;
}
//
Update database
con = getConnection();
stmt =
con.prepareStatement(updateSql);
int idx = 1;
refIdx = 0;
for (int i = 0;i < dirtyField.length; i++)
{
int jdbcType
= getCMPFieldJDBCType(i);
if (jdbcType == Types.REF)
{
if (dirtyField[i])
{
idx = setForeignKey(stmt,
idx, refIdx++, currentState[i]);
}
} else
{
if (dirtyField[i])
{
setParameter(stmt, !
idx++, jdbcType, currentState[i]);
}
}
}
// Primary key in WHERE-clause
for (int i = 0; i < pkFields.size();
i++)
{
int jdbcType = getPkFieldJDBCType(i);
Object
value = getCMPFieldValue(ctx.getInstance(), i);
setParameter(stmt, idx++,
jdbcType, value);
}
// Execute update
stmt.execute();
} catch (Exception e)
{
throw new
ServerException("Store failed", e);
} finally
{
if (stmt != null)
try { stmt.close(); } catch (Exception e) { e.printStackTrace(); }
if (con !=
null) try { con.close(); } catch (Exception e) { e.printStackTrace(); }
}
}
public void passivateEntity(EntityEnterpriseContext ctx)
throws
RemoteException
{
// Call bean
try
{
ejbPassivate.invoke(ctx.getInstance(), new Object[0]);
} catch (Exception e)
{
!
throw new ServerException("Passivation failed", e);
}
}
public
void removeEntity(EntityEnterpriseContext ctx)
throws RemoteException,
RemoveException
{
Connection con = null;
PreparedStatement stmt = null;
try
{
// Call ejbRemove
ejbRemove.invoke(ctx.getInstance(), new Object[0]);
// Remove from DB
con = getConnection();
stmt = con.prepareStatement(removeSql);
// Primary key in WHERE-clause
if (compoundKey)
{
// Compound key
for (int i = 0; i < pkClassFields.size(); i++)
{
int jdbcType = getPkFieldJDBCType(i);
Object
value = getPkFieldValue(ctx.getId(), i);
setParameter(stmt, i+1,
jdbcType, value);
}
} else
{
// Primitive
key
Object value = ctx.getId();
int jdbcType =
getPkFieldJDBCTy!
pe(0);
setParameter(stmt, 1, jdbcType, value);
}
int count = stmt.executeUpdate();
if (count == 0)
{
throw new RemoveException("Could not remove entity");
}
//
System.out.println("Removed file for"+ctx.getId());
} catch (Exception e)
{
throw new RemoveException("Could not remove "+ctx.getId());
} finally
{
if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
if (con != null) try { con.close(); } catch (Exception
e) { e.printStackTrace(); }
}
}
// Z implementation
----------------------------------------------
// Package protected
---------------------------------------------
// Protected
-----------------------------------------------------
// Private
-------------------------------------------------------
private Connection
getConnection()
throws SQLEx!
ception
{
if (ds != null)
return ds.getConnection();
else
return DriverManager.getConnection(url,"sa","");
}
private void
makeSql()
{
// initialize the table name we replace the . by - because some
dbs die on it...
tableName = entity.getTableName().replace('.','_');
// Remove SQL
removeSql = "DELETE FROM "+tableName+" WHERE "+pkColumnWhereList;
log.debug("Remove:"+removeSql);
// Drop table
dropSql =
"DROP TABLE "+tableName;
log.debug("Drop:"+dropSql);
// Create
table
createSql = "CREATE TABLE "+tableName+" (";
int refIdx = 0;
for (int i = 0;i < CMPFields.size(); i++)
{
if
(((Integer)jdbcTypes.get(i)).intValue() == Types.REF)
{
JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx);
for (int j
= 0; j < pkFields.length; j++)
{
createSql += (i==0 &&
j==0?"!
":",") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].getColumnName()+"
"+pkFields[j].getSqlType();
}
refIdx++;
} else
{
JawsCMPField field = (JawsCMPField)CMPFields.get(i);
createSql += (i==0?"":",") + field.getColumnName()+" "+field.getSqlType();
}
}
createSql += ")";
log.debug("Create
table:"+createSql);
// Insert SQL fields
insertSql = "INSERT INTO
"+tableName;
String fieldSql = "";
String valueSql = "";
refIdx = 0;
for (int i = 0;i < CMPFields.size(); i++)
{
if
(((Integer)jdbcTypes.get(i)).intValue() == Types.REF)
{
JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx);
for (int j
= 0; j < pkFields.length; j++)
{
fieldSql +=
(fieldSql.equals("") ? "":",") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].ge!
tColumnName();
valueSql += (valueSql.equals("") ? "?":",?");
}
refIdx++;
} else
{
JawsCMPField field =
(JawsCMPField)CMPFields.get(i);
fieldSql += (fieldSql.equals("") ? "":",")
+ field.getColumnName();
valueSql += (valueSql.equals("") ? "?":",?");
}
}
insertSql += " ("+fieldSql+") VALUES ("+valueSql+")";
log.debug("Insert:"+insertSql);
// Select SQL fields
selectSql =
"SELECT ";
refIdx = 0;
for (int i = 0;i < CMPFields.size(); i++)
{
if (((Integer)jdbcTypes.get(i)).intValue() == Types.REF)
{
JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx);
for (int j
= 0; j < pkFields.length; j++)
{
selectSql += (i==0 &&
j==0?"":",") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].getColumnName();
}
refIdx++!
;
} else
{
JawsCMPField field =
(JawsCMPField)CMPFields.get(i);
selectSql += (i==0?"":",") +
field.getColumnName();
}
}
selectSql += " FROM "+tableName+ "
WHERE "+pkColumnWhereList;
log.debug("Select:"+selectSql);
//
Exist SQL query
existSql = "SELECT COUNT(*) AS Total FROM " + tableName+ " WHERE
"+pkColumnWhereList;
log.debug("Exists:"+existSql);
/* //
Update SQL fields
updateSql = "UPDATE "+tableName+" SET ";
fieldSql = "";
for (int i = 0; i < CMPFields.length; i++)
{
CMPField field =
CMPFields[i];
if (field.getJdbcType().equals("REF"))
{
String[] pk = getPkColumn(field);
fieldSql += (fieldSql.equals("") ? "":",")+pk[0]+"=?";
} else
{
fieldSql += (fieldSql.equals("") ? "":",")+field.getColumnName()+"=?";
!
}
}
updateSql += fieldSql +" WHERE "+idColumn+"=?";
log.debug("Update:"+updateSql);
*/
// Defined finders
Iterator
finders = entity.getFinders();
while(finders.hasNext())
{
Finder
f = (Finder)finders.next();
// Replace placeholders with
?
String query = "";
StringTokenizer finderQuery = new
StringTokenizer(f.getQuery(),"{}", true);
ArrayList parameters =
new ArrayList();
while (finderQuery.hasMoreTokens())
{
String t = finderQuery.nextToken();
if (t.equals("{"))
{
query += "?";
String idx =
finderQuery.nextToken(); // Remove number
parameters.add(new Integer(idx));
finderQuery.nextToken(); // Remove }
} else
query += t;
}
// Copy index numbers to array
int[] parameterArray = new
int[parameters.size()];
for (int i = 0; i <
parameterArray.length; i++)
parameterArray[i] =
((Integer)parameters.get(i)).intValue()!
;
// Construct SQL
String sql = "SELECT
"+pkColumnList+(f.getOrder().equals("")?"":","+f.getOrder())+" FROM "+tableName+"
WHERE "+query;
if (!f.getOrder().equals(""))
{
sql += "
ORDER BY "+f.getOrder();
}
log.debug(f.getName()+"="+sql);
//
Store in map
DefinedFinder df = new DefinedFinder();
df.sql = sql;
df.parameters = parameterArray;
definedFinders.put(f.getName(), df);
}
}
private
Object[] getState(EntityEnterpriseContext ctx)
{
Object[] state = new
Object[cmpFields.size()];
for (int i = 0; i < state.length; i++)
{
try
{
state[i] =
((Field)cmpFields.get(i)).get(ctx.getInstance());
} catch (Exception e)
{
return null;
}
}
return state;
}
private int getJDBCType(String name)
{
try
{
Integer
constant = (Integer)Types.class.ge!
tField(name).get(null);
return constant.intValue();
} catch (Exception
e)
{
e.printStackTrace();
return Types.OTHER;
}
}
private JawsCMPField[] getPkColumns(JawsCMPField field)
throws
RemoteException
{
// Find reference
Iterator enum =
((JawsEntity)field.getBeanContext()).getEjbReferences();
while (enum.hasNext())
{
JawsEjbReference ref = (JawsEjbReference)enum.next();
if
(ref.getName().equals(field.getSqlType()))
{
// Find referenced
entity
JawsEnterpriseBeans eb =
(JawsEnterpriseBeans)field.getBeanContext().getBeanContext();
JawsEntity
referencedEntity = (JawsEntity)eb.getEjb(ref.getLink());
// Extract pk
String pk = referencedEntity.getPrimaryKeyField();
if
(pk.equals(""))
{
// Compound key
try
{
Class pkClass = cont!
ainer.getClassLoader().loadClass(referencedEntity.getPrimaryKeyClass());
Field[] pkFields = pkClass.getFields();
ArrayList result = new
ArrayList();
for (int i = 0; i < pkFields.length; i++)
{
// Find db mapping for pk field
Iterator fieldEnum = referencedEntity.getCMPFields();
while
(fieldEnum.hasNext())
{
JawsCMPField
pkField = (JawsCMPField)fieldEnum.next();
if
(pkField.getFieldName().equals(pkFields[i].getName()))
result.add(pkField);
}
}
return (JawsCMPField[])result.toArray(new JawsCMPField[0]);
} catch
(ClassNotFoundException e)
{
throw new
ServerException("Could not load pk class of referenced entity",e);
}
} els!
e
{
// Find db mapping for pk
Iterator
fieldEnum = referencedEntity.getCMPFields();
while
(fieldEnum.hasNext())
{
JawsCMPField pkField =
(JawsCMPField)fieldEnum.next();
if
(pkField.getFieldName().equals(pk))
return new JawsCMPField[] {
pkField };
}
return new JawsCMPField[0];
}
}
}
throw new ServerException("Could not find EJB reference.
Must be defined in XML-descriptor");
}
private void
setParameter(PreparedStatement stmt,
int idx,
int jdbcType,
Object value)
throws
SQLException
{
if (value == null)
{
stmt.setNull(idx,
jdbcType);
} else
{
System.out.println("Set
parameter:"+value);
stmt.setObject(idx, value, jdbcType);
}
}!
private int setForeignKey(PreparedStatement stmt,
int idx,
int refIdx,
Object
value)
throws SQLException
{
JawsCMPField[] pkInfo =
(JawsCMPField[])ejbRefs.get(refIdx);
Object pk = null;
if (value !=
null)
{
try
{
pk =
((EJBObject)value).getPrimaryKey();
} catch (RemoteException e)
{
throw new SQLException("Could not extract primary key from EJB
reference:"+e);
}
}
if
(!((JawsEntity)pkInfo[0].getBeanContext()).getPrimaryKeyField().equals(""))
{
// Primitive key
int jdbcType = getJawsCMPFieldJDBCType(pkInfo[0]);
Object fieldValue = (value == null) ? null : pk;
setParameter(stmt, idx,
jdbcType, fieldValue);
return idx+1;
} else
{
//
Compound key
// ***** PROBLEM ***** pk may be nu!
ll
Field[] fields = pk.getClass().getFields();
try
{
for (int i = 0; i < pkInfo.length; i++)
{
int jdbcType
= getJawsCMPFieldJDBCType(pkInfo[i]);
Object fieldValue = (value ==
null) ? null : fields[i].get(pk);
setParameter(stmt, idx+i, jdbcType,
fieldValue);
}
} catch (IllegalAccessException e)
{
throw new SQLException("Could not extract fields from primary key:"+e);
}
return idx+pkInfo.length;
}
}
private Object
getCMPFieldValue(Object instance, int i)
throws IllegalAccessException
{
Field field = (Field)cmpFields.get(i);
return field.get(instance);
}
private Object getPkFieldValue(Object pk, int i)
throws IllegalAccessException
{
Field field = (Field)pkClassFields.get(i);
return field.get(pk);
}
private int getCMPFieldJDBCType(int i)
{
!
return ((Integer)jdbcTypes.get(i)).intValue();
}
private int
getPkFieldJDBCType(int i)
{
return ((Integer)pkJdbcTypes.get(i)).intValue();
}
private int getJawsCMPFieldJDBCType(JawsCMPField fieldInfo)
{
return getJDBCType(fieldInfo.getJdbcType());
}
// Inner classes
-------------------------------------------------
static class
PersistenceContext
{
Object[] state;
long lastRead = -1;
}
static class DefinedFinder
{
String sql; // The SQL to be
executed in prepared statement form
int[] parameters; // List of finder
method indices
}
}
\ No newline at end of file
+/*
+ * jBoss, the OpenSource EJB server
+ *
+ * Distributable under GPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.ejb.plugins.jaws;
+
+import java.beans.Beans;
+import java.beans.beancontext.BeanContextServicesSupport;
+import java.lang.reflect.Method;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.rmi.RemoteException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.ServerException;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import java.util.HashMap;
+import java.sql.Types;
+import java.sql.SQLException;
+import java.sql.ResultSet;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.Connection;
+import java.text.MessageFormat;
+
+import javax.ejb.EJBObject;
+import javax.ejb.EntityBean;
+import javax.ejb.CreateException;
+import javax.ejb.DuplicateKeyException;
+import javax.ejb.FinderException;
+import javax.ejb.RemoveException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
+
+import org.jboss.ejb.Container;
+import org.jboss.ejb.EntityContainer;
+import org.jboss.ejb.EntityPersistenceManager;
+import org.jboss.ejb.EntityEnterpriseContext;
+
+import org.jboss.logging.Log;
+
+import com.dreambean.ejx.ejb.EjbReference;
+import org.jboss.ejb.plugins.jaws.deployment.JawsFileManager;
+import org.jboss.ejb.plugins.jaws.deployment.JawsFileManagerFactory;
+import org.jboss.ejb.plugins.jaws.deployment.JawsEjbJar;
+import org.jboss.ejb.plugins.jaws.deployment.JawsEnterpriseBeans;
+import org.jboss.ejb.plugins.jaws.deployment.JawsEjbReference;
+import org.jboss.ejb.plugins.jaws.deployment.JawsEntity;
+import org.jboss.ejb.plugins.jaws.deployment.JawsCMPField;
+import org.jboss.ejb.plugins.jaws.deployment.Finder;
+
+/**
+ * Just Another Web Store - an O/R mapper
+ *
+ *
+ * Note: This is a really long class, but I thought that splitting it up
+ * would only make things more confusing. To compensate for the size
+ * I have tried to make many helper methods to keep each method small.
+ *
+ * @see <related>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Rickard �berg</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a>
+ * @version $Revision: 1.17 $
+ */
+public class JAWSPersistenceManager
+ implements EntityPersistenceManager
+{
+ // Constants -----------------------------------------------------
+
+ // Attributes ----------------------------------------------------
+ EntityContainer container;
+
+ Method ejbStore;
+ Method ejbLoad;
+ Method ejbActivate;
+ Method ejbPassivate;
+ Method ejbRemove;
+
+ // Pre-calculated fields to speed things up
+ ArrayList pkFields = new ArrayList(); // Field's in entity class
+ ArrayList pkClassFields = new ArrayList(); // Field's in pk class
+ ArrayList pkColumns = new ArrayList(); // String's
+ String pkColumnList; // Comma-separated list of column names
+ String pkColumnWhereList; // Comma-separated list of column names (for WHERE
clauses)
+ ArrayList cmpFields = new ArrayList(); // The fields from the actual Bean
+ ArrayList CMPFields = new ArrayList(); // The JawsCMPField representation
+ ArrayList jdbcTypes = new ArrayList(); // Integer's
+ ArrayList pkJdbcTypes = new ArrayList(); // Integer's describing pk
+ ArrayList ejbRefs = new ArrayList(); // EJB-references
+
+ HashMap definedFinders = new HashMap();
+
+ boolean compoundKey;
+ Class primaryKeyClass;
+
+ JawsEntity entity;
+ String dbName;
+ String tableName;
+
+ String createSql;
+ String insertSql;
+ String existSql;
+ // String updateSql; Calculated dynamically (=tuned updates)
+ String selectSql;
+ String removeSql;
+ String dropSql;
+
+ Context javaCtx;
+
+ Log log = new Log("JAWS");
+
+ DataSource ds;
+ String url;
+
+ boolean readOnly;
+ long readOnlyTimeOut;
+
+ // Static --------------------------------------------------------
+
+ // Constructors --------------------------------------------------
+
+ // Public --------------------------------------------------------
+ public void setContainer(Container c)
+ {
+ container = (EntityContainer)c;
+ }
+
+ public void init()
+ throws Exception
+ {
+ log.debug("Initializing JAWS plugin for
"+container.getMetaData().getEjbName());
+
+ javaCtx = (Context)new InitialContext().lookup("java:comp/env");
+
+ JawsFileManager jfm = (JawsFileManager)new
JawsFileManagerFactory().createFileManager();
+
+ // Setup beancontext
+ BeanContextServicesSupport beanCtx = new BeanContextServicesSupport();
+ beanCtx.add(Beans.instantiate(getClass().getClassLoader(),
"com.dreambean.ejx.xml.ProjectX"));
+ beanCtx.add(jfm);
+
+ // Load XML, if the URL doesn't have default information the filemanager uses
defaults
+ JawsEjbJar jar = jfm.load(container.getApplication().getURL());
+
+ // Extract meta-info
+ entity =
(JawsEntity)jar.getEnterpriseBeans().getEjb(container.getMetaData().getEjbName());
+ Iterator fields = entity.getCMPFields();
+ while (fields.hasNext())
+ {
+ JawsCMPField field = (JawsCMPField)fields.next();
+
+ CMPFields.add(field);
+ cmpFields.add(container.getBeanClass().getField(field.getFieldName()));
+ // Identify JDBC-type
+
+ jdbcTypes.add(new Integer(getJDBCType(field.getJdbcType())));
+
+ // EJB-reference
+ if (field.getJdbcType().equals("REF"))
+ {
+ ejbRefs.add(getPkColumns(field));
+ }
+ }
+
+ // Read-only?
+ readOnly = entity.getReadOnly();
+ readOnlyTimeOut = entity.getTimeOut();
+
+ // Identify pk
+ pkColumnList = "";
+ pkColumnWhereList = "";
+ compoundKey = entity.getPrimaryKeyField().equals("");
+ if (compoundKey)
+ {
+ // Compound key
+ Field[] pkClassFieldList =
container.getClassLoader().loadClass(entity.getPrimaryKeyClass()).getFields();
+
+ // Build pk field list and SQL-pk string
+ for (int i = 0; i < pkClassFieldList.length; i++)
+ {
+ pkClassFields.add(pkClassFieldList[i]);
+ Field field =
container.getBeanClass().getField(pkClassFieldList[i].getName());
+ pkFields.add(field);
+ for (int j = 0; j < CMPFields.size(); j++)
+ {
+ JawsCMPField cmpField = (JawsCMPField)CMPFields.get(j);
+ if (cmpField.getFieldName().equals(field.getName()))
+ {
+ pkColumnList += ((i == 0)?"":",") + cmpField.getColumnName();
+ pkColumnWhereList += ((i == 0)?"":" AND ") +
cmpField.getColumnName()+"=?";
+ pkJdbcTypes.add(new Integer(getJDBCType(cmpField.getJdbcType())));
+ pkColumns.add(cmpFields.get(j));
+ break;
+ }
+ }
+ }
+
+ // Get compound key class
+ primaryKeyClass =
container.getClassLoader().loadClass(entity.getPrimaryKeyClass());
+ } else
+ {
+ // Primitive key
+
pkFields.add(container.getBeanClass().getField(entity.getPrimaryKeyField()));
+ for (int j = 0; j < CMPFields.size(); j++)
+ {
+ JawsCMPField cmpField = (JawsCMPField)CMPFields.get(j);
+ if (cmpField.getFieldName().equals(entity.getPrimaryKeyField()))
+ {
+ pkColumnList = cmpField.getColumnName();
+ pkColumnWhereList = cmpField.getColumnName()+"=?";
+ pkJdbcTypes.add(new Integer(getJDBCType(cmpField.getJdbcType())));
+ pkColumns.add(cmpFields.get(j));
+ break;
+ }
+ }
+ }
+
+ // Create SQL commands
+ makeSql();
+
+ // Find EJB-methods
+ ejbStore = EntityBean.class.getMethod("ejbStore", new Class[0]);
+ ejbLoad = EntityBean.class.getMethod("ejbLoad", new Class[0]);
+ ejbActivate = EntityBean.class.getMethod("ejbActivate", new Class[0]);
+ ejbPassivate = EntityBean.class.getMethod("ejbPassivate", new Class[0]);
+ ejbRemove = EntityBean.class.getMethod("ejbRemove", new Class[0]);
+ }
+
+ public void start()
+ throws Exception
+ {
+ // Find datasource
+ url = ((JawsEjbJar)entity.getBeanContext().getBeanContext()).getDataSource();
+ if (!url.startsWith("jdbc:"))
+ {
+ ds = (DataSource)new
InitialContext().lookup(((JawsEjbJar)entity.getBeanContext().getBeanContext()).getDataSource());
+ }
+
+ // Create table if necessary
+ if (entity.getCreateTable())
+ {
+
+ // Try to create it
+ Connection con = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try
+ {
+ con = getConnection();
+ stmt = con.prepareStatement(createSql);
+ stmt.executeQuery();
+ log.debug("Table "+tableName+" created");
+ } catch (SQLException e)
+ {
+ // For debug only
+ // e.printStackTrace();
+ log.debug("Table "+tableName+" exists");
+ } finally
+ {
+ if (rs != null) try { rs.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (con != null) try { con.close(); } catch (Exception e) {
e.printStackTrace(); }
+ }
+ }
+ }
+
+ public void stop()
+ {
+ }
+
+ public void destroy()
+ {
+ if (entity.getRemoveTable())
+ {
+ // Remove it!
+ Connection con = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try
+ {
+ con = getConnection();
+ stmt = con.prepareStatement(dropSql);
+ stmt.executeUpdate();
+ log.debug("Table "+tableName+" removed");
+ } catch (SQLException e)
+ {
+ log.debug("Table "+tableName+" could not be removed");
+ } finally
+ {
+ if (rs != null) try { rs.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (con != null) try { con.close(); } catch (Exception e) {
e.printStackTrace(); }
+ }
+ }
+ }
+
+ public void createEntity(Method m, Object[] args, EntityEnterpriseContext ctx)
+ throws RemoteException, CreateException
+ {
+ // Get methods
+ try
+ {
+ Method createMethod = container.getBeanClass().getMethod("ejbCreate",
m.getParameterTypes());
+ Method postCreateMethod =
container.getBeanClass().getMethod("ejbPostCreate", m.getParameterTypes());
+
+ // Call ejbCreate
+ createMethod.invoke(ctx.getInstance(), args);
+
+ // Extract pk
+ Object id = null;
+ if (compoundKey)
+ {
+ try
+ {
+ id = primaryKeyClass.newInstance();
+ } catch (InstantiationException e)
+ {
+ throw new ServerException("Could not create primary key",e);
+ }
+
+ for (int i = 0; i < pkFields.size(); i++)
+ {
+ Field from = (Field)pkFields.get(i);
+ Field to = (Field)pkClassFields.get(i);
+ to.set(id,from.get(ctx.getInstance()));
+ }
+ } else
+ {
+ id = ((Field)pkFields.get(0)).get(ctx.getInstance());
+ }
+
+ log.debug("Create, id is "+id);
+
+ // Check duplicate
+ if (beanExists(id)) {
+
+ // it exists, we need the DuplicateKey thingy
+ throw new DuplicateKeyException("Entity with key "+id+" already exists");
+ }
+
+ // We know we are OK and can proceed with the insert
+ // Set id
+ ctx.setId(id);
+
+ // Lock instance in cache
+ ((EntityContainer)container).getInstanceCache().insert(ctx);
+
+ // Create EJBObject
+ ctx.setEJBObject(container.getContainerInvoker().getEntityEJBObject(id));
+
+ // Insert in db
+ log.debug("Insert");
+ Connection con = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try
+ {
+ con = getConnection();
+ log.debug("SQL:"+insertSql);
+ stmt = con.prepareStatement(insertSql);
+
+ int idx = 1; // Parameter-index
+ int refIdx = 0; // EJB-reference index, into ejbRefs
+ for (int i = 0; i < cmpFields.size(); i++)
+ {
+ int jdbcType = getCMPFieldJDBCType(i);
+ Object value = getCMPFieldValue(ctx.getInstance(), i);
+ if (jdbcType == Types.REF)
+ {
+ idx = setForeignKey(stmt, idx, refIdx++, value);
+ } else
+ {
+ setParameter(stmt, idx++, jdbcType, value);
+ }
+ }
+
+ stmt.executeUpdate();
+ } catch (SQLException e)
+ {
+ log.exception(e);
+ throw new CreateException("Could not create entity:"+e);
+ } finally
+ {
+ if (rs != null) try { rs.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (con != null) try { con.close(); } catch (Exception e) {
e.printStackTrace(); }
+ }
+
+ // Store state to be able to do tuned updates
+ PersistenceContext pCtx = new PersistenceContext();
+
+ // If read-only, set last read to now
+ if (readOnly) pCtx.lastRead = System.currentTimeMillis();
+
+ // Save initial state for tuned updates
+ pCtx.state = getState(ctx);
+
+ ctx.setPersistenceContext(pCtx);
+
+ // Invoke postCreate
+ postCreateMethod.invoke(ctx.getInstance(), args);
+ } catch (InvocationTargetException e)
+ {
+
+ throw new CreateException("Create failed:"+e);
+ } catch (NoSuchMethodException e)
+ {
+ throw new CreateException("Create methods not found:"+e);
+ } catch (IllegalAccessException e)
+ {
+ throw new CreateException("Could not create entity:"+e);
+ }
+ }
+
+ /*
+ * beanExists
+ *
+ * Checks in the database that the backend already holds the entity
+ *
+ */
+ public boolean beanExists(EntityEnterpriseContext ctx)
+ {
+
+ return beanExists(ctx.getId());
+ }
+
+ public boolean beanExists(Object id)
+ {
+ Connection con = null;
+
+ PreparedStatement stmt = null;
+
+ ResultSet rs = null;
+
+ boolean exists = false;
+
+ try
+ {
+ //Get the connection
+ con = getConnection();
+
+ stmt = con.prepareStatement(existSql);
+ log.debug("SQL:"+existSql);
+
+ // Primary key in WHERE-clause
+ if (compoundKey)
+ {
+ // Compound key
+ for (int i = 0; i < pkClassFields.size(); i++)
+ {
+ int jdbcType = getPkFieldJDBCType(i);
+ Object value = getPkFieldValue(id, i);
+
+ // Set this field of the key
+ setParameter(stmt, i+1, jdbcType, value);
+ }
+ } else // We have a Field key
+ {
+ // So just set that field
+ int jdbcType = getPkFieldJDBCType(0);
+ setParameter(stmt, 1, jdbcType, id);
+ }
+
+ rs = stmt.executeQuery();
+
+ // Unlikely we'll fall into the next if statement, as the
+ // COUNT(*) should always return a value, unless something dubious occurs
+
+ if ( !rs.next() ) {
+ stmt.close();
+ throw new SQLException("Unable to check for EJB in database");
+ }
+
+ int total = rs.getInt("Total");
+
+ log.debug("Object count:"+total);
+
+ if ( total >= 1 )
+ exists = true;
+ else
+ exists = false;
+
+ stmt.close();
+ }
+
+ catch (Exception e ) {
+
+ log.exception(e);
+
+ // An exception means something erroneous has occurred, either
+ // the table doesn't exist or something else. Either way, indicate
+ // we failed to find the bean
+
+ exists = false;
+ }
+
+ finally {
+
+ // Ensure our database connection is released
+ try {
+
+ if ( con != null ) con.close();
+ } catch ( SQLException se ) {
+
+ log.exception(se);
+ }
+
+ return exists;
+ }
+ }
+
+ public Object findByPrimaryKey(Object id) throws FinderException
+ {
+ if (beanExists(id))
+ {
+ return id;
+ }
+ else
+ {
+ throw new FinderException ("Object with primary key "+
+ id+
+ " not found in storage");
+ }
+ }
+
+ public Object findEntity(Method finderMethod, Object[] args,
EntityEnterpriseContext ctx)
+ throws RemoteException, FinderException
+ {
+ if (finderMethod.getName().equals("findByPrimaryKey"))
+ {
+
+ return findByPrimaryKey(args[0]);
+ }
+ else
+ {
+ ArrayList result = (ArrayList)findEntities(finderMethod, args, ctx);
+ if (result.size() == 0)
+ throw new FinderException("No such entity!");
+ else
+ return result.get(0);
+ }
+ }
+
+ public Collection findEntities(Method finderMethod, Object[] args,
EntityEnterpriseContext ctx)
+ throws RemoteException, FinderException
+ {
+ Connection con = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+
+ try
+ {
+ // Try defined finders
+ DefinedFinder df =
(DefinedFinder)definedFinders.get(finderMethod.getName());
+
+ if (df != null)
+ {
+ con = getConnection();
+ log.debug("SQL:"+df.sql);
+ stmt = con.prepareStatement(df.sql);
+
+ // Set parameters
+ for (int i = 0; i < df.parameters.length; i++)
+ {
+ stmt.setObject(i+1, args[df.parameters[i]]);
+ }
+ }
+ else
+ {
+ if (finderMethod.getName().equals("findAll"))
+ {
+ // Try findAll
+ con = getConnection();
+ stmt = con.prepareStatement("SELECT "+pkColumnList+" FROM
"+tableName);
+ } else if (finderMethod.getName().startsWith("findBy"))
+ {
+ // Try findByX
+ String cmpFieldName =
finderMethod.getName().substring(6).toLowerCase();
+ System.out.println("Finder:"+cmpFieldName);
+
+ for (int i = 0; i < CMPFields.size(); i++)
+ {
+ JawsCMPField cmpField = (JawsCMPField)CMPFields.get(i);
+
+ // Find field
+ if (cmpFieldName.equals(cmpField.getFieldName().toLowerCase()))
+ {
+ int jdbcType = getCMPFieldJDBCType(i);
+
+ // Is reference?
+ if (jdbcType == Types.REF)
+ {
+ // TODO: Precompute SQL
+ String sql = "SELECT "+pkColumnList+" FROM "+tableName+ "
WHERE ";
+
+ // TODO: Fix this.. I mean it's already been computed
once..
+ JawsCMPField[] cmpFields = getPkColumns(cmpField);
+ for (int j = 0; j < cmpFields.length; j++)
+ {
+ sql += (j==0?"":" AND ") +
cmpField.getColumnName()+"_"+cmpFields[j].getColumnName()+"=?";
+ }
+
+ con = getConnection();
+ log.debug("SQL:"+sql);
+ stmt = con.prepareStatement(sql);
+
+ // Set parameters
+ setForeignKey(stmt, 1, 0, args[0]);
+ } else
+ {
+ // Find in db
+ // TODO: Precompute SQL
+ String sql = "SELECT "+pkColumnList+" FROM "+tableName+ "
WHERE "+cmpField.getColumnName()+"=?";
+
+ con = getConnection();
+ log.debug("SQL:"+sql);
+ stmt = con.prepareStatement(sql);
+
+ // Set parameters
+ setParameter(stmt, 1, jdbcType, args[0]);
+ }
+ }
+ }
+ } else
+ {
+ log.warning("No finder for this method:"+finderMethod.getName());
+ return new java.util.ArrayList();
+ }
+ }
+
+ // Compute result
+ rs = stmt.executeQuery();
+ ArrayList result = new ArrayList();
+ if (compoundKey)
+ {
+ // Compound key
+ try
+ {
+ while (rs.next())
+ {
+ Object pk = primaryKeyClass.newInstance();
+ for (int i = 0; i < pkClassFields.size(); i++)
+ {
+ Field field = (Field)pkClassFields.get(i);
+ field.set(pk, rs.getObject(i+1));
+ }
+ result.add(pk);
+ }
+ } catch (Exception e)
+ {
+ throw new ServerException("Finder failed",e);
+ }
+ } else
+ {
+ // Primitive key
+ while (rs.next())
+ {
+ result.add(rs.getObject(1));
+ }
+ }
+
+ return result;
+ } catch (SQLException e)
+ {
+ log.exception(e);
+ throw new FinderException("Find failed");
+ } finally
+ {
+ if (rs != null) try { rs.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (con != null) try { con.close(); } catch (Exception e) {
e.printStackTrace(); }
+ }
+ }
+
+ public void activateEntity(EntityEnterpriseContext ctx)
+ throws RemoteException
+ {
+ // Call bean
+ try
+ {
+ ejbActivate.invoke(ctx.getInstance(), new Object[0]);
+ } catch (Exception e)
+ {
+ throw new ServerException("Activation failed", e);
+ }
+
+ // Set new persistence context
+ ctx.setPersistenceContext(new PersistenceContext());
+ }
+
+ public void loadEntity(EntityEnterpriseContext ctx)
+ throws RemoteException
+ {
+ // Check read only
+ if (readOnly)
+ {
+ PersistenceContext pCtx = (PersistenceContext)ctx.getPersistenceContext();
+
+ // Timeout has expired for this entity?
+ if ((pCtx.lastRead + readOnlyTimeOut) > System.currentTimeMillis())
+ return; // State is still "up to date"
+ }
+
+ Connection con = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+
+ try
+ {
+ // Load from db
+ con = getConnection();
+ stmt = con.prepareStatement(selectSql);
+
+ log.debug("Load SQL:"+selectSql);
+
+ // Primary key in WHERE-clause
+ if (compoundKey)
+ {
+ // Compound key
+ for (int i = 0; i < pkClassFields.size(); i++)
+ {
+ int jdbcType = getPkFieldJDBCType(i);
+ Object value = getPkFieldValue(ctx.getId(), i);
+ setParameter(stmt, i+1, jdbcType, value);
+ }
+ } else
+ {
+ // Primitive key
+ Object value = ctx.getId();
+ int jdbcType = getPkFieldJDBCType(0);
+ setParameter(stmt, 1, jdbcType, value);
+ }
+
+ rs = stmt.executeQuery();
+
+ if (!rs.next())
+ throw new NoSuchObjectException("Entity "+ctx.getId()+" not found");
+
+ // Set values
+ int idx = 1;
+ int refIdx = 0;
+ for (int i = 0; i < CMPFields.size(); i++)
+ {
+ JawsCMPField cmpField = (JawsCMPField)CMPFields.get(i);
+ if (((Integer)jdbcTypes.get(i)).intValue() == Types.REF)
+ {
+ // Create pk
+ JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx++);
+ JawsEntity referencedEntity =
(JawsEntity)pkFields[0].getBeanContext();
+ Object pk;
+ if (referencedEntity.getPrimaryKeyField().equals(""))
+ {
+ // Compound key
+ pk =
container.getClassLoader().loadClass(referencedEntity.getPrimaryKeyClass()).newInstance();
+ Field[] fields = pk.getClass().getFields();
+ for(int j = 0; j < fields.length; j++)
+ {
+ Object val =
rs.getObject(idx++);
+ fields[j].set(pk, val);
+ log.debug("Referenced pk field:"+val);
+ }
+ } else
+ {
+ // Primitive key
+ pk = rs.getObject(idx++);
+ log.debug("Referenced pk:"+pk);
+ }
+
+ // Find referenced entity
+ try
+ {
+ Object home = javaCtx.lookup(cmpField.getSqlType());
+ Method[] homeMethods = home.getClass().getMethods();
+ Method finder = null;
+
+ // We have to locate fBPK iteratively since we don't really know
the pk-class
+ for (int j = 0; j < homeMethods.length; j++)
+ if (homeMethods[j].getName().equals("findByPrimaryKey"))
+ {
+ finder = homeMethods[j];
+ break;
+ }
+
+ if (finder == null)
+ throw new NoSuchMethodException("FindByPrimaryKey method not
found in home interface");
+
+ log.debug("PK="+pk);
+ Object ref = finder.invoke(home, new Object[] { pk });
+
+ // Set found entity
+ ((Field)cmpFields.get(i)).set(ctx.getInstance(), ref);
+ } catch (Exception e)
+ {
+ throw new ServerException("Could not restore reference", e);
+ }
+ } else
+ {
+ // Load primitive
+
+ // TODO: this probably needs to be fixed for BLOB's etc.
+ ((Field)cmpFields.get(i)).set(ctx.getInstance(),
rs.getObject(idx++));
+ }
+ }
+
+ // Store state to be able to do tuned updates
+ PersistenceContext pCtx = (PersistenceContext)ctx.getPersistenceContext();
+ if (readOnly) pCtx.lastRead = System.currentTimeMillis();
+
+ // Call ejbLoad on bean instance
+ ejbLoad.invoke(ctx.getInstance(), new Object[0]);
+
+ // Done
+ } catch (Exception e)
+ {
+ throw new ServerException("Load failed", e);
+ } finally
+ {
+ if (rs != null) try { rs.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (con != null) try { con.close(); } catch (Exception e) {
e.printStackTrace(); }
+ }
+ }
+
+ /*
+ * storeEntity(EntityEnterpriseContext ctx)
+ *
+ * if the readOnly flag is specified in the xml file this won't store.
+ * if not a tuned update is issued.
+ *
+ * MF: FIXME: In case of findByPrimaryKey existing it seems the "oldState"
variable is null
+ * This is a quick fix that tests for the "null" old state, better fixed when
retrieving
+ *
+ */
+ public void storeEntity(EntityEnterpriseContext ctx)
+ throws RemoteException
+ {
+ // Check for read-only
+ if (readOnly)
+ return;
+
+ Connection con = null;
+ PreparedStatement stmt = null;
+ try
+ {
+ // Call bean
+ ejbStore.invoke(ctx.getInstance(), new Object[0]);
+
+ // Create tuned update
+ String updateSql = "UPDATE "+tableName+" SET ";
+ //MF: PERF???
+ Object[] currentState = getState(ctx);
+ boolean[] dirtyField = new boolean[currentState.length];
+ //MF: PERF???
+ Object[] oldState =
((PersistenceContext)ctx.getPersistenceContext()).state;
+ boolean dirty = false;
+ int refIdx = 0;
+
+ //System.out.println("THE CURRENTSTATE "+getState(ctx));
+ for (int i = 0;i < currentState.length; i++)
+ {
+ if (((Integer)jdbcTypes.get(i)).intValue() == Types.REF) {
+ /*if (((currentState[i] != null) &&
+ (oldState[i] == null || !currentState[i].equals(oldState[i])))
||
+ (oldState[i] != null))
+ */
+ if (
+ // The field must be non null
+ (currentState[i] != null) &&
+ // Old field or object null qualify automatically
+ ((oldState == null || oldState[i] == null) ||
+ // Otherwise condition is "non-equality"
+ !currentState[i].equals(oldState[i]))
+ )
+ {
+ JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx);
+ for (int j = 0; j < pkFields.length; j++)
+ {
+ updateSql += (dirty?",":"") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].getColumnName()+"=?";
+ dirty = true;
+ }
+ dirtyField[i] = true;
+ }
+ refIdx++;
+ } else
+ {
+ System.out.println("CURRENTSTATE I"+ currentState[i]);
+ System.out.println("OLDSTATE ARRAY" + oldState);
+ //System.out.println("OLDSTATE I"+ oldState[i]);
+
+ // MF FIXME I can't make sense of the following if...
+ // also it dies on a method call after an existing id
+ /*
+ if (
+ ((currentState[i] != null) &&
+ (oldState[i] == null ||
!currentState[i].equals(oldState[i]))) ||
+ (oldState[i] != null)
+ // MF What? if the oldState[i] is not null it
qualifies automatically? makes no sense
+ )
+ */
+
+ // MF I want to use the following, seems to work
+
+ if (
+ // The field must be non null
+ (currentState[i] != null) &&
+ // Old field or old object null qualify
automatically
+ ((oldState == null || oldState[i] == null) ||
+ // Otherwise condition is "non-equality"
+ !currentState[i].equals(oldState[i]))
+ )
+
+ {
+ updateSql += (dirty?",":"") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"=?";
+ dirty = true;
+ dirtyField[i] = true;
+ }
+ }
+ }
+
+ if (!dirty)
+ {
+ return;
+ } else
+ {
+ updateSql += " WHERE "+pkColumnWhereList;
+ }
+
+ // Update database
+ con = getConnection();
+ stmt = con.prepareStatement(updateSql);
+
+ int idx = 1;
+ refIdx = 0;
+ for (int i = 0;i < dirtyField.length; i++)
+ {
+ int jdbcType = getCMPFieldJDBCType(i);
+ if (jdbcType == Types.REF)
+ {
+ if (dirtyField[i])
+ {
+ idx = setForeignKey(stmt, idx, refIdx++, currentState[i]);
+ }
+ } else
+ {
+ if (dirtyField[i])
+ {
+ setParameter(stmt, idx++, jdbcType, currentState[i]);
+ }
+ }
+ }
+
+ // Primary key in WHERE-clause
+ for (int i = 0; i < pkFields.size(); i++)
+ {
+ int jdbcType = getPkFieldJDBCType(i);
+ Object value = getCMPFieldValue(ctx.getInstance(), i);
+ setParameter(stmt, idx++, jdbcType, value);
+ }
+
+ // Execute update
+ stmt.execute();
+ } catch (Exception e)
+ {
+ throw new ServerException("Store failed", e);
+ } finally
+ {
+ if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (con != null) try { con.close(); } catch (Exception e) {
e.printStackTrace(); }
+ }
+
+ }
+
+ public void passivateEntity(EntityEnterpriseContext ctx)
+ throws RemoteException
+ {
+ // Call bean
+ try
+ {
+ ejbPassivate.invoke(ctx.getInstance(), new Object[0]);
+ } catch (Exception e)
+ {
+ throw new ServerException("Passivation failed", e);
+ }
+ }
+
+ public void removeEntity(EntityEnterpriseContext ctx)
+ throws RemoteException, RemoveException
+ {
+ Connection con = null;
+ PreparedStatement stmt = null;
+
+ try
+ {
+ // Call ejbRemove
+ ejbRemove.invoke(ctx.getInstance(), new Object[0]);
+
+ // Remove from DB
+ con = getConnection();
+ stmt = con.prepareStatement(removeSql);
+
+ // Primary key in WHERE-clause
+ if (compoundKey)
+ {
+ // Compound key
+ for (int i = 0; i < pkClassFields.size(); i++)
+ {
+ int jdbcType = getPkFieldJDBCType(i);
+ Object value = getPkFieldValue(ctx.getId(), i);
+ setParameter(stmt, i+1, jdbcType, value);
+ }
+ } else
+ {
+ // Primitive key
+ Object value = ctx.getId();
+ int jdbcType = getPkFieldJDBCType(0);
+ setParameter(stmt, 1, jdbcType, value);
+ }
+
+ int count = stmt.executeUpdate();
+
+ if (count == 0)
+ {
+ throw new RemoveException("Could not remove entity");
+ }
+ // System.out.println("Removed file for"+ctx.getId());
+ } catch (Exception e)
+ {
+ throw new RemoveException("Could not remove "+ctx.getId());
+ } finally
+ {
+ if (stmt != null) try { stmt.close(); } catch (Exception e) {
e.printStackTrace(); }
+ if (con != null) try { con.close(); } catch (Exception e) {
e.printStackTrace(); }
+ }
+ }
+
+ // Z implementation ----------------------------------------------
+
+ // Package protected ---------------------------------------------
+
+ // Protected -----------------------------------------------------
+
+ // Private -------------------------------------------------------
+ private Connection getConnection()
+ throws SQLException
+ {
+ if (ds != null)
+ return ds.getConnection();
+ else
+ return DriverManager.getConnection(url,"sa","");
+ }
+
+ private void makeSql()
+ {
+ // initialize the table name we replace the . by - because some dbs die on
it...
+ tableName = entity.getTableName().replace('.','_');
+
+ // Remove SQL
+ removeSql = "DELETE FROM "+tableName+" WHERE "+pkColumnWhereList;
+ log.debug("Remove:"+removeSql);
+
+ // Drop table
+ dropSql = "DROP TABLE "+tableName;
+ log.debug("Drop:"+dropSql);
+
+ // Create table
+ createSql = "CREATE TABLE "+tableName+" (";
+
+ int refIdx = 0;
+ for (int i = 0;i < CMPFields.size(); i++)
+ {
+ if (((Integer)jdbcTypes.get(i)).intValue() == Types.REF)
+ {
+ JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx);
+ for (int j = 0; j < pkFields.length; j++)
+ {
+ createSql += (i==0 && j==0?"":",") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].getColumnName()+"
"+pkFields[j].getSqlType();
+ }
+ refIdx++;
+ } else
+ {
+ JawsCMPField field = (JawsCMPField)CMPFields.get(i);
+ createSql += (i==0?"":",") + field.getColumnName()+"
"+field.getSqlType();
+ }
+ }
+
+ createSql += ")";
+
+ log.debug("Create table:"+createSql);
+
+ // Insert SQL fields
+ insertSql = "INSERT INTO "+tableName;
+ String fieldSql = "";
+ String valueSql = "";
+ refIdx = 0;
+ for (int i = 0;i < CMPFields.size(); i++)
+ {
+ if (((Integer)jdbcTypes.get(i)).intValue() == Types.REF)
+ {
+ JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx);
+ for (int j = 0; j < pkFields.length; j++)
+ {
+ fieldSql += (fieldSql.equals("") ? "":",") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].getColumnName();
+ valueSql += (valueSql.equals("") ? "?":",?");
+ }
+ refIdx++;
+ } else
+ {
+ JawsCMPField field = (JawsCMPField)CMPFields.get(i);
+ fieldSql += (fieldSql.equals("") ? "":",") + field.getColumnName();
+ valueSql += (valueSql.equals("") ? "?":",?");
+ }
+ }
+
+ insertSql += " ("+fieldSql+") VALUES ("+valueSql+")";
+ log.debug("Insert:"+insertSql);
+
+ // Select SQL fields
+ selectSql = "SELECT ";
+ refIdx = 0;
+ for (int i = 0;i < CMPFields.size(); i++)
+ {
+ if (((Integer)jdbcTypes.get(i)).intValue() == Types.REF)
+ {
+ JawsCMPField[] pkFields = (JawsCMPField[])ejbRefs.get(refIdx);
+ for (int j = 0; j < pkFields.length; j++)
+ {
+ selectSql += (i==0 && j==0?"":",") +
((JawsCMPField)CMPFields.get(i)).getColumnName()+"_"+pkFields[j].getColumnName();
+ }
+ refIdx++;
+ } else
+ {
+ JawsCMPField field = (JawsCMPField)CMPFields.get(i);
+ selectSql += (i==0?"":",") + field.getColumnName();
+ }
+ }
+
+ selectSql += " FROM "+tableName+ " WHERE "+pkColumnWhereList;
+ log.debug("Select:"+selectSql);
+
+
+ // Exist SQL query
+ existSql = "SELECT COUNT(*) AS Total FROM " + tableName+ " WHERE
"+pkColumnWhereList;
+
+ log.debug("Exists:"+existSql);
+
+
+
+/* // Update SQL fields
+ updateSql = "UPDATE "+tableName+" SET ";
+ fieldSql = "";
+ for (int i = 0; i < CMPFields.length; i++)
+ {
+ CMPField field = CMPFields[i];
+ if (field.getJdbcType().equals("REF"))
+ {
+ String[] pk = getPkColumn(field);
+ fieldSql += (fieldSql.equals("") ? "":",")+pk[0]+"=?";
+ } else
+ {
+ fieldSql += (fieldSql.equals("") ? "":",")+field.getColumnName()+"=?";
+ }
+
+ }
+ updateSql += fieldSql +" WHERE "+idColumn+"=?";
+
+ log.debug("Update:"+updateSql);
+*/
+
+ // Defined finders
+ Iterator finders = entity.getFinders();
+ while(finders.hasNext())
+ {
+ Finder f = (Finder)finders.next();
+
+ // Replace placeholders with ?
+ String query = "";
+ StringTokenizer finderQuery = new
StringTokenizer(f.getQuery(),"{}", true);
+ ArrayList parameters = new ArrayList();
+ while (finderQuery.hasMoreTokens())
+ {
+ String t = finderQuery.nextToken();
+ if (t.equals("{"))
+ {
+ query += "?";
+ String idx = finderQuery.nextToken(); //
Remove number
+ parameters.add(new Integer(idx));
+ finderQuery.nextToken(); // Remove }
+ } else
+ query += t;
+ }
+
+ // Copy index numbers to array
+ int[] parameterArray = new int[parameters.size()];
+ for (int i = 0; i < parameterArray.length; i++)
+ parameterArray[i] =
((Integer)parameters.get(i)).intValue();
+
+ // Construct SQL
+ String sql = "SELECT
"+pkColumnList+(f.getOrder().equals("")?"":","+f.getOrder())+" FROM "+tableName+"
WHERE "+query;
+ if (!f.getOrder().equals(""))
+ {
+ sql += " ORDER BY "+f.getOrder();
+ }
+
+ log.debug(f.getName()+"="+sql);
+
+ // Store in map
+ DefinedFinder df = new DefinedFinder();
+ df.sql = sql;
+ df.parameters = parameterArray;
+ definedFinders.put(f.getName(), df);
+ }
+ }
+
+ //MF: PERF!!!!!!!
+ private Object[] getState(EntityEnterpriseContext ctx)
+ {
+ Object[] state = new Object[cmpFields.size()];
+ for (int i = 0; i < state.length; i++)
+ {
+ try
+ {
+ state[i] = ((Field)cmpFields.get(i)).get(ctx.getInstance());
+ } catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ return state;
+ }
+
+ private int getJDBCType(String name)
+ {
+ try
+ {
+
+ Integer constant = (Integer)Types.class.getField(name).get(null);
+ return constant.intValue();
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ return Types.OTHER;
+ }
+ }
+
+ private JawsCMPField[] getPkColumns(JawsCMPField field)
+ throws RemoteException
+ {
+ // Find reference
+ Iterator enum = ((JawsEntity)field.getBeanContext()).getEjbReferences();
+ while (enum.hasNext())
+ {
+ JawsEjbReference ref = (JawsEjbReference)enum.next();
+ if (ref.getName().equals(field.getSqlType()))
+ {
+ // Find referenced entity
+ JawsEnterpriseBeans eb =
(JawsEnterpriseBeans)field.getBeanContext().getBeanContext();
+ JawsEntity referencedEntity = (JawsEntity)eb.getEjb(ref.getLink());
+ // Extract pk
+ String pk = referencedEntity.getPrimaryKeyField();
+ if (pk.equals(""))
+ {
+ // Compound key
+ try
+ {
+ Class pkClass =
container.getClassLoader().loadClass(referencedEntity.getPrimaryKeyClass());
+ Field[] pkFields = pkClass.getFields();
+ ArrayList result = new ArrayList();
+ for (int i = 0; i < pkFields.length; i++)
+ {
+ // Find db mapping for pk field
+ Iterator fieldEnum = referencedEntity.getCMPFields();
+ while (fieldEnum.hasNext())
+ {
+ JawsCMPField pkField = (JawsCMPField)fieldEnum.next();
+ if (pkField.getFieldName().equals(pkFields[i].getName()))
+ result.add(pkField);
+ }
+ }
+ return (JawsCMPField[])result.toArray(new JawsCMPField[0]);
+ } catch (ClassNotFoundException e)
+ {
+ throw new ServerException("Could not load pk class of referenced
entity",e);
+ }
+ } else
+ {
+ // Find db mapping for pk
+ Iterator fieldEnum = referencedEntity.getCMPFields();
+ while (fieldEnum.hasNext())
+ {
+ JawsCMPField pkField = (JawsCMPField)fieldEnum.next();
+ if (pkField.getFieldName().equals(pk))
+ return new JawsCMPField[] { pkField };
+ }
+ return new JawsCMPField[0];
+ }
+ }
+ }
+
+ throw new ServerException("Could not find EJB reference. Must be defined in
XML-descriptor");
+ }
+
+ private void setParameter(PreparedStatement stmt,
+ int idx,
+ int jdbcType,
+ Object value)
+ throws SQLException
+ {
+ if (value == null)
+ {
+ stmt.setNull(idx, jdbcType);
+ } else
+ {
+ System.out.println("Set parameter:"+value);
+ stmt.setObject(idx, value, jdbcType);
+ }
+ }
+
+ private int setForeignKey(PreparedStatement stmt,
+ int idx,
+ int refIdx,
+ Object value)
+ throws SQLException
+ {
+ JawsCMPField[] pkInfo = (JawsCMPField[])ejbRefs.get(refIdx);
+ Object pk = null;
+
+ if (value != null)
+ {
+ try
+ {
+ pk = ((EJBObject)value).getPrimaryKey();
+ } catch (RemoteException e)
+ {
+ throw new SQLException("Could not extract primary key from EJB
reference:"+e);
+ }
+ }
+
+ if (!((JawsEntity)pkInfo[0].getBeanContext()).getPrimaryKeyField().equals(""))
+ {
+ // Primitive key
+ int jdbcType = getJawsCMPFieldJDBCType(pkInfo[0]);
+ Object fieldValue = (value == null) ? null : pk;
+ setParameter(stmt, idx, jdbcType, fieldValue);
+ return idx+1;
+ } else
+ {
+ // Compound key
+ // ***** PROBLEM ***** pk may be null
+ Field[] fields = pk.getClass().getFields();
+ try
+ {
+ for (int i = 0; i < pkInfo.length; i++)
+ {
+ int jdbcType = getJawsCMPFieldJDBCType(pkInfo[i]);
+ Object fieldValue = (value == null) ? null : fields[i].get(pk);
+ setParameter(stmt, idx+i, jdbcType, fieldValue);
+ }
+ } catch (IllegalAccessException e)
+ {
+ throw new SQLException("Could not extract fields from primary key:"+e);
+ }
+ return idx+pkInfo.length;
+ }
+ }
+
+ private Object getCMPFieldValue(Object instance, int i)
+ throws IllegalAccessException
+ {
+ Field field = (Field)cmpFields.get(i);
+ return field.get(instance);
+ }
+
+ private Object getPkFieldValue(Object pk, int i)
+ throws IllegalAccessException
+ {
+ Field field = (Field)pkClassFields.get(i);
+ return field.get(pk);
+ }
+
+ private int getCMPFieldJDBCType(int i)
+ {
+ return ((Integer)jdbcTypes.get(i)).intValue();
+ }
+
+ private int getPkFieldJDBCType(int i)
+ {
+ return ((Integer)pkJdbcTypes.get(i)).intValue();
+ }
+
+ private int getJawsCMPFieldJDBCType(JawsCMPField fieldInfo)
+ {
+ return getJDBCType(fieldInfo.getJdbcType());
+ }
+
+
+ // Inner classes -------------------------------------------------
+
+ static class PersistenceContext
+ {
+ Object[] state;
+ long lastRead = -1;
+ }
+
+ static class DefinedFinder
+ {
+ String sql; // The SQL to be executed in prepared statement form
+ int[] parameters; // List of finder method indices
+ }
+}