blob: 9c0d5aa7b9df647e82601f283e29926ab57a8102 [file] [log] [blame]
/*
* 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.apache.ofbiz.entity.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.ofbiz.base.lang.ThreadSafe;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.base.util.UtilXml;
import org.apache.ofbiz.entity.jdbc.DatabaseUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* An object that models the <code>&lt;relation&gt;</code> element.
*
*/
@ThreadSafe
@SuppressWarnings("serial")
public final class ModelRelation extends ModelChild {
/*
* Developers - this is an immutable class. Once constructed, the object should not change state.
* Therefore, 'setter' methods are not allowed. If client code needs to modify the object's
* state, then it can create a new copy with the changed values.
*/
/** the title, gives a name/description to the relation */
private final String title;
/** the type: either "one" or "many" or "one-nofk" */
private final String type;
/** the name of the related entity */
private final String relEntityName;
/** the name to use for a database foreign key, if applies */
private final String fkName;
/** keyMaps defining how to lookup the relatedTable using columns from this table */
private final List<ModelKeyMap> keyMaps;
private final boolean isAutoRelation;
/** A String to uniquely identify this relation. */
private final String fullName;
private final String combinedName;
/**
* Returns a new <code>ModelRelation</code> instance, initialized with the specified values.
* @param modelEntity The <code>ModelEntity</code> this relation is a member of.
* @param description The relation description.
* @param type The relation type.
* @param title The relation title.
* @param relEntityName The related entity's name.
* @param fkName The foreign key name.
* @param keyMaps The key maps included in this relation.
* @param isAutoRelation <code>true</code> if this relation was generated automatically by the entity engine.
*/
public static ModelRelation create(ModelEntity modelEntity, String description, String type, String title, String relEntityName,
String fkName, List<ModelKeyMap> keyMaps, boolean isAutoRelation) {
if (description == null) {
description = "";
}
if (type == null) {
type = "";
}
if (title == null) {
title = "";
}
if (relEntityName == null) {
relEntityName = "";
}
if (fkName == null) {
fkName = "";
}
if (keyMaps == null) {
keyMaps = Collections.emptyList();
} else {
keyMaps = Collections.unmodifiableList(keyMaps);
}
return new ModelRelation(modelEntity, description, type, title, relEntityName, fkName, keyMaps, isAutoRelation);
}
/**
* Returns a new <code>ModelRelation</code> instance, initialized with the specified values.
* @param modelEntity The <code>ModelEntity</code> this relation is a member of.
* @param relationElement The <code>&lt;relation&gt;</code> element containing the values for this relation.
* @param isAutoRelation <code>true</code> if this relation was generated automatically by the entity engine.
*/
public static ModelRelation create(ModelEntity modelEntity, Element relationElement, boolean isAutoRelation) {
String type = relationElement.getAttribute("type").intern();
String title = relationElement.getAttribute("title").intern();
String relEntityName = relationElement.getAttribute("rel-entity-name").intern();
String fkName = relationElement.getAttribute("fk-name").intern();
String description = UtilXml.childElementValue(relationElement, "description");
List<ModelKeyMap> keyMaps = Collections.emptyList();
List<? extends Element> elementList = UtilXml.childElementList(relationElement, "key-map");
if (!elementList.isEmpty()) {
keyMaps = new ArrayList<>(elementList.size());
for (Element keyMapElement : elementList) {
keyMaps.add(new ModelKeyMap(keyMapElement));
}
keyMaps = Collections.unmodifiableList(keyMaps);
}
return new ModelRelation(modelEntity, description, type, title, relEntityName, fkName, keyMaps, isAutoRelation);
}
public static ModelRelation create(ModelEntity modelEntity, DatabaseUtil.ReferenceCheckInfo refInfo, boolean isAutoRelation) {
String fkName = refInfo.getFkName();
String title = null;
String type = null;
String description = null;
String relEntityName = ModelUtil.dbNameToClassName(refInfo.getPkTableName());
List<ModelKeyMap> keyMaps = refInfo.toModelKeyMapList();
return new ModelRelation(modelEntity, description, type, title, relEntityName, fkName, keyMaps, isAutoRelation);
}
private ModelRelation(ModelEntity modelEntity, String description, String type, String title, String relEntityName, String fkName,
List<ModelKeyMap> keyMaps, boolean isAutoRelation) {
super(modelEntity, description);
this.title = title;
this.type = type;
this.relEntityName = relEntityName;
this.fkName = fkName;
this.keyMaps = keyMaps;
this.isAutoRelation = isAutoRelation;
StringBuilder sb = new StringBuilder();
sb.append(modelEntity == null ? "Unknown" : modelEntity.getEntityName()).append("->").append(title).append(relEntityName).append("[");
Set<ModelKeyMap> keyMapSet = new TreeSet<>(keyMaps);
Iterator<ModelKeyMap> setIter = keyMapSet.iterator();
while (setIter.hasNext()) {
ModelKeyMap keyMap = setIter.next();
sb.append(keyMap);
if (setIter.hasNext()) {
sb.append(",");
}
}
sb.append("]");
this.fullName = sb.toString();
this.combinedName = title != null ? title.concat(relEntityName) : relEntityName;
}
/** Returns the combined name (title + related entity name). */
public String getCombinedName() {
return this.combinedName;
}
/** Returns the title. */
public String getTitle() {
return this.title;
}
/** Returns the type. */
public String getType() {
return this.type;
}
/** Returns the related entity name. */
public String getRelEntityName() {
return this.relEntityName;
}
/** Returns the foreign key name. */
public String getFkName() {
return this.fkName;
}
/** Returns the key maps. */
public List<ModelKeyMap> getKeyMaps() {
return this.keyMaps;
}
/** Returns <code>true</code> if this relation was generated automatically by the entity engine. */
public boolean isAutoRelation() {
return isAutoRelation;
}
/** Find a KeyMap with the specified fieldName */
public ModelKeyMap findKeyMap(String fieldName) {
for (ModelKeyMap keyMap: keyMaps) {
if (keyMap.getFieldName().equals(fieldName)) return keyMap;
}
return null;
}
/** Find a KeyMap with the specified relFieldName */
public ModelKeyMap findKeyMapByRelated(String relFieldName) {
for (ModelKeyMap keyMap: keyMaps) {
if (keyMap.getRelFieldName().equals(relFieldName)) {
return keyMap;
}
}
return null;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ModelRelation) {
ModelRelation that = (ModelRelation) obj;
return this.fullName.equals(that.fullName);
}
return false;
}
@Override
public int hashCode() {
return this.fullName.hashCode();
}
@Override
public String toString() {
return this.fullName;
}
// TODO: Externalize this.
public String keyMapString(String separator, String afterLast) {
StringBuilder stringBuilder = new StringBuilder("");
if (keyMaps.size() < 1) {
return "";
}
int i = 0;
for (; i < keyMaps.size() - 1; i++) {
stringBuilder.append(keyMaps.get(i).getFieldName());
stringBuilder.append(separator);
}
stringBuilder.append(keyMaps.get(i).getFieldName());
stringBuilder.append(afterLast);
return stringBuilder.toString();
}
// TODO: Externalize this.
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.getFieldName()));
i++;
if (i >= keyMaps.size()) {
returnString.append(afterLast);
break;
}
returnString.append(separator);
}
return returnString.toString();
}
// TODO: Externalize this.
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.getRelFieldName()));
i++;
if (i >= keyMaps.size()) {
returnString.append(afterLast);
break;
}
returnString.append(separator);
}
return returnString.toString();
}
// TODO: Externalize this.
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.keyMaps.iterator();
while (kmIter != null && kmIter.hasNext()) {
ModelKeyMap km = kmIter.next();
root.appendChild(km.toXmlElement(document));
}
return root;
}
}