You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2009/08/18 20:10:47 UTC

svn commit: r805519 [6/9] - in /ofbiz/branches/executioncontext20090812: ./ applications/accounting/config/ applications/accounting/data/ applications/accounting/data/helpdata/ applications/accounting/script/org/ofbiz/accounting/finaccount/ application...

Modified: ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelField.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelField.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelField.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelField.java Tue Aug 18 18:10:44 2009
@@ -1,60 +1,227 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
 package org.ofbiz.entity.model;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
+import java.util.*;
+import org.w3c.dom.*;
 
-public interface ModelField {
+import org.ofbiz.entity.jdbc.*;
+import org.ofbiz.base.util.*;
 
-    public void addValidator(String validator);
+/**
+ * Generic Entity - Field model class
+ *
+ */
+public class ModelField extends ModelChild {
 
-    /** The col-name of the Field */
-	public String getColName();
-
-    /** The description for documentation purposes */
-    public String getDescription();
-
-    public boolean getEnableAuditLog();
-
-	public boolean getEncrypt();
-
-	public boolean getIsAutoCreatedInternal();
-
-	public boolean getIsNotNull();
-
-	/** boolean which specifies whether or not the Field is a Primary Key */
-	public boolean getIsPk();
-
-	public ModelEntity getModelEntity();
-
-	/** The name of the Field */
-	public String getName();
-
-	/** The type of the Field */
-	public String getType();
-
-	/** validators to be called when an update is done */
-	public String getValidator(int index);
+    /** The name of the Field */
+    protected String name = "";
 
-	public int getValidatorsSize();
+    /** The type of the Field */
+    protected String type = "";
 
-	public String removeValidator(int index);
-
-	public void setColName(String colName);
-
-	public void setDescription(String description);
-
-	public void setEncrypt(boolean encrypt);
-
-	public void setIsAutoCreatedInternal(boolean isAutoCreatedInternal);
-
-	public void setIsNotNull(boolean isNotNull);
-
-	public void setIsPk(boolean isPk);
-
-	public void setName(String name);
-
-	public void setType(String type);
+    /** The col-name of the Field */
+    protected String colName = "";
 
-	public Element toXmlElement(Document document);
+    /** boolean which specifies whether or not the Field is a Primary Key */
+    protected boolean isPk = false;
+    protected boolean encrypt = false;
+    protected boolean isNotNull = false;
+    protected boolean isAutoCreatedInternal = false;
+    protected boolean enableAuditLog = false;
+
+    /** validators to be called when an update is done */
+    protected List<String> validators = new ArrayList<String>();
+
+    /** Default Constructor */
+    public ModelField() {}
+
+    /** Fields Constructor */
+    public ModelField(String name, String type, String colName, boolean isPk) {
+        this(name, type, colName, isPk, false, false);
+    }
+
+    public ModelField(String name, String type, String colName, boolean isPk, boolean encrypt, boolean enableAuditLog) {
+        this.name = name;
+        this.type = type;
+        this.setColName(colName);
+        this.isPk = isPk;
+        this.encrypt = encrypt;
+        this.enableAuditLog = enableAuditLog;
+    }
+
+    /** XML Constructor */
+    public ModelField(Element fieldElement) {
+        this.type = UtilXml.checkEmpty(fieldElement.getAttribute("type")).intern();
+        this.name = UtilXml.checkEmpty(fieldElement.getAttribute("name")).intern();
+        this.setColName(UtilXml.checkEmpty(fieldElement.getAttribute("col-name")).intern());
+        this.isPk = false; // is set elsewhere
+        this.encrypt = UtilXml.checkBoolean(fieldElement.getAttribute("encrypt"), false);
+        this.description = UtilXml.childElementValue(fieldElement, "description");
+        this.enableAuditLog = UtilXml.checkBoolean(fieldElement.getAttribute("enable-audit-log"), false);
+        this.isNotNull = UtilXml.checkBoolean(fieldElement.getAttribute("not-null"), false);
+
+        NodeList validateList = fieldElement.getElementsByTagName("validate");
+
+        for (int i = 0; i < validateList.getLength(); i++) {
+            Element element = (Element) validateList.item(i);
+
+            this.validators.add(UtilXml.checkEmpty(element.getAttribute("name")).intern());
+        }
+    }
+
+    /** DB Names Constructor */
+    public ModelField(DatabaseUtil.ColumnCheckInfo ccInfo, ModelFieldTypeReader modelFieldTypeReader) {
+        this.colName = ccInfo.columnName;
+        this.name = ModelUtil.dbNameToVarName(this.colName);
+
+        // figure out the type according to the typeName, columnSize and decimalDigits
+        this.type = ModelUtil.induceFieldType(ccInfo.typeName, ccInfo.columnSize, ccInfo.decimalDigits, modelFieldTypeReader);
+
+        this.isPk = ccInfo.isPk;
+    }
+
+    /** The name of the Field */
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /** The type of the Field */
+    public String getType() {
+        return this.type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
 
-}
\ No newline at end of file
+    /** The col-name of the Field */
+    public String getColName() {
+        return this.colName;
+    }
+
+    public void setColName(String colName) {
+        this.colName = colName;
+        if (this.colName == null || this.colName.length() == 0) {
+            this.colName = ModelUtil.javaNameToDbName(UtilXml.checkEmpty(this.name));
+        }
+    }
+
+    /** boolean which specifies whether or not the Field is a Primary Key */
+    public boolean getIsPk() {
+        return this.isPk;
+    }
+
+    public void setIsPk(boolean isPk) {
+        this.isPk = isPk;
+    }
+
+    public boolean getIsNotNull() {
+        return this.isNotNull;
+    }
+
+    public void setIsNotNull(boolean isNotNull) {
+        this.isNotNull = isNotNull;
+    }
+
+    public boolean getEncrypt() {
+        return this.encrypt;
+    }
+
+    public void setEncrypt(boolean encrypt) {
+        this.encrypt = encrypt;
+    }
+
+    public boolean getEnableAuditLog() {
+        return this.enableAuditLog;
+    }
+
+    public boolean getIsAutoCreatedInternal() {
+        return this.isAutoCreatedInternal;
+    }
+
+    public void setIsAutoCreatedInternal(boolean isAutoCreatedInternal) {
+        this.isAutoCreatedInternal = isAutoCreatedInternal;
+    }
+
+    /** validators to be called when an update is done */
+    public String getValidator(int index) {
+        return this.validators.get(index);
+    }
+
+    public int getValidatorsSize() {
+        return this.validators.size();
+    }
+
+    public void addValidator(String validator) {
+        this.validators.add(validator);
+    }
+
+    public String removeValidator(int index) {
+        return this.validators.remove(index);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj.getClass() != getClass()) return false;
+        ModelField other = (ModelField) obj;
+        return other.getName().equals(getName()) && other.getModelEntity() == getModelEntity();
+    }
+
+    @Override
+    public int hashCode() {
+        return getModelEntity().hashCode() ^ getName().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return getModelEntity() + "@" + getName();
+    }
+
+    public Element toXmlElement(Document document) {
+        Element root = document.createElement("field");
+        root.setAttribute("name", this.getName());
+        if (!this.getColName().equals(ModelUtil.javaNameToDbName(this.getName()))) {
+            root.setAttribute("col-name", this.getColName());
+        }
+        root.setAttribute("type", this.getType());
+        if (this.getEncrypt()) {
+            root.setAttribute("encrypt", "true");
+        }
+        if (this.getIsNotNull()) {
+            root.setAttribute("not-null", "true");
+        }
+
+        Iterator<String> valIter = this.validators.iterator();
+        if (valIter != null) {
+            while (valIter.hasNext()) {
+                String validator = valIter.next();
+                Element val = document.createElement("validate");
+                val.setAttribute("name", validator);
+                root.appendChild(val);
+            }
+        }
+
+        return root;
+    }
+}

