/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.dm.eo.model;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.logging.FlexoLogger;
import org.openflexo.toolbox.PListHelper;
/**
* @author gpolet
*
*/
public class EOAttribute extends EOProperty {
private static final Logger logger = FlexoLogger.getLogger(EOAttribute.class.getPackage().getName());
private static final String COLUMN_NAME_KEY = "columnName";
private static final String PROTOTYPE_NAME_KEY = "prototypeName";
private static final String CLASS_NAME_KEY = "className";
private static final String ALLOWS_NULL_KEY = "allowsNull";
private static final String WIDTH_KEY = "width";
private static final String EXTERNAL_TYPE_KEY = "externalType";
private static final String IS_READ_ONLY_KEY = "isReadOnly";
private static final String VALUE_TYPE_KEY = "valueType";
private static final String VALUE_CLASS_NAME_KEY = "valueClassName";
private String className;
private String columnName;
private String valueType;
private boolean allowsNull;
private boolean isReadOnly;
private int width;
private String externalType;
private EOAttribute prototype;
/**
* Incoming relationships are relationships that have one of their join that has this attribute as a destination attribute
*/
private Vector<EORelationship> incomingRelationships;
/**
* Outgoing relationships are relationships that have one of their join that has this attribute as a source attribute
*/
private Vector<EORelationship> outgoingRelationships;
public static EOAttribute createAttributeFromMap(Map<Object, Object> map) {
return createAttributeFromMap(map, null);
}
public static EOAttribute createAttributeFromMap(Map<Object, Object> map, EOEntity entity) {
EOAttribute attribute = new EOAttribute();
attribute.setOriginalMap(map);
attribute.setName((String) map.get(NAME_KEY));
attribute.setColumnName((String) map.get(COLUMN_NAME_KEY));
attribute.setClassName((String) map.get(CLASS_NAME_KEY));
if (map.get(CLASS_NAME_KEY) == null && map.get(VALUE_CLASS_NAME_KEY) != null) {
attribute.setClassName(getJavaNameForNSClassName((String) map.get(VALUE_CLASS_NAME_KEY)));
}
attribute.setValueType((String) map.get(VALUE_TYPE_KEY));
if (map.get(WIDTH_KEY) != null) {
attribute.setWidth(PListHelper.getInteger(map.get(WIDTH_KEY)));
} else {
attribute.setWidth(0);
}
attribute.setExternalType((String) map.get(EXTERNAL_TYPE_KEY));
if (map.get(ALLOWS_NULL_KEY) != null) {
attribute.setAllowsNull(PListHelper.getBoolean(map.get(ALLOWS_NULL_KEY)));
} else {
attribute.setAllowsNull(true);
}
if (map.get(IS_READ_ONLY_KEY) != null) {
attribute.setIsReadOnly(PListHelper.getBoolean(map.get(IS_READ_ONLY_KEY)));
} else {
attribute.setIsReadOnly(false);
}
attribute.setEntity(entity);
if (attribute.getValueType() != null && attribute.getValueType().trim().length() > 0) {
if (attribute.getValueType().equals("b")) {
attribute.setClassName("java.lang.Byte");
} else if (attribute.getValueType().equals("s")) {
attribute.setClassName("java.lang.Short");
} else if (attribute.getValueType().equals("i")) {
attribute.setClassName("java.lang.Integer");
} else if (attribute.getValueType().equals("l")) {
attribute.setClassName("java.lang.Long");
} else if (attribute.getValueType().equals("f")) {
attribute.setClassName("java.lang.Float");
} else if (attribute.getValueType().equals("d")) {
attribute.setClassName("java.lang.Double");
} else if (attribute.getValueType().equals("B")) {
attribute.setClassName("java.math.BigDecimal");
} else if (attribute.getValueType().equals("c")) {
attribute.setClassName("java.lang.Boolean");
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Unknown valueType: " + attribute.getValueType() + ". We will use String");
}
attribute.setClassName("java.lang.String");
}
}
return attribute;
}
public EOAttribute() {
incomingRelationships = new Vector<EORelationship>();
outgoingRelationships = new Vector<EORelationship>();
createHashMap();
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getValueType() {
return valueType;
}
public void setValueType(String valueType) {
this.valueType = valueType;
}
public String getExternalType() {
return externalType;
}
public void setExternalType(String externalType) {
this.externalType = externalType;
}
public boolean getAllowsNull() {
return allowsNull;
}
public void setAllowsNull(boolean allowsNull) {
this.allowsNull = allowsNull;
}
public boolean getIsReadOnly() {
return isReadOnly;
}
public void setIsReadOnly(boolean isReadOnly) {
this.isReadOnly = isReadOnly;
}
public EOAttribute getPrototype() {
return prototype;
}
public void setPrototype(EOAttribute prototype) {
this.prototype = prototype;
if (prototype != null) {
this.width = prototype.getWidth();
}
}
public int getWidth() {
if (this.width == 0 && prototype != null) {
this.width = prototype.getWidth();
}
return width;
}
public void setWidth(int width) {
this.width = width;
}
/**
* @return
*/
public boolean getIsPrimaryKey() {
if (getEntity() != null) {
return getEntity().getPrimaryKeyAttributes().contains(this);
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Impossible to determine if attribute is primary key because it has no entity");
}
return false;
}
public boolean getIsUsedForLocking() {
if (getEntity() != null) {
return getEntity().getAttributesUsedForLocking().contains(this);
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Impossible to determine if attribute is used for locking because it has no entity");
}
return false;
}
/**
* Overrides resolveObjects
*
* @see org.openflexo.foundation.dm.eo.model.EOObject#resolveObjects()
*/
@Override
protected void resolveObjects() {
String prototype = (String) getOriginalMap().get(PROTOTYPE_NAME_KEY);
if (prototype != null) {
EOAttribute a = getEntity().getModel().getPrototypeNamed(prototype);
if (a != null) {
this.prototype = a;
}
}
}
public void addToIncomingRelationships(EORelationship relationship) {
if (!incomingRelationships.contains(relationship)) {
incomingRelationships.add(relationship);
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Attempt to add twice the same relationship to incoming relationships of entity " + getName());
}
}
public void removeFromIncomingRelationships(EORelationship relationship) {
incomingRelationships.remove(relationship);
}
public void addToOutgoingRelationships(EORelationship relationship) {
if (!outgoingRelationships.contains(relationship)) {
outgoingRelationships.add(relationship);
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Attempt to add twice the same relationship to outgoing relationships of entity " + getName());
}
}
public void removeFromOutgoingRelationships(EORelationship relationship) {
outgoingRelationships.remove(relationship);
}
public String getPListRepresentation() {
return FlexoPropertyListSerialization.getPListRepresentation(getMapRepresentation());
}
public Map<Object, Object> getMapRepresentation() {
Map<Object, Object> map = new HashMap<Object, Object>();
if (getName() != null) {
map.put(NAME_KEY, getName());
} else {
map.remove(NAME_KEY);
}
if (getColumnName() != null) {
map.put(COLUMN_NAME_KEY, getColumnName());
} else {
map.remove(COLUMN_NAME_KEY);
}
if (getClassName() != null) {
map.put(CLASS_NAME_KEY, getClassName());
} else {
map.remove(CLASS_NAME_KEY);
}
if (getValueType() != null) {
map.put(VALUE_TYPE_KEY, getValueType());
} else {
map.remove(VALUE_TYPE_KEY);
}
if (getWidth() != 0) {
map.put(WIDTH_KEY, PListHelper.getObject(getWidth()));
} else {
map.remove(WIDTH_KEY);
}
if (getExternalType() != null) {
map.put(EXTERNAL_TYPE_KEY, getExternalType());
} else {
map.remove(EXTERNAL_TYPE_KEY);
}
if (!getAllowsNull()) {
map.put(ALLOWS_NULL_KEY, PListHelper.getObject(getAllowsNull()));
} else {
map.remove(ALLOWS_NULL_KEY);
}
if (getIsReadOnly()) {
map.put(IS_READ_ONLY_KEY, PListHelper.getObject(getIsReadOnly()));
} else {
map.remove(IS_READ_ONLY_KEY);
}
if (getPrototype() != null) {
map.put(PROTOTYPE_NAME_KEY, getPrototype().getName());
} else {
map.remove(PROTOTYPE_NAME_KEY);
}
return map;
}
/**
* Updates the original map so that it matches the in-memory model
*/
public void synchronizeObjectWithOriginalMap() {
Map<Object, Object> map = getOriginalMap();
if (getName() != null) {
map.put(NAME_KEY, getName());
} else {
map.remove(NAME_KEY);
}
if (getColumnName() != null) {
map.put(COLUMN_NAME_KEY, getColumnName());
} else {
map.remove(COLUMN_NAME_KEY);
}
if (getClassName() != null) {
map.put(CLASS_NAME_KEY, getClassName());
} else {
map.remove(CLASS_NAME_KEY);
}
if (getValueType() != null) {
map.put(VALUE_TYPE_KEY, getValueType());
} else {
map.remove(VALUE_TYPE_KEY);
}
if (getWidth() != 0) {
map.put(WIDTH_KEY, PListHelper.getObject(getWidth()));
} else {
map.remove(WIDTH_KEY);
}
if (getExternalType() != null) {
map.put(EXTERNAL_TYPE_KEY, getExternalType());
} else {
map.remove(EXTERNAL_TYPE_KEY);
}
if (!getAllowsNull()) {
map.put(ALLOWS_NULL_KEY, PListHelper.getObject(getAllowsNull()));
} else {
map.remove(ALLOWS_NULL_KEY);
}
if (getIsReadOnly()) {
map.put(IS_READ_ONLY_KEY, PListHelper.getObject(getIsReadOnly()));
} else {
map.remove(IS_READ_ONLY_KEY);
}
if (getPrototype() != null) {
map.put(PROTOTYPE_NAME_KEY, getPrototype().getName());
} else {
map.remove(PROTOTYPE_NAME_KEY);
}
}
/**
* Overrides delete
*
* @see org.openflexo.foundation.dm.eo.model.EOObject#delete()
*/
@SuppressWarnings("unchecked")
@Override
public void delete() {
Iterator<EORelationship> i = ((Vector) incomingRelationships.clone()).iterator();
while (i.hasNext()) {
EORelationship r = i.next();
EOJoin j = r.joinWithDestinationAttribute(this);
try {
j.setDestinationAttribute(null);
} catch (InvalidJoinException e) {
// NEVER happen because arg is null
}
}
Iterator<EORelationship> k = ((Vector) outgoingRelationships.clone()).iterator();
while (k.hasNext()) {
EORelationship r = k.next();
EOJoin j = r.joinWithSourceAttribute(this);
try {
j.setSourceAttribute(null);
} catch (InvalidJoinException e) {
// NEVER happen because arg is null
}
}
getEntity().removeAttribute(this);
}
/**
* Overrides clearObjects
*
* @see org.openflexo.foundation.dm.eo.model.EOObject#clearObjects()
*/
@Override
protected void clearObjects() {
incomingRelationships.clear();
outgoingRelationships.clear();
prototype = null;
}
private static String getJavaNameForNSClassName(String nsClassName) {
if (nsClassName.startsWith("NS")) {
if (nsClassName.equals("NSString")) {
return "java.lang.String";
}
if (nsClassName.equals("NSNumber")) {
return "java.lang.Number";
}
if (nsClassName.equals("NSDecimalNumber")) {
return "java.math.BigDecimal";
}
if (nsClassName.equals("NSCalendarDate")) {
return "java.util.Date";
}
if (nsClassName.equals("NSGregorianDate")) {
return "java.util.Date";
}
if (nsClassName.equals("NSData")) {
return "com.webobjects.foundation.NSData";
}
} else if (nsClassName.equals("")) {
return null;
}
return nsClassName;
}
public Vector<EORelationship> getIncomingRelationships() {
return incomingRelationships;
}
public Vector<EORelationship> getOutgoingRelationships() {
return outgoingRelationships;
}
/**
* @param isPK
*/
public void setIsPrimaryKey(boolean isPK) {
if (getEntity() == null) {
throw new IllegalStateException("Trying to set a attribute as primary key while the attribute has no entity");
}
if (getIsPrimaryKey() != isPK) {
if (isPK) {
getEntity().getPrimaryKeyAttributes().add(this);
} else {
getEntity().getPrimaryKeyAttributes().remove(this);
}
}
}
/**
* @param isUsedForLocking
*/
public void setIsUsedForLocking(boolean isUsedForLocking) {
if (getEntity() == null) {
throw new IllegalStateException("Trying to set a attribute as an attribute used for locking while the attribute has no entity");
}
if (getIsUsedForLocking() != isUsedForLocking) {
if (isUsedForLocking) {
getEntity().getAttributesUsedForLocking().add(this);
} else {
getEntity().getAttributesUsedForLocking().remove(this);
}
}
}
/**
* Overrides toString
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "EOAttribute " + getName() + " " + getEntity() != null ? getEntity().getName() : "no entity";
}
}