Source code: org/objectstyle/cayenne/wocompat/EOModelHelper.java
1 /* ====================================================================
2 *
3 * The ObjectStyle Group Software License, Version 1.0
4 *
5 * Copyright (c) 2002-2003 The ObjectStyle Group
6 * and individual authors of the software. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution, if
21 * any, must include the following acknowlegement:
22 * "This product includes software developed by the
23 * ObjectStyle Group (http://objectstyle.org/)."
24 * Alternately, this acknowlegement may appear in the software itself,
25 * if and wherever such third-party acknowlegements normally appear.
26 *
27 * 4. The names "ObjectStyle Group" and "Cayenne"
28 * must not be used to endorse or promote products derived
29 * from this software without prior written permission. For written
30 * permission, please contact andrus@objectstyle.org.
31 *
32 * 5. Products derived from this software may not be called "ObjectStyle"
33 * nor may "ObjectStyle" appear in their names without prior written
34 * permission of the ObjectStyle Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the ObjectStyle Group. For more
52 * information on the ObjectStyle Group, please see
53 * <http://objectstyle.org/>.
54 *
55 */
56 package org.objectstyle.cayenne.wocompat;
57
58 import java.io.InputStream;
59 import java.net.URL;
60 import java.util.Collections;
61 import java.util.HashMap;
62 import java.util.Iterator;
63 import java.util.List;
64 import java.util.Map;
65
66 import org.objectstyle.cayenne.map.DataMap;
67 import org.objectstyle.cayenne.util.ResourceLocator;
68 import org.objectstyle.cayenne.wocompat.parser.Parser;
69
70 /**
71 * Helper class used by EOModelProcessor. During creation, it loads
72 * EOModel from the specified location and parses EOModel files storing them
73 * internally as maps. EOModelProcessor will use this information to create
74 * DataMap instance.
75 */
76 public class EOModelHelper {
77 private static final ResourceLocator locator = new ResourceLocator();
78
79 private Parser plistParser = new Parser();
80 protected URL modelUrl;
81 protected Map entityIndex;
82 protected Map entityClassIndex;
83 protected DataMap dataMap;
84 private Map prototypeValues;
85
86 static {
87 // configure locator
88 locator.setSkipClasspath(false);
89 locator.setSkipCurrentDirectory(false);
90 locator.setSkipHomeDirectory(true);
91 locator.setSkipAbsolutePath(false);
92 }
93
94 /**
95 * Creates helper instance and tries to locate
96 * EOModel and load index file.
97 */
98 public EOModelHelper(String path) throws Exception {
99 // configure URL
100 modelUrl = findModelUrl(path);
101
102 // configure name
103 dataMap = new DataMap(findModelName(path));
104
105 // load index file
106 List modelIndex = (List) loadModelIndex().get("entities");
107
108 // load entity indices
109 entityIndex = new HashMap();
110 entityClassIndex = new HashMap();
111
112 Iterator it = modelIndex.iterator();
113 while (it.hasNext()) {
114 Map info = (Map) it.next();
115 String name = (String) info.get("name");
116 entityIndex.put(name, loadEntityIndex(name));
117 entityClassIndex.put(name, info.get("className"));
118 }
119 }
120
121 /** Performs Objective C data types conversion to Java types.
122 *
123 * @return String representation for Java type corresponding
124 * to String representation of Objective C type.
125 */
126 public String javaTypeForEOModelerType(String type) {
127 if (type == null) {
128 return null;
129 }
130
131 if (type.equals("NSString"))
132 return "java.lang.String";
133 if (type.equals("NSNumber"))
134 return "java.lang.Integer";
135 if (type.equals("NSCalendarDate"))
136 return "java.sql.Date";
137 if (type.equals("NSDecimalNumber"))
138 return "java.math.BigDecimal";
139 if (type.equals("NSData"))
140 return "byte[]";
141
142 // don't know what the class is mapped to...
143 // do some minimum sanity check and use as is
144 try {
145 return Class.forName(type).getName();
146 }
147 catch (ClassNotFoundException aClassNotFoundException) {
148 try {
149 return Class.forName("java.lang." + type).getName();
150 }
151 catch (ClassNotFoundException anotherClassNotFoundException) {
152 try {
153 return Class.forName("java.util." + type).getName();
154 }
155 catch (ClassNotFoundException yetAnotherClassNotFoundException) {
156 try {
157 return ClassLoader
158 .getSystemClassLoader()
159 .loadClass(type)
160 .getName();
161 }
162 catch (ClassNotFoundException e) {
163 throw new IllegalArgumentException("Unknown data type: " + type);
164 }
165 }
166 }
167 }
168 }
169
170 /** Returns a DataMap associated with this helper. */
171 public DataMap getDataMap() {
172 return dataMap;
173 }
174
175 /** Returns EOModel location as URL. */
176 public URL getModelUrl() {
177 return modelUrl;
178 }
179
180 /** Returns an iterator of model names. */
181 public Iterator modelNames() {
182 return entityClassIndex.keySet().iterator();
183 }
184
185 public Map getPrototypeAttributeMapFor(String aPrototypeAttributeName) {
186 if (prototypeValues == null) {
187
188 Map eoPrototypesEntityMap = this.entityInfo("EOPrototypes");
189
190 // no prototypes
191 if (eoPrototypesEntityMap == null) {
192 prototypeValues = Collections.EMPTY_MAP;
193 }
194 else {
195 List eoPrototypeAttributes =
196 (List) eoPrototypesEntityMap.get("attributes");
197
198 prototypeValues = new HashMap();
199 Iterator it = eoPrototypeAttributes.iterator();
200 while (it.hasNext()) {
201 Map attrMap = (Map) it.next();
202
203 String attrName = (String) attrMap.get("name");
204
205 Map prototypeAttrMap = new HashMap();
206 prototypeValues.put(attrName, prototypeAttrMap);
207
208 prototypeAttrMap.put("name", attrMap.get("name"));
209 prototypeAttrMap.put("prototypeName", attrMap.get("prototypeName"));
210 prototypeAttrMap.put("columnName", attrMap.get("columnName"));
211 prototypeAttrMap.put("valueClassName", attrMap.get("valueClassName"));
212 prototypeAttrMap.put("width", attrMap.get("width"));
213 prototypeAttrMap.put("allowsNull", attrMap.get("allowsNull"));
214 prototypeAttrMap.put("scale", attrMap.get("scale"));
215 }
216 }
217 }
218
219 Map aMap = (Map) prototypeValues.get(aPrototypeAttributeName);
220 if (null == aMap)
221 aMap = Collections.EMPTY_MAP;
222
223 return aMap;
224 }
225
226 /** Returns an info map for the entity called <code>entityName</code>. */
227 public Map entityInfo(String entityName) {
228 return (Map) entityIndex.get(entityName);
229 }
230
231 /** Returns an info map for the entity called <code>entityName</code>. */
232 public String entityClass(String entityName) {
233 return (String) entityClassIndex.get(entityName);
234 }
235
236 /** Loads EOModel index and returns it as a map. */
237 protected Map loadModelIndex() throws Exception {
238 InputStream indexIn = openIndexStream();
239 try {
240 plistParser.ReInit(indexIn);
241 return (Map) plistParser.propertyList();
242 }
243 finally {
244 indexIn.close();
245 }
246 }
247
248 /** Loads EOEntity information and returns it as a map. */
249 protected Map loadEntityIndex(String entityName) throws Exception {
250 InputStream entIn = openEntityStream(entityName);
251 try {
252 plistParser.ReInit(entIn);
253 return (Map) plistParser.propertyList();
254 }
255 finally {
256 entIn.close();
257 }
258 }
259
260 /** Returns EOModel name based on its path. */
261 protected String findModelName(String path) {
262 // strip trailing slashes
263 if (path.endsWith("/") || path.endsWith("\\")) {
264 path = path.substring(0, path.length() - 1);
265 }
266
267 // strip path components
268 int i1 = path.lastIndexOf("/");
269 int i2 = path.lastIndexOf("\\");
270 int i = (i1 > i2) ? i1 : i2;
271 if (i >= 0) {
272 path = path.substring(i + 1);
273 }
274
275 // strip .eomodeld suffix
276 if (path.endsWith(".eomodeld")) {
277 path = path.substring(0, path.length() - ".eomodeld".length());
278 }
279
280 return path;
281 }
282
283 /** Returns a URL of the EOModel directory. Throws exception if it
284 * can't be found. */
285 protected URL findModelUrl(String path) {
286 if (!path.endsWith(".eomodeld")) {
287 path += ".eomodeld";
288 }
289
290 URL base = locator.findDirectoryResource(path);
291 if (base == null) {
292 throw new IllegalArgumentException("Can't find EOModel: " + path);
293 }
294 return base;
295 }
296
297 /**
298 * Returns InputStream to read an EOModel index file.
299 */
300 protected InputStream openIndexStream() throws Exception {
301 return new URL(modelUrl, "index.eomodeld").openStream();
302 }
303
304 /** Returns InputStream to read an EOEntity plist file.
305 *
306 * @param entityName name of EOEntity to be loaded.
307 *
308 * @return InputStream to read an EOEntity plist file or null if
309 * <code>entityname.plist</code> file can not be located.
310 */
311 protected InputStream openEntityStream(String entityName) throws Exception {
312 return new URL(modelUrl, entityName + ".plist").openStream();
313 }
314 }