Added delegates (validation, setting, ...) for AQL expressions.

Change-Id: I0423078bc4de01ee268e86d035bb5cc703c9e324
diff --git a/query/plugins/org.eclipse.acceleo.query/META-INF/MANIFEST.MF b/query/plugins/org.eclipse.acceleo.query/META-INF/MANIFEST.MF
index 0db05ed..ae96600 100644
--- a/query/plugins/org.eclipse.acceleo.query/META-INF/MANIFEST.MF
+++ b/query/plugins/org.eclipse.acceleo.query/META-INF/MANIFEST.MF
@@ -14,6 +14,7 @@
  org.eclipse.acceleo.query.ast.impl;x-friends:="org.eclipse.acceleo.query.tests,org.eclipse.acceleo.query.ide.ui,org.eclipse.acceleo.query.ide.ui.test",
  org.eclipse.acceleo.query.ast.util;x-friends:="org.eclipse.acceleo.query.tests,org.eclipse.acceleo.query.ide.ui,org.eclipse.acceleo.query.ide.ui.test",
  org.eclipse.acceleo.query.ast.validation;version="5.0.0",
+ org.eclipse.acceleo.query.delegates;version="5.0.0",
  org.eclipse.acceleo.query.parser;x-friends:="org.eclipse.acceleo.query.tests,org.eclipse.acceleo.query.ide.ui,org.eclipse.acceleo.query.ide.ui.test",
  org.eclipse.acceleo.query.runtime;version="5.0.0",
  org.eclipse.acceleo.query.runtime.impl;x-friends:="org.eclipse.acceleo.query.tests,org.eclipse.acceleo.query.ide.ui,org.eclipse.acceleo.query.ide.ui.test",
diff --git a/query/plugins/org.eclipse.acceleo.query/plugin.xml b/query/plugins/org.eclipse.acceleo.query/plugin.xml
index eb06a7d..935ff85 100644
--- a/query/plugins/org.eclipse.acceleo.query/plugin.xml
+++ b/query/plugins/org.eclipse.acceleo.query/plugin.xml
@@ -23,5 +23,33 @@
             class="org.eclipse.acceleo.query.ast.AstPackage"
             genModel="model/ast.genmodel"/>
    </extension>
