KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > DataObjectUtils


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56 package org.objectstyle.cayenne;
57
58 import java.util.Collection JavaDoc;
59 import java.util.Collections JavaDoc;
60 import java.util.Iterator JavaDoc;
61 import java.util.List JavaDoc;
62 import java.util.Map JavaDoc;
63
64 import org.objectstyle.cayenne.access.DataContext;
65 import org.objectstyle.cayenne.access.ObjectStore;
66 import org.objectstyle.cayenne.conf.Configuration;
67 import org.objectstyle.cayenne.map.DbAttribute;
68 import org.objectstyle.cayenne.map.DbEntity;
69 import org.objectstyle.cayenne.map.EntityInheritanceTree;
70 import org.objectstyle.cayenne.map.ObjEntity;
71
72 /**
73  * A collection of utility methods to work with DataObjects.
74  * <p>
75  * <i>DataObjects and Primary Keys: All methods that allow to extract primary key values
76  * or use primary keys to find objects are provided for convenience. Still the author's
77  * belief is that integer sequential primary keys are meaningless in the object model and
78  * are pure database artifacts. Therefore relying heavily on direct access to PK provided
79  * via this class (or other such Cayenne API) is not a clean design practice in many
80  * cases, and sometimes may actually lead to security issues. </i>
81  * </p>
82  *
83  * @since 1.1
84  * @author Andrei Adamchik
85  */

