001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins.cmp.jdbc2.bridge;
023:
024: import org.jboss.ejb.plugins.cmp.bridge.CMPFieldBridge;
025: import org.jboss.ejb.plugins.cmp.jdbc2.JDBCStoreManager2;
026: import org.jboss.ejb.plugins.cmp.jdbc2.PersistentContext;
027: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData;
028: import org.jboss.ejb.plugins.cmp.jdbc.JDBCType;
029: import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore;
030: import org.jboss.ejb.plugins.cmp.jdbc.JDBCResultSetReader;
031: import org.jboss.ejb.EntityEnterpriseContext;
032: import org.jboss.deployment.DeploymentException;
033: import org.jboss.logging.Logger;
034:
035: import javax.ejb.EJBException;
036: import java.lang.reflect.Field;
037: import java.sql.PreparedStatement;
038: import java.sql.SQLException;
039: import java.sql.ResultSet;
040:
041: /**
042: * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
043: * @version <tt>$Revision: 61737 $</tt>
044: */
045: public class JDBCCMPFieldBridge2 implements CMPFieldBridge {
046: private final JDBCEntityBridge2 entity;
047: private final int rowIndex;
048: private final JDBCType jdbcType;
049: private final Class pkClass;
050: private final Field pkField;
051: private final boolean isPrimaryKeyMember;
052: private final String fieldName;
053: private final Class fieldType;
054: private final String columnName;
055:
056: private final JDBCCMPFieldBridge2 cmpFieldIAmMappedTo;
057:
058: private final Logger log;
059:
060: private int versionIndex = -1;
061:
062: public JDBCCMPFieldBridge2(JDBCStoreManager2 manager,
063: JDBCEntityBridge2 entity, JDBCCMPFieldMetaData metadata,
064: int rowIndex) throws DeploymentException {
065: this .rowIndex = rowIndex;
066: this .entity = entity;
067: jdbcType = manager.getJDBCTypeFactory().getJDBCType(metadata);
068: pkClass = metadata.getEntity().getPrimaryKeyClass();
069: pkField = metadata.getPrimaryKeyField();
070: isPrimaryKeyMember = metadata.isPrimaryKeyMember();
071: fieldName = metadata.getFieldName();
072: fieldType = metadata.getFieldType();
073: cmpFieldIAmMappedTo = null;
074: columnName = metadata.getColumnName();
075:
076: log = Logger.getLogger(this .getClass().getName() + "."
077: + entity.getEntityName() + "#" + getFieldName());
078: }
079:
080: public JDBCCMPFieldBridge2(JDBCCMPFieldBridge2 cmpField,
081: JDBCCMPFieldBridge2 relatedPKField) {
082: entity = cmpField.entity;
083: rowIndex = cmpField.rowIndex;
084: jdbcType = cmpField.jdbcType;
085: columnName = cmpField.columnName;
086:
087: fieldName = relatedPKField.fieldName;
088: fieldType = relatedPKField.fieldType;
089: pkClass = relatedPKField.pkClass;
090: pkField = relatedPKField.pkField;
091:
092: isPrimaryKeyMember = false;
093:
094: cmpFieldIAmMappedTo = cmpField;
095:
096: log = Logger.getLogger(this .getClass().getName() + "."
097: + entity.getEntityName() + "#" + getFieldName());
098: }
099:
100: // Public
101:
102: public void initVersion() {
103: versionIndex = entity.getTable().addVersionField();
104: }
105:
106: public int getVersionIndex() {
107: return versionIndex;
108: }
109:
110: public String getColumnName() {
111: return columnName;
112: }
113:
114: public Object setPrimaryKeyValue(Object primaryKey, Object value)
115: throws IllegalArgumentException {
116: try {
117: if (pkField != null) {
118: // if we are trying to set a null value into a null pk, we are already done.
119: if (value == null && primaryKey == null) {
120: return null;
121: }
122:
123: // if we don't have a pk object yet create one
124: if (primaryKey == null) {
125: primaryKey = pkClass.newInstance();
126: }
127:
128: // Set this field's value into the primary key object.
129: pkField.set(primaryKey, value);
130: return primaryKey;
131: } else {
132: // This field is the primary key, so no extraction is necessary.
133: return value;
134: }
135: } catch (Exception e) {
136: // Non recoverable internal exception
137: throw new EJBException(
138: "Internal error setting instance field "
139: + getFieldName(), e);
140: }
141: }
142:
143: public void setValueInternal(EntityEnterpriseContext ctx,
144: Object value, boolean makeDirty) {
145: PersistentContext pctx = (PersistentContext) ctx
146: .getPersistenceContext();
147:
148: // todo this is weird
149: if (cmpFieldIAmMappedTo != null
150: && cmpFieldIAmMappedTo.isPrimaryKeyMember) {
151: Object curValue = pctx.getFieldValue(rowIndex);
152: if (value != null && !value.equals(curValue)) {
153: throw new IllegalStateException(
154: "Attempt to modify a primary key field through a foreign key field mapped to it: "
155: + entity.getEntityName()
156: + "."
157: + cmpFieldIAmMappedTo.getFieldName()
158: + " -> "
159: + entity.getQualifiedTableName()
160: + "."
161: + cmpFieldIAmMappedTo.getColumnName()
162: + ", current value="
163: + curValue
164: + ", new value=" + value);
165: }
166:
167: makeDirty = false;
168: } else {
169: pctx.setFieldValue(rowIndex, value);
170: }
171:
172: if (makeDirty) {
173: pctx.setDirty();
174: }
175: }
176:
177: public int setArgumentParameters(PreparedStatement ps,
178: int parameterIndex, Object arg) {
179: try {
180: int[] jdbcTypes = jdbcType.getJDBCTypes();
181: for (int i = 0; i < jdbcTypes.length; i++) {
182: Object columnValue = jdbcType.getColumnValue(i, arg);
183: jdbcType.getParameterSetter()[i].set(ps,
184: parameterIndex++, jdbcTypes[i], columnValue,
185: log);
186: //JDBCUtil.setParameter(log, ps, parameterIndex++, jdbcTypes[i], columnValue);
187: }
188: return parameterIndex;
189: } catch (SQLException e) {
190: // Non recoverable internal exception
191: throw new EJBException(
192: "Internal error setting parameters for field "
193: + getFieldName(), e);
194: }
195: }
196:
197: public Object loadArgumentResults(ResultSet rs, int parameterIndex)
198: throws IllegalArgumentException {
199: try {
200: // update the value from the result set
201: Class[] javaTypes = jdbcType.getJavaTypes();
202: if (javaTypes.length > 1) {
203: throw new IllegalStateException(
204: "Complex types are not supported yet.");
205: }
206:
207: JDBCResultSetReader[] rsReaders = jdbcType
208: .getResultSetReaders();
209:
210: Object columnValue = null;
211: for (int i = 0; i < javaTypes.length; i++) {
212: columnValue = rsReaders[i].get(rs, parameterIndex++,
213: javaTypes[i], log);
214: columnValue = jdbcType.setColumnValue(i, null,
215: columnValue);
216: }
217:
218: // retrun the updated parameterIndex
219: return columnValue;
220: } catch (SQLException e) {
221: // Non recoverable internal exception
222: throw new EJBException(
223: "Internal error getting results for field member "
224: + getFieldName(), e);
225: }
226: }
227:
228: public int getRowIndex() {
229: return rowIndex;
230: }
231:
232: public JDBCEntityPersistenceStore getManager() {
233: return entity.getManager();
234: }
235:
236: // JDBCFieldBridge implementation
237:
238: public void initInstance(EntityEnterpriseContext ctx) {
239: Object value;
240: Class fieldType = getFieldType();
241: if (fieldType == boolean.class) {
242: value = Boolean.FALSE;
243: } else if (fieldType == byte.class) {
244: value = new Byte((byte) 0);
245: } else if (fieldType == int.class) {
246: value = new Integer(0);
247: } else if (fieldType == long.class) {
248: value = new Long(0L);
249: } else if (fieldType == short.class) {
250: value = new Short((short) 0);
251: } else if (fieldType == char.class) {
252: value = new Character('\u0000');
253: } else if (fieldType == double.class) {
254: value = new Double(0d);
255: } else if (fieldType == float.class) {
256: value = new Float(0f);
257: } else {
258: value = null;
259: }
260: setValueInternal(ctx, value, false);
261: }
262:
263: public void resetPersistenceContext(EntityEnterpriseContext ctx) {
264: throw new UnsupportedOperationException();
265: }
266:
267: public int setInstanceParameters(PreparedStatement ps,
268: int parameterIndex, EntityEnterpriseContext ctx) {
269: throw new UnsupportedOperationException();
270: }
271:
272: public Object getInstanceValue(EntityEnterpriseContext ctx) {
273: throw new UnsupportedOperationException();
274: }
275:
276: public void setInstanceValue(EntityEnterpriseContext ctx,
277: Object value) {
278: throw new UnsupportedOperationException();
279: }
280:
281: public int loadInstanceResults(ResultSet rs, int parameterIndex,
282: EntityEnterpriseContext ctx) {
283: throw new UnsupportedOperationException();
284: }
285:
286: public int loadArgumentResults(ResultSet rs, int parameterIndex,
287: Object[] argumentRef) {
288: throw new UnsupportedOperationException();
289: }
290:
291: public boolean isDirty(EntityEnterpriseContext ctx) {
292: throw new UnsupportedOperationException();
293: }
294:
295: public void setClean(EntityEnterpriseContext ctx) {
296: throw new UnsupportedOperationException();
297: }
298:
299: public boolean isCMPField() {
300: return true;
301: }
302:
303: public boolean isPrimaryKeyMember() {
304: return isPrimaryKeyMember;
305: }
306:
307: public boolean isReadOnly() {
308: throw new UnsupportedOperationException();
309: }
310:
311: public boolean isReadTimedOut(EntityEnterpriseContext ctx) {
312: throw new UnsupportedOperationException();
313: }
314:
315: public boolean isLoaded(EntityEnterpriseContext ctx) {
316: throw new UnsupportedOperationException();
317: }
318:
319: public JDBCType getJDBCType() {
320: return jdbcType;
321: }
322:
323: public Object getPrimaryKeyValue(Object primaryKey)
324: throws IllegalArgumentException {
325: try {
326: if (pkField != null) {
327: if (primaryKey == null) {
328: return null;
329: }
330:
331: return pkField.get(primaryKey);
332: } else {
333: return primaryKey;
334: }
335: } catch (Exception e) {
336: throw new EJBException(
337: "Internal error getting primary key field member "
338: + getFieldName(), e);
339: }
340: }
341:
342: // CMPFieldBridge implementation
343:
344: public String getFieldName() {
345: return fieldName;
346: }
347:
348: public Object getValue(EntityEnterpriseContext ctx) {
349: PersistentContext pctx = (PersistentContext) ctx
350: .getPersistenceContext();
351: return pctx.getFieldValue(rowIndex);
352: }
353:
354: public void setValue(EntityEnterpriseContext ctx, Object value) {
355: setValueInternal(ctx, value, true);
356: }
357:
358: public Class getFieldType() {
359: return fieldType;
360: }
361: }
|