Modified: ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelKeyMap.java Tue Aug 18 18:10:44 2009
@@ -18,24 +18,98 @@
  *******************************************************************************/
 package org.ofbiz.entity.model;
 
+import java.util.List;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilXml;
+
+
 /**
  * Generic Entity - KeyMap model class
  *
  */
-public interface ModelKeyMap {
+public class ModelKeyMap implements java.io.Serializable {
 
     /** name of the field in this entity */
-    public String getFieldName();
-
-    public void setFieldName(String fieldName);
+    protected String fieldName = "";
 
     /** name of the field in related entity */
-    public String getRelFieldName();
+    protected String relFieldName = "";
+
+    /** Default Constructor */
+    public ModelKeyMap() {}
 
-    public void setRelFieldName(String relFieldName);
+    /** Data Constructor, if relFieldName is null defaults to fieldName */
+    public ModelKeyMap(String fieldName, String relFieldName) {
+        this.fieldName = fieldName;
+        this.relFieldName = UtilXml.checkEmpty(relFieldName, this.fieldName);
+    }
+
+    /** XML Constructor */
+    public ModelKeyMap(Element keyMapElement) {
+        this.fieldName = UtilXml.checkEmpty(keyMapElement.getAttribute("field-name")).intern();
+        // if no relFieldName is specified, use the fieldName; this is convenient for when they are named the same, which is often the case
+        this.relFieldName = UtilXml.checkEmpty(keyMapElement.getAttribute("rel-field-name"), this.fieldName).intern();
+    }
+
+    /** name of the field in this entity */
+    public String getFieldName() {
+        return this.fieldName;
+    }
+
+    public void setFieldName(String fieldName) {
+        this.fieldName = fieldName;
+    }
+
+    /** name of the field in related entity */
+    public String getRelFieldName() {
+        return this.relFieldName;
+    }
+
+    public void setRelFieldName(String relFieldName) {
+        this.relFieldName = relFieldName;
+    }
+
+    // ======= Some Convenience Oriented Factory Methods =======
+    public static List<ModelKeyMap> makeKeyMapList(String fieldName1) {
+        return UtilMisc.toList(new ModelKeyMap(fieldName1, null));
+    }
+    public static List<ModelKeyMap> makeKeyMapList(String fieldName1, String relFieldName1) {
+        return UtilMisc.toList(new ModelKeyMap(fieldName1, relFieldName1));
+    }
+    public static List<ModelKeyMap> makeKeyMapList(String fieldName1, String relFieldName1, String fieldName2, String relFieldName2) {
+        return UtilMisc.toList(new ModelKeyMap(fieldName1, relFieldName1), new ModelKeyMap(fieldName2, relFieldName2));
+    }
+    public static List<ModelKeyMap> makeKeyMapList(String fieldName1, String relFieldName1, String fieldName2, String relFieldName2, String fieldName3, String relFieldName3) {
+        return UtilMisc.toList(new ModelKeyMap(fieldName1, relFieldName1), new ModelKeyMap(fieldName2, relFieldName2), new ModelKeyMap(fieldName3, relFieldName3));
+    }
+
+    @Override
+    public int hashCode() {
+        return this.fieldName.hashCode() + this.relFieldName.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof ModelKeyMap)) return false;
+        ModelKeyMap otherKeyMap = (ModelKeyMap) other;
+
+        if (!otherKeyMap.fieldName.equals(this.fieldName)) return false;
+        if (!otherKeyMap.relFieldName.equals(this.relFieldName)) return false;
+
+        return true;
+    }
+
+    public Element toXmlElement(Document document) {
+        Element root = document.createElement("key-map");
+        root.setAttribute("field-name", this.getFieldName());
+        if (!this.getFieldName().equals(this.getRelFieldName())) {
+            root.setAttribute("rel-field-name", this.getRelFieldName());
+        }
 
-    public Element toXmlElement(Document document);
+        return root;
+    }
 }

