http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
 
b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
index 95f6d8e..4797b43 100644
--- 
a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
+++ 
b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
@@ -55,722 +55,720 @@ import org.apache.commons.logging.LogFactory;
  */
 public class EOModelProcessor {
 
-    private static final Log logger = 
LogFactory.getLog(EOModelProcessor.class);
-
-    protected Predicate prototypeChecker;
-
-    public EOModelProcessor() {
-        prototypeChecker = new Predicate() {
-
-            public boolean evaluate(Object object) {
-                if (object == null) {
-                    return false;
-                }
-
-                String entityName = object.toString();
-                return entityName.startsWith("EO") && 
entityName.endsWith("Prototypes");
-            }
-        };
-    }
-
-    /**
-     * @deprecated since 4.0 in favor of {@link #loadModeIndex(URL)}.
-     */
-    @Deprecated
-    public Map loadModeIndex(String path) throws Exception {
-        return loadModeIndex(new File(path).toURI().toURL());
-    }
-
-    /**
-     * Returns index.eomodeld contents as a Map.
-     * 
-     * @since 4.0
-     */
-    // TODO: refactor EOModelHelper to provide a similar method without loading
-    // all entity files in memory... here we simply copied stuff from
-    // EOModelHelper
-    public Map loadModeIndex(URL url) throws Exception {
-
-        String urlString = url.toExternalForm();
-
-        if (!urlString.endsWith(".eomodeld")) {
-            url = new URL(urlString + ".eomodeld");
-        }
-
-        Parser plistParser = new Parser();
-        InputStream in = new URL(url, "index.eomodeld").openStream();
-
-        try {
-            plistParser.ReInit(in);
-            return (Map) plistParser.propertyList();
-        } finally {
-            in.close();
-        }
-    }
-
-    /**
-     * @deprecated since 4.0 in favor of {@link #loadEOModel(URL)}.
-     */
-    @Deprecated
-    public DataMap loadEOModel(String path) throws Exception {
-        return loadEOModel(path, false);
-    }
-
-    /**
-     * @deprecated since 4.0 in favor of {@link #loadEOModel(URL, boolean)}.
-     */
-    @Deprecated
-    public DataMap loadEOModel(String path, boolean generateClientClass) 
throws Exception {
-        return loadEOModel(new File(path).toURI().toURL(), 
generateClientClass);
-    }
-
-    /**
-     * Performs EOModel loading.
-     * 
-     * @param url
-     *            URL of ".eomodeld" directory.
-     */
-    public DataMap loadEOModel(URL url) throws Exception {
-        return loadEOModel(url, false);
-    }
-
-    /**
-     * Performs EOModel loading.
-     * 
-     * @param url
-     *            URL of ".eomodeld" directory.
-     * @param generateClientClass
-     *            if true then loading of EOModel is java client classes aware
-     *            and the following processing will work with Java client class
-     *            settings of the EOModel.
-     */
-    public DataMap loadEOModel(URL url, boolean generateClientClass) throws 
Exception {
-        EOModelHelper helper = makeHelper(url);
-
-        // create empty map
-        DataMap dataMap = helper.getDataMap();
-
-        // process enitities ... throw out prototypes ... for now
-        List modelNames = new ArrayList(helper.modelNamesAsList());
-        CollectionUtils.filter(modelNames, 
PredicateUtils.notPredicate(prototypeChecker));
-
-        Iterator it = modelNames.iterator();
-        while (it.hasNext()) {
-            String name = (String) it.next();
-
-            // create and register entity
-            makeEntity(helper, name, generateClientClass);
-        }
-
-        // now sort following inheritance hierarchy
-        Collections.sort(modelNames, new InheritanceComparator(dataMap));
-
-        // after all entities are loaded, process attributes
-        it = modelNames.iterator();
-        while (it.hasNext()) {
-            String name = (String) it.next();
-
-            EOObjEntity e = (EOObjEntity) dataMap.getObjEntity(name);
-            // process entity attributes
-            makeAttributes(helper, e);
-        }
-
-        // after all entities are loaded, process relationships
-        it = modelNames.iterator();
-        while (it.hasNext()) {
-            String name = (String) it.next();
-            makeRelationships(helper, dataMap.getObjEntity(name));
-        }
-
-        // after all normal relationships are loaded, process flattened
-        // relationships
-        it = modelNames.iterator();
-        while (it.hasNext()) {
-            String name = (String) it.next();
-            makeFlatRelationships(helper, dataMap.getObjEntity(name));
-        }
-
-        // now create missing reverse DB (but not OBJ) relationships
-        // since Cayenne requires them
-        it = modelNames.iterator();
-        while (it.hasNext()) {
-            String name = (String) it.next();
-            DbEntity dbEntity = dataMap.getObjEntity(name).getDbEntity();
-
-            if (dbEntity != null) {
-                makeReverseDbRelationships(dbEntity);
-            }
-        }
-
-        // build SelectQueries out of EOFetchSpecifications...
-        it = modelNames.iterator();
-        while (it.hasNext()) {
-            String name = (String) it.next();
-            Iterator queries = helper.queryNames(name);
-            while (queries.hasNext()) {
-                String queryName = (String) queries.next();
-                EOObjEntity entity = (EOObjEntity) dataMap.getObjEntity(name);
-                makeQuery(helper, entity, queryName);
-            }
-        }
-
-        return dataMap;
-    }
-
-    /**
-     * Returns whether an Entity is an EOF EOPrototypes entity. According to 
EOF
-     * conventions EOPrototypes and EO[Adapter]Prototypes entities are
-     * considered to be prototypes.
-     * 
-     * @since 1.1
-     */
-    protected boolean isPrototypesEntity(String entityName) {
-        return prototypeChecker.evaluate(entityName);
-    }
-
-    /**
-     * Creates an returns new EOModelHelper to process EOModel. Exists mostly
-     * for the benefit of subclasses.
-     */
-    protected EOModelHelper makeHelper(URL url) throws Exception {
-        return new EOModelHelper(url);
-    }
-
-    /**
-     * Creates a Cayenne query out of EOFetchSpecification data.
-     * 
-     * @since 1.1
-     */
-    protected Query makeQuery(EOModelHelper helper, EOObjEntity entity, String 
queryName) {
-
-        DataMap dataMap = helper.getDataMap();
-        Map queryPlist = helper.queryPListMap(entity.getName(), queryName);
-        if (queryPlist == null) {
-            return null;
-        }
-
-        AbstractQuery query;
-        if (queryPlist.containsKey("hints")) { // just a predefined SQL query
-            query = new EOSQLQuery(entity, queryPlist);
-        } else {
-            query = new EOQuery(entity, queryPlist);
-        }
-        query.setName(entity.qualifiedQueryName(queryName));
-        dataMap.addQuery(query);
-
-        return query;
-    }
-
-    /**
-     * Creates and returns a new ObjEntity linked to a corresponding DbEntity.
-     */
-    protected EOObjEntity makeEntity(EOModelHelper helper, String name, 
boolean generateClientClass) {
-
-        DataMap dataMap = helper.getDataMap();
-        Map entityPlist = helper.entityPListMap(name);
-
-        // create ObjEntity
-        EOObjEntity objEntity = new EOObjEntity(name);
-        objEntity.setEoMap(entityPlist);
-        objEntity.setServerOnly(!generateClientClass);
-        String parent = (String) entityPlist.get("parent");
-        objEntity.setClassName(helper.entityClass(name, generateClientClass));
-
-        if (parent != null) {
-            objEntity.setSubclass(true);
-            objEntity.setSuperClassName(helper.entityClass(parent, 
generateClientClass));
-        }
-
-        // add flag whether this entity is set as abstract in the model
-        
objEntity.setAbstractEntity("Y".equals(entityPlist.get("isAbstractEntity")));
-
-        // create DbEntity...since EOF allows the same table to be
-        // associated with multiple EOEntities, check for name duplicates
-        String dbEntityName = (String) entityPlist.get("externalName");
-        if (dbEntityName != null) {
-
-            // ... if inheritance is involved and parent hierarchy uses the 
same
-            // DBEntity,
-            // do not create a DbEntity...
-            boolean createDbEntity = true;
-            if (parent != null) {
-                String parentName = parent;
-                while (parentName != null) {
-                    Map parentData = helper.entityPListMap(parentName);
-                    if (parentData == null) {
-                        break;
-                    }
-
-                    String parentExternalName = (String) 
parentData.get("externalName");
-                    if (parentExternalName == null) {
-                        parentName = (String) parentData.get("parent");
-                        continue;
-                    }
-
-                    if (dbEntityName.equals(parentExternalName)) {
-                        createDbEntity = false;
-                    }
-
-                    break;
-                }
-            }
-
-            if (createDbEntity) {
-                int i = 0;
-                String dbEntityBaseName = dbEntityName;
-                while (dataMap.getDbEntity(dbEntityName) != null) {
-                    dbEntityName = dbEntityBaseName + i++;
-                }
-
-                objEntity.setDbEntityName(dbEntityName);
-                DbEntity de = new DbEntity(dbEntityName);
-                dataMap.addDbEntity(de);
-            }
-        }
-
-        // set various flags
-        objEntity.setReadOnly("Y".equals(entityPlist.get("isReadOnly")));
-        objEntity.setSuperEntityName((String) entityPlist.get("parent"));
-
-        dataMap.addObjEntity(objEntity);
-
-        return objEntity;
-    }
-
-    /**
-     * Create ObjAttributes of the specified entity, as well as DbAttributes of
-     * the corresponding DbEntity.
-     */
-    protected void makeAttributes(EOModelHelper helper, EOObjEntity objEntity) 
{
-        Map entityPlistMap = helper.entityPListMap(objEntity.getName());
-        List primaryKeys = (List) entityPlistMap.get("primaryKeyAttributes");
-
-        List classProperties;
-        if (objEntity.isServerOnly()) {
-            classProperties = (List) entityPlistMap.get("classProperties");
-        } else {
-            classProperties = (List) 
entityPlistMap.get("clientClassProperties");
-        }
-
-        List attributes = (List) entityPlistMap.get("attributes");
-        DbEntity dbEntity = objEntity.getDbEntity();
-
-        if (primaryKeys == null) {
-            primaryKeys = Collections.EMPTY_LIST;
-        }
-
-        if (classProperties == null) {
-            classProperties = Collections.EMPTY_LIST;
-        }
-
-        if (attributes == null) {
-            attributes = Collections.EMPTY_LIST;
-        }
-
-        // detect single table inheritance
-        boolean singleTableInheritance = false;
-        String parentName = (String) entityPlistMap.get("parent");
-        while (parentName != null) {
-            Map parentData = helper.entityPListMap(parentName);
-            if (parentData == null) {
-                break;
-            }
-
-            String parentExternalName = (String) 
parentData.get("externalName");
-            if (parentExternalName == null) {
-                parentName = (String) parentData.get("parent");
-                continue;
-            }
-
-            if (dbEntity.getName() != null && 
dbEntity.getName().equals(parentExternalName)) {
-                singleTableInheritance = true;
-            }
-
-            break;
-        }
-
-        Iterator it = attributes.iterator();
-        while (it.hasNext()) {
-            Map attrMap = (Map) it.next();
-
-            String prototypeName = (String) attrMap.get("prototypeName");
-            Map prototypeAttrMap = 
helper.getPrototypeAttributeMapFor(prototypeName);
-
-            String dbAttrName = (String) attrMap.get("columnName");
-            if (null == dbAttrName) {
-                dbAttrName = (String) prototypeAttrMap.get("columnName");
-            }
-
-            String attrName = (String) attrMap.get("name");
-            if (null == attrName) {
-                attrName = (String) prototypeAttrMap.get("name");
-            }
-
-            String attrType = (String) attrMap.get("valueClassName");
-            if (null == attrType) {
-                attrType = (String) prototypeAttrMap.get("valueClassName");
-            }
-
-            String valueType = (String) attrMap.get("valueType");
-            if (valueType == null) {
-                valueType = (String) prototypeAttrMap.get("valueType");
-            }
-
-            String javaType = helper.javaTypeForEOModelerType(attrType, 
valueType);
-            EODbAttribute dbAttr = null;
-
-            if (dbAttrName != null && dbEntity != null) {
-
-                // if inherited attribute, skip it for DbEntity...
-                if (!singleTableInheritance || 
dbEntity.getAttribute(dbAttrName) == null) {
-
-                    // create DbAttribute...since EOF allows the same column
-                    // name for
-                    // more than one Java attribute, we need to check for name
-                    // duplicates
-                    int i = 0;
-                    String dbAttributeBaseName = dbAttrName;
-                    while (dbEntity.getAttribute(dbAttrName) != null) {
-                        dbAttrName = dbAttributeBaseName + i++;
-                    }
-
-                    dbAttr = new EODbAttribute(dbAttrName, 
TypesMapping.getSqlTypeByJava(javaType), dbEntity);
-                    dbAttr.setEoAttributeName(attrName);
-                    dbEntity.addAttribute(dbAttr);
-
-                    int width = getInt("width", attrMap, prototypeAttrMap, -1);
-                    if (width >= 0) {
-                        dbAttr.setMaxLength(width);
-                    }
-
-                    int scale = getInt("scale", attrMap, prototypeAttrMap, -1);
-                    if (scale >= 0) {
-                        dbAttr.setScale(scale);
-                    }
-
-                    if (primaryKeys.contains(attrName))
-                        dbAttr.setPrimaryKey(true);
-
-                    Object allowsNull = attrMap.get("allowsNull");
-                    // TODO: Unclear that allowsNull should be inherited from
-                    // EOPrototypes
-                    // if (null == allowsNull) allowsNull =
-                    // prototypeAttrMap.get("allowsNull");;
-
-                    dbAttr.setMandatory(!"Y".equals(allowsNull));
-                }
-            }
-
-            if (classProperties.contains(attrName)) {
-                EOObjAttribute attr = new EOObjAttribute(attrName, javaType, 
objEntity);
-
-                // set readOnly flag of Attribute if either attribute is read 
or
-                // if entity is readOnly
-                String entityReadOnlyString = (String) 
entityPlistMap.get("isReadOnly");
-                String attributeReadOnlyString = (String) 
attrMap.get("isReadOnly");
-                if ("Y".equals(entityReadOnlyString) || 
"Y".equals(attributeReadOnlyString)) {
-                    attr.setReadOnly(true);
-                }
-
-                // set name instead of the actual attribute, as it may be
-                // inherited....
-                attr.setDbAttributePath(dbAttrName);
-                objEntity.addAttribute(attr);
-            }
-        }
-    }
-
-    int getInt(String key, Map map, Map prototypes, int defaultValue) {
-
-        Object value = map.get(key);
-        if (value == null) {
-            value = prototypes.get(key);
-        }
-
-        if (value == null) {
-            return defaultValue;
-        }
-
-        // per CAY-752, value can be a String or a Number, so handle both
-        if (value instanceof Number) {
-            return ((Number) value).intValue();
-        } else {
-            try {
-                return Integer.parseInt(value.toString());
-            } catch (NumberFormatException nfex) {
-                return defaultValue;
-            }
-        }
-    }
-
-    /**
-     * Create ObjRelationships of the specified entity, as well as
-     * DbRelationships of the corresponding DbEntity.
-     */
-    protected void makeRelationships(EOModelHelper helper, ObjEntity 
objEntity) {
-        Map entityPlistMap = helper.entityPListMap(objEntity.getName());
-        List classProps = (List) entityPlistMap.get("classProperties");
-        List rinfo = (List) entityPlistMap.get("relationships");
-
-        Collection attributes = (Collection) entityPlistMap.get("attributes");
-
-        if (rinfo == null) {
-            return;
-        }
-
-        if (classProps == null) {
-            classProps = Collections.EMPTY_LIST;
-        }
-
-        if (attributes == null) {
-            attributes = Collections.EMPTY_LIST;
-        }
-
-        DbEntity dbSrc = objEntity.getDbEntity();
-        Iterator it = rinfo.iterator();
-        while (it.hasNext()) {
-            Map relMap = (Map) it.next();
-            String targetName = (String) relMap.get("destination");
-
-            // ignore flattened relationships for now
-            if (targetName == null) {
-                continue;
-            }
-
-            String relName = (String) relMap.get("name");
-            boolean toMany = "Y".equals(relMap.get("isToMany"));
-            boolean toDependentPK = 
"Y".equals(relMap.get("propagatesPrimaryKey"));
-            ObjEntity target = helper.getDataMap().getObjEntity(targetName);
-
-            // target maybe null for cross-EOModel relationships
-            // ignoring those now.
-            if (target == null) {
-                continue;
-            }
-
-            DbEntity dbTarget = target.getDbEntity();
-            Map targetPlistMap = helper.entityPListMap(targetName);
-            Collection targetAttributes = (Collection) 
targetPlistMap.get("attributes");
-            DbRelationship dbRel = null;
-
-            // process underlying DbRelationship
-            // Note: there is no flattened rel. support here....
-            // Note: source maybe null, e.g. an abstract entity.
-            if (dbSrc != null && dbTarget != null) {
-
-                // in case of inheritance EOF stores duplicates of all 
inherited
-                // relationships, so we must skip this relationship in DB 
entity
-                // if it is
-                // already there...
-
-                dbRel = dbSrc.getRelationship(relName);
-                if (dbRel == null) {
-
-                    dbRel = new DbRelationship();
-                    dbRel.setSourceEntity(dbSrc);
-                    dbRel.setTargetEntityName(dbTarget);
-                    dbRel.setToMany(toMany);
-                    dbRel.setName(relName);
-                    dbRel.setToDependentPK(toDependentPK);
-                    dbSrc.addRelationship(dbRel);
-
-                    List joins = (List) relMap.get("joins");
-                    Iterator jIt = joins.iterator();
-                    while (jIt.hasNext()) {
-                        Map joinMap = (Map) jIt.next();
-
-                        DbJoin join = new DbJoin(dbRel);
-
-                        // find source attribute dictionary and extract the
-                        // column name
-                        String sourceAttributeName = (String) 
joinMap.get("sourceAttribute");
-                        join.setSourceName(columnName(attributes, 
sourceAttributeName));
-
-                        String targetAttributeName = (String) 
joinMap.get("destinationAttribute");
-
-                        join.setTargetName(columnName(targetAttributes, 
targetAttributeName));
-                        dbRel.addJoin(join);
-                    }
-                }
-            }
-
-            // only create obj relationship if it is a class property
-            if (classProps.contains(relName)) {
-                ObjRelationship rel = new ObjRelationship();
-                rel.setName(relName);
-                rel.setSourceEntity(objEntity);
-                rel.setTargetEntityName(target);
-                objEntity.addRelationship(rel);
-
-                if (dbRel != null) {
-                    rel.addDbRelationship(dbRel);
-                }
-            }
-        }
-    }
-
-    /**
-     * Create reverse DbRelationships that were not created so far, since
-     * Cayenne requires them.
-     * 
-     * @since 1.0.5
-     */
-    protected void makeReverseDbRelationships(DbEntity dbEntity) {
-        if (dbEntity == null) {
-            throw new NullPointerException("Attempt to create reverse 
relationships for the null DbEntity.");
-        }
-
-        // iterate over a copy of the collection, since in case of
-        // reflexive relationships, we may modify source entity relationship 
map
-
-        for (DbRelationship relationship : new 
ArrayList<DbRelationship>(dbEntity.getRelationships())) {
-
-            if (relationship.getReverseRelationship() == null) {
-                DbRelationship reverse = 
relationship.createReverseRelationship();
-
-                String name = 
DefaultUniqueNameGenerator.generate(NameCheckers.dbRelationship, 
reverse.getSourceEntity(), relationship.getName() + "Reverse");
-                reverse.setName(name);
-                relationship.getTargetEntity().addRelationship(reverse);
-            }
-        }
-    }
-
-    /**
-     * Create Flattened ObjRelationships of the specified entity.
-     */
-    protected void makeFlatRelationships(EOModelHelper helper, ObjEntity e) {
-        Map info = helper.entityPListMap(e.getName());
-        List rinfo = (List) info.get("relationships");
-        if (rinfo == null) {
-            return;
-        }
-
-        Iterator it = rinfo.iterator();
-        while (it.hasNext()) {
-            Map relMap = (Map) it.next();
-            String targetPath = (String) relMap.get("definition");
-
-            // ignore normal relationships
-            if (targetPath == null) {
-                continue;
-            }
-
-            ObjRelationship flatRel = new ObjRelationship();
-            flatRel.setName((String) relMap.get("name"));
-            flatRel.setSourceEntity(e);
-
-            try {
-                flatRel.setDbRelationshipPath(targetPath);
-            } catch (ExpressionException ex) {
-                logger.warn("Invalid relationship: " + targetPath);
-                continue;
-            }
-
-            // find target entity
-            Map entityInfo = info;
-            StringTokenizer toks = new StringTokenizer(targetPath, ".");
-            while (toks.hasMoreTokens() && entityInfo != null) {
-                String pathComponent = toks.nextToken();
-
-                // get relationship info and reset entityInfo, so that we could
-                // use
-                // entityInfo state as an indicator of valid flat relationship
-                // enpoint
-                // outside the loop
-                Collection relationshipInfo = (Collection) 
entityInfo.get("relationships");
-                entityInfo = null;
-
-                if (relationshipInfo == null) {
-                    break;
-                }
-
-                Iterator rit = relationshipInfo.iterator();
-                while (rit.hasNext()) {
-                    Map pathRelationship = (Map) rit.next();
-                    if (pathComponent.equals(pathRelationship.get("name"))) {
-                        String targetName = (String) 
pathRelationship.get("destination");
-                        entityInfo = helper.entityPListMap(targetName);
-                        break;
-                    }
-                }
-            }
-
-            if (entityInfo != null) {
-                flatRel.setTargetEntityName((String) entityInfo.get("name"));
-            }
-
-            e.addRelationship(flatRel);
-        }
-    }
-
-    /**
-     * Locates an attribute map matching the name and returns column name for
-     * this attribute.
-     * 
-     * @since 1.1
-     */
-    String columnName(Collection entityAttributes, String attributeName) {
-        if (attributeName == null) {
-            return null;
-        }
-
-        Iterator it = entityAttributes.iterator();
-        while (it.hasNext()) {
-            Map map = (Map) it.next();
-            if (attributeName.equals(map.get("name"))) {
-                return (String) map.get("columnName");
-            }
-        }
-
-        return null;
-    }
-
-    // sorts ObjEntities so that subentities in inheritance hierarchy are shown
-    // last
-    final class InheritanceComparator implements Comparator {
-
-        DataMap dataMap;
-
-        InheritanceComparator(DataMap dataMap) {
-            this.dataMap = dataMap;
-        }
-
-        public int compare(Object o1, Object o2) {
-            if (o1 == null) {
-                return o2 != null ? -1 : 0;
-            } else if (o2 == null) {
-                return 1;
-            }
-
-            String name1 = o1.toString();
-            String name2 = o2.toString();
-
-            ObjEntity e1 = dataMap.getObjEntity(name1);
-            ObjEntity e2 = dataMap.getObjEntity(name2);
-
-            return compareEntities(e1, e2);
-        }
-
-        int compareEntities(ObjEntity e1, ObjEntity e2) {
-            if (e1 == null) {
-                return e2 != null ? -1 : 0;
-            } else if (e2 == null) {
-                return 1;
-            }
-
-            // entity goes first if it is a direct or indirect superentity of
-            // another
-            // one
-            if (e1.isSubentityOf(e2)) {
-                return 1;
-            }
-
-            if (e2.isSubentityOf(e1)) {
-                return -1;
-            }
-
-            // sort alphabetically
-            return e1.getName().compareTo(e2.getName());
-        }
-    }
+       private static final Log logger = 
LogFactory.getLog(EOModelProcessor.class);
+
+       protected Predicate prototypeChecker;
+
+       public EOModelProcessor() {
+               prototypeChecker = new Predicate() {
+
+                       public boolean evaluate(Object object) {
+                               if (object == null) {
+                                       return false;
+                               }
+
+                               String entityName = object.toString();
+                               return entityName.startsWith("EO") && 
entityName.endsWith("Prototypes");
+                       }
+               };
+       }
+
+       /**
+        * @deprecated since 4.0 in favor of {@link #loadModeIndex(URL)}.
+        */
+       @Deprecated
+       public Map loadModeIndex(String path) throws Exception {
+               return loadModeIndex(new File(path).toURI().toURL());
+       }
+
+       /**
+        * Returns index.eomodeld contents as a Map.
+        * 
+        * @since 4.0
+        */
+       // TODO: refactor EOModelHelper to provide a similar method without 
loading
+       // all entity files in memory... here we simply copied stuff from
+       // EOModelHelper
+       public Map loadModeIndex(URL url) throws Exception {
+
+               String urlString = url.toExternalForm();
+
+               if (!urlString.endsWith(".eomodeld")) {
+                       url = new URL(urlString + ".eomodeld");
+               }
+
+               Parser plistParser = new Parser();
+
+               try (InputStream in = new URL(url, 
"index.eomodeld").openStream();) {
+                       plistParser.ReInit(in);
+                       return (Map) plistParser.propertyList();
+               }
+       }
+
+       /**
+        * @deprecated since 4.0 in favor of {@link #loadEOModel(URL)}.
+        */
+       @Deprecated
+       public DataMap loadEOModel(String path) throws Exception {
+               return loadEOModel(path, false);
+       }
+
+       /**
+        * @deprecated since 4.0 in favor of {@link #loadEOModel(URL, boolean)}.
+        */
+       @Deprecated
+       public DataMap loadEOModel(String path, boolean generateClientClass) 
throws Exception {
+               return loadEOModel(new File(path).toURI().toURL(), 
generateClientClass);
+       }
+
+       /**
+        * Performs EOModel loading.
+        * 
+        * @param url
+        *            URL of ".eomodeld" directory.
+        */
+       public DataMap loadEOModel(URL url) throws Exception {
+               return loadEOModel(url, false);
+       }
+
+       /**
+        * Performs EOModel loading.
+        * 
+        * @param url
+        *            URL of ".eomodeld" directory.
+        * @param generateClientClass
+        *            if true then loading of EOModel is java client classes 
aware
+        *            and the following processing will work with Java client 
class
+        *            settings of the EOModel.
+        */
+       public DataMap loadEOModel(URL url, boolean generateClientClass) throws 
Exception {
+               EOModelHelper helper = makeHelper(url);
+
+               // create empty map
+               DataMap dataMap = helper.getDataMap();
+
+               // process enitities ... throw out prototypes ... for now
+               List modelNames = new ArrayList(helper.modelNamesAsList());
+               CollectionUtils.filter(modelNames, 
PredicateUtils.notPredicate(prototypeChecker));
+
+               Iterator it = modelNames.iterator();
+               while (it.hasNext()) {
+                       String name = (String) it.next();
+
+                       // create and register entity
+                       makeEntity(helper, name, generateClientClass);
+               }
+
+               // now sort following inheritance hierarchy
+               Collections.sort(modelNames, new 
InheritanceComparator(dataMap));
+
+               // after all entities are loaded, process attributes
+               it = modelNames.iterator();
+               while (it.hasNext()) {
+                       String name = (String) it.next();
+
+                       EOObjEntity e = (EOObjEntity) 
dataMap.getObjEntity(name);
+                       // process entity attributes
+                       makeAttributes(helper, e);
+               }
+
+               // after all entities are loaded, process relationships
+               it = modelNames.iterator();
+               while (it.hasNext()) {
+                       String name = (String) it.next();
+                       makeRelationships(helper, dataMap.getObjEntity(name));
+               }
+
+               // after all normal relationships are loaded, process flattened
+               // relationships
+               it = modelNames.iterator();
+               while (it.hasNext()) {
+                       String name = (String) it.next();
+                       makeFlatRelationships(helper, 
dataMap.getObjEntity(name));
+               }
+
+               // now create missing reverse DB (but not OBJ) relationships
+               // since Cayenne requires them
+               it = modelNames.iterator();
+               while (it.hasNext()) {
+                       String name = (String) it.next();
+                       DbEntity dbEntity = 
dataMap.getObjEntity(name).getDbEntity();
+
+                       if (dbEntity != null) {
+                               makeReverseDbRelationships(dbEntity);
+                       }
+               }
+
+               // build SelectQueries out of EOFetchSpecifications...
+               it = modelNames.iterator();
+               while (it.hasNext()) {
+                       String name = (String) it.next();
+                       Iterator queries = helper.queryNames(name);
+                       while (queries.hasNext()) {
+                               String queryName = (String) queries.next();
+                               EOObjEntity entity = (EOObjEntity) 
dataMap.getObjEntity(name);
+                               makeQuery(helper, entity, queryName);
+                       }
+               }
+
+               return dataMap;
+       }
+
+       /**
+        * Returns whether an Entity is an EOF EOPrototypes entity. According 
to EOF
+        * conventions EOPrototypes and EO[Adapter]Prototypes entities are
+        * considered to be prototypes.
+        * 
+        * @since 1.1
+        */
+       protected boolean isPrototypesEntity(String entityName) {
+               return prototypeChecker.evaluate(entityName);
+       }
+
+       /**
+        * Creates an returns new EOModelHelper to process EOModel. Exists 
mostly
+        * for the benefit of subclasses.
+        */
+       protected EOModelHelper makeHelper(URL url) throws Exception {
+               return new EOModelHelper(url);
+       }
+
+       /**
+        * Creates a Cayenne query out of EOFetchSpecification data.
+        * 
+        * @since 1.1
+        */
+       protected Query makeQuery(EOModelHelper helper, EOObjEntity entity, 
String queryName) {
+
+               DataMap dataMap = helper.getDataMap();
+               Map queryPlist = helper.queryPListMap(entity.getName(), 
queryName);
+               if (queryPlist == null) {
+                       return null;
+               }
+
+               AbstractQuery query;
+               if (queryPlist.containsKey("hints")) { // just a predefined SQL 
query
+                       query = new EOSQLQuery(entity, queryPlist);
+               } else {
+                       query = new EOQuery(entity, queryPlist);
+               }
+               query.setName(entity.qualifiedQueryName(queryName));
+               dataMap.addQuery(query);
+
+               return query;
+       }
+
+       /**
+        * Creates and returns a new ObjEntity linked to a corresponding 
DbEntity.
+        */
+       protected EOObjEntity makeEntity(EOModelHelper helper, String name, 
boolean generateClientClass) {
+
+               DataMap dataMap = helper.getDataMap();
+               Map entityPlist = helper.entityPListMap(name);
+
+               // create ObjEntity
+               EOObjEntity objEntity = new EOObjEntity(name);
+               objEntity.setEoMap(entityPlist);
+               objEntity.setServerOnly(!generateClientClass);
+               String parent = (String) entityPlist.get("parent");
+               objEntity.setClassName(helper.entityClass(name, 
generateClientClass));
+
+               if (parent != null) {
+                       objEntity.setSubclass(true);
+                       objEntity.setSuperClassName(helper.entityClass(parent, 
generateClientClass));
+               }
+
+               // add flag whether this entity is set as abstract in the model
+               
objEntity.setAbstractEntity("Y".equals(entityPlist.get("isAbstractEntity")));
+
+               // create DbEntity...since EOF allows the same table to be
+               // associated with multiple EOEntities, check for name 
duplicates
+               String dbEntityName = (String) entityPlist.get("externalName");
+               if (dbEntityName != null) {
+
+                       // ... if inheritance is involved and parent hierarchy 
uses the same
+                       // DBEntity,
+                       // do not create a DbEntity...
+                       boolean createDbEntity = true;
+                       if (parent != null) {
+                               String parentName = parent;
+                               while (parentName != null) {
+                                       Map parentData = 
helper.entityPListMap(parentName);
+                                       if (parentData == null) {
+                                               break;
+                                       }
+
+                                       String parentExternalName = (String) 
parentData.get("externalName");
+                                       if (parentExternalName == null) {
+                                               parentName = (String) 
parentData.get("parent");
+                                               continue;
+                                       }
+
+                                       if 
(dbEntityName.equals(parentExternalName)) {
+                                               createDbEntity = false;
+                                       }
+
+                                       break;
+                               }
+                       }
+
+                       if (createDbEntity) {
+                               int i = 0;
+                               String dbEntityBaseName = dbEntityName;
+                               while (dataMap.getDbEntity(dbEntityName) != 
null) {
+                                       dbEntityName = dbEntityBaseName + i++;
+                               }
+
+                               objEntity.setDbEntityName(dbEntityName);
+                               DbEntity de = new DbEntity(dbEntityName);
+                               dataMap.addDbEntity(de);
+                       }
+               }
+
+               // set various flags
+               
objEntity.setReadOnly("Y".equals(entityPlist.get("isReadOnly")));
+               objEntity.setSuperEntityName((String) 
entityPlist.get("parent"));
+
+               dataMap.addObjEntity(objEntity);
+
+               return objEntity;
+       }
+
+       /**
+        * Create ObjAttributes of the specified entity, as well as 
DbAttributes of
+        * the corresponding DbEntity.
+        */
+       protected void makeAttributes(EOModelHelper helper, EOObjEntity 
objEntity) {
+               Map entityPlistMap = helper.entityPListMap(objEntity.getName());
+               List primaryKeys = (List) 
entityPlistMap.get("primaryKeyAttributes");
+
+               List classProperties;
+               if (objEntity.isServerOnly()) {
+                       classProperties = (List) 
entityPlistMap.get("classProperties");
+               } else {
+                       classProperties = (List) 
entityPlistMap.get("clientClassProperties");
+               }
+
+               List attributes = (List) entityPlistMap.get("attributes");
+               DbEntity dbEntity = objEntity.getDbEntity();
+
+               if (primaryKeys == null) {
+                       primaryKeys = Collections.EMPTY_LIST;
+               }
+
+               if (classProperties == null) {
+                       classProperties = Collections.EMPTY_LIST;
+               }
+
+               if (attributes == null) {
+                       attributes = Collections.EMPTY_LIST;
+               }
+
+               // detect single table inheritance
+               boolean singleTableInheritance = false;
+               String parentName = (String) entityPlistMap.get("parent");
+               while (parentName != null) {
+                       Map parentData = helper.entityPListMap(parentName);
+                       if (parentData == null) {
+                               break;
+                       }
+
+                       String parentExternalName = (String) 
parentData.get("externalName");
+                       if (parentExternalName == null) {
+                               parentName = (String) parentData.get("parent");
+                               continue;
+                       }
+
+                       if (dbEntity.getName() != null && 
dbEntity.getName().equals(parentExternalName)) {
+                               singleTableInheritance = true;
+                       }
+
+                       break;
+               }
+
+               Iterator it = attributes.iterator();
+               while (it.hasNext()) {
+                       Map attrMap = (Map) it.next();
+
+                       String prototypeName = (String) 
attrMap.get("prototypeName");
+                       Map prototypeAttrMap = 
helper.getPrototypeAttributeMapFor(prototypeName);
+
+                       String dbAttrName = (String) attrMap.get("columnName");
+                       if (null == dbAttrName) {
+                               dbAttrName = (String) 
prototypeAttrMap.get("columnName");
+                       }
+
+                       String attrName = (String) attrMap.get("name");
+                       if (null == attrName) {
+                               attrName = (String) 
prototypeAttrMap.get("name");
+                       }
+
+                       String attrType = (String) 
attrMap.get("valueClassName");
+                       if (null == attrType) {
+                               attrType = (String) 
prototypeAttrMap.get("valueClassName");
+                       }
+
+                       String valueType = (String) attrMap.get("valueType");
+                       if (valueType == null) {
+                               valueType = (String) 
prototypeAttrMap.get("valueType");
+                       }
+
+                       String javaType = 
helper.javaTypeForEOModelerType(attrType, valueType);
+                       EODbAttribute dbAttr = null;
+
+                       if (dbAttrName != null && dbEntity != null) {
+
+                               // if inherited attribute, skip it for 
DbEntity...
+                               if (!singleTableInheritance || 
dbEntity.getAttribute(dbAttrName) == null) {
+
+                                       // create DbAttribute...since EOF 
allows the same column
+                                       // name for
+                                       // more than one Java attribute, we 
need to check for name
+                                       // duplicates
+                                       int i = 0;
+                                       String dbAttributeBaseName = dbAttrName;
+                                       while 
(dbEntity.getAttribute(dbAttrName) != null) {
+                                               dbAttrName = 
dbAttributeBaseName + i++;
+                                       }
+
+                                       dbAttr = new EODbAttribute(dbAttrName, 
TypesMapping.getSqlTypeByJava(javaType), dbEntity);
+                                       dbAttr.setEoAttributeName(attrName);
+                                       dbEntity.addAttribute(dbAttr);
+
+                                       int width = getInt("width", attrMap, 
prototypeAttrMap, -1);
+                                       if (width >= 0) {
+                                               dbAttr.setMaxLength(width);
+                                       }
+
+                                       int scale = getInt("scale", attrMap, 
prototypeAttrMap, -1);
+                                       if (scale >= 0) {
+                                               dbAttr.setScale(scale);
+                                       }
+
+                                       if (primaryKeys.contains(attrName))
+                                               dbAttr.setPrimaryKey(true);
+
+                                       Object allowsNull = 
attrMap.get("allowsNull");
+                                       // TODO: Unclear that allowsNull should 
be inherited from
+                                       // EOPrototypes
+                                       // if (null == allowsNull) allowsNull =
+                                       // prototypeAttrMap.get("allowsNull");;
+
+                                       
dbAttr.setMandatory(!"Y".equals(allowsNull));
+                               }
+                       }
+
+                       if (classProperties.contains(attrName)) {
+                               EOObjAttribute attr = new 
EOObjAttribute(attrName, javaType, objEntity);
+
+                               // set readOnly flag of Attribute if either 
attribute is read or
+                               // if entity is readOnly
+                               String entityReadOnlyString = (String) 
entityPlistMap.get("isReadOnly");
+                               String attributeReadOnlyString = (String) 
attrMap.get("isReadOnly");
+                               if ("Y".equals(entityReadOnlyString) || 
"Y".equals(attributeReadOnlyString)) {
+                                       attr.setReadOnly(true);
+                               }
+
+                               // set name instead of the actual attribute, as 
it may be
+                               // inherited....
+                               attr.setDbAttributePath(dbAttrName);
+                               objEntity.addAttribute(attr);
+                       }
+               }
+       }
+
+       int getInt(String key, Map map, Map prototypes, int defaultValue) {
+
+               Object value = map.get(key);
+               if (value == null) {
+                       value = prototypes.get(key);
+               }
+
+               if (value == null) {
+                       return defaultValue;
+               }
+
+               // per CAY-752, value can be a String or a Number, so handle 
both
+               if (value instanceof Number) {
+                       return ((Number) value).intValue();
+               } else {
+                       try {
+                               return Integer.parseInt(value.toString());
+                       } catch (NumberFormatException nfex) {
+                               return defaultValue;
+                       }
+               }
+       }
+
+       /**
+        * Create ObjRelationships of the specified entity, as well as
+        * DbRelationships of the corresponding DbEntity.
+        */
+       protected void makeRelationships(EOModelHelper helper, ObjEntity 
objEntity) {
+               Map entityPlistMap = helper.entityPListMap(objEntity.getName());
+               List classProps = (List) entityPlistMap.get("classProperties");
+               List rinfo = (List) entityPlistMap.get("relationships");
+
+               Collection attributes = (Collection) 
entityPlistMap.get("attributes");
+
+               if (rinfo == null) {
+                       return;
+               }
+
+               if (classProps == null) {
+                       classProps = Collections.EMPTY_LIST;
+               }
+
+               if (attributes == null) {
+                       attributes = Collections.EMPTY_LIST;
+               }
+
+               DbEntity dbSrc = objEntity.getDbEntity();
+               Iterator it = rinfo.iterator();
+               while (it.hasNext()) {
+                       Map relMap = (Map) it.next();
+                       String targetName = (String) relMap.get("destination");
+
+                       // ignore flattened relationships for now
+                       if (targetName == null) {
+                               continue;
+                       }
+
+                       String relName = (String) relMap.get("name");
+                       boolean toMany = "Y".equals(relMap.get("isToMany"));
+                       boolean toDependentPK = 
"Y".equals(relMap.get("propagatesPrimaryKey"));
+                       ObjEntity target = 
helper.getDataMap().getObjEntity(targetName);
+
+                       // target maybe null for cross-EOModel relationships
+                       // ignoring those now.
+                       if (target == null) {
+                               continue;
+                       }
+
+                       DbEntity dbTarget = target.getDbEntity();
+                       Map targetPlistMap = helper.entityPListMap(targetName);
+                       Collection targetAttributes = (Collection) 
targetPlistMap.get("attributes");
+                       DbRelationship dbRel = null;
+
+                       // process underlying DbRelationship
+                       // Note: there is no flattened rel. support here....
+                       // Note: source maybe null, e.g. an abstract entity.
+                       if (dbSrc != null && dbTarget != null) {
+
+                               // in case of inheritance EOF stores duplicates 
of all inherited
+                               // relationships, so we must skip this 
relationship in DB entity
+                               // if it is
+                               // already there...
+
+                               dbRel = dbSrc.getRelationship(relName);
+                               if (dbRel == null) {
+
+                                       dbRel = new DbRelationship();
+                                       dbRel.setSourceEntity(dbSrc);
+                                       dbRel.setTargetEntityName(dbTarget);
+                                       dbRel.setToMany(toMany);
+                                       dbRel.setName(relName);
+                                       dbRel.setToDependentPK(toDependentPK);
+                                       dbSrc.addRelationship(dbRel);
+
+                                       List joins = (List) relMap.get("joins");
+                                       Iterator jIt = joins.iterator();
+                                       while (jIt.hasNext()) {
+                                               Map joinMap = (Map) jIt.next();
+
+                                               DbJoin join = new DbJoin(dbRel);
+
+                                               // find source attribute 
dictionary and extract the
+                                               // column name
+                                               String sourceAttributeName = 
(String) joinMap.get("sourceAttribute");
+                                               
join.setSourceName(columnName(attributes, sourceAttributeName));
+
+                                               String targetAttributeName = 
(String) joinMap.get("destinationAttribute");
+
+                                               
join.setTargetName(columnName(targetAttributes, targetAttributeName));
+                                               dbRel.addJoin(join);
+                                       }
+                               }
+                       }
+
+                       // only create obj relationship if it is a class 
property
+                       if (classProps.contains(relName)) {
+                               ObjRelationship rel = new ObjRelationship();
+                               rel.setName(relName);
+                               rel.setSourceEntity(objEntity);
+                               rel.setTargetEntityName(target);
+                               objEntity.addRelationship(rel);
+
+                               if (dbRel != null) {
+                                       rel.addDbRelationship(dbRel);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Create reverse DbRelationships that were not created so far, since
+        * Cayenne requires them.
+        * 
+        * @since 1.0.5
+        */
+       protected void makeReverseDbRelationships(DbEntity dbEntity) {
+               if (dbEntity == null) {
+                       throw new NullPointerException("Attempt to create 
reverse relationships for the null DbEntity.");
+               }
+
+               // iterate over a copy of the collection, since in case of
+               // reflexive relationships, we may modify source entity 
relationship map
+
+               for (DbRelationship relationship : new 
ArrayList<DbRelationship>(dbEntity.getRelationships())) {
+
+                       if (relationship.getReverseRelationship() == null) {
+                               DbRelationship reverse = 
relationship.createReverseRelationship();
+
+                               String name = 
DefaultUniqueNameGenerator.generate(NameCheckers.dbRelationship,
+                                               reverse.getSourceEntity(), 
relationship.getName() + "Reverse");
+                               reverse.setName(name);
+                               
relationship.getTargetEntity().addRelationship(reverse);
+                       }
+               }
+       }
+
+       /**
+        * Create Flattened ObjRelationships of the specified entity.
+        */
+       protected void makeFlatRelationships(EOModelHelper helper, ObjEntity e) 
{
+               Map info = helper.entityPListMap(e.getName());
+               List rinfo = (List) info.get("relationships");
+               if (rinfo == null) {
+                       return;
+               }
+
+               Iterator it = rinfo.iterator();
+               while (it.hasNext()) {
+                       Map relMap = (Map) it.next();
+                       String targetPath = (String) relMap.get("definition");
+
+                       // ignore normal relationships
+                       if (targetPath == null) {
+                               continue;
+                       }
+
+                       ObjRelationship flatRel = new ObjRelationship();
+                       flatRel.setName((String) relMap.get("name"));
+                       flatRel.setSourceEntity(e);
+
+                       try {
+                               flatRel.setDbRelationshipPath(targetPath);
+                       } catch (ExpressionException ex) {
+                               logger.warn("Invalid relationship: " + 
targetPath);
+                               continue;
+                       }
+
+                       // find target entity
+                       Map entityInfo = info;
+                       StringTokenizer toks = new StringTokenizer(targetPath, 
".");
+                       while (toks.hasMoreTokens() && entityInfo != null) {
+                               String pathComponent = toks.nextToken();
+
+                               // get relationship info and reset entityInfo, 
so that we could
+                               // use
+                               // entityInfo state as an indicator of valid 
flat relationship
+                               // enpoint
+                               // outside the loop
+                               Collection relationshipInfo = (Collection) 
entityInfo.get("relationships");
+                               entityInfo = null;
+
+                               if (relationshipInfo == null) {
+                                       break;
+                               }
+
+                               Iterator rit = relationshipInfo.iterator();
+                               while (rit.hasNext()) {
+                                       Map pathRelationship = (Map) rit.next();
+                                       if 
(pathComponent.equals(pathRelationship.get("name"))) {
+                                               String targetName = (String) 
pathRelationship.get("destination");
+                                               entityInfo = 
helper.entityPListMap(targetName);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if (entityInfo != null) {
+                               flatRel.setTargetEntityName((String) 
entityInfo.get("name"));
+                       }
+
+                       e.addRelationship(flatRel);
+               }
+       }
+
+       /**
+        * Locates an attribute map matching the name and returns column name 
for
+        * this attribute.
+        * 
+        * @since 1.1
+        */
+       String columnName(Collection entityAttributes, String attributeName) {
+               if (attributeName == null) {
+                       return null;
+               }
+
+               Iterator it = entityAttributes.iterator();
+               while (it.hasNext()) {
+                       Map map = (Map) it.next();
+                       if (attributeName.equals(map.get("name"))) {
+                               return (String) map.get("columnName");
+                       }
+               }
+
+               return null;
+       }
+
+       // sorts ObjEntities so that subentities in inheritance hierarchy are 
shown
+       // last
+       final class InheritanceComparator implements Comparator {
+
+               DataMap dataMap;
+
+               InheritanceComparator(DataMap dataMap) {
+                       this.dataMap = dataMap;
+               }
+
+               public int compare(Object o1, Object o2) {
+                       if (o1 == null) {
+                               return o2 != null ? -1 : 0;
+                       } else if (o2 == null) {
+                               return 1;
+                       }
+
+                       String name1 = o1.toString();
+                       String name2 = o2.toString();
+
+                       ObjEntity e1 = dataMap.getObjEntity(name1);
+                       ObjEntity e2 = dataMap.getObjEntity(name2);
+
+                       return compareEntities(e1, e2);
+               }
+
+               int compareEntities(ObjEntity e1, ObjEntity e2) {
+                       if (e1 == null) {
+                               return e2 != null ? -1 : 0;
+                       } else if (e2 == null) {
+                               return 1;
+                       }
+
+                       // entity goes first if it is a direct or indirect 
superentity of
+                       // another
+                       // one
+                       if (e1.isSubentityOf(e2)) {
+                               return 1;
+                       }
+
+                       if (e2.isSubentityOf(e1)) {
+                               return -1;
+                       }
+
+                       // sort alphabetically
+                       return e1.getName().compareTo(e2.getName());
+               }
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/PropertyListSerialization.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/PropertyListSerialization.java
 
b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/PropertyListSerialization.java
index e58e62d..7393f88 100644
--- 
a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/PropertyListSerialization.java
+++ 
b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/PropertyListSerialization.java
@@ -36,247 +36,229 @@ import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.wocompat.parser.Parser;
 
 /**
- * A <b>PropertyListSerialization</b> is a utility class that reads and stores 
files in
- * NeXT/Apple property list format. Unlike corresponding WebObjects class,
- * <code>PropertyListSerialization</code> uses standard Java collections 
(lists and
- * maps) to store property lists.
+ * A <b>PropertyListSerialization</b> is a utility class that reads and stores
+ * files in NeXT/Apple property list format. Unlike corresponding WebObjects
+ * class, <code>PropertyListSerialization</code> uses standard Java collections
+ * (lists and maps) to store property lists.
  * 
  */
 public class PropertyListSerialization {
 
-    /**
-     * Reads a property list file. Returns a property list object, that is 
normally a
-     * java.util.List or a java.util.Map, but can also be a String or a Number.
-     */
-    public static Object propertyListFromFile(File f) throws 
FileNotFoundException {
-        return propertyListFromFile(f, null);
-    }
-
-    /**
-     * Reads a property list file. Returns a property list object, that is 
normally a
-     * java.util.List or a java.util.Map, but can also be a String or a Number.
-     */
-    public static Object propertyListFromFile(File f, 
PlistDataStructureFactory factory)
-            throws FileNotFoundException {
-        if (!f.isFile()) {
-            throw new FileNotFoundException("No such file: " + f);
-        }
-
-        return new Parser(f, factory).propertyList();
-    }
-
-    /**
-     * Reads a property list data from InputStream. Returns a property list o 
bject, that
-     * is normally a java.util.List or a java.util.Map, but can also be a 
String or a
-     * Number.
-     */
-    public static Object propertyListFromStream(InputStream in) {
-        return propertyListFromStream(in, null);
-    }
-
-    /**
-     * Reads a property list data from InputStream. Returns a property list o 
bject, that
-     * is normally a java.util.List or a java.util.Map, but can also be a 
String or a
-     * Number.
-     */
-    public static Object propertyListFromStream(
-            InputStream in,
-            PlistDataStructureFactory factory) {
-        return new Parser(in, factory).propertyList();
-    }
-
-    /**
-     * Saves property list to file.
-     */
-    public static void propertyListToFile(File f, Object plist) {
-        try {
-            BufferedWriter out = new BufferedWriter(new FileWriter(f));
-            try {
-                writeObject("", out, plist);
-            }
-            finally {
-                out.close();
-            }
-        }
-        catch (IOException ioex) {
-            throw new CayenneRuntimeException("Error saving plist.", ioex);
-        }
-    }
-
-    /**
-     * Saves property list to file.
-     */
-    public static void propertyListToStream(OutputStream os, Object plist) {
-        try {
-            BufferedWriter out = new BufferedWriter(new 
OutputStreamWriter(os));
-            try {
-                writeObject("", out, plist);
-            }
-            finally {
-                out.close();
-            }
-        }
-        catch (IOException ioex) {
-            throw new CayenneRuntimeException("Error saving plist.", ioex);
-        }
-    }
-
-    /**
-     * Internal method to recursively write a property list object.
-     */
-    protected static void writeObject(String offset, Writer out, Object plist)
-            throws IOException {
-        if (plist == null) {
-            return;
-        }
-
-        if (plist instanceof Collection) {
-            Collection list = (Collection) plist;
-
-            out.write('\n');
-            out.write(offset);
-
-            if (list.size() == 0) {
-                out.write("()");
-                return;
-            }
-
-            out.write("(\n");
-
-            String childOffset = offset + "   ";
-            Iterator it = list.iterator();
-            boolean appended = false;
-            while (it.hasNext()) {
-                // Java collections can contain nulls, skip them
-                Object obj = it.next();
-                if (obj != null) {
-                    if (appended) {
-                        out.write(", \n");
-                    }
-
-                    out.write(childOffset);
-                    writeObject(childOffset, out, obj);
-                    appended = true;
-                }
-            }
-
-            out.write('\n');
-            out.write(offset);
-            out.write(')');
-        }
-        else if (plist instanceof Map) {
-            Map map = (Map) plist;
-            out.write('\n');
-            out.write(offset);
-
-            if (map.size() == 0) {
-                out.write("{}");
-                return;
-            }
-
-            out.write("{");
-
-            String childOffset = offset + "    ";
-
-            Iterator it = map.entrySet().iterator();
-            while (it.hasNext()) {
-                // Java collections can contain nulls, skip them
-                Map.Entry entry = (Map.Entry) it.next();
-                Object key = entry.getKey();
-                if (key == null) {
-                    continue;
-                }
-                Object obj = entry.getValue();
-                if (obj == null) {
-                    continue;
-                }
-                out.write('\n');
-                out.write(childOffset);
-                out.write(quoteString(key.toString()));
-                out.write(" = ");
-                writeObject(childOffset, out, obj);
-                out.write(';');
-            }
-
-            out.write('\n');
-            out.write(offset);
-            out.write('}');
-        }
-        else if (plist instanceof String) {
-            out.write(quoteString(plist.toString()));
-        }
-        else if (plist instanceof Number) {
-            out.write(plist.toString());
-        }
-        else {
-            throw new CayenneRuntimeException(
-                    "Unsupported class for property list serialization: "
-                            + plist.getClass().getName());
-        }
-    }
-
-    /**
-     * Escapes all doublequotes and backslashes.
-     */
-    protected static String escapeString(String str) {
-        char[] chars = str.toCharArray();
-        int len = chars.length;
-        StringBuilder buf = new StringBuilder(len + 3);
-
-        for (int i = 0; i < len; i++) {
-            if (chars[i] == '\"' || chars[i] == '\\') {
-                buf.append('\\');
-            }
-            buf.append(chars[i]);
-        }
-
-        return buf.toString();
-    }
-
-    /**
-     * Returns a quoted String, with all the escapes preprocessed. May return 
an unquoted
-     * String if it contains no special characters. The rule for a non-special 
character
-     * is the following:
-     * 
-     * <pre>
-     *       c &gt;= 'a' &amp;&amp; c &lt;= 'z'
-     *       c &gt;= 'A' &amp;&amp; c &lt;= 'Z'
-     *       c &gt;= '0' &amp;&amp; c &lt;= '9'
-     *       c == '_'
-     *       c == '$'
-     *       c == ':'
-     *       c == '.'
-     *       c == '/'
-     * </pre>
-     */
-    protected static String quoteString(String str) {
-        boolean shouldQuote = false;
-
-        // scan string for special chars,
-        // if we have them, string must be quoted
-
-        String noQuoteExtras = "_$:./";
-        char[] chars = str.toCharArray();
-        int len = chars.length;
-        if (len == 0) {
-            shouldQuote = true;
-        }
-        for (int i = 0; !shouldQuote && i < len; i++) {
-            char c = chars[i];
-
-            if ((c >= 'a' && c <= 'z')
-                    || (c >= 'A' && c <= 'Z')
-                    || (c >= '0' && c <= '9')
-                    || noQuoteExtras.indexOf(c) >= 0) {
-                continue;
-            }
-
-            shouldQuote = true;
-        }
-
-        str = escapeString(str);
-        return (shouldQuote) ? '\"' + str + '\"' : str;
-    }
-
-    
+       /**
+        * Reads a property list file. Returns a property list object, that is
+        * normally a java.util.List or a java.util.Map, but can also be a 
String or
+        * a Number.
+        */
+       public static Object propertyListFromFile(File f) throws 
FileNotFoundException {
+               return propertyListFromFile(f, null);
+       }
+
+       /**
+        * Reads a property list file. Returns a property list object, that is
+        * normally a java.util.List or a java.util.Map, but can also be a 
String or
+        * a Number.
+        */
+       public static Object propertyListFromFile(File f, 
PlistDataStructureFactory factory) throws FileNotFoundException {
+               if (!f.isFile()) {
+                       throw new FileNotFoundException("No such file: " + f);
+               }
+
+               return new Parser(f, factory).propertyList();
+       }
+
+       /**
+        * Reads a property list data from InputStream. Returns a property list 
o
+        * bject, that is normally a java.util.List or a java.util.Map, but can 
also
+        * be a String or a Number.
+        */
+       public static Object propertyListFromStream(InputStream in) {
+               return propertyListFromStream(in, null);
+       }
+
+       /**
+        * Reads a property list data from InputStream. Returns a property list 
o
+        * bject, that is normally a java.util.List or a java.util.Map, but can 
also
+        * be a String or a Number.
+        */
+       public static Object propertyListFromStream(InputStream in, 
PlistDataStructureFactory factory) {
+               return new Parser(in, factory).propertyList();
+       }
+
+       /**
+        * Saves property list to file.
+        */
+       public static void propertyListToFile(File f, Object plist) {
+               try {
+
+                       try (BufferedWriter out = new BufferedWriter(new 
FileWriter(f));) {
+                               writeObject("", out, plist);
+                       }
+               } catch (IOException ioex) {
+                       throw new CayenneRuntimeException("Error saving 
plist.", ioex);
+               }
+       }
+
+       /**
+        * Saves property list to file.
+        */
+       public static void propertyListToStream(OutputStream os, Object plist) {
+               try {
+
+                       try (BufferedWriter out = new BufferedWriter(new 
OutputStreamWriter(os));) {
+                               writeObject("", out, plist);
+                       }
+               } catch (IOException ioex) {
+                       throw new CayenneRuntimeException("Error saving 
plist.", ioex);
+               }
+       }
+
+       /**
+        * Internal method to recursively write a property list object.
+        */
+       protected static void writeObject(String offset, Writer out, Object 
plist) throws IOException {
+               if (plist == null) {
+                       return;
+               }
+
+               if (plist instanceof Collection) {
+                       Collection list = (Collection) plist;
+
+                       out.write('\n');
+                       out.write(offset);
+
+                       if (list.size() == 0) {
+                               out.write("()");
+                               return;
+                       }
+
+                       out.write("(\n");
+
+                       String childOffset = offset + "   ";
+                       Iterator it = list.iterator();
+                       boolean appended = false;
+                       while (it.hasNext()) {
+                               // Java collections can contain nulls, skip them
+                               Object obj = it.next();
+                               if (obj != null) {
+                                       if (appended) {
+                                               out.write(", \n");
+                                       }
+
+                                       out.write(childOffset);
+                                       writeObject(childOffset, out, obj);
+                                       appended = true;
+                               }
+                       }
+
+                       out.write('\n');
+                       out.write(offset);
+                       out.write(')');
+               } else if (plist instanceof Map) {
+                       Map map = (Map) plist;
+                       out.write('\n');
+                       out.write(offset);
+
+                       if (map.size() == 0) {
+                               out.write("{}");
+                               return;
+                       }
+
+                       out.write("{");
+
+                       String childOffset = offset + "    ";
+
+                       Iterator it = map.entrySet().iterator();
+                       while (it.hasNext()) {
+                               // Java collections can contain nulls, skip them
+                               Map.Entry entry = (Map.Entry) it.next();
+                               Object key = entry.getKey();
+                               if (key == null) {
+                                       continue;
+                               }
+                               Object obj = entry.getValue();
+                               if (obj == null) {
+                                       continue;
+                               }
+                               out.write('\n');
+                               out.write(childOffset);
+                               out.write(quoteString(key.toString()));
+                               out.write(" = ");
+                               writeObject(childOffset, out, obj);
+                               out.write(';');
+                       }
+
+                       out.write('\n');
+                       out.write(offset);
+                       out.write('}');
+               } else if (plist instanceof String) {
+                       out.write(quoteString(plist.toString()));
+               } else if (plist instanceof Number) {
+                       out.write(plist.toString());
+               } else {
+                       throw new CayenneRuntimeException("Unsupported class 
for property list serialization: "
+                                       + plist.getClass().getName());
+               }
+       }
+
+       /**
+        * Escapes all doublequotes and backslashes.
+        */
+       protected static String escapeString(String str) {
+               char[] chars = str.toCharArray();
+               int len = chars.length;
+               StringBuilder buf = new StringBuilder(len + 3);
+
+               for (int i = 0; i < len; i++) {
+                       if (chars[i] == '\"' || chars[i] == '\\') {
+                               buf.append('\\');
+                       }
+                       buf.append(chars[i]);
+               }
+
+               return buf.toString();
+       }
+
+       /**
+        * Returns a quoted String, with all the escapes preprocessed. May 
return an
+        * unquoted String if it contains no special characters. The rule for a
+        * non-special character is the following:
+        * 
+        * <pre>
+        *       c &gt;= 'a' &amp;&amp; c &lt;= 'z'
+        *       c &gt;= 'A' &amp;&amp; c &lt;= 'Z'
+        *       c &gt;= '0' &amp;&amp; c &lt;= '9'
+        *       c == '_'
+        *       c == '$'
+        *       c == ':'
+        *       c == '.'
+        *       c == '/'
+        * </pre>
+        */
+       protected static String quoteString(String str) {
+               boolean shouldQuote = false;
+
+               // scan string for special chars,
+               // if we have them, string must be quoted
+
+               String noQuoteExtras = "_$:./";
+               char[] chars = str.toCharArray();
+               int len = chars.length;
+               if (len == 0) {
+                       shouldQuote = true;
+               }
+               for (int i = 0; !shouldQuote && i < len; i++) {
+                       char c = chars[i];
+
+                       if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || 
(c >= '0' && c <= '9')
+                                       || noQuoteExtras.indexOf(c) >= 0) {
+                               continue;
+                       }
+
+                       shouldQuote = true;
+               }
+
+               str = escapeString(str);
+               return (shouldQuote) ? '\"' + str + '\"' : str;
+       }
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/modeler/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOModelHelperTest.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOModelHelperTest.java
 
b/modeler/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOModelHelperTest.java
index 0d78ea6..f2b5201 100644
--- 
a/modeler/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOModelHelperTest.java
+++ 
b/modeler/cayenne-wocompat/src/test/java/org/apache/cayenne/wocompat/EOModelHelperTest.java
@@ -19,8 +19,12 @@
 
 package org.apache.cayenne.wocompat;
 
-import org.junit.Before;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -30,91 +34,86 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
 
 public class EOModelHelperTest {
 
-    protected EOModelHelper helper;
-
-    @Before
-    public void setUp() throws Exception {
-        URL url = 
getClass().getClassLoader().getResource("wotests/art.eomodeld/");
-        assertNotNull(url);
-        helper = new EOModelHelper(url);
-    }
-
-    @Test
-    public void testModelNames() throws Exception {
-        Iterator names = helper.modelNames();
-
-        // collect to list and then analyze
-        List list = new ArrayList();
-        while (names.hasNext()) {
-            list.add(names.next());
-        }
-
-        assertEquals(8, list.size());
-        assertTrue(list.contains("Artist"));
-        assertTrue(list.contains("Painting"));
-        assertTrue(list.contains("ExhibitType"));
-    }
-
-    @Test
-    public void testQueryNames() throws Exception {
-        Iterator artistNames = helper.queryNames("Artist");
-        assertFalse(artistNames.hasNext());
-
-        Iterator etNames = helper.queryNames("ExhibitType");
-        assertTrue(etNames.hasNext());
-
-        // collect to list and then analyze
-        List list = new ArrayList();
-        while (etNames.hasNext()) {
-            list.add(etNames.next());
-        }
-
-        assertEquals(2, list.size());
-        assertTrue(list.contains("FetchAll"));
-        assertTrue(list.contains("TestQuery"));
-    }
-
-    @Test
-    public void testQueryPListMap() throws Exception {
-        assertNull(helper.queryPListMap("Artist", "AAA"));
-        assertNull(helper.queryPListMap("ExhibitType", "AAA"));
-
-        Map query = helper.queryPListMap("ExhibitType", "FetchAll");
-        assertNotNull(query);
-        assertFalse(query.isEmpty());
-    }
-
-    @Test
-    public void testLoadQueryIndex() throws Exception {
-        Map index = helper.loadQueryIndex("ExhibitType");
-        assertNotNull(index);
-        assertTrue(index.containsKey("FetchAll"));
-    }
-
-    @Test
-    public void testOpenQueryStream() throws Exception {
-        InputStream in = helper.openQueryStream("ExhibitType");
-        assertNotNull(in);
-        in.close();
-    }
-
-    @Test
-    public void testOpenNonExistentQueryStream() throws Exception {
-        try {
-            helper.openQueryStream("Artist");
-            fail("Exception expected - artist has no fetch spec.");
-        }
-        catch (IOException ioex) {
-            // expected...
-        }
-    }
+       protected EOModelHelper helper;
+
+       @Before
+       public void setUp() throws Exception {
+               URL url = 
getClass().getClassLoader().getResource("wotests/art.eomodeld/");
+               assertNotNull(url);
+               helper = new EOModelHelper(url);
+       }
+
+       @Test
+       public void testModelNames() throws Exception {
+               Iterator names = helper.modelNames();
+
+               // collect to list and then analyze
+               List list = new ArrayList();
+               while (names.hasNext()) {
+                       list.add(names.next());
+               }
+
+               assertEquals(8, list.size());
+               assertTrue(list.contains("Artist"));
+               assertTrue(list.contains("Painting"));
+               assertTrue(list.contains("ExhibitType"));
+       }
+
+       @Test
+       public void testQueryNames() throws Exception {
+               Iterator artistNames = helper.queryNames("Artist");
+               assertFalse(artistNames.hasNext());
+
+               Iterator etNames = helper.queryNames("ExhibitType");
+               assertTrue(etNames.hasNext());
+
+               // collect to list and then analyze
+               List list = new ArrayList();
+               while (etNames.hasNext()) {
+                       list.add(etNames.next());
+               }
+
+               assertEquals(2, list.size());
+               assertTrue(list.contains("FetchAll"));
+               assertTrue(list.contains("TestQuery"));
+       }
+
+       @Test
+       public void testQueryPListMap() throws Exception {
+               assertNull(helper.queryPListMap("Artist", "AAA"));
+               assertNull(helper.queryPListMap("ExhibitType", "AAA"));
+
+               Map query = helper.queryPListMap("ExhibitType", "FetchAll");
+               assertNotNull(query);
+               assertFalse(query.isEmpty());
+       }
+
+       @Test
+       public void testLoadQueryIndex() throws Exception {
+               Map index = helper.loadQueryIndex("ExhibitType");
+               assertNotNull(index);
+               assertTrue(index.containsKey("FetchAll"));
+       }
+
+       @Test
+       public void testOpenQueryStream() throws Exception {
+               try (InputStream in = helper.openQueryStream("ExhibitType");) {
+                       assertNotNull(in);
+               }
+       }
+
+       @Test
+       public void testOpenNonExistentQueryStream() throws Exception {
+               try {
+                       helper.openQueryStream("Artist");
+                       fail("Exception expected - artist has no fetch spec.");
+               } catch (IOException ioex) {
+                       // expected...
+               }
+       }
 }

Reply via email to