001: //$Id: EntityEntry.java 9283 2006-02-14 03:24:18Z steveebersole $
002: package org.hibernate.engine;
003:
004: import java.io.Serializable;
005: import java.io.ObjectOutputStream;
006: import java.io.IOException;
007: import java.io.ObjectInputStream;
008:
009: import org.hibernate.EntityMode;
010: import org.hibernate.HibernateException;
011: import org.hibernate.LockMode;
012: import org.hibernate.intercept.FieldInterceptionHelper;
013: import org.hibernate.persister.entity.EntityPersister;
014: import org.hibernate.persister.entity.UniqueKeyLoadable;
015: import org.hibernate.pretty.MessageHelper;
016:
017: /**
018: * We need an entry to tell us all about the current state
019: * of an object with respect to its persistent state
020: *
021: * @author Gavin King
022: */
023: public final class EntityEntry implements Serializable {
024:
025: private LockMode lockMode;
026: private Status status;
027: private final Serializable id;
028: private Object[] loadedState;
029: private Object[] deletedState;
030: private boolean existsInDatabase;
031: private Object version;
032: private transient EntityPersister persister; // for convenience to save some lookups
033: private final EntityMode entityMode;
034: private final String entityName;
035: private boolean isBeingReplicated;
036: private boolean loadedWithLazyPropertiesUnfetched; //NOTE: this is not updated when properties are fetched lazily!
037: private final transient Object rowId;
038:
039: EntityEntry(final Status status, final Object[] loadedState,
040: final Object rowId, final Serializable id,
041: final Object version, final LockMode lockMode,
042: final boolean existsInDatabase,
043: final EntityPersister persister,
044: final EntityMode entityMode,
045: final boolean disableVersionIncrement,
046: final boolean lazyPropertiesAreUnfetched) {
047: this .status = status;
048: this .loadedState = loadedState;
049: this .id = id;
050: this .rowId = rowId;
051: this .existsInDatabase = existsInDatabase;
052: this .version = version;
053: this .lockMode = lockMode;
054: this .isBeingReplicated = disableVersionIncrement;
055: this .loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
056: this .persister = persister;
057: this .entityMode = entityMode;
058: this .entityName = persister == null ? null : persister
059: .getEntityName();
060: }
061:
062: /**
063: * Used during custom deserialization
064: */
065: private EntityEntry(final SessionFactoryImplementor factory,
066: final String entityName, final Serializable id,
067: final EntityMode entityMode, final Status status,
068: final Object[] loadedState, final Object[] deletedState,
069: final Object version, final LockMode lockMode,
070: final boolean existsInDatabase,
071: final boolean isBeingReplicated,
072: final boolean loadedWithLazyPropertiesUnfetched) {
073: this .entityName = entityName;
074: this .persister = factory.getEntityPersister(entityName);
075: this .id = id;
076: this .entityMode = entityMode;
077: this .status = status;
078: this .loadedState = loadedState;
079: this .deletedState = deletedState;
080: this .version = version;
081: this .lockMode = lockMode;
082: this .existsInDatabase = existsInDatabase;
083: this .isBeingReplicated = isBeingReplicated;
084: this .loadedWithLazyPropertiesUnfetched = loadedWithLazyPropertiesUnfetched;
085: this .rowId = null; // this is equivalent to the old behavior...
086: }
087:
088: public LockMode getLockMode() {
089: return lockMode;
090: }
091:
092: public void setLockMode(LockMode lockMode) {
093: this .lockMode = lockMode;
094: }
095:
096: public Status getStatus() {
097: return status;
098: }
099:
100: public void setStatus(Status status) {
101: if (status == Status.READ_ONLY) {
102: loadedState = null; //memory optimization
103: }
104: this .status = status;
105: }
106:
107: public Serializable getId() {
108: return id;
109: }
110:
111: public Object[] getLoadedState() {
112: return loadedState;
113: }
114:
115: public Object[] getDeletedState() {
116: return deletedState;
117: }
118:
119: public void setDeletedState(Object[] deletedState) {
120: this .deletedState = deletedState;
121: }
122:
123: public boolean isExistsInDatabase() {
124: return existsInDatabase;
125: }
126:
127: public Object getVersion() {
128: return version;
129: }
130:
131: public EntityPersister getPersister() {
132: return persister;
133: }
134:
135: void afterDeserialize(SessionFactoryImplementor factory) {
136: persister = factory.getEntityPersister(entityName);
137: }
138:
139: public String getEntityName() {
140: return entityName;
141: }
142:
143: public boolean isBeingReplicated() {
144: return isBeingReplicated;
145: }
146:
147: public Object getRowId() {
148: return rowId;
149: }
150:
151: /**
152: * After actually updating the database, update the snapshot information,
153: * and escalate the lock mode
154: */
155: public void postUpdate(Object entity, Object[] updatedState,
156: Object nextVersion) {
157: this .loadedState = updatedState;
158:
159: setLockMode(LockMode.WRITE);
160:
161: if (getPersister().isVersioned()) {
162: this .version = nextVersion;
163: getPersister().setPropertyValue(entity,
164: getPersister().getVersionProperty(), nextVersion,
165: entityMode);
166: }
167:
168: FieldInterceptionHelper.clearDirty(entity);
169: }
170:
171: /**
172: * After actually deleting a row, record the fact that the instance no longer
173: * exists in the database
174: */
175: public void postDelete() {
176: status = Status.GONE;
177: existsInDatabase = false;
178: }
179:
180: /**
181: * After actually inserting a row, record the fact that the instance exists on the
182: * database (needed for identity-column key generation)
183: */
184: public void postInsert() {
185: existsInDatabase = true;
186: }
187:
188: public boolean isNullifiable(boolean earlyInsert,
189: SessionImplementor session) {
190: return getStatus() == Status.SAVING
191: || (earlyInsert ? !isExistsInDatabase() : session
192: .getPersistenceContext()
193: .getNullifiableEntityKeys().contains(
194: new EntityKey(getId(), getPersister(),
195: entityMode)));
196: }
197:
198: public Object getLoadedValue(String propertyName) {
199: int propertyIndex = ((UniqueKeyLoadable) persister)
200: .getPropertyIndex(propertyName);
201: return loadedState[propertyIndex];
202: }
203:
204: public boolean requiresDirtyCheck(Object entity) {
205:
206: boolean isMutableInstance = status != Status.READ_ONLY
207: && persister.isMutable();
208:
209: return isMutableInstance
210: && (getPersister().hasMutableProperties()
211: || !FieldInterceptionHelper
212: .isInstrumented(entity) || FieldInterceptionHelper
213: .extractFieldInterceptor(entity).isDirty());
214:
215: }
216:
217: public void forceLocked(Object entity, Object nextVersion) {
218: version = nextVersion;
219: loadedState[persister.getVersionProperty()] = version;
220: setLockMode(LockMode.FORCE);
221: persister.setPropertyValue(entity, getPersister()
222: .getVersionProperty(), nextVersion, entityMode);
223: }
224:
225: public void setReadOnly(boolean readOnly, Object entity) {
226: if (status != Status.MANAGED && status != Status.READ_ONLY) {
227: throw new HibernateException(
228: "instance was not in a valid state");
229: }
230: if (readOnly) {
231: setStatus(Status.READ_ONLY);
232: loadedState = null;
233: } else {
234: setStatus(Status.MANAGED);
235: loadedState = getPersister().getPropertyValues(entity,
236: entityMode);
237: }
238: }
239:
240: public String toString() {
241: return "EntityEntry" + MessageHelper.infoString(entityName, id)
242: + '(' + status + ')';
243: }
244:
245: public boolean isLoadedWithLazyPropertiesUnfetched() {
246: return loadedWithLazyPropertiesUnfetched;
247: }
248:
249: /**
250: * Custom serialization routine used during serialization of a
251: * Session/PersistenceContext for increased performance.
252: *
253: * @param oos The stream to which we should write the serial data.
254: * @throws java.io.IOException
255: */
256: void serialize(ObjectOutputStream oos) throws IOException {
257: oos.writeObject(entityName);
258: oos.writeObject(id);
259: oos.writeObject(entityMode.toString());
260: oos.writeObject(status.toString());
261: // todo : potentially look at optimizing these two arrays
262: oos.writeObject(loadedState);
263: oos.writeObject(deletedState);
264: oos.writeObject(version);
265: oos.writeObject(lockMode.toString());
266: oos.writeBoolean(existsInDatabase);
267: oos.writeBoolean(isBeingReplicated);
268: oos.writeBoolean(loadedWithLazyPropertiesUnfetched);
269: }
270:
271: /**
272: * Custom deserialization routine used during deserialization of a
273: * Session/PersistenceContext for increased performance.
274: *
275: * @param ois The stream from which to read the entry.
276: * @param session The session being deserialized.
277: * @return The deserialized EntityEntry
278: * @throws IOException
279: * @throws ClassNotFoundException
280: */
281: static EntityEntry deserialize(ObjectInputStream ois,
282: SessionImplementor session) throws IOException,
283: ClassNotFoundException {
284: return new EntityEntry(session.getFactory(), (String) ois
285: .readObject(), (Serializable) ois.readObject(),
286: EntityMode.parse((String) ois.readObject()), Status
287: .parse((String) ois.readObject()),
288: (Object[]) ois.readObject(), (Object[]) ois
289: .readObject(), (Object) ois.readObject(),
290: LockMode.parse((String) ois.readObject()), ois
291: .readBoolean(), ois.readBoolean(), ois
292: .readBoolean());
293: }
294: }
|