Modified: ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelReader.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelReader.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelReader.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelReader.java Tue Aug 18 18:10:44 2009
@@ -307,7 +307,7 @@
                                         }
 
                                         // create the new relationship even if one exists so we can show what we are looking for in the info message
-                                        ModelRelationImpl newRel = new ModelRelationImpl();
+                                        ModelRelation newRel = new ModelRelation();
                                         newRel.setModelEntity(relatedEnt);
                                         newRel.setRelEntityName(curModelEntity.getEntityName());
                                         newRel.setTitle(targetTitle);
@@ -315,7 +315,7 @@
                                         Set<String> curEntityKeyFields = FastSet.newInstance();
                                         for (int kmn = 0; kmn < modelRelation.getKeyMapsSize(); kmn++) {
                                             ModelKeyMap curkm = modelRelation.getKeyMap(kmn);
-                                            ModelKeyMap newkm = new ModelKeyMapImpl();
+                                            ModelKeyMap newkm = new ModelKeyMap();
                                             newRel.addKeyMap(newkm);
                                             newkm.setFieldName(curkm.getRelFieldName());
                                             newkm.setRelFieldName(curkm.getFieldName());
@@ -549,26 +549,26 @@
     ModelEntity createModelEntity(Element entityElement, UtilTimer utilTimer, ModelInfo def) {
         if (entityElement == null) return null;
         this.numEntities++;
-        ModelEntity entity = new ModelEntityImpl(this, entityElement, utilTimer, def);
+        ModelEntity entity = new ModelEntity(this, entityElement, utilTimer, def);
         return entity;
     }
 
     ModelEntity createModelViewEntity(Element entityElement, UtilTimer utilTimer, ModelInfo def) {
         if (entityElement == null) return null;
         this.numViewEntities++;
-        ModelViewEntity entity = new ModelViewEntityImpl(this, entityElement, utilTimer, def);
+        ModelViewEntity entity = new ModelViewEntity(this, entityElement, utilTimer, def);
         return entity;
     }
 
     public ModelRelation createRelation(ModelEntity entity, Element relationElement) {
         this.numRelations++;
-        ModelRelation relation = new ModelRelationImpl(entity, relationElement);
+        ModelRelation relation = new ModelRelation(entity, relationElement);
         return relation;
     }
 
     public ModelField findModelField(ModelEntity entity, String fieldName) {
-        for (ModelField field: entity.getFieldsUnmodifiable()) {
-            if (field.getName().compareTo(fieldName) == 0) {
+        for (ModelField field: entity.fields) {
+            if (field.name.compareTo(fieldName) == 0) {
                 return field;
             }
         }
@@ -577,7 +577,7 @@
 
     public ModelField createModelField(String name, String type, String colName, boolean isPk) {
         this.numFields++;
-        ModelField field = new ModelFieldImpl(name, type, colName, isPk);
+        ModelField field = new ModelField(name, type, colName, isPk);
         return field;
     }
 
@@ -587,7 +587,7 @@
         }
 
         this.numFields++;
-        ModelField field = new ModelFieldImpl(fieldElement);
+        ModelField field = new ModelField(fieldElement);
         return field;
     }
 }

Modified: ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelRelation.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelRelation.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelRelation.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelRelation.java Tue Aug 18 18:10:44 2009
@@ -18,70 +18,299 @@
  */
 package org.ofbiz.entity.model;
 
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
+import javolution.util.FastList;
+
+import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.UtilXml;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
 
 /**
  * Generic Entity - Relation model class
  *
  */
-public interface ModelRelation {
+public class ModelRelation extends ModelChild {
 
-    /** Find a KeyMap with the specified fieldName */
-    public ModelKeyMap findKeyMap(String fieldName);
+    /** the title, gives a name/description to the relation */
+    protected String title;
 
-    /** Find a KeyMap with the specified relFieldName */
-    public ModelKeyMap findKeyMapByRelated(String relFieldName);
+    /** the type: either "one" or "many" or "one-nofk" */
+    protected String type;
 
-    public String getCombinedName();
+    /** the name of the related entity */
+    protected String relEntityName;
 
-    /** The description for documentation purposes */
-    public String getDescription();
+    /** the name to use for a database foreign key, if applies */
+    protected String fkName;
 
-    public String getFkName();
+    /** keyMaps defining how to lookup the relatedTable using columns from this table */
+    protected List<ModelKeyMap> keyMaps = new ArrayList<ModelKeyMap>();
 
-    public ModelKeyMap getKeyMap(int index);
+    /** the main entity of this relation */
+    protected ModelEntity mainEntity = null;
 
-    public List<ModelKeyMap> getKeyMapsClone();
+    protected boolean isAutoRelation = false;
 
-    /** keyMaps defining how to lookup the relatedTable using columns from this table */
-    public Iterator<ModelKeyMap> getKeyMapsIterator();
+    /** Default Constructor */
+    public ModelRelation() {
+        title = "";
+        type = "";
+        relEntityName = "";
+        fkName = "";
+    }
+
+    /** Default Constructor */
+    public ModelRelation(String type, String title, String relEntityName, String fkName, List<ModelKeyMap> keyMaps) {
+        this.title = title;
+        if (title == null) title = "";
+        this.type = type;
+        this.relEntityName = relEntityName;
+        this.fkName = fkName;
+        this.keyMaps.addAll(keyMaps);
+    }
+
+    /** XML Constructor */
+    public ModelRelation(ModelEntity mainEntity, Element relationElement) {
+        this.mainEntity = mainEntity;
+
+        this.type = UtilXml.checkEmpty(relationElement.getAttribute("type")).intern();
+        this.title = UtilXml.checkEmpty(relationElement.getAttribute("title")).intern();
+        this.relEntityName = UtilXml.checkEmpty(relationElement.getAttribute("rel-entity-name")).intern();
+        this.fkName = UtilXml.checkEmpty(relationElement.getAttribute("fk-name")).intern();
+        this.description = StringUtil.internString(UtilXml.childElementValue(relationElement, "description"));
+
+        NodeList keyMapList = relationElement.getElementsByTagName("key-map");
+        for (int i = 0; i < keyMapList.getLength(); i++) {
+            Element keyMapElement = (Element) keyMapList.item(i);
+
+            if (keyMapElement.getParentNode() == relationElement) {
+                ModelKeyMap keyMap = new ModelKeyMap(keyMapElement);
+
+                if (keyMap != null) {
+                    this.keyMaps.add(keyMap);
+                }
+            }
+        }
+    }
+
+    public String getCombinedName() {
+        return this.title + this.relEntityName;
+    }
 
-    public int getKeyMapsSize();
+    /** the title, gives a name/description to the relation */
+    public String getTitle() {
+        if (this.title == null) {
+            this.title = "";
+        }
+        return this.title;
+    }
+
+    public void setTitle(String title) {
+        if (title == null) {
+            this.title = "";
+        } else {
+            this.title = title;
+        }
+    }
 
-    /** @deprecated
-     * the main entity of this relation */
-   @Deprecated
-   public ModelEntity getMainEntity();
+    /** the type: either "one" or "many" or "one-nofk" */
+    public String getType() {
+        return this.type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
 
     /** the name of the related entity */
-    public String getRelEntityName();
+    public String getRelEntityName() {
+        return this.relEntityName;
+    }
+
+    public void setRelEntityName(String relEntityName) {
+        this.relEntityName = relEntityName;
+    }
+
+    public String getFkName() {
+        return this.fkName;
+    }
+
+    public void setFkName(String fkName) {
+        this.fkName = fkName;
+    }
 
-    /** the title, gives a name/description to the relation */
-    public String getTitle();
+    /** @deprecated
+      * the main entity of this relation */
+    @Deprecated
+    public ModelEntity getMainEntity() {
+        return getModelEntity();
+    }
+
+    /** @deprecated */
+    @Deprecated
+    public void setMainEntity(ModelEntity mainEntity) {
+        setModelEntity(mainEntity);
+    }
 
-    /** the type: either "one" or "many" or "one-nofk" */
-    public String getType();
+    /** keyMaps defining how to lookup the relatedTable using columns from this table */
+    public Iterator<ModelKeyMap> getKeyMapsIterator() {
+        return this.keyMaps.iterator();
+    }
+
+    public List<ModelKeyMap> getKeyMapsClone() {
+        List<ModelKeyMap> kmList = FastList.newInstance();
+        kmList.addAll(this.keyMaps);
+        return kmList;
+    }
+
+    public int getKeyMapsSize() {
+        return this.keyMaps.size();
+    }
+
+    public ModelKeyMap getKeyMap(int index) {
+        return this.keyMaps.get(index);
+    }
+
+    public void addKeyMap(ModelKeyMap keyMap) {
+        this.keyMaps.add(keyMap);
+    }
+
+    public ModelKeyMap removeKeyMap(int index) {
+        return this.keyMaps.remove(index);
+    }
+
+    /** Find a KeyMap with the specified fieldName */
+    public ModelKeyMap findKeyMap(String fieldName) {
+        for (ModelKeyMap keyMap: keyMaps) {
+            if (keyMap.fieldName.equals(fieldName)) return keyMap;
+        }
+        return null;
+    }
+
+    /** Find a KeyMap with the specified relFieldName */
+    public ModelKeyMap findKeyMapByRelated(String relFieldName) {
+        for (ModelKeyMap keyMap: keyMaps) {
+            if (keyMap.relFieldName.equals(relFieldName))
+                return keyMap;
+        }
+        return null;
+    }
+
+    public String keyMapString(String separator, String afterLast) {
+        String returnString = "";
+
+        if (keyMaps.size() < 1) {
+            return "";
+        }
+
+        int i = 0;
+
+        for (; i < keyMaps.size() - 1; i++) {
+            returnString = returnString + keyMaps.get(i).fieldName + separator;
+        }
+        returnString = returnString + keyMaps.get(i).fieldName + afterLast;
+        return returnString;
+    }
+
+    public String keyMapUpperString(String separator, String afterLast) {
+        if (keyMaps.size() < 1)
+            return "";
+
+        StringBuilder returnString = new StringBuilder(keyMaps.size() * 10);
+        int i=0;
+        while (true) {
+            ModelKeyMap kmap = keyMaps.get(i);
+            returnString.append(ModelUtil.upperFirstChar(kmap.fieldName));
+
+            i++;
+            if (i >= keyMaps.size()) {
+                returnString.append(afterLast);
+                break;
+            }
+
+            returnString.append(separator);
+        }
+
+        return returnString.toString();
+    }
+
+    public String keyMapRelatedUpperString(String separator, String afterLast) {
+        if (keyMaps.size() < 1)
+            return "";
+
+        StringBuilder returnString = new StringBuilder(keyMaps.size() * 10);
+        int i=0;
+        while (true) {
+            ModelKeyMap kmap = keyMaps.get(i);
+            returnString.append(ModelUtil.upperFirstChar(kmap.relFieldName));
+
+            i++;
+            if (i >= keyMaps.size()) {
+                returnString.append(afterLast);
+                break;
+            }
+
+            returnString.append(separator);
+        }
 
+        return returnString.toString();
+    }
     /**
      * @return Returns the isAutoRelation.
      */
-    public boolean isAutoRelation();
-
+    public boolean isAutoRelation() {
+        return isAutoRelation;
+    }
     /**
      * @param isAutoRelation The isAutoRelation to set.
      */
-    public void setAutoRelation(boolean isAutoRelation);
-
-    public void setFkName(String fkName);
-
-    public void setRelEntityName(String relEntityName);
-
-    public void setTitle(String title);
-    public void setType(String type);
+    public void setAutoRelation(boolean isAutoRelation) {
+        this.isAutoRelation = isAutoRelation;
+    }
+
+    // FIXME: CCE
+    @Override
+    public boolean equals(Object other) {
+        ModelRelation otherRel = (ModelRelation) other;
+
+        if (!otherRel.type.equals(this.type)) return false;
+        if (!otherRel.title.equals(this.title)) return false;
+        if (!otherRel.relEntityName.equals(this.relEntityName)) return false;
+
+        Set<ModelKeyMap> thisKeyNames = new HashSet<ModelKeyMap>(this.keyMaps);
+        Set<ModelKeyMap> otherKeyNames = new HashSet<ModelKeyMap>(otherRel.keyMaps);
+        if (!thisKeyNames.containsAll(otherKeyNames)) return false;
+        if (!otherKeyNames.containsAll(thisKeyNames)) return false;
+
+        return true;
+    }
+
+    public Element toXmlElement(Document document) {
+        Element root = document.createElement("relation");
+        root.setAttribute("type", this.getType());
+        if (UtilValidate.isNotEmpty(this.getTitle())) {
+            root.setAttribute("title", this.getTitle());
+        }
+        root.setAttribute("rel-entity-name", this.getRelEntityName());
+
+        if (UtilValidate.isNotEmpty(this.getFkName())) {
+            root.setAttribute("fk-name", this.getFkName());
+        }
+
+        Iterator<ModelKeyMap> kmIter = this.getKeyMapsIterator();
+        while (kmIter != null && kmIter.hasNext()) {
+            ModelKeyMap km = kmIter.next();
+            root.appendChild(km.toXmlElement(document));
+        }
 
-    public Element toXmlElement(Document document);
+        return root;
+    }
 }