Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/objectstyle/cayenne/wocompat/EOModelProcessor.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.util.Collection;
59  import java.util.Collections;
60  import java.util.Iterator;
61  import java.util.List;
62  import java.util.Map;
63  
64  import org.objectstyle.cayenne.CayenneRuntimeException;
65  import org.objectstyle.cayenne.dba.TypesMapping;
66  import org.objectstyle.cayenne.exp.Expression;
67  import org.objectstyle.cayenne.exp.ExpressionFactory;
68  import org.objectstyle.cayenne.map.DataMap;
69  import org.objectstyle.cayenne.map.DbAttribute;
70  import org.objectstyle.cayenne.map.DbAttributePair;
71  import org.objectstyle.cayenne.map.DbEntity;
72  import org.objectstyle.cayenne.map.DbRelationship;
73  import org.objectstyle.cayenne.map.ObjAttribute;
74  import org.objectstyle.cayenne.map.ObjEntity;
75  import org.objectstyle.cayenne.map.ObjRelationship;
76  
77  /**
78   *  Class that converts EOModels to org.objectstyle.cayenne.map.DataMap objects.
79   */
80  public class EOModelProcessor {
81  
82      /** Performs EOModel loading.  
83       * 
84       *  @param path A path to ".eomodeld" directory. 
85       *  If path doesn't end with ".eomodeld", ".eomodeld"
86       *  suffix is automatically assumed. */
87      public DataMap loadEOModel(String path) throws Exception {
88          EOModelHelper helper = makeHelper(path);
89  
90          // create empty map
91          DataMap dataMap = helper.getDataMap();
92  
93          // process enitities
94          Iterator it = helper.modelNames();
95          while (it.hasNext()) {
96              String name = (String) it.next();
97  
98              // create and register entity
99              ObjEntity e = makeEntity(helper, name);
100 
101             // process entity attributes
102             makeAttributes(helper, e);
103         }
104 
105         // after all entities are loaded, 
106         // process relationships
107         it = helper.modelNames();
108         while (it.hasNext()) {
109             String name = (String) it.next();
110             makeRelationships(helper, dataMap.getObjEntity(name));
111         }
112 
113         // after all normal relationships are loaded, 
114         // process falttened relationships
115         it = helper.modelNames();
116         while (it.hasNext()) {
117             String name = (String) it.next();
118             makeFlatRelationships(helper, dataMap.getObjEntity(name));
119         }
120 
121         return dataMap;
122     }
123 
124     /** 
125      * Creates an returns new EOModelHelper to process EOModel.
126      * Exists mostly for the benefit of subclasses. 
127      */
128     protected EOModelHelper makeHelper(String path) throws Exception {
129         return new EOModelHelper(path);
130     }
131 
132     /** 
133      *  Creates and returns a new ObjEntity linked to a corresponding DbEntity.
134      */
135     protected ObjEntity makeEntity(EOModelHelper helper, String name) {
136         DataMap dataMap = helper.getDataMap();
137 
138         // create ObjEntity
139         ObjEntity e = new ObjEntity(name);
140         e.setClassName(helper.entityClass(name));
141 
142         // create DbEntity...since EOF allows the same table to be 
143         // associated with multiple EOEntities, check for name duplicates
144         String dbEntityName = (String) helper.entityInfo(name).get("externalName");
145 
146         if (dbEntityName != null) {
147             int i = 0;
148             String dbEntityBaseName = dbEntityName;
149             while (dataMap.getDbEntity(dbEntityName, false) != null) {
150                 dbEntityName = dbEntityBaseName + i++;
151             }
152 
153             DbEntity de = new DbEntity(dbEntityName);
154             dataMap.addDbEntity(de);
155             e.setDbEntity(de);
156         }
157 
158         dataMap.addObjEntity(e);
159 
160         return e;
161     }
162 
163     /** 
164      *  Create ObjAttributes of the specified entity, as well as 
165      *  DbAttributes of the corresponding DbEntity.
166      */
167     protected void makeAttributes(EOModelHelper helper, ObjEntity e) {
168         Map entityMap = helper.entityInfo(e.getName());
169         List pks = (List) entityMap.get("primaryKeyAttributes");
170         List classProps = (List) entityMap.get("classProperties");
171         List attributes = (List) entityMap.get("attributes");
172         DbEntity dbEntity = e.getDbEntity();
173 
174     String isReadOnlyString = (String) entityMap.get("isReadOnly");
175     e.setReadOnly("Y".equals(isReadOnlyString));
176     
177         if (pks == null) {
178             pks = Collections.EMPTY_LIST;
179         }
180 
181         if (classProps == null) {
182             classProps = Collections.EMPTY_LIST;
183         }
184 
185         if (attributes == null) {
186             attributes = Collections.EMPTY_LIST;
187         }
188 
189         // process attribute list creating both Db and Obj attributes
190 
191         if (attributes == null) {
192             return;
193         }
194 
195         Iterator it = attributes.iterator();
196         while (it.hasNext()) {
197             Map attrMap = (Map) it.next();
198             
199       String prototypeName = (String) attrMap.get("prototypeName");
200       Map prototypeAttrMap = helper.getPrototypeAttributeMapFor(prototypeName);
201       
202       String dbAttrName = (String) attrMap.get("columnName");
203       if (null == dbAttrName)  dbAttrName = (String) prototypeAttrMap.get("columnName");;
204       
205             String attrName = (String) attrMap.get("name");
206       if (null == attrName)  attrName = (String) prototypeAttrMap.get("name");;
207       
208             String attrType = (String) attrMap.get("valueClassName");
209       if (null == attrType)  attrType = (String) prototypeAttrMap.get("valueClassName");;
210       
211             String javaType = helper.javaTypeForEOModelerType(attrType);
212             EODbAttribute dbAttr = null;
213 
214             if (dbAttrName != null && dbEntity != null) {
215 
216                 // create DbAttribute...since EOF allows the same column name for 
217                 // more than one Java attribute, we need to check for name duplicates
218                 int i = 0;
219                 String dbAttributeBaseName = dbAttrName;
220                 while (dbEntity.getAttribute(dbAttrName) != null) {
221                     dbAttrName = dbAttributeBaseName + i++;
222                 }
223 
224                 dbAttr =
225                     new EODbAttribute(
226                         dbAttrName,
227                         TypesMapping.getSqlTypeByJava(javaType),
228                         dbEntity);
229                 dbAttr.setEoAttributeName(attrName);
230                 dbEntity.addAttribute(dbAttr);
231 
232         Integer width = (Integer) attrMap.get("width");
233         if (null == width)  width = (Integer) prototypeAttrMap.get("width");
234         
235         if (width != null)
236           dbAttr.setMaxLength(width.intValue());
237 
238         Integer scale = (Integer) attrMap.get("scale");
239         if (null == scale)  scale = (Integer) prototypeAttrMap.get("scale");
240         
241         if (scale != null)
242           dbAttr.setPrecision(scale.intValue());
243 
244                 if (pks.contains(attrName))
245                     dbAttr.setPrimaryKey(true);
246 
247                 Object allowsNull = attrMap.get("allowsNull");
248         // TODO: Unclear that allowsNull should be inherited from EOPrototypes
249         // if (null == allowsNull)  allowsNull = prototypeAttrMap.get("allowsNull");;
250                  
251                 dbAttr.setMandatory(!"Y".equals(allowsNull));
252             }
253 
254             if (classProps.contains(attrName)) {
255                 ObjAttribute attr = new ObjAttribute(attrName, javaType, e);
256                 attr.setDbAttribute(dbAttr);
257                 e.addAttribute(attr);
258             }
259         }
260     }
261 
262     /** 
263      *  Create ObjRelationships of the specified entity, as well as 
264      *  DbRelationships of the corresponding DbEntity.
265      */
266     protected void makeRelationships(EOModelHelper helper, ObjEntity e) {
267         Map info = helper.entityInfo(e.getName());
268         List classProps = (List) info.get("classProperties");
269         List rinfo = (List) info.get("relationships");
270 
271         if (rinfo == null) {
272             return;
273         }
274 
275         if (classProps == null) {
276             classProps = Collections.EMPTY_LIST;
277         }
278 
279         DbEntity dbSrc = e.getDbEntity();
280         Iterator it = rinfo.iterator();
281         while (it.hasNext()) {
282             Map relMap = (Map) it.next();
283             String targetName = (String) relMap.get("destination");
284 
285             // ignore flattened relationships for now
286             if (targetName == null) {
287                 continue;
288             }
289 
290             String relName = (String) relMap.get("name");
291             boolean toMany = "Y".equals(relMap.get("isToMany"));
292             boolean toDependentPK = "Y".equals(relMap.get("propagatesPrimaryKey"));
293             ObjEntity target = helper.getDataMap().getObjEntity(targetName);
294 
295             if (target == null) {
296                 continue;
297             }
298 
299             DbEntity dbTarget = target.getDbEntity();
300             DbRelationship dbRel = null;
301             // process underlying DbRelationship
302             // Note - there is no flattened rel. support here....
303             if (dbTarget != null) {
304                 dbRel = new DbRelationship();
305                 dbRel.setSourceEntity(dbSrc);
306                 dbRel.setTargetEntity(dbTarget);
307                 dbRel.setToMany(toMany);
308                 dbRel.setName(relName);
309                 dbRel.setToDependentPK(toDependentPK);
310                 dbSrc.addRelationship(dbRel);
311 
312                 List joins = (List) relMap.get("joins");
313                 Iterator jIt = joins.iterator();
314                 while (jIt.hasNext()) {
315                     Map joinMap = (Map) jIt.next();
316                     String srcAttrName = (String) joinMap.get("sourceAttribute");
317                     String targetAttrName = (String) joinMap.get("destinationAttribute");
318 
319                     DbAttribute srcAttr =
320                         EODbAttribute.findForEOAttributeName(dbSrc, srcAttrName);
321                     DbAttribute targetAttr =
322                         EODbAttribute.findForEOAttributeName(dbTarget, targetAttrName);
323 
324                     DbAttributePair join = new DbAttributePair(srcAttr, targetAttr);
325                     dbRel.addJoin(join);
326                 }
327             }
328 
329             // only create obj relationship if it is a class property
330 
331             if (classProps.contains(relName)) {
332                 ObjRelationship rel = new ObjRelationship();
333                 rel.setName(relName);
334                 rel.setSourceEntity(e);
335                 rel.setTargetEntity(target);
336                 e.addRelationship(rel);
337 
338                 if (dbRel != null) {
339                     rel.addDbRelationship(dbRel);
340                 }
341             }
342         }
343     }
344 
345     /** 
346      *  Create Flattened ObjRelationships of the specified entity.
347      */
348     protected void makeFlatRelationships(EOModelHelper helper, ObjEntity e) {
349         Map info = helper.entityInfo(e.getName());
350         List rinfo = (List) info.get("relationships");
351         if (rinfo == null) {
352             return;
353         }
354 
355         Iterator it = rinfo.iterator();
356         while (it.hasNext()) {
357             Map relMap = (Map) it.next();
358             String targetPath = (String) relMap.get("definition");
359 
360             // ignore normal relationships
361             if (targetPath == null) {
362                 continue;
363             }
364 
365             Expression exp = ExpressionFactory.unaryExp(Expression.DB_PATH, targetPath);
366             Iterator path = e.getDbEntity().resolvePathComponents(exp);
367 
368             ObjRelationship flatRel = new ObjRelationship();
369             flatRel.setName((String) relMap.get("name"));
370 
371             DbRelationship firstRel = null;
372             DbRelationship lastRel = null;
373             while (path.hasNext()) {
374                 lastRel = (DbRelationship) path.next();
375                 flatRel.addDbRelationship(lastRel);
376 
377                 if (firstRel == null) {
378                     firstRel = lastRel;
379                 }
380             }
381 
382             if ((firstRel != null) && (lastRel != null)) {
383                 flatRel.setSourceEntity(e);
384 
385                 Collection potentialTargets =
386                     e.getDataMap().getMappedEntities(
387                         (DbEntity) lastRel.getTargetEntity());
388 
389                 // sanity check
390                 if (potentialTargets.size() != 1) {
391                     throw new CayenneRuntimeException(
392                         "One and only one entity should be mapped"
393                             + " to "
394                             + lastRel.getTargetEntity().getName()
395                             + ". Instead found : "
396                             + potentialTargets.size());
397                 }
398 
399                 flatRel.setTargetEntity((ObjEntity) potentialTargets.iterator().next());
400                 e.addRelationship(flatRel);
401             }
402             else {
403                 throw new CayenneRuntimeException("relationship in path was null!");
404             }
405         }
406     }
407 
408     /** 
409      *  Special DbAttribute subclass that stores extra info needed to work
410      *  with EOModels.
411      */
412     static class EODbAttribute extends DbAttribute {
413         protected String eoAttributeName;
414 
415         public static DbAttribute findForEOAttributeName(DbEntity e, String name) {
416             Iterator it = e.getAttributes().iterator();
417             while (it.hasNext()) {
418                 EODbAttribute attr = (EODbAttribute) it.next();
419                 if (name.equals(attr.getEoAttributeName())) {
420                     return attr;
421                 }
422             }
423             return null;
424         }
425 
426         public EODbAttribute() {
427         }
428 
429         public EODbAttribute(String name, int type, DbEntity entity) {
430             super(name, type, entity);
431         }
432 
433         public String getEoAttributeName() {
434             return eoAttributeName;
435         }
436 
437         public void setEoAttributeName(String eoAttributeName) {
438             this.eoAttributeName = eoAttributeName;
439         }
440     }
441 }