blob: 78d48a337f595d3725f9c48eab9f095266f3207d [file] [log] [blame]
/*
* Copyright (c) 2007, 2010 Borland Software Corporation 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:
* Dmitry Stadnik (Borland) - initial API and implementation
* Artem Tikhomirov (Borland) - introduced GenAuditContext entity
* straightforward and simple #validate() implementation
*/
«IMPORT 'http://www.eclipse.org/gmf/2009/GenModel'»
«EXTENSION xpt::GenAuditRoot»
«DEFINE ValidationProvider FOR gmfgen::GenDiagram
«EXPAND xpt::Common::copyright FOR editorGen
package «providersPackageName»;
«EXPAND xpt::Common::generatedClassComment»
public class «validationProviderClassName» {
«EXPAND constraintsActive
«EXPAND shouldConstraintsBePrivate
«EXPAND runWithActiveConstraints
«EXPAND isInDefaultEditorContext
«EXPAND selectors FOR editorGen.audits
«EXPAND strategy_support»
«EXPAND constraintAdapters(self) FOR editorGen.audits
«EXPAND additions
}
«ENDDEFINE»
«DEFINE constraintsActive FOR gmfgen::GenDiagram
«EXPAND xpt::Common::generatedMemberComment»
private static boolean constraintsActive = false;
«ENDDEFINE»
«DEFINE shouldConstraintsBePrivate FOR gmfgen::GenDiagram
«EXPAND xpt::Common::generatedMemberComment»
public static boolean shouldConstraintsBePrivate() {
return false;
}
«ENDDEFINE»
«DEFINE runWithActiveConstraints FOR gmfgen::GenDiagram
«EXPAND xpt::Common::generatedMemberComment»
public static void runWithConstraints(org.eclipse.emf.transaction.TransactionalEditingDomain editingDomain, Runnable operation) {
final Runnable op = operation;
Runnable task = new Runnable() {
public void run() {
try {
constraintsActive = true;
op.run();
} finally {
constraintsActive = false;
}
}
};
if(editingDomain != null) {
try {
editingDomain.runExclusive(task);
} catch (Exception e) {
«editorGen.plugin.getActivatorQualifiedClassName()».getInstance().logError("Validation failed", e); «EXPAND xpt::Common::nonNLS»
}
} else {
task.run();
}
}
«ENDDEFINE»
«DEFINE additions FOR gmfgen::GenDiagram»«ENDDEFINE»
«DEFINE selectors FOR gmfgen::GenAuditRoot
«FOREACH clientContexts->asSequence() AS ctx»
«EXPAND xpt::Common::generatedMemberComment»
public static class «ctx.className» implements org.eclipse.emf.validation.model.IClientSelector {
«EXPAND xpt::Common::generatedMemberComment»
public boolean selects(Object object) {
«IF (ctx.ruleTargets)[gmfgen::GenDiagramElementTarget]->size() > 0
if (isInDefaultEditorContext(object) && object instanceof org.eclipse.gmf.runtime.notation.View) {
final int id = «EXPAND xpt::editor::VisualIDRegistry::getVisualIDMethodCall FOR editorGen.diagram»((org.eclipse.gmf.runtime.notation.View) object);
boolean result = false;
«FOREACH getTargetDiagramElements(ctx) AS e
result = result || id == «EXPAND xpt::editor::VisualIDRegistry::visualID FOR e»;
«ENDFOREACH
return result;
}
return false;
«ELSE
return isInDefaultEditorContext(object);
«ENDIF
}
}
«ENDFOREACH
«ENDDEFINE»
«DEFINE isInDefaultEditorContext FOR gmfgen::GenDiagram
«EXPAND xpt::Common::generatedMemberComment»
static boolean isInDefaultEditorContext(Object object) {
if(shouldConstraintsBePrivate() && !constraintsActive) {
return false;
}
if (object instanceof org.eclipse.gmf.runtime.notation.View) {
return constraintsActive && «EXPAND xpt::editor::VisualIDRegistry::modelID».equalsEXPAND xpt::editor::VisualIDRegistry::getModelIDMethodCall»((org.eclipse.gmf.runtime.notation.View) object));
}
return true;
}
«ENDDEFINE»
«DEFINE strategy_support FOR gmfgen::GenDiagram
«IF hasDiagramElementTargetRule(editorGen.audits)-»
«EXPAND xpt::Common::generatedMemberComment»
public static org.eclipse.emf.validation.service.ITraversalStrategy getNotationTraversalStrategy(
org.eclipse.emf.validation.service.IBatchValidator validator) {
return new CtxSwitchStrategy(validator);
}
«EXPAND xpt::Common::generatedMemberComment»
private static class CtxSwitchStrategy implements org.eclipse.emf.validation.service.ITraversalStrategy {
«EXPAND xpt::Common::generatedMemberComment»
private org.eclipse.emf.validation.service.ITraversalStrategy defaultStrategy;
«EXPAND xpt::Common::generatedMemberComment»
private int currentSemanticCtxId = -1;
«EXPAND xpt::Common::generatedMemberComment»
private boolean ctxChanged = true;
«EXPAND xpt::Common::generatedMemberComment»
private org.eclipse.emf.ecore.EObject currentTarget;
«EXPAND xpt::Common::generatedMemberComment»
private org.eclipse.emf.ecore.EObject preFetchedNextTarget;
«EXPAND xpt::Common::generatedMemberComment»
private final int[] contextSwitchingIdentifiers;
«EXPAND xpt::Common::generatedMemberComment»
CtxSwitchStrategy(org.eclipse.emf.validation.service.IBatchValidator validator) {
this.defaultStrategy = validator.getDefaultTraversalStrategy();
this.contextSwitchingIdentifiers = new int[] {
«EXPAND xpt::editor::VisualIDRegistry::visualID FOREACH getAllTargetDiagramElements(editorGen.audits) SEPARATOR ','»
};
java.util.Arrays.sort(this.contextSwitchingIdentifiers);
}
«EXPAND xpt::Common::generatedMemberComment»
public void elementValidated(org.eclipse.emf.ecore.EObject element,
org.eclipse.core.runtime.IStatus status) {
defaultStrategy.elementValidated(element, status);
}
«EXPAND xpt::Common::generatedMemberComment»
public boolean hasNext() {
return defaultStrategy.hasNext();
}
«EXPAND xpt::Common::generatedMemberComment»
public boolean isClientContextChanged() {
if (preFetchedNextTarget == null) {
preFetchedNextTarget = next();
prepareNextClientContext(preFetchedNextTarget);
}
return ctxChanged;
}
«EXPAND xpt::Common::generatedMemberComment»
public org.eclipse.emf.ecore.EObject next() {
org.eclipse.emf.ecore.EObject nextTarget = preFetchedNextTarget;
if (nextTarget == null) {
nextTarget = defaultStrategy.next();
}
this.preFetchedNextTarget = null;
return this.currentTarget = nextTarget;
}
«EXPAND xpt::Common::generatedMemberComment»
public void startTraversal(java.util.Collection traversalRoots, org.eclipse.core.runtime.IProgressMonitor monitor) {
defaultStrategy.startTraversal(traversalRoots, monitor);
}
«EXPAND xpt::Common::generatedMemberComment»
private void prepareNextClientContext(org.eclipse.emf.ecore.EObject nextTarget) {
if (nextTarget != null && currentTarget != null) {
if (nextTarget instanceof org.eclipse.gmf.runtime.notation.View) {
final int id = «EXPAND xpt::editor::VisualIDRegistry::getVisualIDMethodCall FOR editorGen.diagram»((org.eclipse.gmf.runtime.notation.View) nextTarget);
int nextSemanticId = (id != -1 && java.util.Arrays.binarySearch(contextSwitchingIdentifiers, id) >= 0) ? id : -1;
if ((currentSemanticCtxId != -1 && currentSemanticCtxId != nextSemanticId)
|| (nextSemanticId != -1 && nextSemanticId != currentSemanticCtxId)) {
this.ctxChanged = true;
/*[artem] not sure why not ctxChanged = <expr>, is it intentional not to reset ctxChanged if condition did not match? I doubt. FIXME?*/»
currentSemanticCtxId = nextSemanticId;
} else {
// context of domain model
this.ctxChanged = currentSemanticCtxId != -1;
currentSemanticCtxId = -1;
}
} else {
this.ctxChanged = false;
}
}
}
«ENDIF
«ENDDEFINE»
«DEFINE constraintAdapters(diagram : gmfgen::GenDiagram) FOR gmfgen::GenAuditRoot
«IF diagram.editorGen.expressionProviders <> null
«EXPAND constraintAdapter(diagram.editorGen.expressionProviders) FOREACH rules->select(a | a.requiresConstraintAdapter)-»
«IF not rules->select(a | a.requiresConstraintAdapter)->isEmpty()»
«EXPAND constraintAdapters_formatMethod»
«ENDIF»
«ENDIF
«ENDDEFINE»
«DEFINE constraintAdapter(container : gmfgen::GenExpressionProviderContainer) FOR gmfgen::GenAuditRule
«IF target <> null and target.getContext() <> null
«EXPAND xpt::Common::generatedMemberComment»
public static class «getConstraintAdapterLocalClassName()» extends org.eclipse.emf.validation.AbstractModelConstraint {
«EXPAND xpt::Common::generatedMemberComment»
public org.eclipse.core.runtime.IStatus validate(org.eclipse.emf.validation.IValidationContext ctx) {
«EXPAND constraintAdapter_initContext(self) FOR target
«EXPAND constraintAdapter_validateMethod(self) FOR rule.provider
}
}
«ENDIF
«ENDDEFINE»
«DEFINE constraintAdapters_formatMethod FOR gmfgen::GenAuditRoot
«EXPAND xpt::Common::generatedMemberComment»
static String formatElement(org.eclipse.emf.ecore.EObject object) {
return org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil.getQualifiedName(object, true);
}
«ENDDEFINE»
/*
* Expects 'context' variable to be initialized
*/
«DEFINE constraintAdapter_validateMethod(audit : gmfgen::GenAuditRule) FOR gmfgen::GenExpressionProviderBase»«ERROR 'No idea how to evaluate an audit rule for ' + self.repr()»«ENDDEFINE»
«DEFINE constraintAdapter_validateMethod(audit : gmfgen::GenAuditRule) FOR gmfgen::GenExpressionInterpreter
Object result = «EXPAND xpt::expressions::getExpression::getExpression(audit.rule, audit.target.getContext())».evaluate(context);
if (result instanceof Boolean && ((Boolean) result).booleanValue()) {
return org.eclipse.core.runtime.Status.OK_STATUSREM»XXX why not ctx.createSuccessStatus()???«ENDREM»
}
return ctx.createFailureStatus(new Object[] { formatElement(ctx.getTarget()) });
«ENDDEFINE»
«DEFINE constraintAdapter_validateMethod(audit : gmfgen::GenAuditRule) FOR gmfgen::GenJavaExpressionProvider
«IF injectExpressionBody and (audit.rule.body <> null and audit.rule.body.size() <> 0)-»
«audit.rule.body»
«ELSEIF throwException or (injectExpressionBody and (audit.rule.body = null or audit.rule.body.size() = 0))-»
// TODO: put validation code here
// Ensure that you remove @generated tag or use @generated NOT
//
// To construct approprate return value, use ctx.createSuccessStatus()
// or ctx.createFailureStatus(...)
throw new java.lang.UnsupportedOperationException("No user java implementation provided for #validate(IValidationContext) operation");«EXPAND xpt::Common::nonNLS»
«ELSE
return ctx.createFailureStatus(new Object[] { "No user java implementation provided for #validate(IValidationContext) operation" });«EXPAND xpt::Common::nonNLS»
«ENDIF
«ENDDEFINE»
/*
* Contract: declare variable with the name 'context' of appropriate type
*/
«DEFINE constraintAdapter_initContext(audit : gmfgen::GenAuditRule) FOR gmfgen::GenAuditable
«EXPAND MetaModel::DeclareAndAssign('context', 'ctx.getTarget()', false) FOR getContext()»
«ENDDEFINE»
«DEFINE constraintAdapter_initContext(audit : gmfgen::GenAuditRule) FOR gmfgen::GenDomainAttributeTarget
final Object«REM»Actual context type is genDomainAttributeTarget.getContext()«ENDREM» context = ctx.getTarget().eGetEXPAND MetaModel::MetaFeature FOR attribute»);
«REM»
For now, leave reflective access that gives Object-compatible result.
FIXME: introduce MetaModel::DeclareAndAssignAttributeValueAsObject, that would
check if attibute type is primitive and wrap accordingly, but access attribute directly!
«ENDREM
if (context == null) {
«IF nullAsError
return ctx.createFailureStatus(new Object[] { formatElement(ctx.getTarget()) });
«ELSE
return org.eclipse.core.runtime.Status.OK_STATUS;
«ENDIF
}
«ENDDEFINE»
«DEFINE constraintAdapter_initContext(audit : gmfgen::GenAuditRule) FOR gmfgen::GenAuditedMetricTarget
final Number context = «IF metric = null /*though metamodel constraint should not allow this*/»null /*FIXME: metric target was not correctly specified in the model*/«ELSE»«EXPAND MetricProvider::invokeCalcMethod('ctx.getTarget()', false) FOR metric»«ENDIF»;
«ENDDEFINE»