blob: 0050efef70bcd5a56aa9b705248b00111364ce7d [file] [log] [blame]
/**
* Copyright (c) 2005-2009 Sven Efftinge (http://www.efftinge.de) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sven Efftinge (http://www.efftinge.de) - Initial API and implementation
*/
package org.eclipse.xtend.typesystem.emf;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.internal.xtend.type.baseimpl.FeatureImpl;
import org.eclipse.internal.xtend.type.baseimpl.OperationImpl;
import org.eclipse.internal.xtend.type.baseimpl.PropertyImpl;
import org.eclipse.internal.xtend.util.StringHelper;
import org.eclipse.xtend.typesystem.AbstractTypeImpl;
import org.eclipse.xtend.typesystem.Feature;
import org.eclipse.xtend.typesystem.Type;
public class EClassType extends AbstractTypeImpl {
private final static Log log = LogFactory.getLog(EClassType.class);
private final EmfRegistryMetaModel emfMetaModel;
private final EClass eClass;
public EClassType(final EmfRegistryMetaModel model, final String name, final EClass class1) {
super(model.getTypeSystem(), name);
emfMetaModel = model;
eClass = class1;
}
@Override
public Feature[] getContributedFeatures() {
final Set<FeatureImpl> result = new HashSet<FeatureImpl>();
// Attributes
for (final EStructuralFeature feature : eClass.getEStructuralFeatures()) {
final Type t = emfMetaModel.getTypeForETypedElement(feature);
if (t == null) {
if (feature.getEType().eIsProxy()) {
log.warn(String.format("Unresolved proxy for type of feature %s::%s, eProxyURI: %s", eClass.getName(), feature.getName(), EcoreUtil.getURI(feature.getEType())));
}
else
log.warn("Couldn't resolve type for " + getTypeName(feature.getEType()));
}
else {
result.add(new PropertyImpl(this, feature.getName(), t) {
public Object get(final Object target) {
return ((EObject) target).eGet(feature);
}
@Override
public void set(final Object target, Object newValue) {
if (feature.isChangeable() && !feature.isDerived()) {
if (feature.getEType() instanceof EDataType && !(feature.getEType() instanceof EEnum)) {
final EDataType dt = (EDataType) feature.getEType();
newValue = getReturnType().convert(newValue, dt.getInstanceClass());
}
((EObject) target).eSet(feature, newValue);
}
else
throw new UnsupportedOperationException("setting property '" + feature.getName()
+ "' is not allowed!");
}
});
// setter
if (feature.isChangeable() && !feature.isMany()){ // && !feature.isDerived()
// &&
result.add(new OperationImpl(this, "set" + StringHelper.firstUpper(feature.getName()), this,
new Type[] { t }) {
@Override
protected Object evaluateInternal(final Object target, final Object[] params) {
Object newValue = params[0];
if (newValue != null && feature.getEType() instanceof EDataType
&& !(feature.getEType() instanceof EEnum)) {
final EDataType dt = (EDataType) feature.getEType();
newValue = getParameterTypes().get(0).convert(newValue, dt.getInstanceClass());
}
((EObject) target).eSet(feature, newValue);
return target;
}
});
}
else if (feature.isMany()) {
result.add(new OperationImpl(this, "set" + StringHelper.firstUpper(feature.getName()), this, new Type[] { t }) {
@SuppressWarnings("unchecked")
@Override
protected Object evaluateInternal(Object target, Object[] params) {
if (params != null) {
Object newValue = params[0];
if (newValue != null && feature.getEType() instanceof EDataType
&& !(feature.getEType() instanceof EEnum)) {
final EDataType dt = (EDataType) feature.getEType();
newValue = getParameterTypes().get(0).convert(newValue, dt.getInstanceClass());
}
EList<Object> newColl = new BasicEList<Object>((List<?>)newValue);
EObject targetObject = ((EObject) target);
EClass targetClass = targetObject.eClass();
EStructuralFeature eStructuralFeature = targetClass.getEStructuralFeature(feature.getName());
EList<Object> coll = (EList<Object>) targetObject.eGet(eStructuralFeature);
ECollections.setEList(coll, newColl);
return target;
}
return null;
}
});
}
// isSetXXX and unsetXXX operation if feature is unsettable
if (feature.isUnsettable()) {
result.add(new OperationImpl(this, "isSet" + StringHelper.firstUpper(feature.getName()), getTypeSystem().getBooleanType()) {
@Override
protected Object evaluateInternal(final Object target, final Object[] params) {
return ((EObject) target).eIsSet(feature);
}
});
result.add(new OperationImpl(this, "unset" + StringHelper.firstUpper(feature.getName()), getTypeSystem().getVoidType()) {
@Override
protected Object evaluateInternal(final Object target, final Object[] params) {
((EObject) target).eUnset(feature);
return null;
}
});
}
}
}
// Operations
final EList<EOperation> eOperations = eClass.getEOperations();
for (EOperation op : eOperations) {
final EList<EParameter> emfParams = op.getEParameters();
final Type[] paramTypes = new Type[emfParams.size()];
boolean errors = false;
for (int i = 0, x = emfParams.size(); i < x; i++) {
final EParameter param = emfParams.get(i);
paramTypes[i] = emfMetaModel.getTypeForETypedElement(param);
if (paramTypes[i] == null) {
log.warn("Couldn't resolve type for " + getTypeName(param.getEType()));
errors = true;
}
}
final Type t = emfMetaModel.getTypeForETypedElement(op);
if (t == null) {
log.warn("Couldn't resolve type for " + getTypeName(op.getEType()));
errors = true;
}
if (!errors) {
result.add(new OperationImpl(this, op.getName(), t, paramTypes) {
@Override
protected Object evaluateInternal(final Object target, final Object[] params) {
final Class<?>[] paramClasses = new Class<?>[emfParams.size()];
for (int i = 0, x = emfParams.size(); i < x; i++) {
final EParameter param = emfParams.get(i);
if (param.isMany()) {
paramClasses[i] = EList.class;
}
else {
paramClasses[i] = param.getEType().getInstanceClass();
}
params[i] = getParameterTypes().get(i).convert(params[i], paramClasses[i]);
}
try {
final Method m = target.getClass().getMethod(getName(), paramClasses);
return m.invoke(target, params);
}
catch (final Exception e) {
throw new RuntimeException(e);
}
}
});
}
}
return result.toArray(new Feature[result.size()]);
}
private String getTypeName(final EClassifier type) {
if (type == null)
return "null";
return type.getName();
}
public boolean isInstance(final Object o) {
return eClass.isInstance(o);
}
public Object newInstance() {
return eClass.getEPackage().getEFactoryInstance().create(eClass);
}
@Override
protected Set<Type> internalGetSuperTypes() {
final EList<EClass> superTypes = eClass.getESuperTypes();
final Set<Type> result = new HashSet<Type>();
for (EClass element : superTypes) {
result.add(emfMetaModel.getTypeForEClassifier(element));
}
result.add(emfMetaModel.getEobjectType());
return result;
}
@Override
public boolean isAbstract() {
return eClass.isAbstract();
}
@Override
protected boolean internalIsAssignableFrom(Type t) {
if (super.internalIsAssignableFrom(t))
return true;
//
if (getName().equals("ecore::EObject")) {
if (t instanceof EClassType)
return true;
final Set<? extends Type> superTypes = t.getSuperTypes();
for (Type type : superTypes) {
if (type instanceof EClassType)
return true;
}
}
return false;
}
/**
* @since 1.4
*/
public EClass eClass () {
return eClass;
}
}