/*
* (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;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.antar.expr.EvaluationType;
import org.openflexo.foundation.DataModification;
import org.openflexo.foundation.FlexoObservable;
import org.openflexo.foundation.FlexoObserver;
import org.openflexo.foundation.TemporaryFlexoModelObject;
import org.openflexo.foundation.dkv.DKVModel;
import org.openflexo.foundation.dkv.Domain;
import org.openflexo.foundation.dm.DMEntity.DMTypeVariable;
import org.openflexo.foundation.dm.dm.DMEntityClassNameChanged;
import org.openflexo.foundation.dm.dm.EntityDeleted;
import org.openflexo.foundation.dm.eo.DMEOEntity;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.inspector.InspectableObject;
import org.openflexo.inspector.InspectorObserver;
import org.openflexo.inspector.model.TabModel;
import org.openflexo.kvc.KeyValueCoding;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.toolbox.Duration;
import org.openflexo.xmlcode.KeyValueCoder;
import org.openflexo.xmlcode.KeyValueDecoder;
import org.openflexo.xmlcode.StringConvertable;
import org.openflexo.xmlcode.StringEncoder;
import org.openflexo.xmlcode.StringEncoder.Converter;
import com.thoughtworks.qdox.model.JavaClassParent;
import com.thoughtworks.qdox.model.Type;
/**
* Represents a Type in DataModel
*
* Take care that a type is here mutable: don't try to implement caches !!!!
*
* @author sylvain
*
*/
public class DMType extends Type implements FlexoObserver, StringConvertable<DMType>, KeyValueCoding, DMTypeOwner, InspectableObject,
java.lang.reflect.Type {
protected static final Logger logger = Logger.getLogger(DMType.class.getPackage().getName());
// UNRESOLVED types
private String name;
// RESOLVED types
private DMEntity baseEntity;
Vector<DMType> parameters;
private int dimensions;
// DKV types
private Domain domain;
// TYPE_VARIABLE types
private DMTypeVariable typeVariable;
// WILDCARD types
Vector<WildcardBound> lowerBounds;
Vector<WildcardBound> upperBounds;
private Vector<Typed> typedWithThisType;
// private DMGenericDeclaration typeVariableContext;
private DMTypeOwner _owner;
private FlexoProject _project;
private Vector<ParameterizedTypeVariable> _parameterizedTypeVariables = null;
private boolean triedToResolve = false;
private boolean isResolved = false;
protected org.openflexo.foundation.dm.DMType.DMTypeStringConverter.ParsedTypeInfo _pendingInformations;
public static final String DKV_PREFIX = "DKV.";
@Override
public DMType clone() {
DMType clone = new DMType(getStringRepresentation());
// System.out.println("Cloned as "+Integer.toHexString(clone.typeId)+" from "+Integer.toHexString(typeId)+" : "+getStringRepresentation()+" which is "+getKindOfType());
clone._owner = _owner;
clone._project = _project;
clone.name = name;
clone.baseEntity = baseEntity;
clone.parameters.addAll(parameters);
clone.dimensions = dimensions;
clone.domain = domain;
clone.typeVariable = typeVariable;
// clone.typeVariableContext = typeVariableContext;
if (lowerBounds != null) {
clone.lowerBounds = new Vector<WildcardBound>();
clone.lowerBounds.addAll(lowerBounds);
}
if (upperBounds != null) {
clone.upperBounds = new Vector<WildcardBound>();
clone.upperBounds.addAll(upperBounds);
}
if (_parameterizedTypeVariables != null) {
clone._parameterizedTypeVariables = new Vector<ParameterizedTypeVariable>();
clone._parameterizedTypeVariables.addAll(_parameterizedTypeVariables);
}
clone.typedWithThisType.addAll(typedWithThisType);
clone.triedToResolve = triedToResolve;
clone.isResolved = isResolved;
clone._pendingInformations = _pendingInformations;
return clone;
}
public static EvaluationType kindOf(DMType type) {
if (type.isBoolean()) {
return EvaluationType.BOOLEAN;
} else if (type.isInteger() || type.isLong() || type.isShort() || type.isChar() || type.isByte()) {
return EvaluationType.ARITHMETIC_INTEGER;
} else if (type.isFloat() || type.isDouble()) {
return EvaluationType.ARITHMETIC_FLOAT;
} else if (type.isString()) {
return EvaluationType.STRING;
} else if (type.isDate()) {
return EvaluationType.DATE;
} else if (type.isDuration()) {
return EvaluationType.DURATION;
} else if (type.getKindOfType() == KindOfType.DKV) {
return EvaluationType.ENUM;
}
return EvaluationType.LITERAL;
}
// ==========================================================
// =================== Factory methods ======================
// ==========================================================
public static DMType makeUnresolvedDMType(String unresolvedTypeName) {
return new DMType(unresolvedTypeName);
}
public static DMType makeUnresolvedDMType(String unresolvedTypeName, int dimensions) {
return new DMType(unresolvedTypeName, dimensions);
}
public static DMType makeResolvedDMType(DMEntity entity) {
return new DMType(entity);
}
public static DMType makeResolvedDMType(Class<?> typeClass, FlexoProject project) {
DMEntity accessedEntity = project.getDataModel().getDMEntity(typeClass, true);
if (accessedEntity != null) {
return makeResolvedDMType(accessedEntity);
}
return null;
}
public static DMType makeObjectDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Object.class));
}
public static DMType makeLongDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Long.class));
}
public static DMType makeIntegerDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Integer.class));
}
public static DMType makeShortDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Short.class));
}
public static DMType makeDoubleDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Double.class));
}
public static DMType makeBooleanDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Boolean.class));
}
public static DMType makeStringDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(String.class));
}
public static DMType makeDateDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Date.class));
}
public static DMType makeDurationDMType(FlexoProject project) {
return makeResolvedDMType(project.getDataModel().getDMEntity(Duration.class));
}
public static DMType makeVectorDMType(DMType valueType, FlexoProject project) {
DMType returned = new DMType(project.getDataModel().getDMEntity(Vector.class));
returned.setProject(project);
if (valueType != null) {
returned.setParameterAtIndex(valueType, 0);
}
return returned;
}
public static DMType makeListDMType(DMType valueType, FlexoProject project) {
DMType returned = new DMType(project.getDataModel().getDMEntity(List.class));
returned.setProject(project);
if (valueType != null) {
returned.setParameterAtIndex(valueType, 0);
}
return returned;
}
public static DMType makeHashtableDMType(DMType keyType, DMType valueType, FlexoProject project) {
DMType returned = new DMType(project.getDataModel().getDMEntity(Hashtable.class));
returned.setProject(project);
if (keyType != null) {
returned.setParameterAtIndex(keyType, 0);
}
if (valueType != null) {
returned.setParameterAtIndex(valueType, 1);
}
return returned;
}
public static DMType makeResolvedDMType(DMEntity entity, int dimensions) {
return new DMType(entity, dimensions);
}
public static DMType makeResolvedDMType(DMEntity entity, int dimensions, Vector<DMType> parameters) {
return new DMType(entity, dimensions, parameters);
}
public static DMType makeResolvedDMType(DMEntity entity, Vector<DMType> parameters) {
return makeResolvedDMType(entity, 0, parameters);
}
public static DMType makeResolvedDMType(DMEntity entity, int dimensions, DMType... parameters) {
Vector<DMType> params = new Vector<DMType>();
for (DMType t : parameters) {
params.add(t);
}
return makeResolvedDMType(entity, dimensions, params);
}
public static DMType makeResolvedDMType(DMEntity entity, DMType... parameters) {
return makeResolvedDMType(entity, 0, parameters);
}
public static DMType makeTypeVariableDMType(DMTypeVariable typeVariable) {
return new DMType(typeVariable);
}
public static DMType makeDKVDMType(Domain aDomain) {
return new DMType(aDomain);
}
public static DMType makeWildcardDMType(Vector<DMType> upperBounds, Vector<DMType> lowerBounds) {
return new DMType(upperBounds, lowerBounds);
}
/**
* Build instanciated DMType considering supplied type is generic (contains TypeVariable definitions) Returns a clone of DMType where
* all references to TypeVariable are replaced by values defined in context type. For example, given type=Enumeration<E> and
* context=Vector<String>, returns Enumeration<String> If supplied type is not generic, return type value (without cloning!)
*
* @param type
* : type to instanciate
* @param context
* : context used to instanciate type
* @return
*/
public static DMType makeInstantiatedDMType(DMType type, DMType context) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("makeInstantiatedDMType type=" + type + " context=" + context);
}
if (type == null) {
return null;
}
if (!type.isGeneric()) {
return type;
}
DMType returned = type.clone();
if (returned.getKindOfType() == KindOfType.UNRESOLVED) {
return returned;
} else if (returned.getKindOfType() == KindOfType.RESOLVED || returned.getKindOfType() == KindOfType.RESOLVED_ARRAY) {
for (int i = 0; i < returned.parameters.size(); i++) {
DMType p = returned.parameters.elementAt(i);
if (p.isGeneric()) {
returned.parameters.setElementAt(makeInstantiatedDMType(p, context), i);
}
}
return returned;
}
else if (returned.getKindOfType() == KindOfType.TYPE_VARIABLE) {
/*
* logger.info("context.getKindOfType()="+context.getKindOfType());
* logger.info("context.getBaseEntity()="+context.getBaseEntity());
* logger.info("returned.getTypeVariable().getEntity()="+returned.getTypeVariable().getEntity());
*/
if (context.getKindOfType() == DMType.KindOfType.RESOLVED) {
if (context.getBaseEntity() == returned.getTypeVariable().getEntity()) {
int index = context.getBaseEntity().getTypeVariables().indexOf(returned.getTypeVariable());
if (logger.isLoggable(Level.FINE)) {
logger.fine("Instanciating type with type at index " + index);
}
if (index < context.parameters.size()) {
return context.parameters.elementAt(index);
}
} else if (returned.getTypeVariable().getEntity().isAncestorOf(context.getBaseEntity())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Delegate instanciation to parent type " + context.getBaseEntity().getParentType());
}
// Computing parent context
DMType parentContext = makeInstantiatedDMType(context.getBaseEntity().getParentType(), context);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Using parent context: " + parentContext);
}
// And use this parent context to recursively call
return makeInstantiatedDMType(type, parentContext);
} else {
logger.warning("Unexpected situation (type generics not instanciated) encountered in makeInstantiatedDMType(" + type
+ "," + context + ")");
return makeObjectDMType(context.getProject());
}
}
return returned;
}
else if (returned.getKindOfType() == KindOfType.WILDCARD) {
if (returned.getUpperBounds() != null) {
for (int i = 0; i < returned.getUpperBounds().size(); i++) {
WildcardBound b = returned.getUpperBounds().elementAt(i);
if (b.bound != null && b.bound.isGeneric()) {
returned.getUpperBounds().setElementAt(returned.new WildcardBound(makeInstantiatedDMType(b.bound, context)), i);
}
}
}
if (returned.getLowerBounds() != null) {
for (int i = 0; i < returned.getLowerBounds().size(); i++) {
WildcardBound b = returned.getLowerBounds().elementAt(i);
if (b.bound != null && b.bound.isGeneric()) {
returned.getLowerBounds().setElementAt(returned.new WildcardBound(makeInstantiatedDMType(b.bound, context)), i);
}
}
}
return returned;
}
else {
logger.warning("Unexpected KindOfType: " + returned.getKindOfType());
return returned;
}
}
// ==========================================================
// ===================== Constructors =======================
// ==========================================================
protected DMType(String fullName, String name, int dimensions, JavaClassParent context) {
super(fullName, name, dimensions, context);
this.name = name;
init();
this.dimensions = dimensions;
if (logger.isLoggable(Level.FINE)) {
logger.fine("makeUnresolved() '" + fullName + "'");
}
}
private DMType(String fullName, int dimensions) {
super(fullName, dimensions);
init();
this.dimensions = dimensions;
if (logger.isLoggable(Level.FINE)) {
logger.fine("makeUnresolved() '" + fullName + "'");
}
}
DMType(String fullName) {
super(fullName);
init();
if (logger.isLoggable(Level.FINE)) {
logger.fine("makeUnresolved() '" + fullName + "'");
}
}
private DMType(DMEntity entity) {
super(entity != null ? entity.getFullQualifiedName() : "null");
init();
setBaseEntity(entity);
}
private DMType(DMEntity entity, int dimensions) {
this(entity);
setDimensions(dimensions);
}
private DMType(DMEntity entity, int dimensions, Vector<DMType> parameters) {
this(entity, dimensions);
this.parameters.addAll(parameters);
for (DMType p : this.parameters) {
if (p != null) {
p.setOwner(this);
}
}
}
private DMType(DMTypeVariable typeVariable) {
this(typeVariable.getName());
setTypeVariable(typeVariable);
}
private DMType(Domain domain) {
this(domain != null ? domain.getName() : "null");
setDomain(domain);
}
private DMType(Vector<DMType> someUpperBounds, Vector<DMType> someLowerBounds) {
this("<wilcard>");
upperBounds = new Vector<WildcardBound>();
lowerBounds = new Vector<WildcardBound>();
if (someUpperBounds != null) {
for (DMType t : someUpperBounds) {
upperBounds.add(new WildcardBound(t));
t.setOwner(this);
}
}
if (someLowerBounds != null) {
for (DMType t : someLowerBounds) {
lowerBounds.add(new WildcardBound(t));
t.setOwner(this);
}
}
}
private static int TYPEID = 0;
public final int typeId = TYPEID++;
private void init() {
// logger.info("New type "+Integer.toHexString(typeId));
parameters = new Vector<DMType>();
typedWithThisType = new Vector<Typed>();
dimensions = 0;
domain = null;
typeVariable = null;
upperBounds = null;
lowerBounds = null;
_parameterizedTypeVariables = null;
}
// Artefact for KV-coding
// TODO: manage 'this' in inspector
public DMType getThis() {
return this;
}
// Artefact for KV-coding
// TODO: manage 'this' in inspector
public void setThis(DMType t) {
}
public synchronized void clearUnresolved() {
triedToResolve = false;
}
/**
* Override parent implementation by providing a cache
*/
@Override
public synchronized boolean isResolved() {
if (getKindOfType() != KindOfType.UNRESOLVED) {
return _isNotUnresolvedTypeResolved();
}
if (!triedToResolve) {
// logger.info("Is type "+name+" resolved ?");
triedToResolve = true;
isResolved = super.isResolved();
}
/*
* if (isResolved == false) { logger.warning("Type: "+name+" is not resolvable"); }
*/
return isResolved;
}
private boolean _isNotUnresolvedTypeResolved() {
if (getKindOfType() == KindOfType.RESOLVED || getKindOfType() == KindOfType.RESOLVED_ARRAY) {
for (DMType p : parameters) {
if (!p.isResolved()) {
return false;
}
}
return true;
}
else if (getKindOfType() == KindOfType.TYPE_VARIABLE) {
return true;
}
else if (getKindOfType() == KindOfType.DKV) {
return true;
}
else if (getKindOfType() == KindOfType.WILDCARD) {
for (WildcardBound b : getUpperBounds()) {
if (!b.bound.isResolved()) {
return false;
}
}
for (WildcardBound b : getLowerBounds()) {
if (!b.bound.isResolved()) {
return false;
}
}
return true;
}
else {
logger.warning("Unexpected KindOfType: " + getKindOfType());
return false;
}
}
public String getName() {
if (getBaseEntity() != null) {
return getBaseEntity().getName();
}
return name;
}
public void resolveAs(DMEntity entity) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("resolve type " + this + " as " + entity.getFullQualifiedName());
}
setBaseEntity(entity);
}
public void resolveAs(DMEntity entity, int dimensions) {
resolveAs(entity);
setDimensions(dimensions);
}
public DMTypeOwner getOwner() {
return _owner;
}
public void setOwner(DMTypeOwner owner) {
_owner = owner;
if (_owner != null) {
_project = _owner.getProject();
}
}
public void setProject(FlexoProject project) {
_project = project;
}
@Override
public FlexoProject getProject() {
if (getKindOfType() == KindOfType.UNRESOLVED) {
return _project;
} else if (getKindOfType() == KindOfType.RESOLVED || getKindOfType() == KindOfType.RESOLVED_ARRAY) {
return getBaseEntity().getProject();
} else if (getKindOfType() == KindOfType.DKV) {
return getDomain().getProject();
} else if (getKindOfType() == KindOfType.TYPE_VARIABLE) {
return getTypeVariable().getProject();
} else if (getKindOfType() == KindOfType.WILDCARD) {
} else {
logger.warning("Unexpected KindOfType: " + getKindOfType());
}
return _project;
}
@Override
public void setChanged() {
clearStringRepresentationCache();
if (getOwner() != null) {
getOwner().setChanged();
}
}
/**
*
*/
private void clearStringRepresentationCache() {
stringRepresentationCache = null;
fullyQualifiedStringRepresentationCache = null;
}
public DMEntity getBaseEntity() {
return baseEntity;
}
public void setBaseEntity(DMEntity aBaseEntity) {
if (baseEntity != aBaseEntity) {
if (baseEntity != null) {
baseEntity.deleteObserver(this);
}
baseEntity = aBaseEntity;
if (baseEntity != null) {
baseEntity.addObserver(this);
setTypeVariable(null);
setDomain(null);
}
if (baseEntity == null || baseEntity.getTypeVariables().size() == 0) {
parameters.clear();
}
_parameterizedTypeVariables = null;
setChanged();
}
}
@Override
public boolean isArray() {
return getDimensions() > 0;
}
@Override
public int getDimensions() {
return dimensions;
}
public void setDimensions(int dim) {
dimensions = dim;
setChanged();
}
/**
* Determines if the type represented by this <code>DMType</code> object is either the same as, or is a superclass or superinterface of,
* the type represented by the specified <code>DMType</code> parameter. It returns <code>true</code> if so; otherwise it returns
* <code>false</code>.
*
* <p>
* Specifically, this method tests whether the type represented by the specified <code>DMType</code> parameter can be converted to the
* type represented by this <code>DMType</code> object.
*
* @param type
* the <code>DMType</code> object to be checked
* @return the <code>boolean</code> value indicating whether objects of the type <code>type</code> can be assigned to objects of this
* type
*
* @param type
* @return
*/
public boolean isAssignableFrom(DMType type) {
return isAssignableFrom(type, true);
}
/**
* Determines if the type represented by this <code>DMType</code> object is either the same as, or is a superclass or superinterface of,
* the type represented by the specified <code>DMType</code> parameter. It returns <code>true</code> if so; otherwise it returns
* <code>false</code>.
*
* <p>
* Specifically, this method tests whether the type represented by the specified <code>DMType</code> parameter can be converted to the
* type represented by this <code>DMType</code> object.
*
* @param type
* the <code>DMType</code> object to be checked
* @return the <code>boolean</code> value indicating whether objects of the type <code>type</code> can be assigned to objects of this
* type
*
* @param type
* @param permissive
* is a flag used to allow casts between primitives types (eg long casted to int). In this case, require an explicit cast
* @return
*/
// Is this type a parent class or interface of type with compatible parameters ?
public boolean isAssignableFrom(DMType type, boolean permissive) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Called " + this + " isAssignableFrom(" + type + ")");
}
// If supplied type is null return false
if (type == null) {
return false;
}
// Everything could be assigned to Object
if (isObject()) {
return true;
}
if (getKindOfType() == KindOfType.RESOLVED && type.getKindOfType() == KindOfType.RESOLVED) {
if (isVoid()) {
return type.isVoid();
}
if (isBoolean()) {
return type.isBoolean();
}
if (isDouble()) {
return type.isDouble() || type.isFloat() || type.isLong() || type.isInteger() || type.isShort() || type.isChar()
|| type.isByte();
}
if (isFloat()) {
return type.isDouble() && permissive || type.isFloat() || type.isLong() || type.isInteger() || type.isShort()
|| type.isChar() || type.isByte();
}
if (isLong()) {
return type.isLong() || type.isInteger() || type.isShort() || type.isChar() || type.isByte();
}
if (isInteger()) {
return type.isLong() && permissive || type.isInteger() || type.isShort() || type.isChar() || type.isByte();
}
if (isShort()) {
return type.isLong() && permissive || type.isInteger() && permissive || type.isShort() || type.isChar() || type.isByte();
}
if (isChar()) {
return type.isLong() && permissive || type.isInteger() && permissive || type.isShort() && permissive || type.isChar()
|| type.isShort() && permissive;
}
if (isByte()) {
return type.isLong() && permissive || type.isInteger() && permissive || type.isShort() && permissive || type.isChar()
&& permissive || type.isByte();
}
if (type.isBooleanPrimitive()) {
DMType booleanType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Boolean.class));
try {
return isAssignableFrom(booleanType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
booleanType.setBaseEntity(null);
}
}
if (type.isIntegerPrimitive()) {
DMType intType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Integer.class));
try {
return isAssignableFrom(intType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
intType.setBaseEntity(null);
}
}
if (type.isLongPrimitive()) {
DMType longType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Long.class));
try {
return isAssignableFrom(longType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
longType.setBaseEntity(null);
}
}
if (type.isShortPrimitive()) {
DMType shortType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Short.class));
try {
return isAssignableFrom(shortType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
shortType.setBaseEntity(null);
}
}
if (type.isDoublePrimitive()) {
DMType doubleType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Double.class));
try {
return isAssignableFrom(doubleType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
doubleType.setBaseEntity(null);
}
}
if (type.isFloatPrimitive()) {
DMType floatType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Float.class));
try {
return isAssignableFrom(floatType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
floatType.setBaseEntity(null);
}
}
if (type.isCharPrimitive()) {
DMType characterType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Character.class));
try {
return isAssignableFrom(characterType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
characterType.setBaseEntity(null);
}
}
if (type.isBytePrimitive()) {
DMType byteType = makeResolvedDMType(type.getBaseEntity().getDMModel().getDMEntity(java.lang.Byte.class));
try {
return isAssignableFrom(byteType, permissive);
} finally {
// To Remove the type from observers (otherwise it grows, grows, grows....)
byteType.setBaseEntity(null);
}
}
if (!getBaseEntity().isAncestorOf(type.getBaseEntity())) {
return false;
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Entity: " + getBaseEntity() + " is ancestor of " + type.getBaseEntity());
}
if (getBaseEntity() == type.getBaseEntity()) {
// Base entities are the same, let's analyse parameters
// If one of both paramters def is empty (parameters are not defined, as before java5)
// accept it without performing a test which is impossible to perform
if (getParameters().size() == 0 || type.getParameters().size() == 0) {
return true;
}
// Now check that parameters size are the same
if (getParameters().size() != type.getParameters().size()) {
return false;
}
// Now, we have to compare parameter per parameter
for (int i = 0; i < getParameters().size(); i++) {
DMType localParam = getParameters().elementAt(i);
DMType sourceParam = type.getParameters().elementAt(i);
if (localParam.getKindOfType() == KindOfType.WILDCARD && localParam.getUpperBounds().size() == 1) {
DMType resultingSourceParamType;
if (sourceParam.getKindOfType() == KindOfType.WILDCARD && sourceParam.getUpperBounds().size() == 1) {
resultingSourceParamType = sourceParam.getUpperBounds().firstElement().bound;
} else {
resultingSourceParamType = sourceParam;
}
if (!localParam.getUpperBounds().firstElement().bound.isAssignableFrom(resultingSourceParamType, permissive)) {
return false;
}
} else if (!localParam.equals(sourceParam)) {
return false;
}
}
return true;
}
// Else it's a true ancestor
else {
// DMType parentType = makeInstantiatedDMType(type.getBaseEntity().getParentType(),type);
DMType parentType = makeInstantiatedDMType(getBaseEntity().getClosestAncestorOf(type.getBaseEntity()), type);
return isAssignableFrom(parentType, permissive);
}
}
if (getKindOfType() == KindOfType.DKV && type.getKindOfType() == KindOfType.DKV) {
return getDomain() == type.getDomain();
}
else if (getKindOfType() == KindOfType.WILDCARD) {
// Not implemented yet, perform check on bounds here
return true;
} else {
return false;
}
}
@Override
public void update(FlexoObservable observable, DataModification dataModification) {
if (dataModification instanceof DMEntityClassNameChanged && observable == getBaseEntity()) {
// TODO: handle class name changed
// Then forward this notification to all Typed declared to have this type
for (Typed t : new ArrayList<Typed>(typedWithThisType)) {
t.update(observable, dataModification);
}
clearStringRepresentationCache();
} else if (dataModification instanceof EntityDeleted && observable == getBaseEntity()) {
// TODO: handle entity deleted
// Then forward this notification to all Typed declared to have this type
for (Typed t : new ArrayList<Typed>(typedWithThisType)) {
t.update(observable, dataModification);
}
clearStringRepresentationCache();
}
}
public Vector<Typed> getTypedWithThisType() {
return typedWithThisType;
}
public void addToTypedWithThisType(Typed aTyped) {
if (aTyped.getType().equals(this)) {
typedWithThisType.add(aTyped);
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Type doesn't match !");
}
}
}
public void removeFromTypedWithThisType(Typed aTyped) {
typedWithThisType.remove(aTyped);
}
@Override
public boolean equals(Object object) {
if (object == null) {
return false;
}
if (object instanceof DMType) {
String stringRepresentation = getStringRepresentation();
if (stringRepresentation == null) {
return ((DMType) object).getStringRepresentation() == null;
}
return stringRepresentation.equals(((DMType) object).getStringRepresentation());
} else if (object instanceof Type) {
return super.equals(object);
} else {
return false;
}
}
@Override
public int hashCode() {
if (getStringRepresentation() != null) {
return getStringRepresentation().hashCode();
}
return super.hashCode();
}
void notifyTypeResolved() {
for (Typed t : getTypedWithThisType()) {
t.update(null, new Typed.TypeResolved(this));
if (logger.isLoggable(Level.FINE)) {
logger.fine("Type: " + this + " is resolved: notify " + t);
}
}
if (getRootType() != this) {
if (getRootType().getKindOfType() != KindOfType.UNRESOLVED) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Type resolved: " + this + " notify root type: " + getRootType());
}
getRootType().notifyTypeResolved();
}
}
}
public DMType getRootType() {
while (getOwner() instanceof DMType) {
return ((DMType) getOwner()).getRootType();
}
return this;
}
public String getStringRepresentation() {
return getStringRepresentation(true);
}
@Override
public String toString() {
return getStringRepresentation();
}
public String getSimplifiedStringRepresentation() {
return getStringRepresentation(false);
}
private String stringRepresentationCache;
private String fullyQualifiedStringRepresentationCache;
private String getStringRepresentation(boolean fullyQualified) {
if (getKindOfType() == KindOfType.UNRESOLVED) {
// logger.info("Unresolved: "+getValue());
return getValue();
}
else if (getKindOfType() == KindOfType.RESOLVED || getKindOfType() == KindOfType.RESOLVED_ARRAY) {
if (stringRepresentationCache == null && !fullyQualified || fullyQualifiedStringRepresentationCache == null && fullyQualified) {
StringBuilder returned = new StringBuilder();
returned.append(fullyQualified ? getBaseEntity().getFullQualifiedName() : getBaseEntity().getEntityClassName());
if (parameters.size() > 0) {
returned.append("<");
boolean isFirst = true;
for (DMType p : parameters) {
if (p != null) {
returned.append((isFirst ? "" : ", ") + p.getStringRepresentation(fullyQualified));
}
isFirst = false;
}
returned.append(">");
}
for (int i = 0; i < getDimensions(); i++) {
returned.append("[]");
}
if (fullyQualified) {
fullyQualifiedStringRepresentationCache = returned.toString();
} else {
stringRepresentationCache = returned.toString();
}
}
if (fullyQualified) {
return fullyQualifiedStringRepresentationCache;
} else {
return stringRepresentationCache;
}
}
else if (getKindOfType() == KindOfType.DKV) {
if (fullyQualified) {
return DKV_PREFIX + getDomain().getName();
} else {
return getDomain().getName();
}
}
else if (getKindOfType() == KindOfType.TYPE_VARIABLE) {
return getTypeVariable().getName();
}
else if (getKindOfType() == KindOfType.WILDCARD) {
if (stringRepresentationCache == null && !fullyQualified || fullyQualifiedStringRepresentationCache == null && fullyQualified) {
StringBuilder returned = new StringBuilder();
returned.append("?");
if (getUpperBounds() != null && getUpperBounds().size() > 0) {
boolean isFirst = true;
for (WildcardBound b : getUpperBounds()) {
if (!b.bound.isObject()) {
returned.append((isFirst ? " extends " : " & ") + b.bound.getStringRepresentation(fullyQualified));
isFirst = false;
}
}
}
if (getLowerBounds() != null && getLowerBounds().size() > 0) {
boolean isFirst = true;
for (WildcardBound b : getLowerBounds()) {
returned.append((isFirst ? " super " : " & ") + b.bound.getStringRepresentation(fullyQualified));
isFirst = false;
}
}
if (fullyQualified) {
fullyQualifiedStringRepresentationCache = returned.toString();
} else {
stringRepresentationCache = returned.toString();
}
}
if (fullyQualified) {
return fullyQualifiedStringRepresentationCache;
} else {
return stringRepresentationCache;
}
}
else {
logger.warning("Unexpected KindOfType: " + getKindOfType());
return "<unexpected>";
}
}
/**
* Return flag indicating if this type is considered as generic A generic type is a type that is parameterized with type variable(s). If
* this type is resolved but contains a type in it definition containing itself a generic definition, then this type is also generic
* (this 'isGeneric' property is recursively transmissible).
*
* @return a flag indicating whether this type is resolved or not
*/
public boolean isGeneric() {
if (getKindOfType() == KindOfType.UNRESOLVED) {
return false;
} else if (getKindOfType() == KindOfType.RESOLVED || getKindOfType() == KindOfType.RESOLVED_ARRAY) {
if (parameters.size() > 0) {
for (DMType p : parameters) {
if (p.isGeneric()) {
return true;
}
}
}
return false;
}
else if (getKindOfType() == KindOfType.DKV) {
return false;
}
else if (getKindOfType() == KindOfType.TYPE_VARIABLE) {
return true;
}
else if (getKindOfType() == KindOfType.WILDCARD) {
if (getUpperBounds() != null && getUpperBounds().size() > 0) {
for (WildcardBound b : getUpperBounds()) {
if (b.bound.isGeneric()) {
return true;
}
}
}
if (getLowerBounds() != null && getLowerBounds().size() > 0) {
for (WildcardBound b : getLowerBounds()) {
if (b.bound.isGeneric()) {
return true;
}
}
}
return false;
}
else {
logger.warning("Unexpected KindOfType: " + getKindOfType());
return false;
}
}
public Domain getDomain() {
return domain;
}
public void setDomain(Domain aDomain) {
if (domain != aDomain) {
this.domain = aDomain;
if (domain != null) {
setBaseEntity(null);
setTypeVariable(null);
}
setChanged();
}
}
public DMTypeVariable getTypeVariable() {
return typeVariable;
}
public void setTypeVariable(DMTypeVariable typeVariable) {
if (this.typeVariable != typeVariable) {
this.typeVariable = typeVariable;
if (typeVariable != null) {
setBaseEntity(null);
setDomain(null);
}
setChanged();
}
}
public DMGenericDeclaration getTypeVariableContext() {
// logger.info("Type: "+this+" owner="+getOwner()+" "+(getOwner()!=null && getOwner() instanceof
// DMType?"owner context="+((DMType)getOwner()).getTypeVariableContext():null));
if (getOwner() != null && getOwner() instanceof DMGenericDeclaration) {
return (DMGenericDeclaration) getOwner();
}
if (getOwner() instanceof DMType) {
return ((DMType) getOwner()).getTypeVariableContext();
}
return null;
// return typeVariableContext;
}
/*
* public void setTypeVariableContext(DMGenericDeclaration typeVariableContext) { this.typeVariableContext = typeVariableContext; }
*/
public class WildcardBound extends TemporaryFlexoModelObject implements InspectableObject, DMTypeOwner {
public WildcardBound(DMType aType) {
super();
bound = aType;
}
public DMType bound;
@Override
public String getInspectorName() {
// never inspected by its own
return null;
}
public String getSuperLabel() {
return "? super ";
}
public String getExtendsLabel() {
return "? extends ";
}
public DMTypeOwner getOwner() {
if (bound != null) {
return bound.getOwner();
}
return DMType.this.getOwner();
}
@Override
public FlexoProject getProject() {
return DMType.this.getProject();
}
}
public Vector<WildcardBound> getLowerBounds() {
return lowerBounds;
}
public Vector<WildcardBound> getUpperBounds() {
return upperBounds;
}
public void addToUpperBounds(DMType type) {
addToUpperBounds(new WildcardBound(type));
}
public void addToUpperBounds(WildcardBound bound) {
upperBounds.add(bound);
setChanged();
}
public void setLowerBounds(Vector<WildcardBound> lowerBounds) {
this.lowerBounds = lowerBounds;
setChanged();
}
public void setUpperBounds(Vector<WildcardBound> upperBounds) {
this.upperBounds = upperBounds;
setChanged();
}
public void addToLowerBounds(DMType type) {
addToLowerBounds(new WildcardBound(type));
setChanged();
}
public void addToLowerBounds(WildcardBound bound) {
lowerBounds.add(bound);
}
public Vector<DMType> getParameters() {
return parameters;
}
public void setParameters(Vector<DMType> parameters) {
this.parameters = parameters;
setChanged();
}
public void setParameterAtIndex(DMType parameter, int index) {
while (parameters.size() <= index) {
DMType newObjectType;
if (getProject() != null) {
newObjectType = makeResolvedDMType(getProject().getDataModel().getDMEntity(Object.class));
} else {
newObjectType = makeUnresolvedDMType("java.lang.Object");
}
newObjectType.setOwner(DMType.this);
parameters.add(newObjectType);
}
if (parameters.elementAt(index) == null || parameters.elementAt(index) != parameter) {
parameters.setElementAt(parameter, index);
parameter.setOwner(DMType.this);
setChanged();
}
}
public Vector<ParameterizedTypeVariable> getParameterizedTypeVariables() {
if (_parameterizedTypeVariables == null) {
_parameterizedTypeVariables = new Vector<ParameterizedTypeVariable>();
if (getBaseEntity() != null) {
for (DMTypeVariable tv : getBaseEntity().getTypeVariables()) {
_parameterizedTypeVariables.add(new ParameterizedTypeVariable(tv));
}
}
}
return _parameterizedTypeVariables;
}
public class ParameterizedTypeVariable extends TemporaryFlexoModelObject implements InspectableObject {
private final DMTypeVariable _typeVariable;
protected ParameterizedTypeVariable(DMTypeVariable typeVariable) {
super();
_typeVariable = typeVariable;
}
@Override
public String getInspectorName() {
// Never inspected by its own
return null;
}
public DMTypeVariable getTypeVariable() {
return _typeVariable;
}
public DMType getValue() {
int index = -1;
if (getBaseEntity() != null) {
index = getBaseEntity().getTypeVariables().indexOf(_typeVariable);
}
if (index < 0) {
return null;
} else {
if (getParameters().size() > index) {
return getParameters().elementAt(index);
} else {
return null;
}
}
}
public void setValue(DMType aType) {
int index = -1;
if (getBaseEntity() != null) {
index = getBaseEntity().getTypeVariables().indexOf(_typeVariable);
}
if (index < 0) {
return;
} else {
setParameterAtIndex(aType, index);
/*
* while(getParameters().size() <= index) { DMType newObjectType =
* makeResolvedDMType(getBaseEntity().getDMModel().getDMEntity(Object.class)); newObjectType.setOwner(DMType.this);
* getParameters().add(newObjectType); } getParameters().setElementAt(aType,index); aType.setOwner(DMType.this);
* setChanged();
*/
}
}
@Override
public FlexoProject getProject() {
return DMType.this.getProject();
}
public DMType getOwner() {
return DMType.this;
}
}
public KindOfType getKindOfType() {
if (getBaseEntity() != null) {
if (getDimensions() == 0) {
return KindOfType.RESOLVED;
} else {
return KindOfType.RESOLVED_ARRAY;
}
}
if (getDomain() != null) {
return KindOfType.DKV;
}
if (getTypeVariable() != null) {
return KindOfType.TYPE_VARIABLE;
}
if (getLowerBounds() != null || getUpperBounds() != null) {
return KindOfType.WILDCARD;
}
return KindOfType.UNRESOLVED;
}
public enum KindOfType implements StringConvertable<KindOfType> {
UNRESOLVED, RESOLVED, RESOLVED_ARRAY, DKV, TYPE_VARIABLE, WILDCARD;
public String getUnlocalizedStringRepresentation() {
if (this == UNRESOLVED) {
return "unresolved_type";
} else if (this == RESOLVED) {
return "basic_type";
} else if (this == RESOLVED_ARRAY) {
return "array_type";
} else if (this == DKV) {
return "dkv_type";
} else if (this == TYPE_VARIABLE) {
return "type_variable_type";
} else if (this == WILDCARD) {
return "wildcard_type";
}
return "???";
}
public String getStringRepresentation() {
return FlexoLocalization.localizedForKey(getUnlocalizedStringRepresentation());
}
@Override
public StringEncoder.Converter<KindOfType> getConverter() {
return kindOfTypeConverter;
}
public static final StringEncoder.Converter<KindOfType> kindOfTypeConverter = new Converter<KindOfType>(KindOfType.class) {
@Override
public KindOfType convertFromString(String value) {
for (KindOfType cs : values()) {
if (cs.getStringRepresentation().equals(value)) {
return cs;
}
}
return null;
}
@Override
public String convertToString(KindOfType value) {
return value.getStringRepresentation();
}
};
}
public boolean isDKV() {
return getKindOfType() == KindOfType.DKV;
}
// ==========================================================
// ================= Serialization stuff ====================
// ==========================================================
public static class DMTypeStringConverter extends StringEncoder.Converter<DMType> {
private DMModel _dataModel;
private final Vector<DMType> _pendingDeserializedTypes;
private DMGenericDeclaration _converterTypeVariableContext;
public DMTypeStringConverter(DMModel model) {
super(DMType.class);
_dataModel = model;
_pendingDeserializedTypes = new Vector<DMType>();
}
protected void dataModelStartDeserialization(DMModel dataModel) {
_dataModel = dataModel;
_pendingDeserializedTypes.clear();
}
protected void dataModelFinishDeserialization(DMModel dataModel) {
logger.fine("BEGIN dataModelFinishDeserialization");
int stillToDecode = _pendingDeserializedTypes.size();
while (stillToDecode > 0) {
logger.fine("Trying to decode remaining " + stillToDecode + " types");
tryToDecodeTypes();
if (stillToDecode <= _pendingDeserializedTypes.size()) {
logger.warning("Some types could not be decoded. Abort");
logger.info("stillToDecode was:" + stillToDecode + " is now " + _pendingDeserializedTypes.size());
for (DMType t : _pendingDeserializedTypes) {
logger.warning("Undecoded type: " + t.getStringRepresentation());
}
return;
}
stillToDecode = _pendingDeserializedTypes.size();
}
logger.fine("END dataModelFinishDeserialization, stillToDecode=" + stillToDecode);
}
@Override
public DMType convertFromString(String aValue) {
return convertFromString(aValue, null, _dataModel.getProject());
}
public DMType convertFromString(String aValue, DMTypeOwner owner, FlexoProject project) {
ParsedTypeInfo infos = new ParsedTypeInfo(aValue);
DMType returned = new DMType(infos.baseString);
if (project != null) {
returned.setProject(project);
}
if (owner != null) {
returned.setOwner(owner);
}
returned._pendingInformations = infos;
if (!decodeType(returned)) {
_pendingDeserializedTypes.add(returned);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Decoding failed for " + aValue);
}
}
return returned;
}
private void tryToDecodeTypes() {
Vector<DMType> decodedTypes = new Vector<DMType>();
Vector<DMType> typesToDecode = new Vector<DMType>(_pendingDeserializedTypes);
for (DMType t : typesToDecode) {
if (decodeType(t)) {
decodedTypes.add(t);
}
}
_pendingDeserializedTypes.removeAll(decodedTypes);
}
private boolean decodeType(DMType type) {
boolean returned = true;
if (type._pendingInformations == null) {
return false;
}
if (type._pendingInformations.dkvDomain != null) {
if (_dataModel == null) {
returned = false;
} else {
DKVModel dkvModel = _dataModel.getProject().getDKVModel();
if (dkvModel == null) {
returned = false;
} else {
Domain domain = dkvModel.getDomainNamed(type._pendingInformations.dkvDomain);
if (domain == null) {
returned = false;
} else {
type.setDomain(domain);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Successfully decoded " + type + " as DKV");
}
returned = true;
}
}
}
} else {
if (_dataModel == null) {
returned = false;
} else {
DMEntity entity = _dataModel.getDMEntity(type._pendingInformations.baseString);
if (entity == null) {
returned = false;
} else {
type.setBaseEntity(entity);
}
}
type.setDimensions(type._pendingInformations.dimensions);
if (!type._pendingInformations.parametersAdded) {
for (String param : type._pendingInformations.parameters) {
DMType t = convertFromString(param);
type.parameters.add(t);
t.setOwner(type);
}
type._pendingInformations.parametersAdded = true;
}
// May be it's a type variable ???
if (returned == false && type.getTypeVariableContext() != null) {
for (DMTypeVariable tv : type.getTypeVariableContext().getTypeVariables()) {
if (type._pendingInformations.baseString.equals(tv.getName())) {
type.setTypeVariable(tv);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Successfully decoded " + type + " as TypeVariable");
}
returned = true;
}
}
}
// Or may be it's a wildcard ???
if (returned == false) {
String supposedWildcard = type._pendingInformations.baseString.trim();
if (supposedWildcard.indexOf("?") == 0) {
String extendsString = "";
String superString = "";
int extendsBeginIndex = supposedWildcard.indexOf("extends");
int superBeginIndex = supposedWildcard.indexOf("super");
if (extendsBeginIndex >= 0) { // extends found
if (superBeginIndex >= 0) { // super found
extendsString = supposedWildcard.substring(extendsBeginIndex + 7, superBeginIndex).trim();
superString = supposedWildcard.substring(superBeginIndex + 5).trim();
} else {
extendsString = supposedWildcard.substring(extendsBeginIndex + 7).trim();
}
} else {
if (superBeginIndex >= 0) { // super found
superString = supposedWildcard.substring(superBeginIndex + 5).trim();
}
}
type.upperBounds = new Vector<WildcardBound>();
type.lowerBounds = new Vector<WildcardBound>();
StringTokenizer st = new StringTokenizer(extendsString, "&");
while (st.hasMoreElements()) {
DMType t = convertFromString(st.nextToken().trim());
t.setOwner(type);
type.addToUpperBounds(t);
}
st = new StringTokenizer(superString, "&");
while (st.hasMoreElements()) {
DMType t = convertFromString(st.nextToken().trim());
t.setOwner(type);
type.addToLowerBounds(t);
}
if (type.upperBounds.size() == 0) {
DMType newObjectType = convertFromString("java.lang.Object");
newObjectType.setOwner(type);
type.addToUpperBounds(newObjectType);
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Successfully decoded " + type + " as WildcardType");
}
returned = true;
}
}
}
if (returned) {
type._pendingInformations = null;
if (logger.isLoggable(Level.FINE)) {
logger.fine("Type " + type + " successfully decoded");
}
type.notifyTypeResolved();
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Type " + type._pendingInformations + " is pending owner=" + type.getOwner() + "variableContext="
+ type.getTypeVariableContext() + " " + Integer.toHexString(type.hashCode()));
}
}
return returned;
}
@Override
public String convertToString(DMType value) {
return value.getStringRepresentation();
}
public DMGenericDeclaration getConverterTypeVariableContext() {
return _converterTypeVariableContext;
}
public void setConverterTypeVariableContext(DMGenericDeclaration typeVariableContext) {
this._converterTypeVariableContext = typeVariableContext;
}
protected class ParsedTypeInfo {
protected String baseString;
protected int dimensions;
Vector<String> parameters;
protected String dkvDomain;
boolean parametersAdded = false;
public ParsedTypeInfo(String value) {
String parsed = value;
dimensions = 0;
parameters = new Vector<String>();
if (value.startsWith(DKV_PREFIX)) {
dkvDomain = value.substring(DKV_PREFIX.length());
return;
}
while (parsed.endsWith("[]")) {
dimensions++;
parsed = parsed.substring(0, parsed.length() - 2);
}
if (parsed.indexOf("<") > -1 && parsed.lastIndexOf(">") > parsed.indexOf("<")) {
String params = parsed.substring(parsed.indexOf("<") + 1, parsed.lastIndexOf(">"));
DMTypeTokenizer tt = new DMTypeTokenizer(params);
while (tt.hasMoreTokens()) {
parameters.add(tt.nextToken());
}
parsed = parsed.substring(0, parsed.indexOf("<"));
}
baseString = parsed.trim();
}
@Override
public String toString() {
return "base: " + baseString + " dims=" + dimensions + " parameters(" + parameters.size() + ")=" + parameters;
}
}
}
@Override
public DMTypeStringConverter getConverter() {
if (getProject() != null) {
return getProject().getDataModel().getDmTypeConverter();
}
if (_project != null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Weird type: getProject returns null but _project is not null!");
}
return _project.getDataModel().getDmTypeConverter();
}
return null;
}
// ==========================================================
// ===================== Utilities ==========================
// ==========================================================
public static int arrayDepth(Class<?> c) {
Class<?> current = c;
int depth = 0;
current = current.getComponentType();
while (current != null) {
current = current.getComponentType();
depth++;
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Class " + c + " array depth = " + depth);
}
return depth;
}
@Override
public boolean isVoid() {
if (isResolved() && getKindOfType() == KindOfType.RESOLVED) {
return getBaseEntity().isVoid();
}
return super.isVoid();
}
public boolean isBoolean() {
return _isBasicType()
&& (isBooleanPrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Boolean.class));
}
public boolean isBooleanPrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("boolean");
}
public boolean isInteger() {
return _isBasicType()
&& (isIntegerPrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Integer.class));
}
public boolean isIntegerPrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("int");
}
public boolean isLong() {
return _isBasicType() && (isLongPrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Long.class));
}
public boolean isLongPrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("long");
}
public boolean isShort() {
return _isBasicType() && (isShortPrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Short.class));
}
public boolean isShortPrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("short");
}
public boolean isChar() {
return _isBasicType()
&& (isCharPrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Character.class));
}
public boolean isCharPrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("char");
}
public boolean isByte() {
return _isBasicType() && (isBytePrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Byte.class));
}
public boolean isBytePrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("byte");
}
public boolean isFloat() {
return _isBasicType() && (isFloatPrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Float.class));
}
public boolean isFloatPrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("float");
}
public boolean isDouble() {
return _isBasicType()
&& (isDoublePrimitive() || getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Double.class));
}
public boolean isDoublePrimitive() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getEntityNamed("double");
}
public boolean isString() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.String.class);
}
public boolean isObject() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(java.lang.Object.class);
}
public boolean isDuration() {
return _isBasicType() && getBaseEntity() == getBaseEntity().getDMModel().getDMEntity(org.openflexo.toolbox.Duration.class);
}
/**
* @return
*/
public boolean isDate() {
return _isBasicType() && getBaseEntity().getDMModel().getDMEntity(Date.class).isAncestorOf(getBaseEntity());
}
public boolean isEOEntity() {
return _isBasicType() && getBaseEntity() instanceof DMEOEntity;
}
public boolean isBasicType() {
return _isBasicType() && getBaseEntity().getTypeVariables().size() == 0;
}
private boolean _isBasicType() {
return getKindOfType() == KindOfType.RESOLVED && getDimensions() == 0;
}
@Override
public boolean isPrimitive() {
return isBooleanPrimitive() || isIntegerPrimitive() || isCharPrimitive() || isFloatPrimitive() || isDoublePrimitive()
|| isLongPrimitive() || isBytePrimitive() || isShortPrimitive();
}
// ==========================================================
// ============ Key/Value coding implementation =============
// ==========================================================
@Override
public String valueForKey(String key) {
if (getProject() != null) {
return KeyValueDecoder.valueForKey(this, key, getProject().getStringEncoder());
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Project is null for " + this);
}
return KeyValueDecoder.valueForKey(this, key);
}
}
@Override
public void setValueForKey(String valueAsString, String key) {
if (getProject() != null) {
KeyValueCoder.setValueForKey(this, valueAsString, key, getProject().getStringEncoder());
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Project is null for " + this);
}
KeyValueCoder.setValueForKey(this, valueAsString, key);
}
}
@Override
public boolean booleanValueForKey(String key) {
return KeyValueDecoder.booleanValueForKey(this, key);
}
@Override
public byte byteValueForKey(String key) {
return KeyValueDecoder.byteValueForKey(this, key);
}
@Override
public char characterForKey(String key) {
return KeyValueDecoder.characterValueForKey(this, key);
}
@Override
public double doubleValueForKey(String key) {
return KeyValueDecoder.doubleValueForKey(this, key);
}
@Override
public float floatValueForKey(String key) {
return KeyValueDecoder.floatValueForKey(this, key);
}
@Override
public int integerValueForKey(String key) {
return KeyValueDecoder.integerValueForKey(this, key);
}
@Override
public long longValueForKey(String key) {
return KeyValueDecoder.longValueForKey(this, key);
}
@Override
public short shortValueForKey(String key) {
return KeyValueDecoder.shortValueForKey(this, key);
}
@Override
public void setBooleanValueForKey(boolean value, String key) {
KeyValueCoder.setBooleanValueForKey(this, value, key);
}
@Override
public void setByteValueForKey(byte value, String key) {
KeyValueCoder.setByteValueForKey(this, value, key);
}
@Override
public void setCharacterForKey(char value, String key) {
KeyValueCoder.setCharacterValueForKey(this, value, key);
}
@Override
public void setDoubleValueForKey(double value, String key) {
KeyValueCoder.setDoubleValueForKey(this, value, key);
}
@Override
public void setFloatValueForKey(float value, String key) {
KeyValueCoder.setFloatValueForKey(this, value, key);
}
@Override
public void setIntegerValueForKey(int value, String key) {
KeyValueCoder.setIntegerValueForKey(this, value, key);
}
@Override
public void setLongValueForKey(long value, String key) {
KeyValueCoder.setLongValueForKey(this, value, key);
}
@Override
public void setShortValueForKey(short value, String key) {
KeyValueCoder.setShortValueForKey(this, value, key);
}
@Override
public Object objectForKey(String key) {
return KeyValueDecoder.objectForKey(this, key);
}
@Override
public void setObjectForKey(Object value, String key) {
KeyValueCoder.setObjectForKey(this, value, key);
}
// Retrieving type
@Override
public Class<?> getTypeForKey(String key) {
return KeyValueDecoder.getTypeForKey(this, key);
}
@Override
public boolean isSingleProperty(String key) {
return KeyValueDecoder.isSingleProperty(this, key);
}
@Override
public boolean isArrayProperty(String key) {
return KeyValueDecoder.isArrayProperty(this, key);
}
@Override
public boolean isVectorProperty(String key) {
return KeyValueDecoder.isVectorProperty(this, key);
}
@Override
public boolean isHashtableProperty(String key) {
return KeyValueDecoder.isHashtableProperty(this, key);
}
// ==========================================================
// =================== InspectableObject ====================
// ==========================================================
@Override
public void addInspectorObserver(InspectorObserver obs) {
// useless
}
@Override
public void deleteInspectorObserver(InspectorObserver obs) {
// useless
}
@Override
public String getInspectorName() {
// useless
return null;
}
/**
* Tokenizer for DMType Tokenize a String using ',' (comma) while escaping < > We make here complex parsing maintaining nested level
*
* @author sylvain
*
*/
public static class DMTypeTokenizer {
private final Enumeration<String> tokens;
public DMTypeTokenizer(String stringToParse) {
Vector<String> computedTokens = new Vector<String>();
// Note: it's not enough to StringTokenize commas (,) since nested <> levels may occur
// Some we have to make complex parsing maintaining nested level
StringTokenizer st = new StringTokenizer(stringToParse, ",<>", true);
String nextTokenToConsider = "";
int nestedLevel = 0;
while (st.hasMoreTokens()) {
String nextToken = st.nextToken();
if (nestedLevel > 0) {
nextTokenToConsider += nextToken;
} else {
if (nextToken.equals("<")) {
nextTokenToConsider += "<";
} else if (nextToken.equals(">")) {
nextTokenToConsider += ">";
} else if (nextToken.equals(",")) {
computedTokens.add(nextTokenToConsider);
nextTokenToConsider = "";
} else {
nextTokenToConsider += nextToken;
}
}
if (nextToken.equals("<")) {
nestedLevel++;
}
if (nextToken.equals(">")) {
nestedLevel--;
}
}
if (!nextTokenToConsider.equals("")) {
computedTokens.add(nextTokenToConsider);
nextTokenToConsider = "";
}
tokens = computedTokens.elements();
}
public boolean hasMoreTokens() {
return tokens.hasMoreElements();
}
public String nextToken() {
return tokens.nextElement();
}
}
public String getDefaultValue() {
if (isPrimitive() && getDimensions() == 0) {
if (isBooleanPrimitive()) {
return "false";
} else if (isBytePrimitive()) {
return "0";
} else if (isCharPrimitive()) {
return "' '";
} else if (isDoublePrimitive()) {
return "0.0d";
} else if (isFloatPrimitive()) {
return "0.0f";
} else if (isIntegerPrimitive()) {
return "0";
} else if (isLongPrimitive()) {
return "0L";
} else if (isShortPrimitive()) {
return "0";
} else {
return "null";
}
} else {
return "null";
}
}
@Override
public boolean isDeleted() {
return false;
}
@Override
public String getInspectorTitle() {
return null;
}
@Override
public Vector<TabModel> inspectionExtraTabs() {
// TODO Auto-generated method stub
return null;
}
}