/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* 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:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.emftext.language.efactory.builder;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.emftext.language.efactory.Attribute;
import org.emftext.language.efactory.BooleanAttribute;
import org.emftext.language.efactory.Containment;
import org.emftext.language.efactory.DateAttribute;
import org.emftext.language.efactory.DoubleAttribute;
import org.emftext.language.efactory.EnumAttribute;
import org.emftext.language.efactory.Factory;
import org.emftext.language.efactory.Feature;
import org.emftext.language.efactory.IntegerAttribute;
import org.emftext.language.efactory.NewObject;
import org.emftext.language.efactory.NullAttribute;
import org.emftext.language.efactory.Reference;
import org.emftext.language.efactory.StringAttribute;
import org.emftext.language.efactory.Value;
/**
* A Builder can be used to obtain a model instance from the
* EFactory model.
*/
public class Builder {
public List<EObject> build(Factory eFactory, Map<EObject, String> problems) {
List<EObject> result = new ArrayList<EObject>();
// stores the commands that set references after creating all objects
List<Runnable> commands = new ArrayList<Runnable>();
// stores the created objects
Map<NewObject, EObject> createdObjectsMap = new LinkedHashMap<NewObject, EObject>();
for (NewObject root : eFactory.getRoots()) {
// create the model tree
EObject rootEObject = createEObject(root, createdObjectsMap, commands, problems);
// set the cross references
for (Runnable runnable : commands) {
runnable.run();
}
result.add(rootEObject);
}
return result;
}
private EObject createEObject(
NewObject newObject,
Map<NewObject, EObject> createdObjectsMap,
List<Runnable> commands,
Map<EObject, String> problems) {
EClass eClass = newObject.getEClass();
EPackage ePackage = eClass.getEPackage();
EFactory eFactoryInstance = ePackage.getEFactoryInstance();
EObject eObject = eFactoryInstance.create(eClass);
createdObjectsMap.put(newObject, eObject);
EList<Feature> features = newObject.getFeatures();
for (Feature feature : features) {
boolean isMany = feature.isIsMany();
EStructuralFeature eFeature = feature.getEFeature();
Value value = feature.getValue();
setFeature(eObject, eFeature, value, isMany, createdObjectsMap, commands, problems);
}
return eObject;
}
private void setFeature(
final EObject object,
final EStructuralFeature eFeature,
final Value value,
final boolean isMany,
final Map<NewObject, EObject> createdObjectsMap,
final List<Runnable> commands,
final Map<EObject, String> problems) {
if (value instanceof Reference) {
// references need to be set at the end, because
// the referenced object may not exist yet
commands.add(new Runnable() {
public void run() {
setFeatureBasic(object, eFeature, value, isMany, createdObjectsMap, commands, problems);
}
});
} else {
setFeatureBasic(object, eFeature, value, isMany, createdObjectsMap, commands, problems);
}
}
@SuppressWarnings("unchecked")
private void setFeatureBasic(EObject object, EStructuralFeature eFeature,
Value value, boolean isMany, Map<NewObject, EObject> createdObjectsMap,
List<Runnable> commands, Map<EObject, String> problems) {
Object newValue = getValue(eFeature, value, createdObjectsMap, commands, problems);
try {
if (!eFeature.getEType().isInstance(newValue)) {
throw new IllegalArgumentException();
}
int upperBound = eFeature.getUpperBound();
if (upperBound > 1 || upperBound < 0) {
Object oldValue = object.eGet(eFeature);
if (oldValue instanceof List<?>) {
List<Object> list = (List<Object>) oldValue;
if (!isMany) {
list.clear();
}
list.add(newValue);
} else {
assert false;
}
} else {
object.eSet(eFeature, newValue);
}
} catch (IllegalArgumentException e) {
String msg = "Can't set value of type '" + newValue.getClass().getSimpleName()
+ "' to feature '" + eFeature.getName() + "'.";
problems.put(value, msg);
}
}
private Object getValue(EStructuralFeature eFeature, Value value, Map<NewObject, EObject> createdObjectsMap, List<Runnable> commands, Map<EObject, String> problems) {
if (value instanceof Reference) {
Reference reference = (Reference) value;
EObject referencedNewObject = reference.getValue();
if (!(referencedNewObject instanceof NewObject)) {
// this is a 'native' reference to an existing model not wrapped in a NewObject
return referencedNewObject;
}
EObject referencedEObject = createdObjectsMap.get(referencedNewObject);
return referencedEObject;
} else if (value instanceof Containment) {
Containment containment = (Containment) value;
return createEObject(containment.getValue(), createdObjectsMap, commands, problems);
} else if (value instanceof Attribute) {
return createAttributeValue(eFeature, (Attribute) value);
} else {
// unknown sub-type of Value
assert false;
return null;
}
}
private Object createAttributeValue(EStructuralFeature eFeature, Attribute value) {
if (value instanceof EnumAttribute) {
EnumAttribute enumAttribute = (EnumAttribute) value;
EEnumLiteral literal = enumAttribute.getValue();
return literal.getInstance();
} else if (value instanceof StringAttribute) {
StringAttribute stringAttribute = (StringAttribute) value;
String string = stringAttribute.getValue();
return string;
} else if (value instanceof IntegerAttribute) {
IntegerAttribute integerAttribute = (IntegerAttribute) value;
if (eFeature.getEType().getInstanceClassName().equals(Long.class.getName())) {
Long longValue = integerAttribute.getValue();
return longValue;
} else {
Integer integerValue = (int) integerAttribute.getValue();
return integerValue;
}
} else if (value instanceof DoubleAttribute) {
DoubleAttribute doubleAttribute = (DoubleAttribute) value;
if (eFeature.getEType().getInstanceClassName().equals(Double.class.getName())) {
Double doubleValue = doubleAttribute.getValue();
return doubleValue;
} else {
Float floatValue = (float) doubleAttribute.getValue();
return floatValue;
}
} else if (value instanceof DateAttribute) {
DateAttribute dateAttribute = (DateAttribute) value;
Date date = dateAttribute.getValue();
return date;
} else if (value instanceof NullAttribute) {
return null;
} else if (value instanceof BooleanAttribute) {
return Boolean.TRUE;
} else {
// unknown sub-type of Attribute
assert false;
return null;
}
}
}