86 public final class DataObjectUtils {
87
88     /**
89      * Returns an int primary key value for a DataObject. Only works for single column
90      * numeric primary keys. If a DataObjects is transient or has an ObjectId that can not
91      * be converted to an int PK, an exception is thrown.
92      */

93     public static int intPKForObject(DataObject dataObject) {
94         Object JavaDoc value = pkForObject(dataObject);
95
96         if (!(value instanceof Number JavaDoc)) {
97             throw new CayenneRuntimeException("PK is not a number: "
98                     + dataObject.getObjectId());
99         }
100
101         return ((Number JavaDoc) value).intValue();
102     }
103
104     /**
105      * Returns a primary key value for a DataObject. Only works for single column primary
106      * keys. If a DataObjects is transient or has a compound ObjectId, an exception is
107      * thrown.
108      */

109     public static Object JavaDoc pkForObject(DataObject dataObject) {
110         Map JavaDoc pk = extractObjectId(dataObject);
111
112         if (pk.size() != 1) {
113             throw new CayenneRuntimeException("Expected single column PK, got "
114                     + pk.size()
115                     + " columns, ID: "
116                     + pk);
117         }
118
119         Map.Entry JavaDoc pkEntry = (Map.Entry JavaDoc) pk.entrySet().iterator().next();
120         return pkEntry.getValue();
121     }
122
123     /**
124      * Returns a primary key map for a DataObject. This method is the most generic out of
125      * all methods for primary key retrieval. It will work for all possible types of
126      * primary keys. If a DataObjects is transient, an exception is thrown.
127      */

128     public static Map JavaDoc compoundPKForObject(DataObject dataObject) {
129         return Collections.unmodifiableMap(extractObjectId(dataObject));
130     }
131
132     static Map JavaDoc extractObjectId(DataObject dataObject) {
133         if (dataObject == null) {
134             throw new IllegalArgumentException JavaDoc("Null DataObject");
135         }
136
137         ObjectId id = dataObject.getObjectId();
138         if (!id.isTemporary()) {
139             return id.getIdSnapshot();
140         }
141
142         // replacement ID is more tricky... do some sanity check...
143
if (id.isReplacementIdAttached()) {
144             DbEntity entity = dataObject
145                     .getDataContext()
146                     .getEntityResolver()
147                     .lookupDbEntity(dataObject);
148             
149             if(entity != null && entity.isFullReplacementIdAttached(id)) {
150                 return id.getReplacementIdMap();
151             }
152         }
153
154         throw new CayenneRuntimeException("Can't get primary key from temporary id.");
155     }
156
157     /**
158      * Returns an object matching an int primary key. If the object is mapped to use
159      * non-integer PK or a compound PK, CayenneRuntimeException is thrown.
160      * <p>
161      * If this object is already cached in the ObjectStore, it is returned without a
162      * query. Otherwise a query is built and executed against the database.
163      * </p>
164      *
165      * @see #objectForPK(DataContext, ObjectId)
166      */

167     public static DataObject objectForPK(
168             DataContext context,
169             Class JavaDoc dataObjectClass,
170             int pk) {
171         return objectForPK(context, buildId(context, dataObjectClass, new Integer JavaDoc(pk)));
172     }
173
174     /**
175      * Returns an object matching an Object primary key. If the object is mapped to use a
176      * compound PK, CayenneRuntimeException is thrown.
177      * <p>
178      * If this object is already cached in the ObjectStore, it is returned without a
179      * query. Otherwise a query is built and executed against the database.
180      * </p>
181      *
182      * @see #objectForPK(DataContext, ObjectId)
183      */

184     public static DataObject objectForPK(
185             DataContext context,
186             Class JavaDoc dataObjectClass,
187             Object JavaDoc pk) {
188
189         return objectForPK(context, buildId(context, dataObjectClass, pk));
190     }
191
192     /**
193      * Returns an object matching a primary key. PK map parameter should use database PK
194      * column names as keys.
195      * <p>
196      * If this object is already cached in the ObjectStore, it is returned without a
197      * query. Otherwise a query is built and executed against the database.
198      * </p>
199      *
200      * @see #objectForPK(DataContext, ObjectId)
201      */

202     public static DataObject objectForPK(
203             DataContext context,
204             Class JavaDoc dataObjectClass,
205             Map JavaDoc pk) {
206         return objectForPK(context, new ObjectId(dataObjectClass, pk));
207     }
208
209     /**
210      * Returns an object matching an int primary key. If the object is mapped to use
211      * non-integer PK or a compound PK, CayenneRuntimeException is thrown.
212      * <p>
213      * If this object is already cached in the ObjectStore, it is returned without a
214      * query. Otherwise a query is built and executed against the database.
215      * </p>
216      *
217      * @see #objectForPK(DataContext, ObjectId)
218      */

219     public static DataObject objectForPK(DataContext context, String JavaDoc objEntityName, int pk) {
220         return objectForPK(context, buildId(context, objEntityName, new Integer JavaDoc(pk)));
221     }
222
223     /**
224      * Returns an object matching an Object primary key. If the object is mapped to use a
225      * compound PK, CayenneRuntimeException is thrown.
226      * <p>
227      * If this object is already cached in the ObjectStore, it is returned without a
228      * query. Otherwise a query is built and executed against the database.
229      * </p>
230      *
231      * @see #objectForPK(DataContext, ObjectId)
232      */

233     public static DataObject objectForPK(
234             DataContext context,
235             String JavaDoc objEntityName,
236             Object JavaDoc pk) {
237         return objectForPK(context, buildId(context, objEntityName, pk));
238     }
239
240     /**
241      * Returns an object matching a primary key. PK map parameter should use database PK
242      * column names as keys.
243      * <p>
244      * If this object is already cached in the ObjectStore, it is returned without a
245      * query. Otherwise a query is built and executed against the database.
246      * </p>
247      *
248      * @see #objectForPK(DataContext, ObjectId)
249      */

250     public static DataObject objectForPK(DataContext context, String JavaDoc objEntityName, Map JavaDoc pk) {
251         if (objEntityName == null) {
252             throw new IllegalArgumentException JavaDoc("Null ObjEntity name.");
253         }
254
255         ObjEntity entity = context.getEntityResolver().getObjEntity(objEntityName);
256         if (entity == null) {
257             throw new CayenneRuntimeException("Non-existent ObjEntity: " + objEntityName);
258         }
259
260         Class JavaDoc dataObjectClass = entity.getJavaClass(Configuration.getResourceLoader());
261
262         return objectForPK(context, new ObjectId(dataObjectClass, pk));
263     }
264
265     /**
266      * Returns an object matching ObjectId. If this object is already cached in the
267      * ObjectStore, it is returned without a query. Otherwise a query is built and
268      * executed against the database.
269      *
270      * @return A DataObject that matched the id, null if no matching objects were found
271      * @throws CayenneRuntimeException if more than one object matched ObjectId.
272      */

273     public static DataObject objectForPK(DataContext context, ObjectId id) {
274         ObjectStore objectStore = context.getObjectStore();
275
276         // look for cached object first
277
DataObject object = objectStore.getObject(id);
278         if (object != null) {
279             return object;
280         }
281
282         // CAY-218: check for inheritance... ObjectId maybe wrong
283
// TODO: investigate moving this to the ObjectStore "getObject()" - this should
284
// really be global...
285

286         ObjEntity entity = context.getEntityResolver().lookupObjEntity(
287                 id.getObjectClass());
288         EntityInheritanceTree inheritanceHandler = context
289                 .getEntityResolver()
290                 .lookupInheritanceTree(entity);
291         if (inheritanceHandler != null) {
292             Collection JavaDoc children = inheritanceHandler.getChildren();
293             if (!children.isEmpty()) {
294                 // find cached child
295
Iterator JavaDoc it = children.iterator();
296                 while (it.hasNext()) {
297                     EntityInheritanceTree child = (EntityInheritanceTree) it.next();
298                     ObjectId childID = new ObjectId(child.getEntity().getJavaClass(
299                             Configuration.getResourceLoader()), id.getIdSnapshot());
300
301                     DataObject childObject = objectStore.getObject(childID);
302                     if (childObject != null) {
303                         return childObject;
304                     }
305                 }
306             }
307         }
308
309         // look in shared cache...
310

311         // TODO: take inheritance into account...
312
DataRow row = objectStore.getSnapshot(id, context);
313
314         return (row != null)
315                 ? context.objectFromDataRow(id.getObjectClass(), row, false)
316                 : null;
317     }
318
319     static ObjectId buildId(DataContext context, String JavaDoc objEntityName, Object JavaDoc pk) {
320         if (pk == null) {
321             throw new IllegalArgumentException JavaDoc("Null PK");
322         }
323
324         if (objEntityName == null) {
325             throw new IllegalArgumentException JavaDoc("Null ObjEntity name.");
326         }
327
328         ObjEntity entity = context.getEntityResolver().getObjEntity(objEntityName);
329         if (entity == null) {
330             throw new CayenneRuntimeException("Non-existent ObjEntity: " + objEntityName);
331         }
332
333         DbEntity dbEntity = entity.getDbEntity();
334         if (dbEntity == null) {
335             throw new CayenneRuntimeException("No DbEntity for ObjEntity: "
336                     + entity.getName());
337         }
338
339         List JavaDoc pkAttributes = dbEntity.getPrimaryKey();
340         if (pkAttributes.size() != 1) {
341             throw new CayenneRuntimeException("PK contains "
342                     + pkAttributes.size()
343                     + " columns, expected 1.");
344         }
345
346         DbAttribute attr = (DbAttribute) pkAttributes.get(0);
347         return new ObjectId(entity.getJavaClass(Configuration.getResourceLoader()), attr
348                 .getName(), pk);
349     }
350
351     static ObjectId buildId(DataContext context, Class JavaDoc dataObjectClass, Object JavaDoc pk) {
352         if (pk == null) {
353             throw new IllegalArgumentException JavaDoc("Null PK");
354         }
355
356         if (dataObjectClass == null) {
357             throw new IllegalArgumentException JavaDoc("Null DataObject class.");
358         }
359
360         ObjEntity entity = context.getEntityResolver().lookupObjEntity(dataObjectClass);
361         if (entity == null) {
362             throw new CayenneRuntimeException("Unmapped DataObject Class: "
363                     + dataObjectClass.getName());
364         }
365
366         DbEntity dbEntity = entity.getDbEntity();
367         if (dbEntity == null) {
368             throw new CayenneRuntimeException("No DbEntity for ObjEntity: "
369                     + entity.getName());
370         }
371
372         List JavaDoc pkAttributes = dbEntity.getPrimaryKey();
373         if (pkAttributes.size() != 1) {
374             throw new CayenneRuntimeException("PK contains "
375                     + pkAttributes.size()
376                     + " columns, expected 1.");
377         }
378
379         DbAttribute attr = (DbAttribute) pkAttributes.get(0);
380         return new ObjectId(dataObjectClass, attr.getName(), pk);
381     }
382
383     // not intended for instantiation
384
private DataObjectUtils() {
385     }
386 }
Popular Tags