/******************************************************************************* * Copyright (c) 2008,2010 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.emf.mwe2.language.factory; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.emf.common.util.WrappedException; import org.eclipse.emf.mwe2.language.mwe2.Assignment; import org.eclipse.emf.mwe2.language.mwe2.BooleanLiteral; import org.eclipse.emf.mwe2.language.mwe2.Component; import org.eclipse.emf.mwe2.language.mwe2.DeclaredProperty; import org.eclipse.emf.mwe2.language.mwe2.Module; import org.eclipse.emf.mwe2.language.mwe2.PlainString; import org.eclipse.emf.mwe2.language.mwe2.PropertyReference; import org.eclipse.emf.mwe2.language.mwe2.Reference; import org.eclipse.emf.mwe2.language.mwe2.StringLiteral; import org.eclipse.emf.mwe2.language.mwe2.StringPart; import org.eclipse.emf.mwe2.language.scoping.FactorySupport; import org.eclipse.emf.mwe2.runtime.IFactory; import org.eclipse.xtext.common.types.JvmType; import org.eclipse.xtext.common.types.util.JavaReflectAccess; import org.eclipse.xtext.naming.IQualifiedNameConverter; import org.eclipse.xtext.naming.QualifiedName; import org.eclipse.xtext.util.PolymorphicDispatcher; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.Inject; @SuppressWarnings("restriction") public class Mwe2ExecutionEngine { private PolymorphicDispatcher<Object> dispatcher = PolymorphicDispatcher .createForSingleTarget("inCase", 2,2,this); @Inject private FactorySupport factorySupport; @Inject private JavaReflectAccess reflectAccess; @Inject private ISettingProvider settingProvider; @Inject private IQualifiedNameConverter qualifiedNameConverter; public Object execute(Module m) { return create(m, Maps.<QualifiedName,Object>newHashMap()); } public Object create(Module m, Map<QualifiedName, Object> params) { return internalSwitch(m, Maps.newHashMap(params)); } protected Object internalSwitch(Object o, Map<QualifiedName, Object> variables) { return dispatcher.invoke(o, variables); } protected Object inCase(Module m, Map<QualifiedName, Object> variables) { for (DeclaredProperty prop : m.getDeclaredProperties()) { QualifiedName propertyQualifiedName = qualifiedNameConverter.toQualifiedName(prop.getName()); if (prop.getDefault() == null && !variables.containsKey(propertyQualifiedName)) { throw new IllegalArgumentException("Cannot execute module '" + m.getCanonicalName() + "'.The mandatory parameter '" + prop.getName() + "' has not been passed."); } internalSwitch(prop, variables); } return internalSwitch(m.getRoot(), variables); } protected Object inCase(DeclaredProperty prop, Map<QualifiedName, Object> variables) { QualifiedName propertyQualifiedName = qualifiedNameConverter.toQualifiedName(prop.getName()); if (prop.getDefault() != null && !variables.containsKey(propertyQualifiedName)) { variables.put(propertyQualifiedName, internalSwitch(prop.getDefault(), variables)); } return null; } protected Object inCase(Component comp, Map<QualifiedName, Object> variables) { List<Assignment> assignments = Lists.newArrayList(comp.getAssignment()); if (comp.getModule() != null) { Map<QualifiedName, Object> params = comp.isAutoInject() ? Maps .newHashMap(variables) : Maps.<QualifiedName, Object> newHashMap(); for (Assignment ass : assignments) { params.put(qualifiedNameConverter.toQualifiedName(((DeclaredProperty)ass.getFeature()).getName()), internalSwitch(ass.getValue(), variables)); } return internalSwitch(comp.getModule(), params); } else { JvmType actualType = comp.getActualType(); Object object = create(actualType); JvmType factoryType = factorySupport.findFactoriesCreationType(actualType); if (factoryType!=null) { internalApplyAssignments(object, actualType, comp.isAutoInject(), assignments, variables); object = ((IFactory<?>)object).create(); actualType = factoryType; } if (comp.getName() != null) { variables.put(qualifiedNameConverter.toQualifiedName(comp.getName()), object); } internalApplyAssignments(object, actualType, comp.isAutoInject(), assignments, variables); return object; } } /** * applies the passed assignments to the given object. * !!It removes any consumed assignments from the passed list!! */ protected void internalApplyAssignments(Object object, JvmType type, boolean isAutoInject, List<Assignment> assignments, Map<QualifiedName, Object> variables) { Map<QualifiedName, ISetting> settings = settingProvider.getSettings(object, type); if (isAutoInject) { Set<QualifiedName> explicitAssigned = Sets.newHashSet(); for(Assignment assignment: assignments) { explicitAssigned.add(qualifiedNameConverter.toQualifiedName(assignment.getFeatureName())); } for (ISetting setting : settings.values()) { QualifiedName name = setting.getName(); if (variables.containsKey(name) && !explicitAssigned.contains(name)) setting.setValue(variables.get(name)); } } Iterator<Assignment> iterator = assignments.iterator(); while (iterator.hasNext()) { Assignment assignment = iterator.next(); QualifiedName featureName = qualifiedNameConverter.toQualifiedName(assignment.getFeatureName()); if (settings.containsKey(featureName)) { Object actualValueToSet = internalSwitch(assignment.getValue(), variables); settings.get(featureName).setValue(actualValueToSet); // remove the applied assignment iterator.remove(); } } } protected Object create(JvmType jvmType) { Class<?> class1 = reflectAccess.getRawType(jvmType); if (class1==null) throw new IllegalStateException("Couldn't find java.lang.Class for name '"+jvmType.getIdentifier()+"'"); try { return class1.newInstance(); } catch (Exception e) { throw new WrappedException(e); } } protected Object inCase(Reference ref, Map<QualifiedName, Object> variables) { return variables.get(qualifiedNameConverter.toQualifiedName(ref.getReferable().getName())); } protected Object inCase(BooleanLiteral comp, Map<QualifiedName, Object> variables) { return comp.isIsTrue(); } protected Object inCase(StringLiteral comp, Map<QualifiedName, Object> variables) { StringBuilder builder = new StringBuilder(); for (StringPart part : comp.getParts()) { if (part instanceof PropertyReference) { builder.append(variables.get(qualifiedNameConverter.toQualifiedName(((PropertyReference) part).getReferable().getName()))); } else { builder.append(((PlainString)part).getValue()); } } return builder.toString(); } public void setFactorySupport(FactorySupport factorySupport) { this.factorySupport = factorySupport; } public void setReflectAccess(JavaReflectAccess reflectAccess) { this.reflectAccess = reflectAccess; } public void setSettingProvider(ISettingProvider settingProvider) { this.settingProvider = settingProvider; } }