/* * 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; } }