/*
* (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.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.InvalidNameException;
import org.openflexo.foundation.dm.DMMethod.DMMethodParameter;
import org.openflexo.foundation.dm.DMSet.PackageReference.ClassReference;
import org.openflexo.foundation.dm.DMSet.PackageReference.ClassReference.MethodReference;
import org.openflexo.foundation.dm.DMSet.PackageReference.ClassReference.PropertyReference;
import org.openflexo.foundation.xml.FlexoDMBuilder;
/**
* Represents a class and its definition for objects accessible from a Class object. That could be classes accessible in current ClassLoader
* or classes imported from an external jar-file (see ExternalRepository).
*
* @author sguerin
*
*/
public class LoadableDMEntity extends DMEntity {
private static final Logger logger = Logger.getLogger(LoadableDMEntity.class.getPackage().getName());
private Class<?> javaType;
/**
* Constructor used during deserialization
*/
public LoadableDMEntity(FlexoDMBuilder builder) {
this(builder.dmModel);
initializeDeserialization(builder);
}
/**
* Default constructor
*/
public LoadableDMEntity(DMModel dmModel) {
super(dmModel);
}
/**
* Constructor used for dynamic creation
*/
private LoadableDMEntity(DMRepository repository, Class<?> aClass, boolean includesGetOnlyProperties, boolean includesMethods) {
this(repository.getDMModel());
setRepository(repository);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Build new LoadableDMEntity for " + aClass.getName());
}
javaType = aClass;
if (javaType.isPrimitive()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Supplied class " + javaType + " is a primitive. Please use JDKPrimitive instead !");
}
return;
}
if (javaType.isArray()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Supplied class " + javaType + " is an array which is not permitted !");
}
return;
}
initializeFromClass(includesGetOnlyProperties, includesMethods);
repository.registerEntity(this);
List<String> excludedSignatures = registerProperties(includesGetOnlyProperties);
if (includesMethods) {
registerMethods(excludedSignatures);
}
}
/**
* Static builder used for dynamic creation
*/
public static LoadableDMEntity createLoadableDMEntity(DMRepository repository, Class<?> aClass) {
return createLoadableDMEntity(repository, aClass, false, false);
}
/**
* Static builder used for dynamic creation
*/
public static LoadableDMEntity createLoadableDMEntity(DMRepository repository, Class<?> aClass, boolean includesGetOnlyProperties,
boolean includesMethods) {
DMEntity alreadyExistingEntity = repository.getDMModel().getDMEntity(aClass);
// logger.info("createLoadableDMEntity() for "+aClass+" repository="+repository+" cl="+aClass.getClassLoader());
if (alreadyExistingEntity != null) {
// This entity is already registered somewhere !
// Just unregister it from its old location and register to the new
// one.
DMRepository oldRepository = alreadyExistingEntity.getRepository();
oldRepository.unregisterEntity(alreadyExistingEntity);
repository.registerEntity(alreadyExistingEntity);
return (LoadableDMEntity) alreadyExistingEntity;
}
if (aClass.isPrimitive()) {
return new JDKPrimitive(repository, aClass);
} else {
return new LoadableDMEntity(repository, aClass, includesGetOnlyProperties, includesMethods);
}
}
@Override
public void delete() {
getProject().getJarClassLoader().unloadClass(javaType);
super.delete();
};
@Override
public boolean getIsReadOnly() {
return true;
}
@Override
public void setIsReadOnly(boolean readOnly) {
// Not authorized
}
public Class<?> getJavaType() {
if (javaType == null) {
javaType = retrieveJavaType();
}
return javaType;
}
public Class<?> retrieveJavaType() {
if (getRepository() == getDMModel().getJDKRepository()) {
try {
javaType = Class.forName(getFullyQualifiedName());
} catch (ClassNotFoundException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
} else if (getRepository() instanceof ExternalRepository) {
JarLoader jarLoader = ((ExternalRepository) getRepository()).getJarLoader();
if (jarLoader == null) {
logger.warning("Could not reload JAR !!!");
} else {
javaType = jarLoader.getClassForName(getFullyQualifiedName());
if (javaType == null) {
logger.warning("JarLoader has been succesfully loaded, but class " + getFullyQualifiedName() + " was no found !");
}
}
}
return javaType;
}
@Override
public boolean isAncestorOf(DMEntity entity) {
if (entity == null) {
return false;
}
if (entityPackageName.equals("java.lang")) {
if (entityClassName.equals("Boolean") && entity.getName().equals("boolean")) {
return true;
}
if (entityClassName.equals("Integer") && entity.getName().equals("int")) {
return true;
}
if (entityClassName.equals("Long") && entity.getName().equals("long")) {
return true;
}
if (entityClassName.equals("Short") && entity.getName().equals("short")) {
return true;
}
if (entityClassName.equals("Float") && entity.getName().equals("float")) {
return true;
}
if (entityClassName.equals("Double") && entity.getName().equals("double")) {
return true;
}
if (entityClassName.equals("Character") && entity.getName().equals("char")) {
return true;
}
if (entityClassName.equals("Byte") && entity.getName().equals("byte")) {
return true;
}
}
return super.isAncestorOf(entity);
}
protected static String packageNameForClass(Class<?> aClass) {
return packageNameForClassName(aClass.getName());
}
protected static String packageNameForClassName(String className) {
String packageName = null;
StringTokenizer st = new StringTokenizer(className, ".");
while (st.hasMoreTokens()) {
String nextToken = st.nextToken();
if (st.hasMoreTokens()) {
if (packageName == null) {
packageName = nextToken;
} else {
packageName += "." + nextToken;
}
}
}
return packageName;
}
/**
* Update from data in ClassLoader
*/
private void initializeFromClass(boolean includesGetOnlyProperties, boolean includesMethods) {
if (javaType == null) {
logger.warning("Type could not be determined !");
return;
}
// logger.info("type="+type);
// logger.info("packageNameForClass(type)="+packageNameForClass(type));
if (packageNameForClass(javaType) != null) {
setEntityPackageName(packageNameForClass(javaType));
// entityPackageName = type.getPackage().getName();
}
StringTokenizer st = new StringTokenizer(javaType.getName(), ".");
while (st.hasMoreTokens()) {
name = st.nextToken();
}
try {
setEntityClassName(name);
} catch (DuplicateClassNameException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
} catch (InvalidNameException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
// entityClassName = name;
if (logger.isLoggable(Level.FINE)) {
logger.fine("Registering " + getFullyQualifiedName());
}
// setParentEntity(null);
// Sets the parent entity if relevant
// Register by the way all non-registered intermediate DMEntity in same
// repositery
Class<?> current = javaType;
while (current.getSuperclass() != null) {
current = current.getSuperclass();
DMEntity currentParentEntity = getDMModel().getDMEntity(current);
if (currentParentEntity == null) {
// This entity is not yet known
LoadableDMEntity.createLoadableDMEntity(getRepository(), current, includesGetOnlyProperties, includesMethods);
currentParentEntity = getDMModel().getDMEntity(current);
if (logger.isLoggable(Level.FINE)) {
logger.finer("Force register " + current.getName() + " in DataModel: " + currentParentEntity);
}
}
if (currentParentEntity == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not register " + current.getName() + " in DataModel");
}
}
if (current == javaType.getSuperclass()) {
setParentType(makeType(getRepository(), javaType.getGenericSuperclass(), true), true);
// setParentEntity(currentParentEntity);
}
}
setIsInterface(javaType.isInterface());
setIsEnumeration(javaType.isEnum());
// implements clauses
int implementedTypesIndex = 0;
for (Type t : javaType.getGenericInterfaces()) {
DMType implementsType = makeType(getRepository(), t, true);
implementsType.setOwner(this);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Implements " + implementsType);
}
if (getImplementedTypes().size() > implementedTypesIndex) {
DMType existingTypeAsThisIndex = getImplementedTypes().elementAt(implementedTypesIndex);
if (!existingTypeAsThisIndex.equals(implementsType)) {
getImplementedTypes().setElementAt(implementsType, implementedTypesIndex);
}
} else {
addToImplementedTypes(implementsType);
}
implementedTypesIndex++;
}
int implementedTypesToRemove = getImplementedTypes().size() - javaType.getGenericInterfaces().length;
for (int j = 0; j < implementedTypesToRemove; j++) {
getImplementedTypes().removeElementAt(getTypeVariables().size() - 1);
}
// type variable
int typeVariableIndex = 0;
for (TypeVariable tv : javaType.getTypeParameters()) {
DMTypeVariable typeVariable;
if (getTypeVariables().size() > typeVariableIndex) {
DMTypeVariable existingTV = getTypeVariables().elementAt(typeVariableIndex);
if (!existingTV.getName().equals(tv.getName())) {
existingTV.setName(tv.getName());
}
typeVariable = existingTV;
} else {
typeVariable = new DMTypeVariable(getDMModel(), this);
typeVariable.setName(tv.getName());
addToTypeVariables(typeVariable);
}
if (tv.getBounds().length > 0) {
StringBuffer sb = new StringBuffer();
boolean isFirst = true;
for (Type t : tv.getBounds()) {
DMType type = makeType(getRepository(), t, false);
type.setOwner(this);
sb.append((isFirst ? "" : ",") + type.getStringRepresentation());
isFirst = false;
}
String boundsAsString = sb.toString();
if (!boundsAsString.equals(typeVariable.getBounds())) {
typeVariable.setBounds(boundsAsString);
}
}
typeVariableIndex++;
}
int elementsToRemove = getTypeVariables().size() - javaType.getTypeParameters().length;
for (int j = 0; j < elementsToRemove; j++) {
getTypeVariables().removeElementAt(getTypeVariables().size() - 1);
}
}
private void registerMethods(List<String> excludedSignatures) {
for (DMMethod next : searchForMethods(javaType, getDMModel(), getRepository(), true, excludedSignatures)) {
registerMethod(next);
}
}
/**
* Build a new Vector containing unregistered DMMethod instances, given flags includesGetOnlyProperties and includesMethods
*/
public static List<DMMethod> searchForMethods(Class<?> type, DMModel dmModel, DMRepository repository,
boolean importReferencedEntities, List<String> excludedSignatures) {
List<DMMethod> returned = new ArrayList<DMMethod>();
if (logger.isLoggable(Level.FINE)) {
logger.fine("searchForMethods()");
}
for (String excludedSignature : excludedSignatures) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Excluded: " + excludedSignature);
}
}
try {
Method[] declaredMethods = type.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
Method method = declaredMethods[i];
DMMethod newMethod = makeMethod(method, dmModel, repository, importReferencedEntities);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Examine: " + newMethod.getSignature());
}
if (!excludedSignatures.contains(newMethod.getSignature())) {
returned.add(newMethod);
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Exclude " + DMMethod.signatureForMethod(method, true));
}
}
}
} catch (NoClassDefFoundError e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not find class: " + e.getMessage());
}
} catch (Throwable e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Unexpected exception raised " + e);
}
e.printStackTrace();
}
return returned;
}
/**
* Build a new DMMethod
*/
private static DMMethod makeMethod(Class<?> type, String signature, DMModel dmModel, DMRepository repository,
boolean importReferencedEntities) {
Method method = searchMatchingMethod(type, signature);
if (method != null) {
return makeMethod(method, dmModel, repository, importReferencedEntities);
}
return null;
}
private static DMEntity obtainDMEntity(DMRepository repository, Class<?> aClass, boolean importReferencedEntities) {
DMModel dmModel = repository.getDMModel();
DMEntity returned = dmModel.getDMEntity(aClass);
if (returned == null && importReferencedEntities) {
if (logger.isLoggable(Level.FINE)) {
logger.finer("Force register " + aClass.getName() + " in DataModel");
}
LoadableDMEntity.createLoadableDMEntity(repository, aClass, false, false);
returned = dmModel.getDMEntity(aClass);
if (returned == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not register " + aClass.getName() + " in DataModel");
}
}
}
return returned;
}
private static DMType makeType(DMRepository repository, Type type, boolean importReferencedEntities) {
DMModel dmModel = repository.getDMModel();
if (type instanceof Class) {
Class<?> typeAsClass = (Class<?>) type;
Class<?> baseType;
if (typeAsClass.isArray()) {
baseType = typeAsClass.getComponentType();
while (baseType.isArray()) {
baseType = baseType.getComponentType();
}
} else {
baseType = typeAsClass;
}
DMEntity returnTypeBaseEntity = obtainDMEntity(repository, baseType, importReferencedEntities);
/*
* if ((returnTypeBaseEntity == null) && (importReferencedEntities)) { if (logger.isLoggable(Level.FINE))
* logger.finer("Force register " + baseType.getName() + " in DataModel"); LoadableDMEntity.createLoadableDMEntity(baseType,
* dmModel, false, false); returnTypeBaseEntity = dmModel.getDMEntity(baseType); if (returnTypeBaseEntity == null) { if
* (logger.isLoggable(Level.WARNING)) logger.warning("Could not register " + baseType.getName() + " in DataModel"); } }
*/
if (returnTypeBaseEntity != null) {
return DMType.makeResolvedDMType(returnTypeBaseEntity, DMType.arrayDepth(typeAsClass));
} else {
return DMType.makeUnresolvedDMType(baseType.getCanonicalName(), DMType.arrayDepth(typeAsClass));
}
} else if (type instanceof TypeVariable) {
TypeVariable typeAsTypeVariable = (TypeVariable) type;
GenericDeclaration gd = typeAsTypeVariable.getGenericDeclaration();
if (gd instanceof Class) {
DMEntity owner = obtainDMEntity(repository, (Class<?>) gd, importReferencedEntities);
if (owner != null) {
DMTypeVariable typeVariable = null;
for (DMTypeVariable tv : owner.getTypeVariables()) {
if (tv.getName().equals(typeAsTypeVariable.getName())) {
typeVariable = tv;
}
}
if (typeVariable == null) {
typeVariable = new DMTypeVariable(dmModel, owner);
typeVariable.setName(typeAsTypeVariable.getName());
if (typeAsTypeVariable.getBounds().length > 0) {
typeVariable.setBounds(typeAsTypeVariable.getBounds()[0].toString());
}
owner.addToTypeVariables(typeVariable);
}
return DMType.makeTypeVariableDMType(typeVariable);
} else {
logger.warning("Could not find entity for class " + gd);
return DMType.makeUnresolvedDMType(type.toString());
}
} else if (gd instanceof Method || gd instanceof Constructor<?>) {
logger.warning("GenericDeclaration for method and constructors not implemented yet for " + gd);
return DMType.makeResolvedDMType(dmModel.getDMEntity(Object.class));
} else {
logger.warning("Unexpected type " + gd);
return DMType.makeUnresolvedDMType(type.toString());
}
} else if (type instanceof ParameterizedType) {
ParameterizedType typeAsParameterizedType = (ParameterizedType) type;
if (typeAsParameterizedType.getRawType() instanceof Class) {
DMEntity baseEntity = obtainDMEntity(repository, (Class<?>) typeAsParameterizedType.getRawType(), importReferencedEntities);
if (baseEntity != null) {
Vector<DMType> parameters = new Vector<DMType>();
for (Type t : typeAsParameterizedType.getActualTypeArguments()) {
parameters.add(makeType(repository, t, importReferencedEntities));
}
return DMType.makeResolvedDMType(baseEntity, 0, parameters);
} else {
logger.info("Cannot find entity for " + typeAsParameterizedType.getRawType());
return DMType.makeUnresolvedDMType(type.toString());
}
} else {
logger.warning("Unexpected type " + typeAsParameterizedType.getRawType());
return DMType.makeUnresolvedDMType(type.toString());
}
} else if (type instanceof GenericArrayType) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Found GenericArrayType: " + type);
}
GenericArrayType typeAsGenericArrayType = (GenericArrayType) type;
int dimensions = 1;
Type baseType = typeAsGenericArrayType.getGenericComponentType();
while (baseType instanceof GenericArrayType) {
baseType = ((GenericArrayType) baseType).getGenericComponentType();
dimensions++;
}
DMType returned = makeType(repository, baseType, importReferencedEntities);
returned.setDimensions(dimensions);
return returned;
} else if (type instanceof WildcardType) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Found wildcard: " + type);
}
WildcardType typeAsWildcardType = (WildcardType) type;
Vector<DMType> upperBounds = new Vector<DMType>();
for (Type t : typeAsWildcardType.getUpperBounds()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Upper: " + t);
}
upperBounds.add(makeType(repository, t, importReferencedEntities));
}
Vector<DMType> lowerBounds = new Vector<DMType>();
for (Type t : typeAsWildcardType.getLowerBounds()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Lower: " + t);
}
lowerBounds.add(makeType(repository, t, importReferencedEntities));
}
DMType returned = DMType.makeWildcardDMType(upperBounds, lowerBounds);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Returning wildcard: " + returned.getStringRepresentation());
}
return returned;
}
logger.warning("Unexpected type " + type.getClass());
return DMType.makeUnresolvedDMType(type.toString());
}
/**
* Build a new DMMethod from a Method object
*/
private static DMMethod makeMethod(Method method, DMModel dmModel, DMRepository repository, boolean importReferencedEntities) {
Type returnType = method.getGenericReturnType();
Type[] parameters = method.getGenericParameterTypes();
String methodName = method.getName();
DMMethod newMethod = new DMMethod(dmModel, methodName);
newMethod.setEntity(obtainDMEntity(repository, method.getDeclaringClass(), true));
// Visibility
DMVisibilityType visibility;
if (Modifier.isPublic(method.getModifiers())) {
visibility = DMVisibilityType.PUBLIC;
} else if (Modifier.isProtected(method.getModifiers())) {
visibility = DMVisibilityType.PROTECTED;
} else if (Modifier.isPrivate(method.getModifiers())) {
visibility = DMVisibilityType.PRIVATE;
} else {
visibility = DMVisibilityType.NONE;
}
newMethod.setVisibilityModifier(visibility);
// Static
newMethod.setIsStatic(Modifier.isStatic(method.getModifiers()));
// Abstract
newMethod.setIsAbstract(Modifier.isAbstract(method.getModifiers()));
// Synchronized
newMethod.setIsSynchronized(Modifier.isSynchronized(method.getModifiers()));
// lookup return type
DMType returnedDMType = makeType(repository, returnType, importReferencedEntities);
newMethod.setReturnType(returnedDMType, true);
/*
* DMEntity returnTypeEntity = dmModel.getDMEntity(returnType); if ((returnTypeEntity == null) && (importReferencedEntities)) { if
* (logger.isLoggable(Level.FINE)) logger.finer("Force register " + returnType.getName() + " in DataModel");
* LoadableDMEntity.createLoadableDMEntity(returnType, dmModel, false, false); returnTypeEntity = dmModel.getDMEntity(returnType);
* if (returnTypeEntity == null) { if (logger.isLoggable(Level.WARNING)) logger.warning("Could not register " + returnType.getName()
* + " in DataModel"); } }
*
* if ((!importReferencedEntities) && (returnTypeEntity == null)) { newMethod.setReturnType(new DMType(returnType)); } else {
* newMethod.setReturnType(new DMType(returnTypeEntity)); }
*/
if (parameters != null) {
for (int j = 0; j < parameters.length; j++) {
Type parameter = parameters[j];
DMType paramDMType = makeType(repository, parameter, importReferencedEntities);
DMMethodParameter param = new DMMethodParameter(dmModel, newMethod);
String name = "arg" + j;
if (paramDMType.getBaseEntity() != null) {
name = paramDMType.getBaseEntity().getNameAsMethodArgument();
} else if (paramDMType.getTypeVariable() != null) {
name = paramDMType.getTypeVariable().getName().toLowerCase();
}
name = newMethod.getNextDefautParameterName(name);
param.setName(name);
param.setType(paramDMType);
/*
* DMEntity paramTypeEntity = dmModel.getDMEntity(parameter); if ((paramTypeEntity == null) && (importReferencedEntities)) {
* LoadableDMEntity.createLoadableDMEntity(parameter, dmModel, false, false); paramTypeEntity =
* dmModel.getDMEntity(parameter); if (logger.isLoggable(Level.FINE)) logger.finer("Force register " + parameter.getName() +
* " in DataModel: " + paramTypeEntity); if (paramTypeEntity == null) { if (logger.isLoggable(Level.WARNING))
* logger.warning("Could not register " + parameter.getName() + " in DataModel"); } } DMMethodParameter param = new
* DMMethodParameter(dmModel,newMethod); if (paramTypeEntity != null) {
* param.setName(paramTypeEntity.getNameAsMethodArgument()); param.setType(new DMType(paramTypeEntity)); } else {
* param.setName("???"); param.setType(new DMType(parameter)); //param.setUnresolvedTypeClass(parameter); }
*/
newMethod.addToParametersNoCheck(param);
}
}
newMethod.updateCode();
return newMethod;
}
/**
*
* @param includesGetOnlyProperties
* @return a Vector of signature of all methods used to build properties
*/
private List<String> registerProperties(boolean includesGetOnlyProperties) {
List<String> excludedSignatures = new ArrayList<String>();
List<DMProperty> properties = searchForProperties(javaType, getDMModel(), getRepository(), includesGetOnlyProperties, true,
excludedSignatures);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Properties to register: " + properties);
}
for (DMProperty next : properties) {
registerProperty(next, false);
}
return excludedSignatures;
}
/**
* Build a new Vector containing unregistered DMProperty instances, given flags includesGetOnlyProperties and includesMethods
*/
public static List<DMProperty> searchForProperties(Class<?> type, DMModel dmModel, DMRepository repository,
boolean includesGetOnlyProperties, boolean importReferencedEntities, List<String> excludedSignatures) {
List<DMProperty> returned = new ArrayList<DMProperty>();
try {
Method[] declaredMethods = type.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
Method method = declaredMethods[i];
DMProperty newProperty = makeProperty(method, dmModel, repository, includesGetOnlyProperties, importReferencedEntities,
excludedSignatures);
if (newProperty != null && !containsAPropertyNamed(returned, newProperty.getName())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Make property from method: " + method);
}
returned.add(newProperty);
}
}
Field[] declaredFields = type.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
DMProperty newProperty = makeProperty(field, dmModel, repository, importReferencedEntities);
if (newProperty != null && !containsAPropertyNamed(returned, newProperty.getName())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Make property from field: " + field);
}
returned.add(newProperty);
}
}
} catch (NoClassDefFoundError e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not find class: " + e.getMessage());
}
} catch (Throwable e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Unexpected exception raised " + e);
}
e.printStackTrace();
}
return returned;
}
private static boolean containsAPropertyNamed(List<DMProperty> properties, String aName) {
for (DMProperty p : properties) {
if (p.getName().equals(aName)) {
return true;
}
}
return false;
}
/**
* Build a new DMProperty
*/
private static DMProperty makeProperty(Class<?> type, String propertyName, DMModel dmModel, DMRepository repository,
boolean includesGetOnlyProperties, boolean importReferencedEntities, Vector<String> excludedSignatures) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("makeProperty() " + propertyName + " for " + type);
}
Method method = searchMatchingGetMethod(type, propertyName);
if (method != null) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Found method " + method);
}
return makeProperty(method, dmModel, repository, includesGetOnlyProperties, importReferencedEntities, excludedSignatures);
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Not found method, try field");
}
Field f = searchMatchingField(type, propertyName);
if (f != null) {
return makeProperty(f, dmModel, repository, importReferencedEntities);
}
}
return null;
}
/**
* Build a new DMProperty
*/
private static DMProperty makeProperty(Method method, DMModel dmModel, DMRepository repository, boolean includesGetOnlyProperties,
boolean importReferencedEntities, List<String> excludedSignatures) {
Class<?> type = method.getDeclaringClass();
Type returnType = method.getGenericReturnType();
Type[] parameters = method.getGenericParameterTypes();
if (returnType != Void.TYPE && Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())
&& parameters.length == 0) {
// This signature matches a GET property, lets continue !
// Look for name
String propertyName = method.getName();
// Exclude it from methods
if (excludedSignatures != null) {
excludedSignatures.add(DMMethod.signatureForMethod(method, true));
}
// Beautify property name
if (propertyName.length() > 3 && propertyName.substring(0, 3).equalsIgnoreCase("get")) {
propertyName = propertyName.substring(3);
}
if (propertyName.length() > 1 && propertyName.substring(0, 1).equals("_")) {
propertyName = propertyName.substring(1);
}
// First char always to lower case
propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1, propertyName.length());
// Is there a SET method ?
Method setMethod = searchMatchingSetMethod(type, propertyName, returnType);
boolean isSettable = setMethod != null;
if (setMethod != null && excludedSignatures != null) {
excludedSignatures.add(DMMethod.signatureForMethod(setMethod, true));
}
// OK, we have the name, let's look at the cardinality
DMCardinality cardinality = DMCardinality.get(returnType);
if (cardinality == DMCardinality.VECTOR) {
TreeSet<AccessorMethod> addToMethods = searchMatchingAddToMethods(type, propertyName);
TreeSet<AccessorMethod> removeFromMethods = searchMatchingRemoveFromMethods(type, propertyName);
if (excludedSignatures != null) {
for (AccessorMethod next : addToMethods) {
excludedSignatures.add(DMMethod.signatureForMethod(next.getMethod(), true));
}
for (AccessorMethod next : removeFromMethods) {
excludedSignatures.add(DMMethod.signatureForMethod(next.getMethod(), true));
}
if (addToMethods.size() == 0 || removeFromMethods.size() == 0) {
isSettable = false;
}
}
}
if (cardinality == DMCardinality.HASHTABLE) {
TreeSet<AccessorMethod> setMethods = searchMatchingSetForKeyMethods(type, propertyName);
TreeSet<AccessorMethod> removeMethods = searchMatchingRemoveWithKeyMethods(type, propertyName);
if (excludedSignatures != null) {
for (AccessorMethod next : setMethods) {
excludedSignatures.add(DMMethod.signatureForMethod(next.getMethod(), true));
}
for (AccessorMethod next : removeMethods) {
excludedSignatures.add(DMMethod.signatureForMethod(next.getMethod(), true));
}
if (setMethods.size() == 0 || removeMethods.size() == 0) {
isSettable = false;
}
}
}
// Creates and register the property
if (includesGetOnlyProperties || isSettable) {
// lookup type
DMType propertyType = makeType(repository, returnType, importReferencedEntities);
/*
* DMEntity returnTypeEntity = dmModel.getDMEntity(returnType); if ((returnTypeEntity == null) &&
* (importReferencedEntities)) { if (logger.isLoggable(Level.FINE)) logger.finer("Force register " + type.getName() +
* " in DataModel: " + returnTypeEntity); LoadableDMEntity.createLoadableDMEntity(returnType, dmModel, false, false);
* returnTypeEntity = dmModel.getDMEntity(returnType); if (returnTypeEntity == null) { if (logger.isLoggable(Level.WARNING))
* logger.warning("Could not register " + type.getName() + " in DataModel"); } } DMType propertyType; if (returnTypeEntity
* != null) { propertyType = new DMType(returnTypeEntity); } else { propertyType = new DMType(returnType); }
*/
DMProperty newProperty = new DMProperty(dmModel, propertyName, propertyType, cardinality, true, isSettable,
DMPropertyImplementationType.PUBLIC_ACCESSORS_ONLY);
newProperty.setEntity(obtainDMEntity(repository, method.getDeclaringClass(), true));
// if ((!importReferencedEntities) && (returnTypeEntity == null))
// newProperty.setUnresolvedTypeName(returnType.getCanonicalName());
return newProperty;
}
}
return null;
}
/**
* Build a new DMProperty
*/
private static DMProperty makeProperty(Field field, DMModel dmModel, DMRepository repository, /*
* boolean includesGetOnlyProperties,
* boolean includesMethods,
*/
boolean importReferencedEntities/* , Vector excludedSignatures */) {
// Class type = field.getDeclaringClass();
Type fieldType = field.getGenericType();
if (fieldType != Void.TYPE && Modifier.isPublic(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())) {
// This signature matches a GET property, lets continue !
// lookup type
DMType propertyType = makeType(repository, fieldType, importReferencedEntities);
/*
* DMEntity typeEntity = dmModel.getDMEntity(fieldType); if ((typeEntity == null) && (importReferencedEntities)) { if
* (logger.isLoggable(Level.FINE)) logger.finer("Force register " + type.getName() + " in DataModel: " + typeEntity);
* LoadableDMEntity.createLoadableDMEntity(fieldType, dmModel, false, false); typeEntity = dmModel.getDMEntity(fieldType); if
* (typeEntity == null) { if (logger.isLoggable(Level.WARNING)) logger.warning("Could not register " + type.getName() +
* " in DataModel"); } }
*/
// Look for name
String propertyName = field.getName();
// OK, we have the name, let's look at the cardinality
DMCardinality cardinality = DMCardinality.get(fieldType);
/*
* DMType propertyType = null; if (typeEntity != null) { propertyType = new DMType(typeEntity); } else { propertyType = new
* DMType(fieldType); }
*/
DMProperty newProperty = new DMProperty(dmModel, propertyName, propertyType, cardinality, true, true,
DMPropertyImplementationType.PUBLIC_FIELD);
newProperty.setEntity(obtainDMEntity(repository, field.getDeclaringClass(), true));
/*
* if ((!importReferencedEntities) && (typeEntity == null)) newProperty.setUnresolvedTypeName(fieldType.getCanonicalName());
*/
return newProperty;
}
return null;
}
/**
* Try to find a method matching supplied signature
*
* Returns corresponding method, null if no such method exist
*/
private static Method searchMatchingMethod(Class<?> type, String signature) {
Method[] methods = type.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (DMMethod.signatureForMethod(method, true).equals(signature)) {
return method;
}
if (DMMethod.signatureForMethod(method, false).equals(signature)) {
return method;
}
}
return null;
}
/**
* Try to find a matching "get" method, such as (in order):
* <ul>
* <li>propertyName()</li>
* <li>_propertyName()</li>
* <li>getPropertyName()</li>
* <li>_getPropertyName()</li>
* </ul>
* Returns corresponding method, null if no such method exist
*/
private static Method searchMatchingGetMethod(Class<?> type, String propertyName) {
String propertyNameWithFirstCharToUpperCase = propertyName.substring(0, 1).toUpperCase()
+ propertyName.substring(1, propertyName.length());
Vector<String> tries = new Vector<String>();
tries.add(propertyName);
tries.add("_" + propertyName);
tries.add("get" + propertyNameWithFirstCharToUpperCase);
tries.add("_get" + propertyNameWithFirstCharToUpperCase);
for (Enumeration<String> e = tries.elements(); e.hasMoreElements();) {
try {
String methodName = e.nextElement();
return getMethod(type, methodName, (Type[]) null);
// return type.getMethod((String) e.nextElement(), (Class[])null);
} catch (SecurityException err) {
// we continue
} catch (NoSuchMethodException err) {
// we continue
}
}
return null;
}
/**
* Try to find a matching field, such as (in order):
* <ul>
* <li>propertyName</li>
* <li>_propertyName</li>
* </ul>
* Returns corresponding field, null if no such method exist
*/
private static Field searchMatchingField(Class<?> type, String propertyName) {
Vector<String> tries = new Vector<String>();
tries.add(propertyName);
tries.add("_" + propertyName);
for (Enumeration<String> e = tries.elements(); e.hasMoreElements();) {
try {
String fieldName = e.nextElement();
return type.getField(fieldName);
} catch (SecurityException err) {
// we continue
} catch (NoSuchFieldException err) {
// we continue
}
}
return null;
}
/**
* Try to find a matching "set" method, such as (in order):
* <ul>
* <li>setPropertyName(Type)</li>
* <li>_setPropertyName(Type)</li>
* </ul>
* Returns corresponding method, null if no such method exist
*/
private static Method searchMatchingSetMethod(Class<?> type, String propertyName, Type aType) {
String propertyNameWithFirstCharToUpperCase = propertyName.substring(0, 1).toUpperCase()
+ propertyName.substring(1, propertyName.length());
Vector<String> tries = new Vector<String>();
Type params[] = new Type[1];
params[0] = aType;
/*
* if (aType instanceof Class) params[0] = (Class)aType; else if (aType instanceof ParameterizedType) params[0] =
* (Class)((ParameterizedType)aType).getRawType(); else if (aType instanceof TypeVariable){ logger.warning
* ("Pas tres bien gere pour le moment "+aType.getClass()); params[0] = Object.class; }
*/
tries.add("set" + propertyNameWithFirstCharToUpperCase);
tries.add("_set" + propertyNameWithFirstCharToUpperCase);
for (Enumeration<String> e = tries.elements(); e.hasMoreElements();) {
try {
String methodName = e.nextElement();
// Method returned = type.getMethod(methodName, params);
Method returned = getMethod(type, methodName, params);
return returned;
} catch (SecurityException err) {
// we continue
} catch (NoSuchMethodException err) {
// we continue
}
}
return null;
}
private static Method getMethod(Class<?> type, String methodName, Type... params) throws NoSuchMethodException {
if (params == null) {
params = new Type[0];
}
StringBuffer sb = null;
if (logger.isLoggable(Level.FINE)) {
sb = new StringBuffer();
for (Type t : params) {
sb.append(" " + t.toString());
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Looking for " + methodName + " with" + sb.toString());
}
}
for (Method m : type.getMethods()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Examining " + m);
}
if (m.getName().equals(methodName) && m.getGenericParameterTypes().length == params.length) {
boolean paramMatches = true;
for (int i = 0; i < params.length; i++) {
if (!params[i].equals(m.getGenericParameterTypes()[i])) {
paramMatches = false;
}
}
if (paramMatches) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Looking for " + methodName + " with" + sb.toString() + ": found");
}
return m;
}
}
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Looking for " + methodName + " with" + sb.toString() + ": NOT found");
}
throw new NoSuchMethodException();
}
/**
* Search and return matching "setForKey" methods<br>
* NB: 'setForKey...' methods are methods with general form: <code>setXXXForKey(Class anObject, Class aKey)</code> or
* <code>_setXXXForKey(Class anObject, Class aKey)</code>, where XXX is the property name (try with or without a terminal 's'
* character), and Class could be anything... Returns an ordered TreeSet of {@link AccessorMethod} objects
*/
private static TreeSet<AccessorMethod> searchMatchingSetForKeyMethods(Class<?> type, String propertyName) {
String singularPropertyName;
String pluralPropertyName;
if (propertyName.endsWith("ies")) {
singularPropertyName = propertyName.substring(0, propertyName.length() - 3) + "y";
pluralPropertyName = propertyName;
} else if (propertyName.endsWith("s") || propertyName.endsWith("S")) {
singularPropertyName = propertyName.substring(0, propertyName.length() - 1);
pluralPropertyName = propertyName;
} else {
singularPropertyName = propertyName;
pluralPropertyName = propertyName + "s";
} // end of else
String[] methodNameCondidates = new String[4];
methodNameCondidates[0] = "set" + singularPropertyName + "ForKey";
methodNameCondidates[1] = "_set" + singularPropertyName + "ForKey";
methodNameCondidates[2] = "set" + pluralPropertyName + "ForKey";
methodNameCondidates[3] = "_set" + pluralPropertyName + "ForKey";
return searchMethodsWithNameAndParamsNumber(type, methodNameCondidates, 2);
}
/**
* Search and return matching "removeWithKey" methods<br>
* NB: 'removeWithKey...' methods are methods with general form: <code>removeXXXWithKey(Class aKey)</code> or
* <code>_removeXXXWithKey(Class aKey)</code>, where XXX is the property name (try with or without a terminal 's' character), and Class
* could be anything... Returns an ordered TreeSet of {@link AccessorMethod} objects
*/
private static TreeSet<AccessorMethod> searchMatchingRemoveWithKeyMethods(Class<?> type, String propertyName) {
String singularPropertyName;
String pluralPropertyName;
if (propertyName.endsWith("ies")) {
singularPropertyName = propertyName.substring(0, propertyName.length() - 3) + "y";
pluralPropertyName = propertyName;
} else if (propertyName.endsWith("s") || propertyName.endsWith("S")) {
singularPropertyName = propertyName.substring(0, propertyName.length() - 1);
pluralPropertyName = propertyName;
} else {
singularPropertyName = propertyName;
pluralPropertyName = propertyName + "s";
} // end of else
String[] methodNameCondidates = new String[4];
methodNameCondidates[0] = "remove" + singularPropertyName + "WithKey";
methodNameCondidates[1] = "_remove" + singularPropertyName + "WithKey";
methodNameCondidates[2] = "remove" + pluralPropertyName + "WithKey";
methodNameCondidates[3] = "_remove" + pluralPropertyName + "WithKey";
return searchMethodsWithNameAndParamsNumber(type, methodNameCondidates, 1);
}
/**
* Search and return matching "addTo" methods<br>
* NB: 'addTo...' methods are methods with general form: <code>addToXXX(Class anObject)</code> or <code>_addToXXX(Class anObject)</code>
* , where XXX is the property name (try with or without a terminal 's' character), and Class could be anything... Returns an ordered
* TreeSet of {@link AccessorMethod} objects
*/
private static TreeSet<AccessorMethod> searchMatchingAddToMethods(Class<?> type, String propertyName) {
String singularPropertyName;
String pluralPropertyName;
if (propertyName.endsWith("s") || propertyName.endsWith("S")) {
singularPropertyName = propertyName.substring(0, propertyName.length() - 1);
pluralPropertyName = propertyName;
} else {
singularPropertyName = propertyName;
pluralPropertyName = propertyName + "s";
} // end of else
String[] methodNameCondidates = new String[4];
methodNameCondidates[0] = "addTo" + singularPropertyName;
methodNameCondidates[1] = "_addTo" + singularPropertyName;
methodNameCondidates[2] = "addTo" + pluralPropertyName;
methodNameCondidates[3] = "_addTo" + pluralPropertyName;
return searchMethodsWithNameAndParamsNumber(type, methodNameCondidates, 1);
}
/**
* Search and return matching "removeFrom" methods<br>
* NB: 'removeFrom...' methods are methods with general form: <code>removeFromXXX(Class anObject)</code> or
* <code>_removeFromXXX(Class anObject)</code>, where XXX is the property name (try with or without a terminal 's' character), and Class
* could be anything... Returns an ordered TreeSet of {@link AccessorMethod} objects
*/
private static TreeSet<AccessorMethod> searchMatchingRemoveFromMethods(Class<?> type, String propertyName) {
String singularPropertyName;
String pluralPropertyName;
if (propertyName.endsWith("s") || propertyName.endsWith("S")) {
singularPropertyName = propertyName.substring(0, propertyName.length() - 1);
pluralPropertyName = propertyName;
} else {
singularPropertyName = propertyName;
pluralPropertyName = propertyName + "s";
} // end of else
String[] methodNameCondidates = new String[4];
methodNameCondidates[0] = "removeFrom" + singularPropertyName;
methodNameCondidates[1] = "_removeFrom" + singularPropertyName;
methodNameCondidates[2] = "removeFrom" + pluralPropertyName;
methodNameCondidates[3] = "_removeFrom" + pluralPropertyName;
return searchMethodsWithNameAndParamsNumber(type, methodNameCondidates, 1);
}
/**
* Search and returns all methods (as {@link AccessorMethod} objects) of related class whose names is in the specified string list, with
* exactly the specified number of parameters, ascendant ordered regarding parameters specialization.
*
* @see AccessorMethod
*/
private static TreeSet<AccessorMethod> searchMethodsWithNameAndParamsNumber(Class<?> type, String[] searchedNames, int paramNumber) {
TreeSet<AccessorMethod> returnedTreeSet = new TreeSet<AccessorMethod>();
Method[] allMethods = type.getMethods();
for (int i = 0; i < allMethods.length; i++) {
Method tempMethod = allMethods[i];
for (int j = 0; j < searchedNames.length; j++) {
if (tempMethod.getName().equalsIgnoreCase(searchedNames[j]) && tempMethod.getParameterTypes().length == paramNumber) {
// This is a good candidate
returnedTreeSet.add(new AccessorMethod(tempMethod));
}
}
}
return returnedTreeSet;
}
/**
* <p>
* <code>AccessorMethod</code> is a class representing a KeyValueProperty accessor method.
* </p>
* <p>
* Because many differents accessors could be defined in a class, all implementing different class-specific levels (more or less
* specialized, regarding parameters classes), we store these <code>AccessorMethods</code> in a particular order depending on the
* parameters specialization. This order is implemented in this class through {@link Comparable} interface implementation. Note: this
* class has a natural ordering that is inconsistent with equals, which means that <code>(x.compareTo(y)==0) == (x.equals(y))</code>
* condition is violated.
*/
public static class AccessorMethod implements Comparable<AccessorMethod> {
/** Stores the related <code>Method</code> */
protected Method method;
/**
* Creates a new <code>AccessorMethod</code> instance.
*
* @param aKeyValueProperty
* a <code>KeyValueProperty</code> value
* @param aMethod
* a <code>Method</code> value
*/
public AccessorMethod(Method aMethod) {
super();
method = aMethod;
}
/**
* Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
*
* @param object
* an <code>Object</code> value
* @return an <code>int</code> value
* @exception ClassCastException
* if an error occurs
*/
@Override
public int compareTo(AccessorMethod comparedAccessorMethod) throws ClassCastException {
if (getMethod().getParameterTypes().length != comparedAccessorMethod.getMethod().getParameterTypes().length) {
// Those objects could not be compared and should be treated
// as equals
// regarding the specialization of their parameters
return 2;
} else {
for (int i = 0; i < getMethod().getParameterTypes().length; i++) {
Class<?> localParameterType = getMethod().getParameterTypes()[i];
Class<?> comparedParameterType = comparedAccessorMethod.getMethod().getParameterTypes()[i];
if (!localParameterType.equals(comparedParameterType)) {
boolean localParamIsParentOfComparedParam = localParameterType.isAssignableFrom(comparedParameterType);
boolean localParamIsChildOfComparedParam = comparedParameterType.isAssignableFrom(localParameterType);
if (localParamIsParentOfComparedParam) {
return 1;
}
if (localParamIsChildOfComparedParam) {
return -1;
}
// Those objects could not be compared
return 2;
}
} // end of for
// Those objects are equals regarding the specialization of
// their parameters
return 0;
}
}
/**
* Return the related <code>Method</code>
*
* @return
*/
public Method getMethod() {
return method;
}
}
/**
* Update property Delete supplied property when not found in Class
*
* @param property
* @throws InvalidNameException
* @throws DuplicatePropertyNameException
*/
private void updateProperty(DMProperty property) throws InvalidNameException, DuplicatePropertyNameException {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update property " + property);
}
DMProperty updatedProperty = makeProperty(getJavaType(), property.getName(), getDMModel(), getRepository(), true, true, null);
if (updatedProperty == null) {
logger.info("Delete property: " + property.getName());
property.delete();
} else {
property.update(updatedProperty, false);
}
}
/**
* Create property using property reference
*
* @param property
*/
private DMProperty createProperty(PropertyReference propertyReference) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Create property " + propertyReference.getName());
}
DMProperty returnedProperty = makeProperty(getJavaType(), propertyReference.getName(), getDMModel(), getRepository(), true, true,
null);
registerProperty(returnedProperty, false);
return returnedProperty;
}
/**
* Update method using defined type as Class Delete supplied method when not found in Class
*
* @param method
* @throws DuplicateMethodSignatureException
*/
private void updateMethod(DMMethod method) throws DuplicateMethodSignatureException {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update method " + method);
}
DMMethod updatedMethod = makeMethod(getJavaType(), method.getSignature(), getDMModel(), getRepository(), true);
if (updatedMethod == null) {
method.delete();
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update method " + method.getSignature() + " with " + updatedMethod.getSignature());
}
method.update(updatedMethod, false);
}
}
/**
* Create method using method reference
*
* @param property
*/
private DMMethod createMethod(MethodReference methodReference) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Create method " + methodReference.getSignature());
}
DMMethod returnedMethod = makeMethod(getJavaType(), methodReference.getSignature(), getDMModel(), getRepository(), true);
if (returnedMethod == null) {
logger.warning("Could not retrieve method " + methodReference.getSignature());
return null;
}
registerMethod(returnedMethod);
return returnedMethod;
}
/**
* Update this entity given a supplied set of properties and methods to include
*
* @param aClassReference
*/
public void update(ClassReference aClassReference) {
if (getJavaType() == null) {
logger.warning("Could not update: could not find class !");
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update " + getName() + " with " + aClassReference.getName());
}
// First update package and class name, and parent class if different
initializeFromClass(false, false);
// Then what's about properties ?
List<DMProperty> propertiesToDelete = new ArrayList<DMProperty>(getProperties().values());
for (Enumeration<PropertyReference> en = aClassReference.getPropertiesEnumeration(); en.hasMoreElements();) {
PropertyReference nextPropertyRef = en.nextElement();
if (nextPropertyRef.isSelected()) {
DMProperty property = getDMProperty(nextPropertyRef.getName());
// logger.info("Next selected: "+nextPropertyRef.getName()+" existing="+property);
if (property != null) {
// A selected property already declared, update it
try {
updateProperty(property);
} catch (InvalidNameException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DuplicatePropertyNameException e) {
e.printStackTrace();
logger.warning(e.getMessage());
}
propertiesToDelete.remove(property);
} else {
// This is a newly imported property, creates it
createProperty(nextPropertyRef);
}
}
}
for (DMProperty toDelete : propertiesToDelete) {
logger.info("Delete property: " + toDelete.getName());
if (logger.isLoggable(Level.FINE)) {
logger.fine("Delete property " + toDelete);
}
toDelete.delete();
}
// Then what's about methods ?
List<DMMethod> methodsToDelete = new ArrayList<DMMethod>(getMethods().values());
for (Enumeration<MethodReference> en = aClassReference.getMethodsEnumeration(); en.hasMoreElements();) {
MethodReference nextMethodRef = en.nextElement();
if (nextMethodRef.isSelected()) {
DMMethod method = getDeclaredMethod(nextMethodRef.getSignature());
if (method != null) {
// A selected method already declared, update it
try {
updateMethod(method);
} catch (DuplicateMethodSignatureException e) {
e.printStackTrace();
}
methodsToDelete.remove(method);
} else {
// This is a newly imported property, creates it
createMethod(nextMethodRef);
}
}
}
for (DMMethod toDelete : methodsToDelete) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Delete method " + toDelete);
}
toDelete.delete();
}
}
}
public void update(boolean includeGetOnlyProperties, boolean includeMethods) {
if (getJavaType() == null) {
logger.warning("Could not update: could not find class !");
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update " + this + " with " + includeGetOnlyProperties + " and " + includeMethods);
}
// First update package and class name, and parent class if different
initializeFromClass(false, false);
// Look after all required properties
List<String> excludedSignatures = new Vector<String>();
List<DMProperty> allRequiredProperties = LoadableDMEntity.searchForProperties(getJavaType(), getDMModel(), getRepository(),
includeGetOnlyProperties, false, excludedSignatures);
List<DMMethod> allRequiredMethods;
if (includeMethods) {
allRequiredMethods = LoadableDMEntity.searchForMethods(getJavaType(), getDMModel(), getRepository(), false,
excludedSignatures);
} else {
allRequiredMethods = new Vector<DMMethod>();
}
// Then what's about properties ?
List<DMProperty> properties = new ArrayList<DMProperty>(getProperties().values());
for (DMProperty nextProperty : properties) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update property " + nextProperty);
}
try {
updateProperty(nextProperty);
} catch (InvalidNameException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DuplicatePropertyNameException e) {
e.printStackTrace();
logger.warning(e.getMessage());
}
for (DMProperty next : new ArrayList<DMProperty>(allRequiredProperties)) {
if (next.getName().equals(nextProperty.getName())) {
allRequiredProperties.remove(next);
}
}
}
// Those properties still required, add them:
for (DMProperty nextProperty : allRequiredProperties) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Create property " + nextProperty);
}
registerProperty(nextProperty, false);
}
// Then what's about methods ?
List<DMMethod> methods = new ArrayList<DMMethod>(getMethods().values());
for (DMMethod nextMethod : methods) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update method " + nextMethod);
}
try {
updateMethod(nextMethod);
} catch (DuplicateMethodSignatureException e) {
e.printStackTrace();
}
for (DMMethod next : new ArrayList<DMMethod>(allRequiredMethods)) {
if (next.getSignature().equals(nextMethod.getSignature())) {
allRequiredMethods.remove(next);
}
}
}
// Those methods still required, add them:
for (DMMethod nextMethod : allRequiredMethods) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Create method " + nextMethod);
}
registerMethod(nextMethod);
}
}
}
/**
* Tells if code generation is applicable for related DMEntity Always false for compiled classes
*
* @return
*/
@Override
public boolean isCodeGenerationApplicable() {
return false;
}
}