/*******************************************************************************
* Copyright (c) 2009 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.xtend.profiler;
import java.util.List;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.mwe.core.ConfigurationException;
import org.eclipse.emf.mwe.core.WorkflowContext;
import org.eclipse.emf.mwe.core.container.CompositeComponent;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.internal.xpand2.ast.AbstractDefinition;
import org.eclipse.internal.xtend.expression.ast.SyntaxElement;
import org.eclipse.internal.xtend.xtend.ast.AbstractExtension;
import org.eclipse.internal.xtend.xtend.ast.Check;
import org.eclipse.xtend.expression.ExecutionContext;
import org.eclipse.xtend.expression.VetoableCallback;
import org.eclipse.xtend.profiler.profilermodel.ModelFactory;
import org.eclipse.xtend.profiler.profilermodel.ModelPackage;
import org.eclipse.xtend.profiler.profilermodel.ProfilingResult;
import org.eclipse.xtend.typesystem.Type;
/**
* Use this workflow component to wrap other inside a workflow. Then, refer
* to this via idref as a callback. In the end a profiling model will be stored
* in the resultslot and can be used with one of the templates.
*
* <pre><code>
* <component id="profiler" class="org.eclipse.xtend.profiler.ProfilerComponent">
* <resultSlot value="profilingResult" />
*
* <component class="org.eclipse.xtend.check.CheckComponent">
* <vetoableCallback idRef="profiler" />
* ...
* </component>
* <component class="org.eclipse.xtend.XtendComponent">
* <vetoableCallback idRef="profiler" />
* ...
* </component>
* <component class="org.eclipse.xpand2.Generator">
* <vetoableCallback idRef="profiler" />
* ...
* </component>
* </component>
*
* <component class="org.eclipse.xpand2.Generator" fileEncoding="ISO-8859-1">
* <metaModel idRef="mm"/>
* <expand value="org::eclipse::xtend::profiler::templates::Html::Main FOR profilingResult"/>
* <outlet overwrite="true" path="profiling"/>
* </component>
* </code></pre>
*
* @author Heiko Behrens - Initial contribution and API
*
*/
public class ProfilerComponent extends CompositeComponent implements VetoableCallback {
static {
Registry.INSTANCE.put(ModelPackage.eNS_URI, ModelPackage.eINSTANCE);
}
public ProfilerComponent() {
super("Profiler");
}
private String resultSlot;
public void setResultSlot(String resultSlot) {
this.resultSlot = resultSlot;
}
public String getResultSlot() {
return resultSlot;
}
private Profiler profiler;
public ProfilingResult getProfilingResult() {
return profiler.getProfilingResult();
}
@Override
public void checkConfiguration(Issues issues) throws ConfigurationException {
super.checkConfiguration(issues);
if(resultSlot==null)
issues.addError("resultSlot not specified");
}
@Override
public void invoke(WorkflowContext ctx, ProgressMonitor monitor,
Issues issues) {
prepareProfiler();
super.invoke(ctx, monitor, issues);
finalizeProfiler();
ctx.set(resultSlot, profiler.getProfilingResult());
}
public void finalizeProfiler() {
// TODO: mark component state as freezed -> no more callbacks allowed
CycleDetector detector = new CycleDetector(profiler.getProfilingResult());
detector.detectCycles();
}
public void prepareProfiler() {
profiler = new Profiler(ModelFactory.eINSTANCE.createProfilingResult());
}
public boolean pre(SyntaxElement ele, ExecutionContext ctx) {
String key = findKeyFor(ele, ctx);
profiler.beginRoutine(key);
return true;
}
public void post(SyntaxElement ele, ExecutionContext ctx,
Object expressionResult) {
profiler.endRoutine();
}
private String findKeyFor(SyntaxElement element, ExecutionContext ctx) {
if (element instanceof AbstractDefinition) {
AbstractDefinition def = (AbstractDefinition) element;
return "XPD " + def.getQualifiedName() + def.getParamString(true) + " FOR " + def.getTargetType();
}
if (element instanceof AbstractExtension) {
AbstractExtension ext = (AbstractExtension) element;
return "XTD " + ext.getQualifiedName() + getParamString(ext.getParameterTypes());
}
if (element instanceof Check) {
Check c = (Check) element;
return "CHK " + c.toString();
}
return null;
}
private String getParamString(List<Type> params) {
final StringBuffer buff = new StringBuffer("(");
for (int i = 0; i < params.size(); i++) {
final Type t = params.get(i);
buff.append(t.getName());
if (i + 1 < params.size()) {
buff.append(",");
}
}
return buff.append(")").toString();
}
}