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.jdbc.bridge;
023:
024: import java.lang.reflect.Field;
025:
026: import javax.ejb.EJBException;
027:
028: import org.jboss.deployment.DeploymentException;
029: import org.jboss.ejb.EntityEnterpriseContext;
030:
031: import org.jboss.ejb.plugins.cmp.jdbc.JDBCContext;
032: import org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager;
033: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData;
034:
035: /**
036: * JDBCCMP1xFieldBridge is a concrete implementation of JDBCCMPFieldBridge for
037: * CMP version 1.x. Getting and setting of instance fields set the
038: * corresponding field in bean instance. Dirty checking is performed by
039: * storing the current value in the entity persistence context when ever
040: * setClean is called, and comparing current value to the original value.
041: *
042: * Life-cycle:
043: * Tied to the EntityBridge.
044: *
045: * Multiplicity:
046: * One for each entity bean cmp field.
047: *
048: * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
049: * @author <a href="mailto:alex@jboss.org">Alex Loubyansky</a>
050: * @version $Revision: 57209 $
051: */
052: public class JDBCCMP1xFieldBridge extends JDBCAbstractCMPFieldBridge {
053: private Field field;
054:
055: public JDBCCMP1xFieldBridge(JDBCStoreManager manager,
056: JDBCCMPFieldMetaData metadata) throws DeploymentException {
057: super (manager, metadata);
058:
059: try {
060: field = manager.getMetaData().getEntityClass().getField(
061: getFieldName());
062: } catch (NoSuchFieldException e) {
063: // Non recoverable internal exception
064: throw new DeploymentException("No field named '"
065: + getFieldName() + "' found in entity class.");
066: }
067: }
068:
069: public Object getInstanceValue(EntityEnterpriseContext ctx) {
070: FieldState fieldState = getFieldState(ctx);
071: if (!fieldState.isLoaded()) {
072: throw new EJBException("CMP 1.1 field not loaded: "
073: + getFieldName());
074: }
075:
076: try {
077: return field.get(ctx.getInstance());
078: } catch (Exception e) {
079: // Non recoverable internal exception
080: throw new EJBException(
081: "Internal error getting instance field "
082: + getFieldName(), e);
083: }
084: }
085:
086: public void setInstanceValue(EntityEnterpriseContext ctx,
087: Object value) {
088: try {
089: field.set(ctx.getInstance(), value);
090: FieldState fieldState = getFieldState(ctx);
091: fieldState.setLoaded();
092: fieldState.setCheckDirty();
093: } catch (Exception e) {
094: // Non recoverable internal exception
095: throw new EJBException(
096: "Internal error setting instance field "
097: + getFieldName(), e);
098: }
099: }
100:
101: public Object getLockedValue(EntityEnterpriseContext ctx) {
102: throw new UnsupportedOperationException(
103: "Optimistic locking is not supported in CMP1.1.");
104: }
105:
106: public void lockInstanceValue(EntityEnterpriseContext ctx) {
107: // not supported
108: }
109:
110: public boolean isLoaded(EntityEnterpriseContext ctx) {
111: return getFieldState(ctx).isLoaded();
112: }
113:
114: /**
115: * Has the value of this field changes since the last time clean was called.
116: */
117: public boolean isDirty(EntityEnterpriseContext ctx) {
118: // read only and primary key fields are never dirty
119: if (isReadOnly() || isPrimaryKeyMember()) {
120: return false;
121: }
122:
123: // has the value changes since setClean
124: return isLoaded(ctx)
125: && !stateFactory.isStateValid(getInstanceValue(ctx),
126: getFieldState(ctx).originalValue);
127: }
128:
129: /**
130: * Mark this field as clean.
131: * Saves the current state in context, so it can be compared when
132: * isDirty is called.
133: */
134: public void setClean(EntityEnterpriseContext ctx) {
135: FieldState fieldState = getFieldState(ctx);
136: fieldState.originalValue = getInstanceValue(ctx);
137:
138: // update last read time
139: if (isReadOnly()) {
140: fieldState.lastRead = System.currentTimeMillis();
141: }
142: }
143:
144: public boolean isReadTimedOut(EntityEnterpriseContext ctx) {
145: // if we are read/write then we are always timed out
146: if (!isReadOnly()) {
147: return true;
148: }
149:
150: // if read-time-out is -1 then we never time out.
151: if (getReadTimeOut() == -1) {
152: return false;
153: }
154:
155: long readInterval = System.currentTimeMillis()
156: - getFieldState(ctx).lastRead;
157: return readInterval >= getReadTimeOut();
158: }
159:
160: public void resetPersistenceContext(EntityEnterpriseContext ctx) {
161: if (isReadTimedOut(ctx)) {
162: JDBCContext jdbcCtx = (JDBCContext) ctx
163: .getPersistenceContext();
164: FieldState fieldState = (FieldState) jdbcCtx
165: .getFieldState(jdbcContextIndex);
166: if (fieldState != null)
167: fieldState.reset();
168: }
169: }
170:
171: protected void setDirtyAfterGet(EntityEnterpriseContext ctx) {
172: getFieldState(ctx).setCheckDirty();
173: }
174:
175: private FieldState getFieldState(EntityEnterpriseContext ctx) {
176: JDBCContext jdbcCtx = (JDBCContext) ctx.getPersistenceContext();
177: FieldState fieldState = (FieldState) jdbcCtx
178: .getFieldState(jdbcContextIndex);
179: if (fieldState == null) {
180: fieldState = new FieldState(jdbcCtx);
181: jdbcCtx.setFieldState(jdbcContextIndex, fieldState);
182: }
183: return fieldState;
184: }
185:
186: private class FieldState {
187: private Object originalValue;
188: private long lastRead = -1;
189: private JDBCEntityBridge.EntityState entityState;
190:
191: public FieldState(JDBCContext jdbcContext) {
192: this .entityState = jdbcContext.getEntityState();
193: }
194:
195: public boolean isLoaded() {
196: return entityState.isLoaded(tableIndex);
197: }
198:
199: public void setLoaded() {
200: entityState.setLoaded(tableIndex);
201: }
202:
203: public void setCheckDirty() {
204: entityState.setCheckDirty(tableIndex);
205: }
206:
207: public void reset() {
208: originalValue = null;
209: lastRead = -1;
210: entityState.resetFlags(tableIndex);
211: log.debug("reset field state");
212: }
213: }
214: }
|