package org.reuseware.air.coconut;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.reuseware.air.algebra.GenericFragment;
import org.reuseware.air.coconut.IComplexOperator;
import org.reuseware.air.coconut.IParameterWrapper;
import org.reuseware.air.coconut.IUpperLevelInterpreter;
import org.reuseware.air.coconut.plugin.CoconutCore;
import org.reuseware.air.coconut.ReusewairComposer;
import org.reuseware.air.core.cm.IFragment;
import org.reuseware.air.coconut.util.FragmentUtil;
import org.reuseware.air.core.util.GenericCompositionAlgebra;
import org.reuseware.air.util.FileProcessingException;
import org.reuseware.air.util.FileProcessingProblem;
import org.reuseware.air.language.componentmodel.Location;
public class ComplexComposerInterpreter implements IUpperLevelInterpreter {
private static final String annotationSourceURI = "http://reuseware.org/annotation/location";
private IFragmentRetriever fragmentRetriever = null;
public ComplexComposerInterpreter() {}
/**
* Interprets complex operators (active syntax)
* @throws CoreException
*
*/
public void interpret(EObject fragment, Map<String, List<EObject>> env,
Map<String, EClass> envTypes, List<FileProcessingProblem> problems) throws CoreException {
IComplexOperator operator =
ComposerRegistry.getInstance().getComplexOperator(fragment.eClass());
if (operator != null) {
for (Method method : operator.getClass().getMethods()) {
ReusewairComposer annotation = method.getAnnotation(ReusewairComposer.class);
if (annotation != null) {
if (fragment.eClass().getName().equals(annotation.value())) {
// 1. Construct parameters
ArrayList<ArrayList<EObject>> parameters = constructParameters(fragment);
// 2. Wrap parameters
List<Object> wrappedParameters =
wrapParameters(parameters, fragment.eClass());
// 3. Invoke the method (operator)
if (wrappedParameters != null) {
IFragment returnFragment = null;
try {
returnFragment = (IFragment)method.invoke(operator, wrappedParameters.toArray());
} catch (Exception e) {
throw new CoreException(CoconutCore.createStatusWithStackTrace("Exception occured while visiting composers.", e));
}
// replace the fragment with the result from the operator
GenericCompositionAlgebra.replace(fragment, ((GenericFragment)returnFragment).getFragments());
}
}
}
}
}
// remove the fragment (the operator)
FragmentUtil.selfRemove(fragment);
return;
}
/**
* Construct the parameter list to be passed to the composer (composition operator)
*
* The main job is to resolve locations into concrete fragments
*
* @param fragment
* @return
*/
private ArrayList<ArrayList<EObject>> constructParameters(EObject fragment) {
// holding the parameters to pass to the composer implementation
ArrayList<ArrayList<EObject>> parameters = new ArrayList<ArrayList<EObject>>();
EList<EStructuralFeature> features =
fragment.eClass().getEAllStructuralFeatures();
for (EStructuralFeature feature : features) {
//ArrayList<EObject> parameter = new ArrayList<EObject>();
EObject param = (EObject)fragment.eGet(feature);
// if the fragment is not a Location, then it is a single fragment
if (!(param instanceof Location)) {
ArrayList<EObject> singleParam = new ArrayList<EObject>();
singleParam.add(param);
// add the parameter to the parameter list
parameters.add(singleParam);
}
// if the fragment is a Location, then automatically resolve it
// into EObject instances
else if (param instanceof Location) {
Location location = (Location)param;
// get the annotation containing the type of the
// fragment referenced by the location
EAnnotation annotatedType = feature.getEAnnotation(annotationSourceURI);
EMap<String,String> details = annotatedType.getDetails();
String language = null, construct = null;
/**
* Go through the details containing:
*
* language -> http://www-st.inf.tu-dresden.de/reuseware/language/[language].ecore
* construct -> [construct]
*
*/
for (Iterator<Entry<String,String>> detailIter = details.iterator(); detailIter.hasNext(); ) {
Entry<String,String> detail = detailIter.next();
if (detail.getKey().equals("language")) {
language = detail.getValue();
} else if (detail.getKey().equals("construct")) {
construct = detail.getValue();
}
}
try {
// retrieve the exact location of the fragment and parse it
InterpreterSystem is = InterpreterSystem.getInstance();
/**
* Retrieve the fragment, using the exact type for parsing,
* as specified in the annotated model (see above)
*
*/
List<EObject> frgmt =
fragmentRetriever.getFragmentFromLocation(location.getPath(),
getConstruct(language, construct),
null);
/**
* HACK:
*
* Make sure that the fragment is represented as an ArrayList,
* and not something else, such as LinkedList.
*
* This just to guarantee that we don't encounter a cast problem
* during
*
*/
ArrayList<EObject> frgmtList = new ArrayList<EObject>();
for (EObject obj : frgmt) {
frgmtList.add(obj);
}
// use the resolved fragment as a parameter
parameters.add(frgmtList);
} catch (FileProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return parameters;
}
/**
* Wrap parameter list into composer appropriate types.
*
* The wrapping is done by a component model specific wrapper function
* which is specified using the extension mechanism of Eclipse
*
* @param parameters
* @param annotation
* @return
* @throws CoreException
*/
private List<Object> wrapParameters(ArrayList<ArrayList<EObject>> parameters, EClass construct) throws CoreException {
IParameterWrapper wrapper = ComposerRegistry.getInstance().getWrapper(construct);
if (wrapper != null) {
// call specified wrapper method
List<Object> wrappedParameters = wrapper.wrap(parameters);
return wrappedParameters;
}
// default
return null;
}
/**
* Returns the construct type for a given language and construct
*
* @param language
* @param construct
* @return EClass representing the construct in the given language
*/
private EClass getConstruct(String language, String construct) {
EPackage ePackage =
EPackage.Registry.INSTANCE.getEPackage(language);
EClass eClass = (EClass) ePackage.getEClassifier(construct);
return eClass;
}
public void initialize(IFragmentRetriever retriever) {
this.fragmentRetriever = retriever;
}
}