+   <extension
+         point="org.eclipse.emf.ecore.validation_delegate">
+      <delegate
+            class="org.eclipse.acceleo.query.delegates.AQLValidationDelegate"
+            uri="http://www.eclipse.org/acceleo/query/1.0">
+      </delegate>
+   </extension>
+   <extension
+         point="org.eclipse.emf.ecore.setting_delegate">
+      <factory
+            class="org.eclipse.acceleo.query.delegates.AQLSettingDelegateFactory"
+            uri="http://www.eclipse.org/acceleo/query/1.0">
+      </factory>
+   </extension>
+   <extension
+         point="org.eclipse.emf.ecore.invocation_delegate">
+      <factory
+            class="org.eclipse.acceleo.query.delegates.AQLInvocationDelegateFactory"
+            uri="http://www.eclipse.org/acceleo/query/1.0">
+      </factory>
+   </extension>
+   <extension
+         point="org.eclipse.emf.ecore.query_delegate">
+      <factory
+            class="org.eclipse.acceleo.query.delegates."
+            uri="http://www.eclipse.org/acceleo/query/1.0">
+      </factory>
+   </extension>
 
 </plugin>
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLInvocationDelegate.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLInvocationDelegate.java
new file mode 100644
index 0000000..55eb0f4
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLInvocationDelegate.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.acceleo.query.runtime.AcceleoQueryEvaluationException;
+import org.eclipse.acceleo.query.runtime.EvaluationResult;
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.impl.QueryEvaluationEngine;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EOperation.Internal.InvocationDelegate;
+import org.eclipse.emf.ecore.InternalEObject;
+
+/**
+ * An invocation delegate supporting AQL.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AQLInvocationDelegate implements InvocationDelegate {
+
+	/**
+	 * The {@link QueryEvaluationEngine}.
+	 */
+	private final QueryEvaluationEngine engine;
+
+	/**
+	 * The {@link AstResult}.
+	 */
+	private final AstResult astResult;
+
+	/**
+	 * The {@link List} of {@link org.eclipse.emf.ecore.EParameter#getName() eParameter name}.
+	 */
+	private final List<String> parameterNames;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param queryEnvironment
+	 *            the {@link IQueryEnvironment}
+	 * @param astResult
+	 *            the {@link AstResult}
+	 * @param parameterNames
+	 *            the {@link List} of {@link org.eclipse.emf.ecore.EParameter#getName() eParameter name}
+	 */
+	public AQLInvocationDelegate(IQueryEnvironment queryEnvironment, AstResult astResult,
+			List<String> parameterNames) {
+		engine = new QueryEvaluationEngine(queryEnvironment);
+		this.astResult = astResult;
+		this.parameterNames = parameterNames;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.EOperation.Internal.InvocationDelegate#dynamicInvoke(org.eclipse.emf.ecore.InternalEObject,
+	 *      org.eclipse.emf.common.util.EList)
+	 */
+	@Override
+	public Object dynamicInvoke(InternalEObject target, EList<?> arguments) throws InvocationTargetException {
+		if (arguments.size() != parameterNames.size()) {
+			throw new IllegalArgumentException("number of arguments mismatch " + arguments.size()
+					+ " instead of " + parameterNames.size());
+		}
+
+		final Map<String, Object> variables = new HashMap<String, Object>();
+		variables.put("self", target);
+		for (int index = 0; index < parameterNames.size(); index++) {
+			variables.put(parameterNames.get(index), arguments.get(index));
+		}
+
+		final EvaluationResult evaluationResult;
+		try {
+			evaluationResult = engine.eval(astResult, variables);
+			// CHECKSTYLE:OFF
+		} catch (Exception e) {
+			// CHECKSTYLE:ON
+			throw new InvocationTargetException(e);
+		}
+		if (evaluationResult.getDiagnostic().getSeverity() == Diagnostic.ERROR) {
+			throw new InvocationTargetException(new AcceleoQueryEvaluationException(evaluationResult
+					.getDiagnostic().getMessage()));
+		}
+
+		return evaluationResult.getResult();
+	}
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLInvocationDelegateFactory.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLInvocationDelegateFactory.java
new file mode 100644
index 0000000..5b63ed6
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLInvocationDelegateFactory.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.acceleo.query.ast.AstPackage;
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.impl.QueryBuilderEngine;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EOperation.Internal.InvocationDelegate;
+import org.eclipse.emf.ecore.EOperation.Internal.InvocationDelegate.Factory;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * An invocation delegate factory supporting AQL.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AQLInvocationDelegateFactory extends AbstractEnvironmentProvider implements Factory {
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.EOperation.Internal.InvocationDelegate.Factory#createInvocationDelegate(org.eclipse.emf.ecore.EOperation)
+	 */
+	@Override
+	public InvocationDelegate createInvocationDelegate(EOperation operation) {
+		final IQueryEnvironment env = getEnvironment();
+		final String expression = EcoreUtil.getAnnotation(operation, AstPackage.eNS_URI, "body");
+
+		final QueryBuilderEngine engine = new QueryBuilderEngine(env);
+		final AstResult astResult = engine.build(expression);
+		final List<String> parameterNames = new ArrayList<String>();
+		for (EParameter parameter : operation.getEParameters()) {
+			parameterNames.add(parameter.getName());
+		}
+
+		// TODO test if something went wrong
+
+		return new AQLInvocationDelegate(env, astResult, parameterNames);
+	}
+
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLQueryDelegate.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLQueryDelegate.java
new file mode 100644
index 0000000..6967914
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLQueryDelegate.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.acceleo.query.runtime.AcceleoQueryEvaluationException;
+import org.eclipse.acceleo.query.runtime.EvaluationResult;
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.impl.QueryEvaluationEngine;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.ecore.util.QueryDelegate;
+
+/**
+ * A query delegate supporting AQL.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AQLQueryDelegate implements QueryDelegate {
+
+	/**
+	 * The {@link QueryEvaluationEngine}.
+	 */
+	private final QueryEvaluationEngine engine;
+
+	/**
+	 * The {@link AstResult}.
+	 */
+	private final AstResult astResult;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param queryEnvironment
+	 *            the {@link IQueryEnvironment}
+	 * @param astResult
+	 *            the {@link AstResult}
+	 */
+	public AQLQueryDelegate(IQueryEnvironment queryEnvironment, AstResult astResult) {
+		engine = new QueryEvaluationEngine(queryEnvironment);
+		this.astResult = astResult;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.util.QueryDelegate#prepare()
+	 */
+	@Override
+	public void prepare() throws InvocationTargetException {
+		// nothing to do here
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.util.QueryDelegate#execute(java.lang.Object, java.util.Map)
+	 */
+	@Override
+	public Object execute(Object target, Map<String, ?> arguments) throws InvocationTargetException {
+		final Map<String, Object> variables = new HashMap<String, Object>();
+		variables.put("self", target);
+		variables.putAll(arguments);
+
+		final EvaluationResult evaluationResult;
+		try {
+			evaluationResult = engine.eval(astResult, variables);
+			// CHECKSTYLE:OFF
+		} catch (Exception e) {
+			// CHECKSTYLE:ON
+			throw new InvocationTargetException(e);
+		}
+		if (evaluationResult.getDiagnostic().getSeverity() == Diagnostic.ERROR) {
+			throw new InvocationTargetException(new AcceleoQueryEvaluationException(evaluationResult
+					.getDiagnostic().getMessage()));
+		}
+
+		return evaluationResult.getResult();
+	}
+
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLQueryDelegateFactory.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLQueryDelegateFactory.java
new file mode 100644
index 0000000..7f9982c
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLQueryDelegateFactory.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import java.util.Map;
+
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.impl.QueryBuilderEngine;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.util.QueryDelegate;
+import org.eclipse.emf.ecore.util.QueryDelegate.Factory;
+
+/**
+ * A query delegate factory supporting AQL.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AQLQueryDelegateFactory extends AbstractEnvironmentProvider implements Factory {
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.util.QueryDelegate.Factory#createQueryDelegate(org.eclipse.emf.ecore.EClassifier,
+	 *      java.util.Map, java.lang.String)
+	 */
+	@Override
+	public QueryDelegate createQueryDelegate(EClassifier context, Map<String, EClassifier> parameters,
+			String expression) {
+		final IQueryEnvironment env = getEnvironment();
+
+		final QueryBuilderEngine engine = new QueryBuilderEngine(env);
+		final AstResult astResult = engine.build(expression);
+
+		// TODO test if something went wrong
+
+		return new AQLQueryDelegate(env, astResult);
+	}
+
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLSettingDelegate.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLSettingDelegate.java
new file mode 100644
index 0000000..d9259b2
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLSettingDelegate.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.acceleo.query.runtime.EvaluationResult;
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.impl.QueryEvaluationEngine;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.BasicSettingDelegate;
+
+/**
+ * A setting delegate supporting AQL.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AQLSettingDelegate extends BasicSettingDelegate.Stateless {
+
+	/**
+	 * The {@link QueryEvaluationEngine}.
+	 */
+	private final QueryEvaluationEngine engine;
+
+	/**
+	 * The {@link AstResult}.
+	 */
+	private final AstResult astResult;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param eStructuralFeature
+	 *            the {@link EStructuralFeature}
+	 * @param queryEnvironment
+	 *            the {@link IQueryEnvironment}
+	 * @param astResult
+	 *            the {@link AstResult}
+	 */
+	public AQLSettingDelegate(EStructuralFeature eStructuralFeature, IQueryEnvironment queryEnvironment,
+			AstResult astResult) {
+		super(eStructuralFeature);
+		engine = new QueryEvaluationEngine(queryEnvironment);
+		this.astResult = astResult;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.util.BasicSettingDelegate.Stateless#get(org.eclipse.emf.ecore.InternalEObject,
+	 *      boolean, boolean)
+	 */
+	@Override
+	protected Object get(InternalEObject owner, boolean resolve, boolean coreType) {
+		final Map<String, Object> variables = new HashMap<String, Object>();
+		variables.put("self", owner);
+
+		final EvaluationResult evaluationResult = engine.eval(astResult, variables);
+
+		if (evaluationResult.getDiagnostic().getSeverity() != Diagnostic.OK) {
+			final StringBuilder messages = new StringBuilder();
+			for (Diagnostic child : evaluationResult.getDiagnostic().getChildren()) {
+				messages.append("\n" + child.getMessage());
+			}
+			throw new IllegalArgumentException("Unable to evaluate feature \"" + eStructuralFeature.getName()
+					+ "\"" + messages.toString());
+		}
+
+		return evaluationResult.getResult();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.util.BasicSettingDelegate.Stateless#isSet(org.eclipse.emf.ecore.InternalEObject)
+	 */
+	@Override
+	protected boolean isSet(InternalEObject owner) {
+		// since the setting is derived it should not be setted in anyway.
+		return false;
+	}
+
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLSettingDelegateFactory.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLSettingDelegateFactory.java
new file mode 100644
index 0000000..47aef44
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLSettingDelegateFactory.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import org.eclipse.acceleo.query.ast.AstPackage;
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.impl.QueryBuilderEngine;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EStructuralFeature.Internal.SettingDelegate;
+import org.eclipse.emf.ecore.EStructuralFeature.Internal.SettingDelegate.Factory;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * A setting delegate factory supporting AQL.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AQLSettingDelegateFactory extends AbstractEnvironmentProvider implements Factory {
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.EStructuralFeature.Internal.SettingDelegate.Factory#createSettingDelegate(org.eclipse.emf.ecore.EStructuralFeature)
+	 */
+	@Override
+	public SettingDelegate createSettingDelegate(EStructuralFeature eStructuralFeature) {
+		final IQueryEnvironment env = getEnvironment();
+		final String expression = EcoreUtil.getAnnotation(eStructuralFeature, AstPackage.eNS_URI,
+				"derivation");
+
+		final QueryBuilderEngine engine = new QueryBuilderEngine(env);
+		final AstResult astResult = engine.build(expression);
+
+		// TODO test if something went wrong
+
+		return new AQLSettingDelegate(eStructuralFeature, env, astResult);
+	}
+
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLValidationDelegate.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLValidationDelegate.java
new file mode 100644
index 0000000..4ed35b8
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AQLValidationDelegate.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.acceleo.query.runtime.EvaluationResult;
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.impl.QueryBuilderEngine;
+import org.eclipse.acceleo.query.runtime.impl.QueryEvaluationEngine;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EValidator.ValidationDelegate;
+
+/**
+ * A validation delegate supporting AQL.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AQLValidationDelegate extends AbstractEnvironmentProvider implements ValidationDelegate {
+
+	/**
+	 * The self variable name.
+	 */
+	private static final String SELF = "self";
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.EValidator.ValidationDelegate#validate(org.eclipse.emf.ecore.EClass,
+	 *      org.eclipse.emf.ecore.EObject, java.util.Map, org.eclipse.emf.ecore.EOperation, java.lang.String)
+	 */
+	@Override
+	public boolean validate(EClass eClass, EObject eObject, Map<Object, Object> context,
+			EOperation invariant, String expression) {
+		return Boolean.TRUE.equals(evaluate(eObject, expression));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.EValidator.ValidationDelegate#validate(org.eclipse.emf.ecore.EClass,
+	 *      org.eclipse.emf.ecore.EObject, java.util.Map, java.lang.String, java.lang.String)
+	 */
+	@Override
+	public boolean validate(EClass eClass, EObject eObject, Map<Object, Object> context, String constraint,
+			String expression) {
+		return Boolean.TRUE.equals(evaluate(eObject, expression));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.ecore.EValidator.ValidationDelegate#validate(org.eclipse.emf.ecore.EDataType,
+	 *      java.lang.Object, java.util.Map, java.lang.String, java.lang.String)
+	 */
+	@Override
+	public boolean validate(EDataType eDataType, Object value, Map<Object, Object> context,
+			String constraint, String expression) {
+		return Boolean.TRUE.equals(evaluate(value, expression));
+	}
+
+	/**
+	 * Evaluates the given AQL expression on the given self {@link Object}.
+	 * 
+	 * @param self
+	 *            the self {@link Object}
+	 * @param expression
+	 *            the AQL expression
+	 * @return the evaluated value
+	 */
+	private Object evaluate(Object self, String expression) {
+		final IQueryEnvironment environment = getEnvironment();
+
+		final Map<String, Object> variables = new HashMap<String, Object>();
+		variables.put(SELF, self);
+
+		final QueryBuilderEngine builderEngine = new QueryBuilderEngine(environment);
+		final AstResult astResult = builderEngine.build(expression);
+
+		if (astResult.getDiagnostic().getSeverity() == Diagnostic.OK) {
+			final QueryEvaluationEngine evaluationEngine = new QueryEvaluationEngine(environment);
+			final EvaluationResult evaluationResult = evaluationEngine.eval(astResult, variables);
+
+			if (evaluationResult.getDiagnostic().getSeverity() != Diagnostic.OK) {
+				final StringBuilder messages = new StringBuilder();
+				for (Diagnostic child : evaluationResult.getDiagnostic().getChildren()) {
+					messages.append("\n" + child.getMessage());
+				}
+				throw new IllegalArgumentException("Unable to evaluate \"" + expression + "\""
+						+ messages.toString());
+			}
+			return evaluationResult.getResult();
+		} else {
+			final StringBuilder messages = new StringBuilder();
+			for (Diagnostic child : astResult.getDiagnostic().getChildren()) {
+				messages.append("\n" + child.getMessage());
+			}
+			throw new IllegalArgumentException("Unable to parse \"" + expression + "\"" + messages.toString());
+		}
+
+	}
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AbstractEnvironmentProvider.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AbstractEnvironmentProvider.java
new file mode 100644
index 0000000..7bf6942
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/AbstractEnvironmentProvider.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.Query;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
+
+/**
+ * Provide an {@link IQueryEnvironment}.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public abstract class AbstractEnvironmentProvider {
+
+	/**
+	 * The cached {@link IQueryEnvironment}.
+	 */
+	private IQueryEnvironment environment;
+
+	/**
+	 * Gets the configured {@link IQueryEnvironment}.
+	 * 
+	 * @return the configured {@link IQueryEnvironment}
+	 */
+	protected IQueryEnvironment getEnvironment() {
+		final IQueryEnvironment res;
+
+		if (environment == null) {
+			environment = Query.newEnvironmentWithDefaultServices(null);
+			res = environment;
+
+			for (Object ePkg : EPackageRegistryImpl.createGlobalRegistry().values()) {
+				res.registerEPackage((EPackage)ePkg);
+			}
+		} else {
+			res = environment;
+		}
+
+		return res;
+	}
+
+}
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/DelegateUtils.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/DelegateUtils.java
new file mode 100644
index 0000000..99a056d
--- /dev/null
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/delegates/DelegateUtils.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.delegates;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.acceleo.query.ast.AstPackage;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * Utility class for delegates.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public final class DelegateUtils {
+
+	/**
+	 * Constructor.
+	 */
+	private DelegateUtils() {
+		// nothing to do here
+	}
+
+	/**
+	 * Sets the AQL setting delegate on the given {@link EPackage}.
+	 * 
+	 * @param ePackage
+	 *            the {@link EPackage}
+	 */
+	public static void setSettingDelegates(EPackage ePackage) {
+		final List<String> delegates = EcoreUtil.getSettingDelegates(ePackage);
+		if (!delegates.contains(AstPackage.eNS_URI)) {
+			final List<String> newDelegates = new ArrayList<String>(delegates);
+			newDelegates.add(AstPackage.eNS_URI);
+			EcoreUtil.setSettingDelegates(ePackage, newDelegates);
+		}
+	}
+
+	/**
+	 * Sets the AQL invocation delegate on the given {@link EPackage}.
+	 * 
+	 * @param ePackage
+	 *            the {@link EPackage}
+	 */
+	public static void setInvocationDelegates(EPackage ePackage) {
+		final List<String> delegates = EcoreUtil.getInvocationDelegates(ePackage);
+		if (!delegates.contains(AstPackage.eNS_URI)) {
+			final List<String> newDelegates = new ArrayList<String>(delegates);
+			newDelegates.add(AstPackage.eNS_URI);
+			EcoreUtil.setInvocationDelegates(ePackage, newDelegates);
+		}
+	}
+
+	/**
+	 * Sets the AQL validation delegate on the given {@link EPackage}.
+	 * 
+	 * @param ePackage
+	 *            the {@link EPackage}
+	 */
+	public static void setValidationDelegates(EPackage ePackage) {
+		final List<String> delegates = EcoreUtil.getValidationDelegates(ePackage);
+		if (!delegates.contains(AstPackage.eNS_URI)) {
+			final List<String> newDelegates = new ArrayList<String>(delegates);
+			newDelegates.add(AstPackage.eNS_URI);
+			EcoreUtil.setValidationDelegates(ePackage, newDelegates);
+		}
+	}
+
+	/**
+	 * Gets the AQL expression of the given constraint name for the given {@link EModelElement}.
+	 * 
+	 * @param eModelElement
+	 *            the {@link EModelElement}
+	 * @param constraintName
+	 *            the constraint name
+	 * @return the AQL expression of the given constraint name for the given {@link EModelElement} if any,
+	 *         <code>null</code> otherwise
+	 */
+	public static String getConstraint(EModelElement eModelElement, String constraintName) {
+		return EcoreUtil.getAnnotation(eModelElement, AstPackage.eNS_URI, constraintName);
+	}
+
+	/**
+	 * Gets the given expression as the constraint of the given {@link EModelElement}.
+	 * 
+	 * @param eModelElement
+	 *            the {@link EModelElement}
+	 * @param constraintName
+	 *            the constraint name
+	 * @param expression
+	 *            the AQL expression
+	 */
+	public static void setConstraint(EModelElement eModelElement, String constraintName, String expression) {
+		final List<String> constraints = EcoreUtil.getConstraints(eModelElement);
+		if (!constraints.contains(constraintName)) {
+			final List<String> newConstraints = new ArrayList<String>(constraints);
+			newConstraints.add(constraintName);
+			EcoreUtil.setConstraints(eModelElement, newConstraints);
+		}
+
+		EcoreUtil.setAnnotation(eModelElement, AstPackage.eNS_URI, constraintName, expression);
+	}
+
+	/**
+	 * Gets the AQL body expression of the given {@link EOperation}.
+	 * 
+	 * @param eOperation
+	 *            the {@link EOperation}
+	 * @return the AQL expression body of the given {@link EOperation} if any, <code>null</code> otherwise
+	 */
+	public static String getBody(EOperation eOperation) {
+		return EcoreUtil.getAnnotation(eOperation, AstPackage.eNS_URI, "body");
+	}
+
+	/**
+	 * Sets the given expression as the body of the given {@link EOperation}.
+	 * 
+	 * @param eOperation
+	 *            the {@link EOperation}
+	 * @param expression
+	 *            the AQL expression
+	 */
+	public static void setBody(EOperation eOperation, String expression) {
+		EcoreUtil.setAnnotation(eOperation, AstPackage.eNS_URI, "body", expression);
+	}
+
+	/**
+	 * Gets the AQL derivation expression for the given {@link EStructuralFeature}.
+	 * 
+	 * @param feature
+	 *            the {@link EStructuralFeature}
+	 * @return the AQL derivation expression for the given {@link EStructuralFeature} if any,
+	 *         <code>null</code> otherwise
+	 */
+	public static String getDerivation(EStructuralFeature feature) {
+		return EcoreUtil.getAnnotation(feature, AstPackage.eNS_URI, "derivation");
+	}
+
+	/**
+	 * Sets the given expression as the derivation of the given {@link EStructuralFeature}.
+	 * 
+	 * @param feature
+	 *            the {@link EStructuralFeature}
+	 * @param expression
+	 *            the AQL expression
+	 */
+	public static void setDerivation(EStructuralFeature feature, String expression) {
+		EcoreUtil.setAnnotation(feature, AstPackage.eNS_URI, "derivation", expression);
+	}
+
+}
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/ast/test/delegates/DelegateTests.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/ast/test/delegates/DelegateTests.java
new file mode 100644
index 0000000..703dd40
--- /dev/null
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/ast/test/delegates/DelegateTests.java
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.ast.test.delegates;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.acceleo.query.ast.AstPackage;
+import org.eclipse.acceleo.query.delegates.AQLInvocationDelegateFactory;
+import org.eclipse.acceleo.query.delegates.AQLSettingDelegateFactory;
+import org.eclipse.acceleo.query.delegates.AQLValidationDelegate;
+import org.eclipse.acceleo.query.delegates.DelegateUtils;
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.Diagnostician;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class DelegateTests {
+
+	private static EPackage ePackage;
+
+	private static EClass eClass;
+
+	private static EAttribute eAttribute1;
+
+	private static EAttribute eAttribute2;
+
+	private static EReference eReference;
+
+	private static EOperation eOperation;
+
+	private static EClass eClassParsingError;
+
+	private static EAttribute eAttribute1ParsingError;
+
+	private static EAttribute eAttribute2ParsingError;
+
+	private static EReference eReferenceParsingError;
+
+	private static EOperation eOperationParsingError;
+
+	private static EClass eClassEvaluationError;
+
+	private static EAttribute eAttribute1EvaluationError;
+
+	private static EAttribute eAttribute2EvaluationError;
+
+	private static EReference eReferenceEvaluationError;
+
+	private static EOperation eOperationEvaluationError;
+
+	@BeforeClass
+	public static void beforeClass() {
+		// delegates registration
+		EOperation.Internal.InvocationDelegate.Factory.Registry.INSTANCE.put(AstPackage.eNS_URI,
+				new AQLInvocationDelegateFactory());
+		EStructuralFeature.Internal.SettingDelegate.Factory.Registry.INSTANCE.put(AstPackage.eNS_URI,
+				new AQLSettingDelegateFactory());
+		EValidator.ValidationDelegate.Registry.INSTANCE.put(AstPackage.eNS_URI, new AQLValidationDelegate());
+
+		// EPackage construction
+		ePackage = EcorePackage.eINSTANCE.getEcoreFactory().createEPackage();
+		ePackage.setName("testEPackage");
+		ePackage.setNsPrefix("test");
+		ePackage.setNsURI("test");
+
+		eClass = EcorePackage.eINSTANCE.getEcoreFactory().createEClass();
+		eClass.setName("TestEClass");
+		ePackage.getEClassifiers().add(eClass);
+
+		eAttribute1 = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+		eAttribute1.setName("testAttribute1");
+		eAttribute1.setEType(EcorePackage.eINSTANCE.getEString());
+		eClass.getEStructuralFeatures().add(eAttribute1);
+
+		eAttribute2 = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+		eAttribute2.setName("testAttribute2");
+		eAttribute2.setEType(EcorePackage.eINSTANCE.getEString());
+		eClass.getEStructuralFeatures().add(eAttribute2);
+
+		eReference = EcorePackage.eINSTANCE.getEcoreFactory().createEReference();
+		eReference.setName("testReference");
+		eReference.setEType(eClass);
+		eClass.getEStructuralFeatures().add(eReference);
+
+		eOperation = EcorePackage.eINSTANCE.getEcoreFactory().createEOperation();
+		eOperation.setName("testOperation");
+		eOperation.setEType(EcorePackage.eINSTANCE.getEString());
+		eClass.getEOperations().add(eOperation);
+		final EParameter eParameter1 = EcorePackage.eINSTANCE.getEcoreFactory().createEParameter();
+		eParameter1.setName("testParameter1");
+		eParameter1.setEType(EcorePackage.eINSTANCE.getEString());
+		eOperation.getEParameters().add(eParameter1);
+		final EParameter eParameter2 = EcorePackage.eINSTANCE.getEcoreFactory().createEParameter();
+		eParameter2.setName("testParameter2");
+		eParameter2.setEType(EcorePackage.eINSTANCE.getEString());
+		eOperation.getEParameters().add(eParameter2);
+
+		eClassParsingError = EcorePackage.eINSTANCE.getEcoreFactory().createEClass();
+		eClassParsingError.setName("TestEClassParsingError");
+		ePackage.getEClassifiers().add(eClassParsingError);
+
+		eAttribute1ParsingError = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+		eAttribute1ParsingError.setName("testAttribute1ParsingError");
+		eAttribute1ParsingError.setEType(EcorePackage.eINSTANCE.getEString());
+		eClassParsingError.getEStructuralFeatures().add(eAttribute1ParsingError);
+
+		eAttribute2ParsingError = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+		eAttribute2ParsingError.setName("testAttribute2ParsingError");
+		eAttribute2ParsingError.setEType(EcorePackage.eINSTANCE.getEString());
+		eClassParsingError.getEStructuralFeatures().add(eAttribute2ParsingError);
+
+		eReferenceParsingError = EcorePackage.eINSTANCE.getEcoreFactory().createEReference();
+		eReferenceParsingError.setName("testReferenceParsingError");
+		eReferenceParsingError.setEType(eClass);
+		eClassParsingError.getEStructuralFeatures().add(eReferenceParsingError);
+
+		eOperationParsingError = EcorePackage.eINSTANCE.getEcoreFactory().createEOperation();
+		eOperationParsingError.setName("testOperationParsingError");
+		eOperationParsingError.setEType(EcorePackage.eINSTANCE.getEString());
+		eClassParsingError.getEOperations().add(eOperationParsingError);
+		final EParameter eParameter1ParsingError = EcorePackage.eINSTANCE.getEcoreFactory()
+				.createEParameter();
+		eParameter1ParsingError.setName("testParameter1ParsingError");
+		eParameter1ParsingError.setEType(EcorePackage.eINSTANCE.getEString());
+		eOperationParsingError.getEParameters().add(eParameter1ParsingError);
+		final EParameter eParameter2ParsingError = EcorePackage.eINSTANCE.getEcoreFactory()
+				.createEParameter();
+		eParameter2ParsingError.setName("testParameter2ParsingError");
+		eParameter2ParsingError.setEType(EcorePackage.eINSTANCE.getEString());
+		eOperationParsingError.getEParameters().add(eParameter2ParsingError);
+
+		eClassEvaluationError = EcorePackage.eINSTANCE.getEcoreFactory().createEClass();
+		eClassEvaluationError.setName("TestEClassEvaluationError");
+		ePackage.getEClassifiers().add(eClassEvaluationError);
+
+		eAttribute1EvaluationError = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+		eAttribute1EvaluationError.setName("testAttribute1EvaluationError");
+		eAttribute1EvaluationError.setEType(EcorePackage.eINSTANCE.getEString());
+		eClassEvaluationError.getEStructuralFeatures().add(eAttribute1EvaluationError);
+
+		eAttribute2EvaluationError = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+		eAttribute2EvaluationError.setName("testAttribute2EvaluationError");
+		eAttribute2EvaluationError.setEType(EcorePackage.eINSTANCE.getEString());
+		eClassEvaluationError.getEStructuralFeatures().add(eAttribute2EvaluationError);
+
+		eReferenceEvaluationError = EcorePackage.eINSTANCE.getEcoreFactory().createEReference();
+		eReferenceEvaluationError.setName("testReferenceEvaluationError");
+		eReferenceEvaluationError.setEType(eClass);
+		eClassEvaluationError.getEStructuralFeatures().add(eReferenceEvaluationError);
+
+		eOperationEvaluationError = EcorePackage.eINSTANCE.getEcoreFactory().createEOperation();
+		eOperationEvaluationError.setName("testOperationEvaluationError");
+		eOperationEvaluationError.setEType(EcorePackage.eINSTANCE.getEString());
+		eClassEvaluationError.getEOperations().add(eOperationEvaluationError);
+		final EParameter eParameter1EvaluationError = EcorePackage.eINSTANCE.getEcoreFactory()
+				.createEParameter();
+		eParameter1EvaluationError.setName("testParameter1EvaluationError");
+		eParameter1EvaluationError.setEType(EcorePackage.eINSTANCE.getEString());
+		eOperationEvaluationError.getEParameters().add(eParameter1EvaluationError);
+		final EParameter eParameter2EvaluationError = EcorePackage.eINSTANCE.getEcoreFactory()
+				.createEParameter();
+		eParameter2EvaluationError.setName("testParameter2EvaluationError");
+		eParameter2EvaluationError.setEType(EcorePackage.eINSTANCE.getEString());
+		eOperationEvaluationError.getEParameters().add(eParameter2EvaluationError);
+
+		// set delegates annotations
+		DelegateUtils.setInvocationDelegates(ePackage);
+		DelegateUtils.setSettingDelegates(ePackage);
+		DelegateUtils.setValidationDelegates(ePackage);
+
+		DelegateUtils.setDerivation(eReference, "self.eClass.name");
+		DelegateUtils.setDerivation(eReferenceParsingError, "self.");
+		DelegateUtils.setDerivation(eReferenceEvaluationError, "notAVariable");
+
+		DelegateUtils.setConstraint(eClass, "AttributeIsShort", "self.testAttribute1.size() < 5");
+		DelegateUtils.setConstraint(eClassParsingError, "AttributeParsingError", "5 < ");
+		DelegateUtils.setConstraint(eClassEvaluationError, "AttributeParsingError", "notAVariable");
+
+		DelegateUtils.setDerivation(eReference, "self");
+		DelegateUtils.setDerivation(eReferenceParsingError, "5 < ");
+		DelegateUtils.setDerivation(eReferenceEvaluationError, "notAVariable");
+
+		DelegateUtils.setBody(eOperation, "testParameter1 + testParameter2");
+		DelegateUtils.setBody(eOperationParsingError, "testParameter1 +");
+		DelegateUtils.setBody(eOperationEvaluationError, "notAVariable");
+	}
+
+	@Test
+	public void derivation() {
+		final EObject eObj = EcoreUtil.create(eClass);
+		final Object value = eObj.eGet(eReference);
+
+		assertEquals(eObj, value);
+	}
+
+	@Test(expected = java.lang.IllegalArgumentException.class)
+	public void derivationParsingError() {
+		final EObject eObj = EcoreUtil.create(eClassParsingError);
+		final Object value = eObj.eGet(eReferenceParsingError);
+
+		assertEquals(eObj, value);
+	}
+
+	@Test(expected = java.lang.IllegalArgumentException.class)
+	public void derivationEvaluationError() {
+		final EObject eObj = EcoreUtil.create(eClassEvaluationError);
+		eObj.eGet(eReferenceEvaluationError);
+	}
+
+	@Test
+	public void constraintOK() {
+		final EObject eObj = EcoreUtil.create(eClass);
+
+		eObj.eSet(eAttribute1, "abc");
+
+		Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObj);
+
+		assertEquals(Diagnostic.OK, diagnostic.getSeverity());
+	}
+
+	@Test
+	public void constraintKO() {
+		final EObject eObj = EcoreUtil.create(eClass);
+
+		eObj.eSet(eAttribute1, "abcdefgh");
+
+		Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObj);
+
+		assertEquals(Diagnostic.ERROR, diagnostic.getSeverity());
+		assertEquals(1, diagnostic.getChildren().size());
+		assertTrue(diagnostic.getChildren().get(0).getMessage().startsWith(
+				"The 'AttributeIsShort' constraint is violated on"));
+	}
+
+	@Test
+	public void constraintParsingError() {
+		final EObject eObj = EcoreUtil.create(eClassParsingError);
+
+		eObj.eSet(eAttribute1ParsingError, "abc");
+
+		Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObj);
+
+		assertEquals(Diagnostic.ERROR, diagnostic.getSeverity());
+		assertEquals(1, diagnostic.getChildren().size());
+		assertTrue(diagnostic.getChildren().get(0).getMessage().endsWith("missing expression"));
+	}
+
+	@Test
+	public void constraintEvaluationError() {
+		final EObject eObj = EcoreUtil.create(eClassEvaluationError);
+
+		eObj.eSet(eAttribute1EvaluationError, "abc");
+
+		Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObj);
+
+		assertEquals(Diagnostic.ERROR, diagnostic.getSeverity());
+		assertEquals(1, diagnostic.getChildren().size());
+		assertTrue(diagnostic.getChildren().get(0).getMessage().endsWith(
+				"Couldn't find the notAVariable variable"));
+	}
+
+	@Test
+	public void body() throws InvocationTargetException {
+		final EObject eObj = EcoreUtil.create(eClass);
+		final EList<Object> arguments = new BasicEList<Object>();
+		arguments.add("abc");
+		arguments.add("def");
+		final Object value = eObj.eInvoke(eOperation, arguments);
+
+		assertEquals("abcdef", value);
+	}
+
+	@Test(expected = java.lang.reflect.InvocationTargetException.class)
+	public void bodyParsingError() throws InvocationTargetException {
+		final EObject eObj = EcoreUtil.create(eClassParsingError);
+		final EList<Object> arguments = new BasicEList<Object>();
+		arguments.add("abc");
+		arguments.add("def");
+		eObj.eInvoke(eOperationParsingError, arguments);
+	}
+
+	@Test(expected = java.lang.reflect.InvocationTargetException.class)
+	public void bodyEvaluationError() throws InvocationTargetException {
+		final EObject eObj = EcoreUtil.create(eClassEvaluationError);
+		final EList<Object> arguments = new BasicEList<Object>();
+		arguments.add("abc");
+		arguments.add("def");
+		eObj.eInvoke(eOperationEvaluationError, arguments);
+	}
+
+	@Test(expected = java.lang.IllegalArgumentException.class)
+	public void bodyEvaluationWrongNumberOfArguments() throws InvocationTargetException {
+		final EObject eObj = EcoreUtil.create(eClassEvaluationError);
+		final EList<Object> arguments = new BasicEList<Object>();
+		arguments.add("abc");
+		arguments.add("def");
+		arguments.add("def");
+		eObj.eInvoke(eOperationEvaluationError, arguments);
+	}
+
+}
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/ast/test/delegates/DelegateUtilsTests.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/ast/test/delegates/DelegateUtilsTests.java
new file mode 100644
index 0000000..4315241
--- /dev/null
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/ast/test/delegates/DelegateUtilsTests.java
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * 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:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.ast.test.delegates;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+import org.eclipse.acceleo.query.ast.AstPackage;
+import org.eclipse.acceleo.query.delegates.DelegateUtils;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link DelegateUtils}.
+ * 
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class DelegateUtilsTests {
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void setSettingDelegatesNull() {
+		DelegateUtils.setSettingDelegates(null);
+	}
+
+	@Test
+	public void setSettingDelegatesNotExisting() {
+		final EPackage ePkg = EcorePackage.eINSTANCE.getEcoreFactory().createEPackage();
+
+		EcoreUtil.setSettingDelegates(ePkg, Lists.newArrayList("uri"));
+
+		DelegateUtils.setSettingDelegates(ePkg);
+
+		final List<String> delegates = EcoreUtil.getSettingDelegates(ePkg);
+
+		assertEquals(2, delegates.size());
+		assertEquals("uri", delegates.get(0));
+		assertEquals(AstPackage.eNS_URI, delegates.get(1));
+	}
+
+	@Test
+	public void setSettingDelegatesExisting() {
+		final EPackage ePkg = EcorePackage.eINSTANCE.getEcoreFactory().createEPackage();
+
+		EcoreUtil.setSettingDelegates(ePkg, Lists.newArrayList("uri", AstPackage.eNS_URI));
+
+		DelegateUtils.setSettingDelegates(ePkg);
+
+		final List<String> delegates = EcoreUtil.getSettingDelegates(ePkg);
+
+		assertEquals(2, delegates.size());
+		assertEquals("uri", delegates.get(0));
+		assertEquals(AstPackage.eNS_URI, delegates.get(1));
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void setInvocationDelegatesNull() {
+		DelegateUtils.setInvocationDelegates(null);
+	}
+
+	@Test
+	public void setInvocationDelegatesNotExisting() {
+		final EPackage ePkg = EcorePackage.eINSTANCE.getEcoreFactory().createEPackage();
+
+		EcoreUtil.setInvocationDelegates(ePkg, Lists.newArrayList("uri"));
+
+		DelegateUtils.setInvocationDelegates(ePkg);
+
+		final List<String> delegates = EcoreUtil.getInvocationDelegates(ePkg);
+
+		assertEquals(2, delegates.size());
+		assertEquals("uri", delegates.get(0));
+		assertEquals(AstPackage.eNS_URI, delegates.get(1));
+	}
+
+	@Test
+	public void setInvocationDelegatesExisting() {
+		final EPackage ePkg = EcorePackage.eINSTANCE.getEcoreFactory().createEPackage();
+
+		EcoreUtil.setInvocationDelegates(ePkg, Lists.newArrayList("uri", AstPackage.eNS_URI));
+
+		DelegateUtils.setInvocationDelegates(ePkg);
+
+		final List<String> delegates = EcoreUtil.getInvocationDelegates(ePkg);
+
+		assertEquals(2, delegates.size());
+		assertEquals("uri", delegates.get(0));
+		assertEquals(AstPackage.eNS_URI, delegates.get(1));
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void setValidationDelegatesNull() {
+		DelegateUtils.setValidationDelegates(null);
+	}
+
+	@Test
+	public void setValidationDelegatesNotExisting() {
+		final EPackage ePkg = EcorePackage.eINSTANCE.getEcoreFactory().createEPackage();
+
+		EcoreUtil.setValidationDelegates(ePkg, Lists.newArrayList("uri"));
+
+		DelegateUtils.setValidationDelegates(ePkg);
+
+		final List<String> delegates = EcoreUtil.getValidationDelegates(ePkg);
+
+		assertEquals(2, delegates.size());
+		assertEquals("uri", delegates.get(0));
+		assertEquals(AstPackage.eNS_URI, delegates.get(1));
+	}
+
+	@Test
+	public void setValidationDelegatesExisting() {
+		final EPackage ePkg = EcorePackage.eINSTANCE.getEcoreFactory().createEPackage();
+
+		EcoreUtil.setValidationDelegates(ePkg, Lists.newArrayList("uri", AstPackage.eNS_URI));
+
+		DelegateUtils.setValidationDelegates(ePkg);
+
+		final List<String> delegates = EcoreUtil.getValidationDelegates(ePkg);
+
+		assertEquals(2, delegates.size());
+		assertEquals("uri", delegates.get(0));
+		assertEquals(AstPackage.eNS_URI, delegates.get(1));
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void getConstraintNull() {
+		DelegateUtils.getConstraint(null, "someConstraint");
+	}
+
+	@Test
+	public void getConstraintNotSetted() {
+		final EClass eCls = EcorePackage.eINSTANCE.getEcoreFactory().createEClass();
+
+		assertEquals(null, DelegateUtils.getConstraint(eCls, "someConstraint"));
+	}
+
+	@Test
+	public void getConstraintSetted() {
+		final EClass eCls = EcorePackage.eINSTANCE.getEcoreFactory().createEClass();
+
+		DelegateUtils.setConstraint(eCls, "someConstraint", "self");
+
+		assertEquals("self", DelegateUtils.getConstraint(eCls, "someConstraint"));
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void setConstraintNull() {
+		DelegateUtils.setConstraint(null, "someConstraint", "");
+	}
+
+	@Test
+	public void setConstraintNotExisting() {
+		final EClass eCls = EcorePackage.eINSTANCE.getEcoreFactory().createEClass();
+
+		EcoreUtil.setConstraints(eCls, Lists.newArrayList("someOtherConstraint"));
+
+		DelegateUtils.setConstraint(eCls, "someConstraint", "true");
+
+		final List<String> constraints = EcoreUtil.getConstraints(eCls);
+
+		assertEquals(2, constraints.size());
+		assertEquals("someOtherConstraint", constraints.get(0));
+		assertEquals("someConstraint", constraints.get(1));
+
+		final String expression = EcoreUtil.getAnnotation(eCls, AstPackage.eNS_URI, "someConstraint");
+
+		assertEquals("true", expression);
+	}
+
+	@Test
+	public void setConstraintExisting() {
+		final EClass eCls = EcorePackage.eINSTANCE.getEcoreFactory().createEClass();
+
+		EcoreUtil.setConstraints(eCls, Lists.newArrayList("someConstraint", "someOtherConstraint"));
+
+		DelegateUtils.setConstraint(eCls, "someConstraint", "true");
+
+		final List<String> constraints = EcoreUtil.getConstraints(eCls);
+
+		assertEquals(2, constraints.size());
+		assertEquals("someConstraint", constraints.get(0));
+		assertEquals("someOtherConstraint", constraints.get(1));
+
+		final String expression = EcoreUtil.getAnnotation(eCls, AstPackage.eNS_URI, "someConstraint");
+
+		assertEquals("true", expression);
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void getBodyNull() {
+		DelegateUtils.getBody(null);
+	}
+
+	@Test
+	public void getBodyNotSetted() {
+		final EOperation eOperation = EcorePackage.eINSTANCE.getEcoreFactory().createEOperation();
+
+		assertEquals(null, DelegateUtils.getBody(eOperation));
+	}
+
+	@Test
+	public void getBodySetted() {
+		final EOperation eOperation = EcorePackage.eINSTANCE.getEcoreFactory().createEOperation();
+
+		DelegateUtils.setBody(eOperation, "self");
+
+		assertEquals("self", DelegateUtils.getBody(eOperation));
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void setBodyNull() {
+		DelegateUtils.setBody(null, "true");
+	}
+
+	@Test
+	public void setBody() {
+		final EOperation eOperation = EcorePackage.eINSTANCE.getEcoreFactory().createEOperation();
+
+		DelegateUtils.setBody(eOperation, "true");
+
+		final String expression = EcoreUtil.getAnnotation(eOperation, AstPackage.eNS_URI, "body");
+
+		assertEquals("true", expression);
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void getDerivationNull() {
+		DelegateUtils.getDerivation(null);
+	}
+
+	@Test
+	public void getDerivationNotSetted() {
+		final EStructuralFeature eFeature = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+
+		assertEquals(null, DelegateUtils.getDerivation(eFeature));
+	}
+
+	@Test
+	public void getDerivationSetted() {
+		final EStructuralFeature eFeature = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+
+		DelegateUtils.setDerivation(eFeature, "self");
+
+		assertEquals("self", DelegateUtils.getDerivation(eFeature));
+	}
+
+	@Test(expected = java.lang.NullPointerException.class)
+	public void setDerivationNull() {
+		DelegateUtils.setDerivation(null, "true");
+	}
+
+	@Test
+	public void setDerivation() {
+		final EStructuralFeature eFeature = EcorePackage.eINSTANCE.getEcoreFactory().createEAttribute();
+
+		DelegateUtils.setDerivation(eFeature, "true");
+
+		final String expression = EcoreUtil.getAnnotation(eFeature, AstPackage.eNS_URI, "derivation");
+
+		assertEquals("true", expression);
+	}
+
+}
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java
index 7126271..3a104fa 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java
@@ -12,6 +12,8 @@
 
 import org.eclipse.acceleo.query.ast.test.AstBuilderTest;
 import org.eclipse.acceleo.query.ast.test.AstEvaluatorTest;
+import org.eclipse.acceleo.query.ast.test.delegates.DelegateTests;
+import org.eclipse.acceleo.query.ast.test.delegates.DelegateUtilsTests;
 import org.eclipse.acceleo.query.parser.tests.BuildTest;
 import org.eclipse.acceleo.query.parser.tests.CombineIteratorTest;
 import org.eclipse.acceleo.query.parser.tests.CompletionCheck;
@@ -96,7 +98,7 @@
 		VariableCompletionProposalTests.class, EClassifierCompletionProposalTests.class,
 		ValidationInferrenceTest.class, TypeTests.class, QueryEnvironmentTests.class,
 		EPackageProviderTests.class, CompletionCheck.class, FilterCamelCaseTest.class,
-		CollectionServicesAstValidationTest.class })
+		CollectionServicesAstValidationTest.class, DelegateTests.class })
 public class AllTests {
 
 }