/******************************************************************************* | |
* Copyright (c) 2008 The University of York. | |
* 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: | |
* Dimitrios Kolovos - initial API and implementation | |
******************************************************************************/ | |
package org.eclipse.epsilon.evl.emf.validation; | |
import java.net.URI; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashSet; | |
import java.util.Map; | |
import java.util.Set; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.emf.common.util.BasicDiagnostic; | |
import org.eclipse.emf.common.util.Diagnostic; | |
import org.eclipse.emf.common.util.DiagnosticChain; | |
import org.eclipse.emf.ecore.EClass; | |
import org.eclipse.emf.ecore.EDataType; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.EValidator; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.emf.ecore.util.Diagnostician; | |
import org.eclipse.epsilon.common.dt.util.LogUtil; | |
import org.eclipse.epsilon.emc.emf.EmfPrettyPrinter; | |
import org.eclipse.epsilon.emc.emf.InMemoryEmfModel; | |
import org.eclipse.epsilon.eol.dt.launching.EclipseContextManager; | |
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException; | |
import org.eclipse.epsilon.eol.execute.context.Variable; | |
import org.eclipse.epsilon.eol.types.EolAnyType; | |
import org.eclipse.epsilon.evl.EvlFixInstance; | |
import org.eclipse.epsilon.evl.EvlModule; | |
import org.eclipse.epsilon.evl.EvlUnsatisfiedConstraint; | |
import org.eclipse.epsilon.evl.IEvlFixer; | |
import org.eclipse.epsilon.evl.IEvlModule; | |
public class EvlValidator implements EValidator { | |
protected Set<String> diagnosticVariables = null; | |
protected EvlModule module = null; | |
protected URI source; | |
protected EmfPrettyPrinter printer = new EmfPrettyPrinter(); | |
protected Resource currentResource = null; | |
protected ValidationResults results = new ValidationResults();; | |
protected Collection<EObject> history = new ArrayList<EObject>(); | |
protected String modelName; | |
protected String ePackageUri; | |
protected String bundleId; | |
public static final String DEFAULT_MODEL_NAME = "_Model"; | |
/** | |
* Key for the validation context, that (when provided) holds a | |
* IProgressMonitor object | |
*/ | |
public static final String VALIDATION_MONITOR = "Epsilon EVL Validation Monitor"; | |
public EvlValidator(URI source, String modelName, String ePackageUri, String bundleId) { | |
this.source = source; | |
this.modelName = modelName; | |
this.ePackageUri = ePackageUri; | |
this.bundleId = bundleId; | |
} | |
/** | |
* <p>Indicates that the value of the entry of the {@link Diagnostician} | |
* context {@link java.util.Map} with the specified <code>name</code> should | |
* be published as a global variable in the EVL script. If the context map | |
* does not contain an entry with the specified <code>name</code>, the variable | |
* will be set to <code>null</code>. | |
* | |
* <p>Note: this map is received through the <code>validate</code> methods in this | |
* class.</p> | |
* | |
* @see #validate(EObject, DiagnosticChain, Map) | |
* @see #validate(EClass, EObject, DiagnosticChain, Map) | |
* @see #validate(EDataType, Object, DiagnosticChain, Map) | |
*/ | |
public void addDiagnosticianVariable(String name) { | |
if(diagnosticVariables == null) { | |
diagnosticVariables = new HashSet<String>(); | |
} | |
diagnosticVariables.add(name); | |
} | |
public boolean validate(EObject object, DiagnosticChain diagnostics, | |
Map<Object, Object> context) { | |
return true; | |
} | |
public boolean validate(EClass eClass, EObject eObject, | |
DiagnosticChain diagnostics, Map<Object, Object> context) { | |
if (eObject.eResource() == null) return false; | |
if(diagnostics != null) { | |
// A complete validation is performed, so clear old fixes | |
EvlMarkerResolutionGenerator.INSTANCE.removeFixesFor(eObject); | |
} | |
// If it is the root that is validated validate the whole resource and cache the results | |
if (eObject.eContainer() == null) { | |
validate(eObject.eResource(), context); | |
// Add problem markers for violations in objects in externally referenced models | |
for (Map.Entry<Object, Collection<EvlUnsatisfiedConstraint>> entry : results.entrySet()) { | |
if (!(entry.getKey() instanceof EObject)) { | |
continue; | |
} | |
final EObject key = (EObject)entry.getKey(); | |
if (key.eResource() == eObject.eResource()) { | |
continue; | |
} | |
addMarkers("[" + key.eResource().getURI() + "] ", key, diagnostics); | |
} | |
} | |
addMarkers("", eObject, diagnostics); | |
return results.size() == 0; | |
} | |
public boolean validate(EDataType dataType, Object value, | |
DiagnosticChain diagnostics, Map<Object, Object> context) { | |
return true; | |
} | |
protected Diagnostic createDiagnostic(String msgPrefix, EvlUnsatisfiedConstraint unsatisfied) { | |
int severity = 0; | |
if (unsatisfied.getConstraint().isCritique()) { | |
if (unsatisfied.getConstraint().isInfo()) { | |
severity = Diagnostic.INFO; | |
} | |
else { | |
severity = Diagnostic.WARNING; | |
} | |
} | |
else severity = Diagnostic.ERROR; | |
String message = unsatisfied.getMessage(); | |
int code = 0; | |
BasicDiagnostic diagnostic = new BasicDiagnostic(severity, bundleId, code, msgPrefix + message, new Object[]{ unsatisfied.getInstance() }); | |
return diagnostic; | |
} | |
private void validate(Resource resource, Map<Object, Object> context) { | |
results.clear(); | |
module = new EvlModule(); | |
try { | |
module.parse(source); | |
} catch (Exception e) { | |
LogUtil.log("An error was encountered while parsing " + source + " : " + e.getMessage(), e, true); | |
} | |
if (module.getParseProblems().size() > 0) { | |
LogUtil.log(source + " has one or more syntax errors : " + module.getParseProblems().get(0).toString(), null, true); | |
} | |
InMemoryEmfModel model = new InMemoryEmfModel(modelName, resource, ePackageUri); | |
//model.setName(modelName); | |
module.getContext().getModelRepository().addModel(model); | |
Object monitor = null; | |
if (context != null) { | |
monitor = context.get(VALIDATION_MONITOR); | |
} | |
if (monitor instanceof IProgressMonitor) { | |
EclipseContextManager.setup(module.getContext(), (IProgressMonitor) monitor); | |
} else { | |
EclipseContextManager.setup(module.getContext()); | |
} | |
// Add variables to the EvlModule to make the available to the EVL rules | |
if (diagnosticVariables != null) { | |
for (String diagnosticVariable : diagnosticVariables) { | |
final Variable variable = new Variable(diagnosticVariable, | |
context.get(diagnosticVariable), | |
EolAnyType.Instance); | |
module.getContext().getFrameStack().put(variable); | |
} | |
} | |
try { | |
module.execute(); | |
} catch (EolRuntimeException e) { | |
LogUtil.log("A runtime error was raised during the evaluation of " + source + " : " + e.getMessage(), e, true); | |
} | |
module.setUnsatisfiedConstraintFixer(new IEvlFixer() { | |
public void fix(IEvlModule module) throws EolRuntimeException { | |
// Do nothing | |
} | |
}); | |
for (EvlUnsatisfiedConstraint unsatisfied : module.getContext().getUnsatisfiedConstraints()) { | |
Object key = unsatisfied.getInstance(); | |
if (!results.containsKey(key)) { | |
results.put(key, new ArrayList<EvlUnsatisfiedConstraint>()); | |
} | |
results.get(key).add(unsatisfied); | |
} | |
module.getContext().dispose(); | |
module.getContext().getModelRepository().dispose(); | |
} | |
private void addMarkers(String msgPrefix, EObject eObject, DiagnosticChain diagnostics) { | |
if(diagnostics == null) { | |
// user is not interested in markers... | |
return; | |
} | |
Collection<EvlUnsatisfiedConstraint> unsatisfiedConstraints = results.get(eObject); | |
if (unsatisfiedConstraints != null && unsatisfiedConstraints.size() > 0) { | |
for (EvlUnsatisfiedConstraint unsatisfied : unsatisfiedConstraints) { | |
diagnostics.add(createDiagnostic(msgPrefix, unsatisfied)); | |
for (Object fix : unsatisfied.getFixes()) { | |
EvlMarkerResolutionGenerator.INSTANCE.addResolution(unsatisfied.getMessage(),(EvlFixInstance) fix, modelName, ePackageUri); | |
} | |
} | |
} | |
} | |
} |