blob: 52b14fb541e26bc1cd2d402d296b3520cf35a389 [file] [log] [blame]
/*
* <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));
}
}