|
Re: Incremental Gen. throws nullPointer [message #639547 is a reply to message #639400] |
Tue, 16 November 2010 20:42 |
|
Hi,
you stumbled into https://bugs.eclipse.org/bugs/show_bug.cgi?id=326025
You can try if this patched file works for you
/*******************************************************************************
* Copyright (c) 2005, 2009 eXXcellent solution gmbh 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:
* Achim Demelt - initial API and implementation
*******************************************************************************/
package org.eclipse.xpand2.incremental;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.compare.diff.metamodel.AttributeChange;
import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeLeftTarget;
import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeRightTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChange;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.emf.ecore.util.EcoreUtil.EqualityHelper;
import org.eclipse.emf.mwe.core.WorkflowContext;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.lib.AbstractWorkflowComponent2;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.internal.xpand2.ast.FileStatement;
import org.eclipse.internal.xtend.expression.ast.FeatureCall;
import org.eclipse.internal.xtend.expression.ast.Identifier;
import org.eclipse.internal.xtend.expression.ast.SyntaxElement;
import org.eclipse.xpand.incremental.trace.InputElement;
import org.eclipse.xpand.incremental.trace.OutputFile;
import org.eclipse.xpand.incremental.trace.Trace;
import org.eclipse.xpand.incremental.trace.TraceFactory;
import org.eclipse.xtend.expression.ExecutionContext;
import org.eclipse.xtend.expression.VetoableCallback;
public class IncrementalGenerationCallback extends AbstractWorkflowComponent2 implements VetoableCallback {
private String diffModelSlot;
private String oldTraceModelSlot;
private String newTraceModelSlot;
private EObject diffModel;
private Trace oldTraceModel;
private Trace newTraceModel;
private OutputFile currentOutputFile;
// an array of EObject[2] where target object at index 0 and feature is at index 1
private EObject[][] changedElements;
public void setDiffModelSlot(String diffModelSlot) {
this.diffModelSlot = diffModelSlot;
}
public void setOldTraceModelSlot(String oldTraceModelSlot) {
this.oldTraceModelSlot = oldTraceModelSlot;
}
public void setNewTraceModelSlot(String newTraceModelSlot) {
this.newTraceModelSlot = newTraceModelSlot;
}
@Override
protected void checkConfigurationInternal(Issues issues) {
super.checkConfigurationInternal(issues);
if (diffModelSlot == null) {
issues.addError("No diffModelSlot given. Cannot do incremental generation.");
}
if (oldTraceModelSlot == null) {
issues.addError("No oldTraceModelSlot given. Cannot do incremental generation.");
}
if (newTraceModelSlot == null) {
issues.addError("No newTraceModelSlot given. Cannot do incremental generation.");
}
}
@Override
public void invokeInternal(WorkflowContext workflowContext, ProgressMonitor monitor, Issues issues) {
diffModel = (EObject) workflowContext.get(diffModelSlot);
if (diffModel == null) {
issues.addWarning("No diffModel in slot " + diffModelSlot + ". Cannot do incremental generation.");
} else {
prepareChangedElements();
}
oldTraceModel = (Trace) workflowContext.get(oldTraceModelSlot);
if (oldTraceModel == null) {
issues.addWarning("No oldTraceModel in slot " + oldTraceModelSlot + ". Cannot do incremental generation.");
}
newTraceModel = TraceFactory.eINSTANCE.createTrace();
workflowContext.set(newTraceModelSlot, newTraceModel);
}
/**
* Collects the relevant information out of the diff model. This speeds up later processing.
*/
private void prepareChangedElements() {
List<EObject[]> elements = new ArrayList<EObject[]>();
for (Iterator<EObject> i = diffModel.eAllContents(); i.hasNext();) {
EObject diff = i.next();
if (diff instanceof AttributeChange) {
AttributeChange change = (AttributeChange) diff;
elements.add(new EObject[] {change.getLeftElement(), change.getAttribute()});
} else if (diff instanceof ReferenceChange) {
ReferenceChange change = (ReferenceChange) diff;
elements.add(new EObject[] {change.getLeftElement(), change.getReference()});
} else if (diff instanceof ModelElementChangeLeftTarget) {
ModelElementChangeLeftTarget change = (ModelElementChangeLeftTarget) diff;
elements.add(new EObject[] {change.getLeftElement().eContainer(), change.getLeftElement().eContainingFeature()});
} else if (diff instanceof ModelElementChangeRightTarget) {
ModelElementChangeRightTarget change = (ModelElementChangeRightTarget) diff;
elements.add(new EObject[] {change.getLeftParent(), change.getRightElement().eContainingFeature()});
}
}
changedElements = elements.toArray(new EObject[0][0]);
}
public boolean pre(SyntaxElement element, ExecutionContext ctx) {
if (element instanceof FileStatement) {
return handleFileStatement((FileStatement)element, ctx);
}
if (element instanceof FeatureCall) {
return handleFeatureCall((FeatureCall)element, ctx);
}
return true;
}
private boolean handleFileStatement(FileStatement fileStatement, ExecutionContext ctx) {
String fileName = fileStatement.getTargetFileName().evaluate(ctx).toString();
String outletName = fileStatement.getOutletName();
// sanity check:
if (fileName == null) {
return true;
}
// check if we have an existing trace for that file
// and if so, was there a change that requires the file to be generated
OutputFile oldFileTrace = getOldTrace(fileName, outletName);
if (oldFileTrace == null || hasRelevantChangeForFile(oldFileTrace)) {
// no old trace, or we found a relevant change => generate the file and create new trace for that
currentOutputFile = TraceFactory.eINSTANCE.createOutputFile();
currentOutputFile.setFileName(fileName);
currentOutputFile.setOutlet(outletName);
currentOutputFile.setTargetObject((EObject) ctx.getVariable(ExecutionContext.IMPLICIT_VARIABLE).getValue());
newTraceModel.getOutputFiles().add(currentOutputFile);
// yes, we definitely want to generate this file.
return true;
} else {
// it seems we don't have to generate this file
// copy the trace information over into the new trace model
Copier copier = new Copier();
OutputFile copyOfFileTrace = (OutputFile) copier.copy(oldFileTrace);
copier.copyReferences();
newTraceModel.getOutputFiles().add(copyOfFileTrace);
// now ignore upcoming features
currentOutputFile = null;
// and definitely don't generate the file
return false;
}
}
/**
* Checks if the changes contained in the diff imply that the given file
* has to be generated.
*
* @param oldFileTrace The old trace information for the file to check. Must not be null.
* @return true if the file has to be generated, false if not.
*/
private boolean hasRelevantChangeForFile(OutputFile oldFileTrace) {
// fast exit: no diff model ;-)
if (changedElements == null) {
return true;
}
for (EObject[] diff : changedElements) {
for (InputElement input : oldFileTrace.getInputElements()) {
if (new EqualityHelper().equals(diff[0], input.getModelElement()) &&
new EqualityHelper().equals(diff[1], input.getFeature())) {
// abort at first change
return true;
}
}
}
// no change found
return false;
}
/**
* Finds an OutletFile in the old trace model for the given parameter.
* @param fileName The name of the file too look up. Must not be null.
* @param outletName The name of the outlet the file is located in. May be null.
* @return The requested OutletFile or null if none was found.
*/
private OutputFile getOldTrace(String fileName, String outletName) {
// quick exit. no trace model ;-)
if (oldTraceModel == null) {
return null;
}
// now check each file in the trace
for (OutputFile f : oldTraceModel.getOutputFiles()) {
if (f.getFileName().equals(fileName) &&
(outletName == null ? f.getOutlet() == null : outletName.equals(f.getOutlet()))) {
return f;
}
}
return null;
}
private boolean handleFeatureCall(FeatureCall featureCall, ExecutionContext ctx) {
if (currentOutputFile != null) {
Identifier currentFeature = featureCall.getName();
// get target of feature call
Object target = null;
if (featureCall.getTarget() != null) {
target = featureCall.getTarget().evaluate(ctx);
}
if (target == null && ctx.getVariable(ExecutionContext.IMPLICIT_VARIABLE) != null) {
target = ctx.getVariable(ExecutionContext.IMPLICIT_VARIABLE).getValue();
}
String featureName = currentFeature.getNameString(ctx);
if (target instanceof EObject) {
EObject targetObject = (EObject) target;
addTraceForObject(featureName, targetObject);
}
if (target instanceof Collection<?>) {
@SuppressWarnings("unchecked")
Collection<EObject> targetCollection = (Collection<EObject>) target;
for (EObject targetObject : targetCollection) {
addTraceForObject(featureName, targetObject);
}
}
}
return true;
}
private void addTraceForObject(String featureName, EObject targetObject) {
EStructuralFeature feature = targetObject.eClass().getEStructuralFeature(featureName);
if (feature != null) {
addInputElement(targetObject, feature);
}
}
private void addInputElement(EObject target, EStructuralFeature feature) {
// check for duplicates first
for (InputElement e : currentOutputFile.getInputElements()) {
if (e.getModelElement() == target && e.getFeature() == feature) {
return;
}
}
// okay, new element => add that
InputElement inputElement = TraceFactory.eINSTANCE.createInputElement();
inputElement.setModelElement(target);
inputElement.setFeature(feature);
currentOutputFile.getInputElements().add(inputElement);
}
public void post(SyntaxElement element, ExecutionContext ctx, Object expressionResult) {
// don't register any subsequent changes for the file after the FILE statement has been processed
if (element instanceof FileStatement) {
currentOutputFile = null;
}
}
}
~Christian
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
|
Powered by
FUDForum. Page generated in 0.02864 seconds