| /* |
| * <copyright> |
| * |
| * Copyright (c) 2005-2008 Sven Efftinge 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 - Initial API and implementation |
| * Alexander Shatalin (Borland) |
| * |
| * </copyright> |
| */ |
| package org.eclipse.gmf.internal.xpand.model; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.gmf.internal.xpand.BufferOutput; |
| import org.eclipse.gmf.internal.xpand.ResourceManager; |
| import org.eclipse.gmf.internal.xpand.ResourceMarker; |
| import org.eclipse.gmf.internal.xpand.expression.ExecutionContextImpl; |
| import org.eclipse.gmf.internal.xpand.expression.PolymorphicResolver; |
| import org.eclipse.gmf.internal.xpand.expression.SyntaxConstants; |
| import org.eclipse.gmf.internal.xpand.expression.TypeNameUtil; |
| import org.eclipse.gmf.internal.xpand.expression.Variable; |
| import org.eclipse.gmf.internal.xpand.migration.Activator; |
| |
| /** |
| * * |
| * |
| * @author Sven Efftinge * |
| */ |
| public class XpandExecutionContextImpl extends ExecutionContextImpl implements XpandExecutionContext { |
| |
| protected final Output output; |
| |
| protected final ProtectedRegionResolver protectedRegionResolver; |
| |
| private final List<XpandAdvice> registeredAdvices = new ArrayList<XpandAdvice>(); |
| |
| public XpandExecutionContextImpl(ResourceManager resourceManager, Output output, ProtectedRegionResolver prs) { |
| this (resourceManager, output, prs, null); |
| } |
| |
| public XpandExecutionContextImpl(ResourceManager resourceManager, EPackage... fallbackVisibleModels) { |
| super(resourceManager, fallbackVisibleModels); |
| this.output = new BufferOutput(new StringBuilder()); |
| this.protectedRegionResolver = null; |
| } |
| |
| public XpandExecutionContextImpl(ResourceManager resourceManager, Output output, ProtectedRegionResolver prs, Collection<Variable> globalVars) { |
| super(resourceManager, globalVars); |
| this.output = output; |
| this.protectedRegionResolver = prs; |
| } |
| |
| protected XpandExecutionContextImpl (ResourceManager resourceManager, ResourceMarker currentResource, Collection<Variable> vars, |
| Collection<Variable> globalVars, Output output, ProtectedRegionResolver protectedRegionResolver) { |
| super(resourceManager, currentResource, vars, globalVars); |
| this.output = output; |
| this.protectedRegionResolver = protectedRegionResolver; |
| } |
| |
| /*copy constructor*/ |
| protected XpandExecutionContextImpl(XpandExecutionContextImpl original) { |
| super(original); |
| this.output = original.output; |
| this.protectedRegionResolver = original.protectedRegionResolver; |
| } |
| |
| |
| @Override |
| public XpandExecutionContextImpl cloneContext() { |
| final XpandExecutionContextImpl result = new XpandExecutionContextImpl(this); |
| result.registeredAdvices.addAll(registeredAdvices); //todo: [aha] before I refactored, there was an assignment in this place. Is this modification correct? |
| return result; |
| } |
| |
| public XpandDefinition findDefinition(final String name, final EClassifier target, final EClassifier[] paramTypes) { |
| String templateName; |
| boolean localCall = name.indexOf(SyntaxConstants.NS_DELIM) < 0; |
| if (localCall) { |
| templateName = ((XpandResource) currentResource()).getFullyQualifiedName(); //need an enclosing resource in case of composite |
| } else { |
| templateName = TypeNameUtil.withoutLastSegment(name); |
| } |
| XpandResource tpl = findTemplate(templateName); |
| if (tpl == null) { |
| if (localCall) { |
| tpl = (XpandResource) currentResource(); |
| } else { |
| return null; |
| } |
| } |
| final XpandExecutionContext ctx = (XpandExecutionContext) cloneWithResource(tpl); |
| XpandDefinition def = findDefinition(tpl.getDefinitions(), name, target, paramTypes, ctx); |
| if (def == null) { |
| return null; |
| } |
| XpandAdvice[] advicesInResource = tpl.getAdvices(); |
| for (int x = advicesInResource.length - 1; x >= 0; x--) { |
| final XpandAdvice adv = advicesInResource[x]; |
| if (adv.matches(def, this)) { |
| def = new AdvicedDefinition(adv, def); |
| } |
| } |
| for (int x = registeredAdvices.size() - 1; x >= 0; x--) { |
| final XpandAdvice adv = registeredAdvices.get(x); |
| if (adv.matches(def, this)) { |
| def = new AdvicedDefinition(adv, def); |
| } |
| } |
| return def; |
| } |
| |
| public void registerAdvices(final String fullyQualifiedName) { |
| final XpandResource tpl = findTemplate(fullyQualifiedName); |
| if (tpl == null) { |
| throw new RuntimeException("Couldn't find template : " + fullyQualifiedName); |
| } |
| final XpandAdvice[] as = tpl.getAdvices(); |
| for (final XpandAdvice advice : as) { |
| if (registeredAdvices.contains(advice)) { |
| Activator.logWarn("advice " + advice.toString() + " allready registered!"); |
| } else { |
| registeredAdvices.add(advice); |
| } |
| } |
| } |
| |
| public ProtectedRegionResolver getProtectedRegionResolver() { |
| return protectedRegionResolver; |
| } |
| |
| public Output getOutput() { |
| return output; |
| } |
| |
| @Override |
| protected String[] getImportedNamespaces() { |
| if (currentResource() instanceof XpandResource) { |
| return ((XpandResource) currentResource()).getImportedNamespaces(); |
| } |
| return super.getImportedNamespaces(); |
| } |
| |
| @Override |
| protected String[] getImportedExtensions() { |
| if (currentResource() instanceof XpandResource) { |
| return ((XpandResource) currentResource()).getImportedExtensions(); |
| } |
| return super.getImportedExtensions(); |
| } |
| |
| public XpandResource findTemplate(final String templateName) { |
| if (getResourceManager() == null) { |
| return null; |
| } |
| // XXX findTemplate needs kinda file uri, while metamodel import needs nsURI |
| final List<String> possibleNames = getPossibleNames(templateName, getImportedNamespaces()); |
| for (String name : possibleNames) { |
| final XpandResource tpl = getResourceManager().loadXpandResource(name); |
| if (tpl != null) { |
| // installAspectsFor(templateName); |
| return tpl; |
| } |
| } |
| return null; |
| } |
| |
| // private void installAspectsFor(String templateName) { |
| // String aspectsTemplateName = "aspects" + SyntaxConstants.NS_DELIM + templateName; |
| // XpandResource aspects = getResourceManager().loadXpandResource(aspectsTemplateName); |
| // if (aspects != null) { |
| // registeredAdvices.addAll(Arrays.asList(aspects.getAdvices())); |
| // } |
| // } |
| |
| private List<String> getPossibleNames(final String name, final String[] importedNs) { |
| final String typeName = TypeNameUtil.getTypeName(name); |
| final String typesMetamodelName = TypeNameUtil.getMetaModelName(name); |
| final String collectionTypeName = TypeNameUtil.getCollectionTypeName(name); |
| |
| final List<String> result = new ArrayList<String>(); |
| result.add(name); |
| |
| for (final String string : importedNs) { |
| final StringBuffer s = new StringBuffer(); |
| if (collectionTypeName != null) { |
| s.append(collectionTypeName).append("["); |
| } |
| if (typesMetamodelName != null) { |
| s.append(typesMetamodelName).append("!"); |
| } |
| s.append(string).append(SyntaxConstants.NS_DELIM).append(typeName); |
| if (collectionTypeName != null) { |
| s.append("]"); |
| } |
| result.add(s.toString()); |
| } |
| return result; |
| } |
| |
| /** |
| * resolves the correct definition (using parametric polymorphism) |
| * XXX: get rid of the ctx argument and redeclare as non-static? |
| * @param definitions |
| * @param target |
| * @param paramTypes |
| * @return |
| */ |
| private static XpandDefinition findDefinition(final XpandDefinition[] definitions, final String name, final EClassifier target, |
| EClassifier[] paramTypes, final XpandExecutionContext ctx) { |
| if (paramTypes == null) { |
| paramTypes = new EClassifier[0]; |
| } |
| final String unqualifiedName = TypeNameUtil.getLastSegment(name); |
| // XXX Instead of using map as a mere pair storage, do it like Extension does with init(ctx) |
| // to resolve and keep typed arguments |
| HashMap<XpandDefinition, List<EClassifier>> resolvedDefs = new HashMap<XpandDefinition, List<EClassifier>>(); |
| for (final XpandDefinition def : definitions) { |
| if (!def.getName().equals(unqualifiedName)) { |
| continue; |
| } |
| if (def.getParams().length == paramTypes.length) { |
| final LinkedList<EClassifier> defsParamTypes = new LinkedList<EClassifier>(); |
| EClassifier t = null; |
| boolean complete = true; |
| for (int j = 0; (j < paramTypes.length) && complete; j++) { |
| t = ctx.getTypeForName(def.getParams()[j].getType().getValue()); |
| if (t == null) { |
| complete = false; |
| } |
| defsParamTypes.add(t); |
| } |
| t = ctx.getTypeForName(def.getTargetType()); |
| if (t == null) { |
| complete = false; |
| } else { |
| defsParamTypes.addFirst(t); |
| } |
| if (complete) { |
| resolvedDefs.put(def, defsParamTypes); |
| } |
| } |
| } |
| return PolymorphicResolver.filterDefinition(resolvedDefs, target, Arrays.asList(paramTypes)); |
| } |
| } |