/*******************************************************************************
* Copyright (c) 2005 - 2009 itemis AG (http://www.itemis.eu) 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
*
*******************************************************************************/
package org.eclipse.xtend.typesystem.xsd.type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.EStructuralFeature;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.internal.xtend.type.baseimpl.OperationImpl;
import org.eclipse.internal.xtend.type.baseimpl.StaticPropertyImpl;
import org.eclipse.internal.xtend.util.StringHelper;
import org.eclipse.xtend.typesystem.Feature;
import org.eclipse.xtend.typesystem.Operation;
import org.eclipse.xtend.typesystem.Type;
import org.eclipse.xtend.typesystem.emf.EClassType;
import org.eclipse.xtend.typesystem.xsd.XSDMetaModel;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
public class XMLEClassType extends EClassType {
private class CompositeTypeAwareSetter extends OperationImpl {
private EStructuralFeature feature;
private HashMap<Type, EDataType> members = new HashMap<Type, EDataType>();
public CompositeTypeAwareSetter(EStructuralFeature feature, Type type) {
super(XMLEClassType.this, "set"
+ StringHelper.firstUpper(feature.getName()),
XMLEClassType.this, type);
this.feature = feature;
ExtendedMetaData em = ExtendedMetaData.INSTANCE;
collectMemberTypes(em, (EDataType) feature.getEType());
// log.info("Created " + getClass() + " for " + feature.getName()
// + " with " + members);
}
private void collectMemberTypes(ExtendedMetaData em, EDataType type) {
for (EDataType v : em.getMemberTypes(type)) {
if (!(v instanceof EEnum)) {
Type k = model.getTypeForEClassifier(v);
if (k != null)
members.put(k, v);
else
log.warn("Couldn't resolve type for " + getTypeName(v));
}
collectMemberTypes(em, v);
}
}
@Override
protected Object evaluateInternal(final Object target,
final Object[] params) {
try {
Object newValue = params[0];
if (newValue != null)
for (Type t : members.keySet())
if (t.isInstance(newValue))
newValue = t.convert(newValue, members.get(t)
.getInstanceClass());
((EObject) target).eSet(feature, newValue);
return target;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
private final static Log log = LogFactory.getLog(XMLEClassType.class);
private EClass clazz;
private XSDMetaModel model;
public XMLEClassType(XSDMetaModel model, String name, EClass class1) {
super(model, name, class1);
this.clazz = class1;
this.model = model;
}
@Override
public Feature[] getContributedFeatures() {
ArrayList<Feature> r = new ArrayList<Feature>(Arrays.asList(super
.getContributedFeatures()));
// setter
for (EStructuralFeature f : clazz
.getEStructuralFeatures()) {
if (f.isChangeable() && !f.isMany()
&& f.getEType() instanceof EDataType) {
EDataType dt = (EDataType) f.getEType();
if (ExtendedMetaData.INSTANCE.getMemberTypes(dt).size() != 0) {
Type t = model.getTypeForETypedElement(f);
if (t != null)
replaceOperation(r, new CompositeTypeAwareSetter(f, t));
}
}
}
for (final EStructuralFeature f : clazz.getEStructuralFeatures()) {
r.add(new StaticPropertyImpl(this, f.getName(), model
.getEFeatureType()) {
public Object get() {
return f;
}
});
}
return r.toArray(new Feature[r.size()]);
}
private String getTypeName(EClassifier type) {
if (type == null)
return "null";
return type.getName();
}
private void replaceOperation(ArrayList<Feature> list, Operation op) {
for (int i = 0; i < list.size(); i++) {
Feature f = list.get(i);
if (f instanceof Operation
&& f.getName().equals(op.getName())
&& ((Operation) f).getParameterTypes().equals(
op.getParameterTypes())) {
// log.info("replacing " + f + " with " + op);
list.set(i, op);
return;
}
}
}
}