KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > indirection > UnitOfWorkValueHolder


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.indirection;
23
24 import java.util.*;
25 import java.rmi.server.ObjID JavaDoc;
26 import oracle.toplink.essentials.exceptions.ValidationException;
27 import oracle.toplink.essentials.indirection.*;
28 import oracle.toplink.essentials.mappings.*;
29 import oracle.toplink.essentials.logging.SessionLog;
30 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
31 import oracle.toplink.essentials.descriptors.ClassDescriptor;
32
33 /**
34  * A UnitOfWorkValueHolder is put in a clone object.
35  * It wraps the value holder in the original object to delay
36  * cloning the attribute in a unit of work until it is
37  * needed by the application.
38  * This value holder is used only in the unit of work.
39  *
40  * @author Sati
41  */

42 public abstract class UnitOfWorkValueHolder extends DatabaseValueHolder {
43
44     /** The value holder in the original object. */
45     protected transient ValueHolderInterface wrappedValueHolder;
46
47     /** The mapping for the attribute. */
48     protected transient DatabaseMapping mapping;
49
50     /** The value holder stored in the backup copy, should not be transient. */
51     protected ValueHolder backupValueHolder;
52
53     /** These cannot be transient because they are required for a remote unit of work.
54     When the remote uow is serialized to the server to be committed, these
55     are used to reconstruct the value holder on the server.
56     They should be null for non-remote sessions. */

57     protected UnitOfWorkImpl remoteUnitOfWork;
58     protected Object JavaDoc sourceObject;
59
60     /** This attribute is used specifically for relationship support. It mimicks the
61      * sourceObject attribute which is used for RemoteValueholder
62      */

63     protected transient Object JavaDoc relationshipSourceObject;
64     protected String JavaDoc sourceAttributeName;
65     protected ObjID JavaDoc wrappedValueHolderRemoteID;
66
67     protected UnitOfWorkValueHolder(ValueHolderInterface attributeValue, Object JavaDoc clone, DatabaseMapping mapping, UnitOfWorkImpl unitOfWork) {
68         this.wrappedValueHolder = attributeValue;
69         this.mapping = mapping;
70         this.session = unitOfWork;
71         this.sourceAttributeName = mapping.getAttributeName();
72         this.relationshipSourceObject = clone;
73     }
74
75     /**
76      * Backup the clone attribute value.
77      */

78     protected abstract Object JavaDoc buildBackupCloneFor(Object JavaDoc cloneAttributeValue);
79
80     /**
81      * Clone the original attribute value.
82      */

83     public abstract Object JavaDoc buildCloneFor(Object JavaDoc originalAttributeValue);
84
85     protected ValueHolder getBackupValueHolder() {
86         return backupValueHolder;
87     }
88
89     protected DatabaseMapping getMapping() {
90         return mapping;
91     }
92
93     protected UnitOfWorkImpl getRemoteUnitOfWork() {
94         return remoteUnitOfWork;
95     }
96
97     protected String JavaDoc getSourceAttributeName() {
98         return sourceAttributeName;
99     }
100
101     protected Object JavaDoc getSourceObject() {
102         return sourceObject;
103     }
104
105     protected Object JavaDoc getRelationshipSourceObject() {
106         return this.relationshipSourceObject;
107     }
108
109     protected UnitOfWorkImpl getUnitOfWork() {
110         return (UnitOfWorkImpl)getSession();
111     }
112
113     /**
114      * This is used for a remote unit of work.
115      * If the value holder is sent back to the server uninstantiated and
116      * it needs to be instantiated, then we must find the original
117      * object and get the appropriate attribute from it.
118      */

119     protected Object JavaDoc getValueFromServerObject() {
120         setSession(getRemoteUnitOfWork());
121         Vector primaryKey = getSession().keyFromObject(getSourceObject());
122         Object JavaDoc originalObject = getUnitOfWork().getParent().getIdentityMapAccessor().getFromIdentityMap(primaryKey, getSourceObject().getClass());
123         if (originalObject == null) {
124             originalObject = getUnitOfWork().getParent().readObject(getSourceObject());
125         }
126         ClassDescriptor descriptor = getSession().getDescriptor(originalObject);
127         DatabaseMapping mapping = descriptor.getObjectBuilder().getMappingForAttributeName(getSourceAttributeName());
128         setMapping(mapping);
129         return getMapping().getRealAttributeValueFromObject(originalObject, getSession());
130     }
131
132     /**
133      * a.k.a getValueFromWrappedValueholder.
134      * The old name is no longer correct, as query based valueholders are now
135      * sometimes triggered directly without triggering the underlying valueholder.
136      */

137     protected Object JavaDoc instantiateImpl() {
138         if (getWrappedValueHolder() instanceof DatabaseValueHolder) {
139             // Bug 3835202 - Ensure access to valueholders is thread safe. Several of the methods
140
// called below are not threadsafe alone.
141
synchronized(getWrappedValueHolder()){
142                 DatabaseValueHolder wrapped = (DatabaseValueHolder)getWrappedValueHolder();
143                 UnitOfWorkImpl unitOfWork = getUnitOfWork();
144                 if (!wrapped.isEasilyInstantiated()) {
145                     if (wrapped.isPessimisticLockingValueHolder()) {
146                         if (!unitOfWork.getCommitManager().isActive() && !unitOfWork.wasTransactionBegunPrematurely()) {
147                             unitOfWork.beginEarlyTransaction();
148                         }
149                         unitOfWork.log(SessionLog.FINEST, SessionLog.TRANSACTION, "instantiate_pl_relationship");
150                     }
151                     if (unitOfWork.getCommitManager().isActive() || unitOfWork.wasTransactionBegunPrematurely()) {
152                         // At this point the wrapped valueholder is not triggered,
153
// and we are in transaction. So just trigger the
154
// UnitOfWork valueholder on the UnitOfWork only.
155
return wrapped.instantiateForUnitOfWorkValueHolder(this);
156                     }
157                 }
158             }
159         }
160         Object JavaDoc originalAttributeValue = getWrappedValueHolder().getValue();
161         return buildCloneFor(originalAttributeValue);
162     }
163
164     /**
165      * INTERNAL:
166      * Answers if this valueholder is easy to instantiate.
167      * @return true if getValue() won't trigger a database read.
168      */

169     public boolean isEasilyInstantiated() {
170         return isInstantiated() || ((getWrappedValueHolder() != null) && (getWrappedValueHolder() instanceof DatabaseValueHolder) && ((DatabaseValueHolder)getWrappedValueHolder()).isEasilyInstantiated());
171     }
172
173     /**
174      * INTERNAL:
175      * Answers if this valueholder is a pessimistic locking one. Such valueholders
176      * are special in that they can be triggered multiple times by different
177      * UnitsOfWork. Each time a lock query will be issued. Hence even if
178      * instantiated it may have to be instantiated again, and once instantatiated
179      * all fields can not be reset.
180      */

181     public boolean isPessimisticLockingValueHolder() {
182         // This abstract method needs to be implemented but is not meaningfull for
183
// this subclass.
184
return ((getWrappedValueHolder() != null) && (getWrappedValueHolder() instanceof DatabaseValueHolder) && ((DatabaseValueHolder)getWrappedValueHolder()).isPessimisticLockingValueHolder());
185     }
186
187     public ValueHolderInterface getWrappedValueHolder() {
188         return wrappedValueHolder;
189     }
190
191     /**
192      * returns wrapped ValueHolder ObjID if available
193      */

194     public ObjID JavaDoc getWrappedValueHolderRemoteID() {
195         return this.wrappedValueHolderRemoteID;
196     }
197
198     /**
199      * Used to determine if this is a remote uow value holder that was serialized to the server.
200      * It has no reference to its wrapper value holder, so must find its original object to be able to instantiate.
201      */

202     public boolean isSerializedRemoteUnitOfWorkValueHolder() {
203         return (getRemoteUnitOfWork() != null) && (getRemoteUnitOfWork().getParent() != null) && (getWrappedValueHolder() == null);
204     }
205     
206     /**
207      * Get the value from the wrapped value holder, instantiating it
208      * if necessary, and clone it.
209      */

210     protected Object JavaDoc instantiate() {
211         UnitOfWorkImpl unitOfWork;
212         if (isSerializedRemoteUnitOfWorkValueHolder()) {
213             unitOfWork = getRemoteUnitOfWork();
214         } else {
215             unitOfWork = getUnitOfWork();
216         }
217         if (unitOfWork == null){
218             throw ValidationException.instantiatingValueholderWithNullSession();
219         }
220         if (unitOfWork.isAfterWriteChangesButBeforeCommit()) {
221             throw ValidationException.illegalOperationForUnitOfWorkLifecycle(unitOfWork.getLifecycle(), "ValueHolder.instantiate()");
222         }
223
224         Object JavaDoc originalAttributeValue;
225         Object JavaDoc cloneAttributeValue;
226
227         // the wrapped value holder is transient, so it will be null for a remote UOW
228
if (isSerializedRemoteUnitOfWorkValueHolder()) {
229             originalAttributeValue = getValueFromServerObject();
230             cloneAttributeValue = buildCloneFor(originalAttributeValue);
231         } else {
232             cloneAttributeValue = instantiateImpl();
233         }
234
235         // Set the value in the backup clone also.
236
// In some cases we may want to force instantiation before the backup is built
237
if (getBackupValueHolder() != null) {
238             getBackupValueHolder().setValue(buildBackupCloneFor(cloneAttributeValue));
239         }
240         return cloneAttributeValue;
241     }
242
243     /**
244      * Triggers UnitOfWork valueholders directly without triggering the wrapped
245      * valueholder (this).
246      * <p>
247      * When in transaction and/or for pessimistic locking the UnitOfWorkValueHolder
248      * needs to be triggered directly without triggering the wrapped valueholder.
249      * However only the wrapped valueholder knows how to trigger the indirection,
250      * i.e. it may be a batchValueHolder, and it stores all the info like the row
251      * and the query.
252      */

253     public Object JavaDoc instantiateForUnitOfWorkValueHolder(UnitOfWorkValueHolder unitOfWorkValueHolder) {
254         // This abstract method needs to be implemented but is not meaningfull for
255
// this subclass.
256
return instantiate();
257     }
258
259     /**
260      * Releases a wrapped valueholder privately owned by a particular unit of work.
261      * <p>
262      * When unit of work clones are built directly from rows no object in the shared
263      * cache points to this valueholder, so it can store the unit of work as its
264      * session. However once that UnitOfWork commits and the valueholder is merged
265      * into the shared cache, the session needs to be reset to the root session, ie.
266      * the server session.
267      */

268     public void releaseWrappedValueHolder() {
269         // On UnitOfWork dont want to do anything.
270
return;
271     }
272
273     /**
274      * Reset all the fields that are not needed after instantiation.
275      */

276     protected void resetFields() {
277         //do nothing. nothing should be reset to null;
278
}
279
280     public void setBackupValueHolder(ValueHolder backupValueHolder) {
281         this.backupValueHolder = backupValueHolder;
282     }
283
284     protected void setMapping(DatabaseMapping mapping) {
285         this.mapping = mapping;
286     }
287
288     protected void setRemoteUnitOfWork(UnitOfWorkImpl remoteUnitOfWork) {
289         this.remoteUnitOfWork = remoteUnitOfWork;
290     }
291
292     protected void setSourceAttributeName(String JavaDoc name) {
293         sourceAttributeName = name;
294     }
295
296     protected void setSourceObject(Object JavaDoc sourceObject) {
297         this.sourceObject = sourceObject;
298     }
299
300     protected void setRelationshipSourceObject(Object JavaDoc relationshipSourceObject) {
301         this.relationshipSourceObject = relationshipSourceObject;
302     }
303
304     protected void setWrappedValueHolder(DatabaseValueHolder valueHolder) {
305         wrappedValueHolder = valueHolder;
306     }
307 }
308
Popular Tags