KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > wocompat > EOModelHelper


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
57 package org.objectstyle.cayenne.wocompat;
58
59 import java.io.IOException JavaDoc;
60 import java.io.InputStream JavaDoc;
61 import java.math.BigDecimal JavaDoc;
62 import java.net.URL JavaDoc;
63 import java.util.ArrayList JavaDoc;
64 import java.util.Collections JavaDoc;
65 import java.util.HashMap JavaDoc;
66 import java.util.Iterator JavaDoc;
67 import java.util.List JavaDoc;
68 import java.util.Map JavaDoc;
69
70 import org.apache.commons.collections.IteratorUtils;
71 import org.objectstyle.cayenne.map.DataMap;
72 import org.objectstyle.cayenne.util.ResourceLocator;
73 import org.objectstyle.cayenne.wocompat.parser.Parser;
74
75 /**
76  * Helper class used by EOModelProcessor. EOModelHelper loads an EOModel from the
77  * specified location and gives its users access to the untyped EOModel information.
78  */

79 public class EOModelHelper {
80
81     private static final ResourceLocator locator = new ResourceLocator();
82
83     private Parser plistParser = new Parser();
84     protected URL JavaDoc modelUrl;
85     protected Map JavaDoc entityIndex;
86     protected Map JavaDoc entityClassIndex;
87     protected Map JavaDoc entityQueryIndex;
88     protected Map JavaDoc entityClientClassIndex;
89     protected DataMap dataMap;
90     private Map JavaDoc prototypeValues;
91
92     static {
93         // configure locator
94
locator.setSkipClasspath(false);
95         locator.setSkipCurrentDirectory(false);
96         locator.setSkipHomeDirectory(true);
97         locator.setSkipAbsolutePath(false);
98     }
99
100     /**
101      * Creates helper instance and tries to locate EOModel and load index file.
102      */

103     public EOModelHelper(String JavaDoc path) throws Exception JavaDoc {
104
105         this.modelUrl = findModelUrl(path);
106         this.dataMap = new DataMap(findModelName(path));
107
108         // load index file
109
List JavaDoc modelIndex = (List JavaDoc) loadModelIndex().get("entities");
110
111         // load entity indices
112
entityIndex = new HashMap JavaDoc();
113         entityClassIndex = new HashMap JavaDoc();
114         entityClientClassIndex = new HashMap JavaDoc();
115         entityQueryIndex = new HashMap JavaDoc();
116
117         Iterator JavaDoc it = modelIndex.iterator();
118         while (it.hasNext()) {
119             Map JavaDoc info = (Map JavaDoc) it.next();
120             String JavaDoc name = (String JavaDoc) info.get("name");
121
122             entityIndex.put(name, loadEntityIndex(name));
123             entityQueryIndex.put(name, loadQueryIndex(name));
124             entityClassIndex.put(name, info.get("className"));
125             Map JavaDoc entityPlistMap = entityPListMap(name);
126
127             // get client class information
128
Map JavaDoc internalInfo = (Map JavaDoc) entityPlistMap.get("internalInfo");
129
130             if (internalInfo != null) {
131                 String JavaDoc clientClassName = (String JavaDoc) internalInfo
132                         .get("_javaClientClassName");
133                 entityClientClassIndex.put(name, clientClassName);
134             }
135         }
136
137         it = modelIndex.iterator();
138         while (it.hasNext()) {
139             Map JavaDoc info = (Map JavaDoc) it.next();
140             String JavaDoc name = (String JavaDoc) info.get("name");
141             Map JavaDoc entityPlistMap = entityPListMap(name);
142             List JavaDoc classProperties = (List JavaDoc) entityPlistMap.get("classProperties");
143             if(classProperties == null) {
144                 classProperties = Collections.EMPTY_LIST;
145             }
146
147             // get client class information
148
Map JavaDoc internalInfo = (Map JavaDoc) entityPlistMap.get("internalInfo");
149
150             List JavaDoc clientClassProperties = (internalInfo != null) ? (List JavaDoc) internalInfo
151                     .get("_clientClassPropertyNames") : null;
152
153             // guard against no internal info and no client class properties
154
if (clientClassProperties == null) {
155                 clientClassProperties = Collections.EMPTY_LIST;
156             }
157
158             // there is a bug in EOModeler it sometimes keeps outdated properties in
159
// the client property list. This removes them
160
clientClassProperties.retainAll(classProperties);
161
162             // remove all properties from the entity properties that are already defined
163
// in
164
// a potential parent class.
165
String JavaDoc parentEntity = (String JavaDoc) entityPlistMap.get("parent");
166             while (parentEntity != null) {
167                 Map JavaDoc parentEntityPListMap = entityPListMap(parentEntity);
168                 List JavaDoc parentClassProps = (List JavaDoc) parentEntityPListMap
169                         .get("classProperties");
170                 classProperties.removeAll(parentClassProps);
171                 // get client class information of parent
172
Map JavaDoc parentInternalInfo = (Map JavaDoc) parentEntityPListMap.get("internalInfo");
173
174                 if (parentInternalInfo != null) {
175                     List JavaDoc parentClientClassProps = (List JavaDoc) parentInternalInfo
176                             .get("_clientClassPropertyNames");
177                     clientClassProperties.removeAll(parentClientClassProps);
178                 }
179
180                 parentEntity = (String JavaDoc) parentEntityPListMap.get("parent");
181             }
182
183             // put back processed properties to the map
184
entityPlistMap.put("classProperties", classProperties);
185             // add client classes directly for easier access
186
entityPlistMap.put("clientClassProperties", clientClassProperties);
187         }
188     }
189
190     /**
191      * Performs Objective C data types conversion to Java types.
192      *
193      * @since 1.1
194      * @return String representation for Java type corresponding to String representation
195      * of Objective C type.
196      */

197     public String JavaDoc javaTypeForEOModelerType(String JavaDoc valueClassName, String JavaDoc valueType) {
198         if (valueClassName == null) {
199             return null;
200         }
201
202         if (valueClassName.equals("NSString")) {
203             return String JavaDoc.class.getName();
204         }
205
206         if (valueClassName.equals("NSNumber")) {
207             Class JavaDoc numericClass = numericAttributeClass(valueType);
208             return (numericClass != null) ? numericClass.getName() : Number JavaDoc.class
209                     .getName();
210         }
211
212         if (valueClassName.equals("NSCalendarDate"))
213             return "java.sql.Timestamp";
214
215         if (valueClassName.equals("NSDecimalNumber")) {
216             Class JavaDoc numericClass = numericAttributeClass(valueType);
217             return (numericClass != null) ? numericClass.getName() : BigDecimal JavaDoc.class
218                     .getName();
219         }
220
221         if (valueClassName.equals("NSData"))
222             return "byte[]";
223
224         // don't know what the class is mapped to...
225
// do some minimum sanity check and use as is
226
try {
227             return Class.forName(valueClassName).getName();
228         }
229         catch (ClassNotFoundException JavaDoc aClassNotFoundException) {
230             try {
231                 return Class.forName("java.lang." + valueClassName).getName();
232             }
233             catch (ClassNotFoundException JavaDoc anotherClassNotFoundException) {
234                 try {
235                     return Class.forName("java.util." + valueClassName).getName();
236                 }
237                 catch (ClassNotFoundException JavaDoc yetAnotherClassNotFoundException) {
238                     try {
239                         return ClassLoader.getSystemClassLoader().loadClass(
240                                 valueClassName).getName();
241                     }
242                     catch (ClassNotFoundException JavaDoc e) {
243                         // likely a custom class
244
return valueClassName;
245                     }
246                 }
247             }
248         }
249     }
250
251     /**
252      * @since 1.1
253      */

254     // TODO: create a lookup map, maybe XML-loaded...
255
protected Class JavaDoc numericAttributeClass(String JavaDoc valueType) {
256         if (valueType == null) {
257             return null;
258         } else if ("b".equals(valueType)) {
259             return Byte JavaDoc.class;
260         } else if ("s".equals(valueType)) {
261             return Short JavaDoc.class;
262         } else if ("i".equals(valueType)) {
263             return Integer JavaDoc.class;
264         } else if ("l".equals(valueType)) {
265             return Long JavaDoc.class;
266         } else if ("f".equals(valueType)) {
267             return Float JavaDoc.class;
268         } else if ("d".equals(valueType)) {
269             return Double JavaDoc.class;
270         } else if ("B".equals(valueType)) {
271             return BigDecimal JavaDoc.class;
272         } else if ("c".equals(valueType)) {
273             return Boolean JavaDoc.class;
274         } else {
275             return null;
276         }
277     }
278
279     /** Returns a DataMap associated with this helper. */
280     public DataMap getDataMap() {
281         return dataMap;
282     }
283
284     /** Returns EOModel location as URL. */
285     public URL JavaDoc getModelUrl() {
286         return modelUrl;
287     }
288
289     /**
290      * Returns an iterator of model names.
291      */

292     public Iterator JavaDoc modelNames() {
293         return entityClassIndex.keySet().iterator();
294     }
295     
296     /**
297      * Returns a list of model entity names.
298      *
299      * @since 1.1
300      */

301     public List JavaDoc modelNamesAsList() {
302         return new ArrayList JavaDoc(entityClassIndex.keySet());
303     }
304
305     public Map JavaDoc getPrototypeAttributeMapFor(String JavaDoc aPrototypeAttributeName) {
306         if (prototypeValues == null) {
307
308             Map JavaDoc eoPrototypesEntityMap = this.entityPListMap("EOPrototypes");
309
310             // no prototypes
311
if (eoPrototypesEntityMap == null) {
312                 prototypeValues = Collections.EMPTY_MAP;
313             } else {
314                 List JavaDoc eoPrototypeAttributes = (List JavaDoc) eoPrototypesEntityMap
315                         .get("attributes");
316
317                 prototypeValues = new HashMap JavaDoc();
318                 Iterator JavaDoc it = eoPrototypeAttributes.iterator();
319                 while (it.hasNext()) {
320                     Map JavaDoc attrMap = (Map JavaDoc) it.next();
321
322                     String JavaDoc attrName = (String JavaDoc) attrMap.get("name");
323
324                     // TODO: why are we copying the original map? can we just use it as is?
325
Map JavaDoc prototypeAttrMap = new HashMap JavaDoc();
326                     prototypeValues.put(attrName, prototypeAttrMap);
327
328                     prototypeAttrMap.put("name", attrMap.get("name"));
329                     prototypeAttrMap.put("prototypeName", attrMap.get("prototypeName"));
330                     prototypeAttrMap.put("columnName", attrMap.get("columnName"));
331                     prototypeAttrMap.put("valueClassName", attrMap.get("valueClassName"));
332                     prototypeAttrMap.put("width", attrMap.get("width"));
333                     prototypeAttrMap.put("allowsNull", attrMap.get("allowsNull"));
334                     prototypeAttrMap.put("scale", attrMap.get("scale"));
335                     prototypeAttrMap.put("valueType", attrMap.get("valueType"));
336                 }
337             }
338         }
339
340         Map JavaDoc aMap = (Map JavaDoc) prototypeValues.get(aPrototypeAttributeName);
341         if (null == aMap)
342             aMap = Collections.EMPTY_MAP;
343
344         return aMap;
345     }
346
347     /** Returns an info map for the entity called <code>entityName</code>. */
348     public Map JavaDoc entityPListMap(String JavaDoc entityName) {
349         return (Map JavaDoc) entityIndex.get(entityName);
350     }
351
352     /**
353      * Returns the iterator over EOFetchSpecification names for a given entity.
354      *
355      * @since 1.1
356      */

357     public Iterator JavaDoc queryNames(String JavaDoc entityName) {
358         Map JavaDoc queryPlist = (Map JavaDoc) entityQueryIndex.get(entityName);
359         if (queryPlist == null || queryPlist.isEmpty()) {
360             return IteratorUtils.EMPTY_ITERATOR;
361         }
362
363         return queryPlist.keySet().iterator();
364     }
365
366     /**
367      * Returns a map containing EOFetchSpecification information for entity name and query
368      * name. Returns null if no such query is found.
369      *
370      * @since 1.1
371      */

372     public Map JavaDoc queryPListMap(String JavaDoc entityName, String JavaDoc queryName) {
373         Map JavaDoc queryPlist = (Map JavaDoc) entityQueryIndex.get(entityName);
374         if (queryPlist == null || queryPlist.isEmpty()) {
375             return null;
376         }
377
378         return (Map JavaDoc) queryPlist.get(queryName);
379     }
380
381     public String JavaDoc entityClass(String JavaDoc entityName, boolean getClientClass) {
382         if (getClientClass) {
383             return (String JavaDoc) entityClientClassIndex.get(entityName);
384         } else {
385             return (String JavaDoc) entityClassIndex.get(entityName);
386         }
387     }
388
389     /** Loads EOModel index and returns it as a map. */
390     protected Map JavaDoc loadModelIndex() throws Exception JavaDoc {
391         InputStream JavaDoc indexIn = openIndexStream();
392         try {
393             plistParser.ReInit(indexIn);
394             return (Map JavaDoc) plistParser.propertyList();
395         }
396         finally {
397             indexIn.close();
398         }
399     }
400
401     /**
402      * Loads EOEntity information and returns it as a map.
403      */

404     protected Map JavaDoc loadEntityIndex(String JavaDoc entityName) throws Exception JavaDoc {
405         InputStream JavaDoc entIn = openEntityStream(entityName);
406         try {
407             plistParser.ReInit(entIn);
408             return (Map JavaDoc) plistParser.propertyList();
409         }
410         finally {
411             entIn.close();
412         }
413     }
414
415     /**
416      * Loads EOFetchSpecification information and returns it as a map.
417      */

418     protected Map JavaDoc loadQueryIndex(String JavaDoc entityName) throws Exception JavaDoc {
419         InputStream JavaDoc queryIn = null;
420
421         // catch file open exceptions since not all entities have query files....
422
try {
423             queryIn = openQueryStream(entityName);
424         }
425         catch (IOException JavaDoc ioex) {
426             return Collections.EMPTY_MAP;
427         }
428
429         try {
430             plistParser.ReInit(queryIn);
431             return (Map JavaDoc) plistParser.propertyList();
432         }
433         finally {
434             queryIn.close();
435         }
436     }
437
438     /** Returns EOModel name based on its path. */
439     protected String JavaDoc findModelName(String JavaDoc path) {
440         // strip trailing slashes
441
if (path.endsWith("/") || path.endsWith("\\")) {
442             path = path.substring(0, path.length() - 1);
443         }
444
445         // strip path components
446
int i1 = path.lastIndexOf("/");
447         int i2 = path.lastIndexOf("\\");
448         int i = (i1 > i2) ? i1 : i2;
449         if (i >= 0) {
450             path = path.substring(i + 1);
451         }
452
453         // strip .eomodeld suffix
454
if (path.endsWith(".eomodeld")) {
455             path = path.substring(0, path.length() - ".eomodeld".length());
456         }
457
458         return path;
459     }
460
461     /**
462      * Returns a URL of the EOModel directory. Throws exception if it can't be found.
463      */

464     protected URL JavaDoc findModelUrl(String JavaDoc path) {
465         if (!path.endsWith(".eomodeld")) {
466             path += ".eomodeld";
467         }
468
469         URL JavaDoc base = locator.findDirectoryResource(path);
470         if (base == null) {
471             throw new IllegalArgumentException JavaDoc("Can't find EOModel: " + path);
472         }
473         return base;
474     }
475
476     /**
477      * Returns InputStream to read an EOModel index file.
478      */

479     protected InputStream JavaDoc openIndexStream() throws Exception JavaDoc {
480         return new URL JavaDoc(modelUrl, "index.eomodeld").openStream();
481     }
482
483     /**
484      * Returns InputStream to read an EOEntity plist file.
485      *
486      * @param entityName
487      * name of EOEntity to be loaded.
488      * @return InputStream to read an EOEntity plist file or null if
489      * <code>entityname.plist</code> file can not be located.
490      */

491     protected InputStream JavaDoc openEntityStream(String JavaDoc entityName) throws Exception JavaDoc {
492         return new URL JavaDoc(modelUrl, entityName + ".plist").openStream();
493     }
494
495     /**
496      * Returns InputStream to read an EOFetchSpecification plist file.
497      *
498      * @param entityName
499      * name of EOEntity to be loaded.
500      * @return InputStream to read an EOEntity plist file or null if
501      * <code>entityname.plist</code> file can not be located.
502      */

503     protected InputStream JavaDoc openQueryStream(String JavaDoc entityName) throws Exception JavaDoc {
504         return new URL JavaDoc(modelUrl, entityName + ".fspec").openStream();
505     }
506 }
Popular Tags