/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ejb.plugins.cmp.jdbc2.bridge;
import org.jboss.ejb.plugins.cmp.bridge.CMPFieldBridge;
import org.jboss.ejb.plugins.cmp.jdbc2.JDBCStoreManager2;
import org.jboss.ejb.plugins.cmp.jdbc2.PersistentContext;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.JDBCType;
import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore;
import org.jboss.ejb.plugins.cmp.jdbc.JDBCResultSetReader;
import org.jboss.ejb.EntityEnterpriseContext;
import org.jboss.deployment.DeploymentException;
import org.jboss.logging.Logger;
import javax.ejb.EJBException;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
/**
* @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
* @version <tt>$Revision: 81030 $</tt>
*/
public class JDBCCMPFieldBridge2
implements CMPFieldBridge
{
private final JDBCEntityBridge2 entity;
private final int rowIndex;
private final JDBCType jdbcType;
private final Class pkClass;
private final Field pkField;
private final boolean isPrimaryKeyMember;
private final String fieldName;
private final Class fieldType;
private final String columnName;
private final JDBCCMPFieldBridge2 cmpFieldIAmMappedTo;
private final Logger log;
private int versionIndex = -1;
public JDBCCMPFieldBridge2(JDBCStoreManager2 manager,
JDBCEntityBridge2 entity,
JDBCCMPFieldMetaData metadata,
int rowIndex)
throws DeploymentException
{
this.rowIndex = rowIndex;
this.entity = entity;
jdbcType = manager.getJDBCTypeFactory().getJDBCType(metadata);
pkClass = metadata.getEntity().getPrimaryKeyClass();
pkField = metadata.getPrimaryKeyField();
isPrimaryKeyMember = metadata.isPrimaryKeyMember();
fieldName = metadata.getFieldName();
fieldType = metadata.getFieldType();
cmpFieldIAmMappedTo = null;
columnName = metadata.getColumnName();
log = Logger.getLogger(this.getClass().getName() + "." + entity.getEntityName() + "#" + getFieldName());
}
public JDBCCMPFieldBridge2(JDBCCMPFieldBridge2 cmpField, JDBCCMPFieldBridge2 relatedPKField)
{
entity = cmpField.entity;
rowIndex = cmpField.rowIndex;
jdbcType = cmpField.jdbcType;
columnName = cmpField.columnName;
fieldName = relatedPKField.fieldName;
fieldType = relatedPKField.fieldType;
pkClass = relatedPKField.pkClass;
pkField = relatedPKField.pkField;
isPrimaryKeyMember = false;
cmpFieldIAmMappedTo = cmpField;
log = Logger.getLogger(this.getClass().getName() + "." + entity.getEntityName() + "#" + getFieldName());
}
// Public
public void initVersion()
{
versionIndex = entity.getTable().addVersionField();
}
public int getVersionIndex()
{
return versionIndex;
}
public String getColumnName()
{
return columnName;
}
public Object setPrimaryKeyValue(Object primaryKey, Object value)
throws IllegalArgumentException
{
try
{
if(pkField != null)
{
// if we are trying to set a null value into a null pk, we are already done.
if(value == null && primaryKey == null)
{
return null;
}
// if we don't have a pk object yet create one
if(primaryKey == null)
{
primaryKey = pkClass.newInstance();
}
// Set this field's value into the primary key object.
pkField.set(primaryKey, value);
return primaryKey;
}
else
{
// This field is the primary key, so no extraction is necessary.
return value;
}
}
catch(Exception e)
{
// Non recoverable internal exception
throw new EJBException("Internal error setting instance field " + getFieldName(), e);
}
}
public void setValueInternal(EntityEnterpriseContext ctx, Object value, boolean makeDirty)
{
PersistentContext pctx = (PersistentContext) ctx.getPersistenceContext();
// todo this is weird
if(cmpFieldIAmMappedTo != null && cmpFieldIAmMappedTo.isPrimaryKeyMember)
{
Object curValue = pctx.getFieldValue(rowIndex);
if(value != null && !value.equals(curValue))
{
throw new IllegalStateException(
"Attempt to modify a primary key field through a foreign key field mapped to it: "
+
entity.getEntityName()
+ "."
+ cmpFieldIAmMappedTo.getFieldName()
+
" -> "
+ entity.getQualifiedTableName()
+ "."
+ cmpFieldIAmMappedTo.getColumnName() +
", current value=" + curValue + ", new value=" + value
);
}
makeDirty = false;
}
else
{
pctx.setFieldValue(rowIndex, value);
}
if(makeDirty)
{
pctx.setDirty();
}
}
public int setArgumentParameters(PreparedStatement ps, int parameterIndex, Object arg)
{
try
{
int[] jdbcTypes = jdbcType.getJDBCTypes();
for(int i = 0; i < jdbcTypes.length; i++)
{
Object columnValue = jdbcType.getColumnValue(i, arg);
jdbcType.getParameterSetter()[i].set(ps, parameterIndex++, jdbcTypes[i], columnValue, log);
//JDBCUtil.setParameter(log, ps, parameterIndex++, jdbcTypes[i], columnValue);
}
return parameterIndex;
}
catch(SQLException e)
{
// Non recoverable internal exception
throw new EJBException("Internal error setting parameters for field " + getFieldName(), e);
}
}
public Object loadArgumentResults(ResultSet rs, int parameterIndex)
throws IllegalArgumentException
{
try
{
// update the value from the result set
Class[] javaTypes = jdbcType.getJavaTypes();
if(javaTypes.length > 1)
{
throw new IllegalStateException("Complex types are not supported yet.");
}
JDBCResultSetReader[] rsReaders = jdbcType.getResultSetReaders();
Object columnValue = null;
for(int i = 0; i < javaTypes.length; i++)
{
columnValue = rsReaders[i].get(rs, parameterIndex++, javaTypes[i], log);
columnValue = jdbcType.setColumnValue(i, null, columnValue);
}
// retrun the updated parameterIndex
return columnValue;
}
catch(SQLException e)
{
// Non recoverable internal exception
throw new EJBException("Internal error getting results for field member " + getFieldName(), e);
}
}
public int getRowIndex()
{
return rowIndex;
}
public JDBCEntityPersistenceStore getManager()
{
return entity.getManager();
}
// JDBCFieldBridge implementation
public void initInstance(EntityEnterpriseContext ctx)
{
Object value;
Class fieldType = getFieldType();
if(fieldType == boolean.class)
{
value = Boolean.FALSE;
}
else if(fieldType == byte.class)
{
value = new Byte((byte) 0);
}
else if(fieldType == int.class)
{
value = new Integer(0);
}
else if(fieldType == long.class)
{
value = new Long(0L);
}
else if(fieldType == short.class)
{
value = new Short((short) 0);
}
else if(fieldType == char.class)
{
value = new Character('\u0000');
}
else if(fieldType == double.class)
{
value = new Double(0d);
}
else if(fieldType == float.class)
{
value = new Float(0f);
}
else
{
value = null;
}
setValueInternal(ctx, value, false);
}
public void resetPersistenceContext(EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public int setInstanceParameters(PreparedStatement ps, int parameterIndex, EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public Object getInstanceValue(EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public void setInstanceValue(EntityEnterpriseContext ctx, Object value)
{
throw new UnsupportedOperationException();
}
public int loadInstanceResults(ResultSet rs, int parameterIndex, EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public int loadArgumentResults(ResultSet rs, int parameterIndex, Object[] argumentRef)
{
throw new UnsupportedOperationException();
}
public boolean isDirty(EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public void setClean(EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public boolean isCMPField()
{
return true;
}
public boolean isPrimaryKeyMember()
{
return isPrimaryKeyMember;
}
public boolean isReadOnly()
{
throw new UnsupportedOperationException();
}
public boolean isReadTimedOut(EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public boolean isLoaded(EntityEnterpriseContext ctx)
{
throw new UnsupportedOperationException();
}
public JDBCType getJDBCType()
{
return jdbcType;
}
public Object getPrimaryKeyValue(Object primaryKey)
throws IllegalArgumentException
{
try
{
if(pkField != null)
{
if(primaryKey == null)
{
return null;
}
return pkField.get(primaryKey);
}
else
{
return primaryKey;
}
}
catch(Exception e)
{
throw new EJBException("Internal error getting primary key field member " + getFieldName(), e);
}
}
// CMPFieldBridge implementation
public String getFieldName()
{
return fieldName;
}
public Object getValue(EntityEnterpriseContext ctx)
{
PersistentContext pctx = (PersistentContext) ctx.getPersistenceContext();
return pctx.getFieldValue(rowIndex);
}
public void setValue(EntityEnterpriseContext ctx, Object value)
{
setValueInternal(ctx, value, true);
}
public Class getFieldType()
{
return fieldType;
}
}