Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/org.eclipse.gmf.validate/.classpath7
-rw-r--r--plugins/org.eclipse.gmf.validate/.cvsignore1
-rw-r--r--plugins/org.eclipse.gmf.validate/.options18
-rw-r--r--plugins/org.eclipse.gmf.validate/.project28
-rw-r--r--plugins/org.eclipse.gmf.validate/META-INF/MANIFEST.MF15
-rw-r--r--plugins/org.eclipse.gmf.validate/build.properties6
-rw-r--r--plugins/org.eclipse.gmf.validate/plugin.properties14
-rw-r--r--plugins/org.eclipse.gmf.validate/plugin.xml18
-rw-r--r--plugins/org.eclipse.gmf.validate/schema/expressionProviders.exsd163
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AbstractValidator.java241
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedDefinitionValidator.java583
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedOclValidator.java249
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Annotations.java50
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintAdapter.java92
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintDef.java55
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DebugOptions.java38
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DefUtils.java688
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/EDataTypeConversion.java88
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExpressionCache.java110
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExternModelImport.java218
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/GMFValidationPlugin.java87
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/IDefElementProvider.java57
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/LabelProvider.java84
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Messages.java51
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/StatusCodes.java61
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Trace.java146
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValidatorChain.java137
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValueSpecDef.java77
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/AbstractExpression.java208
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/EnvironmentProvider.java106
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/ExpressionProviderRegistry.java204
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IEvaluationEnvironment.java53
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpression.java133
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpressionProvider.java59
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IParseEnvironment.java71
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/Messages.java36
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/messages.properties5
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/messages.properties26
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionAdapter.java156
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionProvider.java31
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/GMFValidator.java146
-rw-r--r--plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/ValidationOptions.java43
42 files changed, 4659 insertions, 0 deletions
diff --git a/plugins/org.eclipse.gmf.validate/.classpath b/plugins/org.eclipse.gmf.validate/.classpath
new file mode 100644
index 000000000..751c8f2e5
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.gmf.validate/.cvsignore b/plugins/org.eclipse.gmf.validate/.cvsignore
new file mode 100644
index 000000000..ba077a403
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/plugins/org.eclipse.gmf.validate/.options b/plugins/org.eclipse.gmf.validate/.options
new file mode 100644
index 000000000..4c286b98e
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/.options
@@ -0,0 +1,18 @@
+# Turn on general debugging for the GMF Validation plug-in
+org.eclipse.gmf.validate/debug=false
+
+# Trace meta-element definition activity
+org.eclipse.gmf.validate/debug/meta/definitions=false
+
+# Trace when exceptions are caught
+org.eclipse.gmf.validate/debug/exceptions/catching=false
+
+# Trace when exceptions are thrown
+org.eclipse.gmf.validate/debug/exceptions/throwing=false
+
+# Trace constraint-cache related activity
+org.eclipse.gmf.validate/debug/cache=false
+
+
+# Trace constraint-related activity
+org.eclipse.emf.validation/debug/constraints=false \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/.project b/plugins/org.eclipse.gmf.validate/.project
new file mode 100644
index 000000000..18eef538b
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.gmf.validate</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.gmf.validate/META-INF/MANIFEST.MF b/plugins/org.eclipse.gmf.validate/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..25d075e60
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.gmf.validate;singleton:=true
+Bundle-Version: 1.0.0
+Bundle-Activator: org.eclipse.gmf.internal.validate.GMFValidationPlugin
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.emf.validation,
+ org.eclipse.emf.query.ocl,
+ org.eclipse.emf.ecore.edit,
+ org.eclipse.emf.codegen.ecore,
+ org.eclipse.core.runtime
+Eclipse-LazyStart: true
+Export-Package: org.eclipse.gmf.validate
+Bundle-Vendor: %providerName
diff --git a/plugins/org.eclipse.gmf.validate/build.properties b/plugins/org.eclipse.gmf.validate/build.properties
new file mode 100644
index 000000000..0dc34f783
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties
diff --git a/plugins/org.eclipse.gmf.validate/plugin.properties b/plugins/org.eclipse.gmf.validate/plugin.properties
new file mode 100644
index 000000000..7f830a454
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/plugin.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2005 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:
+# Borland Software Corporation - initial API and implementation
+###############################################################################
+pluginName = GMF Validation
+providerName = Eclipse.org
+# ====================================================================
+expressionProviders.Name=GMF Validation expression providers \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/plugin.xml b/plugins/org.eclipse.gmf.validate/plugin.xml
new file mode 100644
index 000000000..a57be2cec
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/plugin.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+ <extension-point id="expressionProviders" name="%expressionProviders.Name" schema="schema/expressionProviders.exsd"/>
+ <extension point="org.eclipse.gmf.validate.expressionProviders">
+ <provider
+ class="org.eclipse.gmf.internal.validate.ocl.OCLExpressionProvider"
+ isLooselyTyped="false"
+ language="ocl"
+ modelReflection="true"
+ name="OCL Expression Provider">
+ <description>
+ Supports parsing and evaluating expression written in OCL (Object Constraint Language)
+ </description>
+ </provider>
+ </extension>
+
+</plugin>
diff --git a/plugins/org.eclipse.gmf.validate/schema/expressionProviders.exsd b/plugins/org.eclipse.gmf.validate/schema/expressionProviders.exsd
new file mode 100644
index 000000000..09dcd387b
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/schema/expressionProviders.exsd
@@ -0,0 +1,163 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.gmf.validate">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.gmf.validate" id="expressionProviders" name="GMF Validation expression providers"/>
+ </appInfo>
+ <documentation>
+ This extension point provides mechanism of registering expression providers for the languages supported by GMF annotation based validator.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="provider"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="provider">
+ <annotation>
+ <documentation>
+ Single expression language provider
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="description"/>
+ </sequence>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ Implementation of the expression provider manifested by this extension point.
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn="org.eclipse.gmf.validate.expressions.IExpressionProvider"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ <attribute name="language" type="string" use="required">
+ <annotation>
+ <documentation>
+ Identifier of the language supported by this expression provider
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="isLooselyTyped" type="boolean" use="default" value="true">
+ <annotation>
+ <documentation>
+ Indicates whether parsed expressions from this provider are loosely typed.
+This means the result type of the parsed expression is declared as java.lang.Object and
+any closer sub-type is detectable only at evaluation time.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="modelReflection" type="boolean" use="default" value="false">
+ <annotation>
+ <documentation>
+ Indicates whether this provider&apos;s expressions support pure ecore reflection access on the model elements passed in context. Model pure reflection stands for reflective access of model elements for which no java code is generated and available at runtime.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ Localizable name of this expression provider
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="description">
+ <annotation>
+ <appInfo>
+ <meta.element translatable="true"/>
+ </appInfo>
+ <documentation>
+ Localizable detailed description of this expression provider
+ </documentation>
+ </annotation>
+ <complexType>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ 1.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ This extension point is &lt;b&gt;internal&lt;/b&gt; and should not be used by external client.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2005 Borland Software Corporation.&lt;br&gt;
+ 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
+&lt;a href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AbstractValidator.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AbstractValidator.java
new file mode 100644
index 000000000..d07bd235f
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AbstractValidator.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.gmf.internal.validate.expressions.AbstractExpression;
+import org.eclipse.gmf.internal.validate.expressions.EnvironmentProvider;
+import org.eclipse.gmf.internal.validate.expressions.ExpressionProviderRegistry;
+import org.eclipse.gmf.internal.validate.expressions.IEvaluationEnvironment;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpression;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpressionProvider;
+import org.eclipse.gmf.internal.validate.expressions.IParseEnvironment;
+import org.eclipse.gmf.validate.ValidationOptions;
+import org.eclipse.osgi.util.NLS;
+
+
+public class AbstractValidator implements EValidator {
+ protected static final String DIAGNOSTIC_SOURCE = "org.eclipse.gmf.validation"; //$NON-NLS-1$
+
+ private static final Object ROOT_TARGET_OBJECT_KEY = new Object();
+
+ protected AbstractValidator() {
+ }
+
+ protected static ExpressionCache getExpressionCache(String language, Map context) {
+ return getExpressionCache(context).getCache(language);
+ }
+
+ protected static IModelExpression getExpression(String language, String body, EClassifier contextClassifier, Map context) {
+ EPackage.Registry reg = ExternModelImport.getPackageRegistry(context);
+ IParseEnvironment env = null;
+ if(reg != null) {
+ env = EnvironmentProvider.createParseEnv();
+ env.setImportRegistry(reg);
+ }
+ return getExpression(language, body, contextClassifier, env, context);
+ }
+
+ protected static IModelExpression getExpression(String language, String body,
+ EClassifier contextClassifier, IParseEnvironment env, Map context) {
+ ExpressionCache cache = getExpressionCache(language, context);
+ if(cache == null) {
+ // no provider for the given language found in registry
+ return new NoProviderExpression(language, body, contextClassifier);
+ }
+
+ // initializer EPackages cross-referenced from the validated model
+ // to be visible in EMFT ocl environment lookup
+ if(Annotations.OCL_KEY.equals(language) && body != null && body.contains("::")) { //$NON-NLS-1$
+ EObject validationTarget = getRootTargetObject(context);
+ ExternModelImport importer = ExternModelImport.getImporter(context, validationTarget);
+ importer.intializeExternPackages(validationTarget);
+ }
+
+ return cache.getExpression(body, contextClassifier, env);
+ }
+
+ protected static SubstitutionLabelProvider getLabelProvider(Map context) {
+ if(context != null && context.containsKey(SubstitutionLabelProvider.class)) {
+ Object provider = context.get(SubstitutionLabelProvider.class);
+ assert provider instanceof SubstitutionLabelProvider : "Invalid label provider"; //$NON-NLS-1$
+ return (SubstitutionLabelProvider)provider;
+ }
+ return LabelProvider.INSTANCE;
+ }
+
+ protected static EObject getRootTargetObject(Map context) {
+ Object rootObj = context.get(ROOT_TARGET_OBJECT_KEY);
+ assert rootObj == null || rootObj instanceof EObject;
+ return (EObject)rootObj;
+ }
+
+ private static void ensureRootTargetInitialized(EObject target, Map context) {
+ if(context != null && !context.containsKey(ROOT_TARGET_OBJECT_KEY)) {
+ setRootTargetObject(target, context);
+ }
+ }
+
+ private static void setRootTargetObject(EObject targetObject, Map context) {
+ assert !context.containsKey(ROOT_TARGET_OBJECT_KEY);
+ context.put(ROOT_TARGET_OBJECT_KEY, EcoreUtil.getRootContainer(targetObject, true));
+ }
+
+ private static MultiProviderCache getExpressionCache(Map context) {
+ if(context != null) {
+ MultiProviderCache cache = (MultiProviderCache)context.get(MultiProviderCache.class);
+ if(cache == null) {
+ cache = new MultiProviderCache();
+ context.put(MultiProviderCache.class, new MultiProviderCache());
+ }
+ return cache;
+ }
+ if(Trace.shouldTrace(DebugOptions.DEBUG)) {
+ Trace.trace("Performance warning: Validation should run in a context for caching"); //$NON-NLS-1$
+ }
+ return new MultiProviderCache();
+ }
+
+ /**
+ * @return Validation options for the given context. If not options is set to context,
+ * the {@link ValidationOptions#getDefault()} default options } are returned.
+ */
+ static ValidationOptions getOptions(Map context) {
+ if(context != null) {
+ ValidationOptions options = (ValidationOptions)context.get(ValidationOptions.class);
+ return options != null ? options : ValidationOptions.getDefault();
+ }
+ return ValidationOptions.getDefault();
+ }
+
+ /**
+ *
+ * @param options
+ * @param context
+ * @throws IllegalArgumentException
+ */
+ static void setOptions(ValidationOptions options, Map context) {
+ if(context == null) {
+ throw new IllegalArgumentException("Null validation options"); //$NON-NLS-1$
+ }
+ if(options.isUseGmfLabelSubtitution()) {
+ context.put(SubstitutionLabelProvider.class, LabelProvider.INSTANCE);
+ }
+ context.put(ValidationOptions.class, options);
+ }
+
+ public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map context) {
+ ensureRootTargetInitialized(eObject, context);
+ return true;
+ }
+
+ public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map context) {
+ return true;
+ }
+
+ public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map context) {
+ ensureRootTargetInitialized(eObject, context);
+ return true;
+ }
+
+
+ private static class ProviderCache extends ExpressionCache {
+ private IModelExpressionProvider expressionProvider;
+
+ public ProviderCache(IModelExpressionProvider expressionProvider) {
+ this.expressionProvider = expressionProvider;
+ }
+
+ protected IModelExpression createExpressionEntry(String body, EClassifier context, IParseEnvironment extEnv) {
+ if (expressionProvider != null) {
+ return expressionProvider.createExpression(body, context, extEnv);
+ }
+ return new NoProviderExpression("", body, context); //$NON-NLS-1$
+ }
+ }
+
+
+ private static class MultiProviderCache {
+ private HashMap lang2ProviderMap = new HashMap();
+
+ public MultiProviderCache() {
+ }
+ /**
+ * Gets expression cache for the given expression language.
+ *
+ * @param language
+ * identifier of the language supported by the provider to be
+ * retrieved.
+ * @return expression cache for the given provider or <code>null</code>
+ * in case the no provider is available for the specified
+ * language.
+ */
+ public ExpressionCache getCache(String language) {
+ ExpressionCache cache = (ExpressionCache) lang2ProviderMap.get(language);
+ if (cache == null) {
+ IModelExpressionProvider provider = ExpressionProviderRegistry.getInstance().getProvider(language);
+ if (provider == null) {
+ return null;
+ }
+ cache = new ProviderCache(provider);
+ lang2ProviderMap.put(language, cache);
+ }
+ return cache;
+ }
+ }
+
+ private static class NoProviderExpression extends AbstractExpression {
+ private String lang;
+
+ public NoProviderExpression(final String language, String body, EClassifier context) {
+ super(body, context, null);
+ this.lang = language;
+ String message = NLS.bind(Messages.noExpressionProviderAvailable, language);
+ IStatus status = new Status(IStatus.ERROR, GMFValidationPlugin.getPluginId(),
+ StatusCodes.EXPRESSION_PROVIDER_NOT_AVAILABLE, message, null);
+ setStatus(status);
+ }
+
+ public boolean isAssignableToElement(ETypedElement typedElement) {
+ return false;
+ }
+
+ public boolean isAssignableTo(EClassifier ecoreType) {
+ return false;
+ }
+
+ public String getLanguage() {
+ return lang;
+ }
+
+ protected Object doEvaluate(Object context) {
+ return null;
+ }
+
+ protected Object doEvaluate(Object context, IEvaluationEnvironment extEnvironment) {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedDefinitionValidator.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedDefinitionValidator.java
new file mode 100644
index 000000000..fd43cf730
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedDefinitionValidator.java
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+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.common.util.EList;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.EObjectValidator;
+import org.eclipse.gmf.internal.validate.Annotations.Meta;
+import org.eclipse.gmf.internal.validate.DefUtils.ContextTypeAdapter;
+import org.eclipse.gmf.internal.validate.DefUtils.ExpressionContextProvider;
+import org.eclipse.gmf.internal.validate.DefUtils.ExpresssionTypeProvider;
+import org.eclipse.gmf.internal.validate.DefUtils.LookupByNameContextProvider;
+import org.eclipse.gmf.internal.validate.DefUtils.TypedElementProvider;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.ContextProvider;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.StringValProvider;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.TypeProvider;
+import org.eclipse.gmf.internal.validate.expressions.EnvironmentProvider;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpression;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpressionProvider;
+import org.eclipse.gmf.internal.validate.expressions.IParseEnvironment;
+import org.eclipse.osgi.util.NLS;
+
+
+public class AnnotatedDefinitionValidator extends AbstractValidator implements EValidator {
+
+ public AnnotatedDefinitionValidator() {
+ }
+
+ public ValueSpecDef getDefinition(EObject eObject, DiagnosticChain diagnostics, Map context) {
+ EClass eClass = (eObject instanceof EClass) ? (EClass) eObject : eObject.eClass();
+ return getDefinition(eClass, eObject, diagnostics, null, context);
+ }
+
+ public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map context) {
+ return true;
+ }
+
+ public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map context) {
+ return validate(eObject.eClass(), eObject, diagnostics, context);
+ }
+
+ /**
+ * @see EObjectValidator#validate(org.eclipse.emf.ecore.EClass, org.eclipse.emf.ecore.EObject, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
+ */
+ public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map context) {
+ if(eObject.eClass().getEPackage() == EcorePackage.eINSTANCE) {
+ if(eObject instanceof EModelElement) {
+ return validateMetaModel((EModelElement)eObject, diagnostics, context);
+ }
+ } else {
+ return validateModel(eObject, diagnostics, context);
+ }
+ return true;
+ }
+
+
+ protected boolean validateModel(EObject eObject, DiagnosticChain diagnostics, Map context) {
+
+ ValueSpecDef def = getDefinition(eObject, diagnostics, context);
+ if(def == null) {
+ return true;
+ } else if(!def.isOK()) {
+ return false;
+ }
+
+ String lang = def.createLanguage(eObject);
+ if(!Annotations.Meta.OCL_KEY.equals(lang)) {
+ // add support for other languages here
+ return true;
+ }
+
+ EObject[] contexEClassEvalCtx = new EObject[1];
+ ContextData contextData = getContextBinding(eObject, contexEClassEvalCtx, context);
+ if(contextData == null) {
+ diagnostics.add(new BasicDiagnostic(
+ Diagnostic.ERROR, DIAGNOSTIC_SOURCE,
+ StatusCodes.NO_VALUESPEC_CONTEXT_AVAILABLE,
+ NLS.bind(Messages.def_NoContextAvailable, getLabelProvider(context).getObjectLabel(eObject)),
+ new Object[] { eObject }));
+ return false;
+ }
+
+ EClassifier contextClass = contextData.contextClass.getContextClassifier(contexEClassEvalCtx[0]);
+ if(contextClass == null) {
+ String noCtxMessage = contextData.contextClass.getStatus().isOK() ?
+ NLS.bind(Messages.def_NoContextAvailable, getLabelProvider(context).getObjectLabel(eObject))
+ : contextData.contextClass.getStatus().getMessage();
+
+ diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, DIAGNOSTIC_SOURCE,
+ StatusCodes.NO_VALUESPEC_CONTEXT_AVAILABLE,
+ noCtxMessage, new Object[] { eObject } ));
+ }
+
+ String body = def.createBody(eObject);
+ if(body != null && contextClass != null) {
+ // get real environment
+ IParseEnvironment env = null;
+ if(contextData.environment != null) {
+ env = EnvironmentProvider.createParseEnv();
+ env.setImportRegistry(ExternModelImport.getPackageRegistry(context));
+ for (Iterator it = contextData.environment.keySet().iterator(); it.hasNext();) {
+ String varName = (String) it.next();
+ TypeProvider typeProvider = (TypeProvider)contextData.environment.get(varName);
+ EClassifier type = typeProvider.getType(contexEClassEvalCtx[0]);
+ if(type != null) {
+ // TODO - produce error status as no variable type is available
+ env.setVariable(varName, type);
+ }
+ }
+ }
+
+ IModelExpression expression = getExpression(Meta.OCL_KEY, body, contextClass, env, context);
+ if(!expression.getStatus().isOK()) {
+ String message = MessageFormat.format(
+ Messages.invalidExpressionBody,
+ new Object[] { expression.getBody(),
+ expression.getStatus().getMessage() });
+ diagnostics.add(new BasicDiagnostic(
+ Diagnostic.ERROR, DIAGNOSTIC_SOURCE,
+ StatusCodes.INVALID_CONSTRAINT_EXPRESSION,
+ message, new Object[] { eObject }));
+ return false;
+ }
+
+ EObject typeResolutionContext = eObject;
+ // check type restriction on the given expression
+ TypeProvider typeProvider = def.getTypeRestriction();
+ if(typeProvider == null && eObject.eContainingFeature() != null) {
+ EStructuralFeature containingFeature = eObject.eContainingFeature();
+ typeProvider = getTypeInfo(containingFeature, eObject.eContainer().eClass(), diagnostics, context);
+ typeResolutionContext = eObject.eContainer();
+ }
+ if(typeProvider != null && typeProvider.getStatus().isOK() && expression.getResultType() != null) {
+ IStatus typeConformanceStatus = getTypeConformancyStatus(typeResolutionContext, typeProvider, expression);
+ if(!typeConformanceStatus.isOK()) {
+ diagnostics.add(DefUtils.statusToDiagnostic(typeConformanceStatus, DIAGNOSTIC_SOURCE, eObject));
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public ContextData getContextBinding(EObject eObject, EObject[] contextHolder, Map context) {
+ EStructuralFeature feature = eObject.eContainingFeature();
+ if(feature != null) {
+ EObject container = eObject.eContainer();
+ ContextData contextData = getCachedCtxBinding(feature, context);
+ if(contextData != null) {
+ contextHolder[0] = container;
+ return contextData;
+ }
+
+ ContextProvider contextProvider = getContextClass(feature, context);
+ if(contextProvider != null) {
+ ContextData newContextData = new ContextData(contextProvider, getEnvProvider(feature, context));
+ registerCtxBinding(feature, newContextData, context);
+ contextHolder[0] = container;
+
+ if(Trace.shouldTrace(DebugOptions.META_DEFINITIONS)) {
+ String msgPtn = "[context-def] {0} binding: {1}::{2}"; //$NON-NLS-1$
+ Trace.trace(MessageFormat.format(msgPtn,
+ new Object[] {
+ newContextData.contextClass.toString(),
+ LabelProvider.INSTANCE.getObjectLabel(container.eClass()),
+ LabelProvider.INSTANCE.getObjectLabel(feature)
+ }));
+ }
+
+ return newContextData;
+ }
+ else if(eObject.eContainer() != null) {
+ return getContextBinding(eObject.eContainer(), contextHolder, context);
+ }
+ }
+ contextHolder[0] = null;
+ return null;
+ }
+
+ protected boolean validateMetaModel(EModelElement modelElement, DiagnosticChain diagnostics, Map context) {
+ EAnnotation annotation = (modelElement instanceof EAnnotation) ? (EAnnotation)modelElement : null;
+ if(annotation != null) {
+ if(!Annotations.CONSTRAINTS_META_URI.equals(annotation.getSource())) {
+ return true;
+ }
+ modelElement = annotation.getEModelElement();
+ if(modelElement == null) {
+ return true;
+ }
+ }
+
+ if(modelElement instanceof EStructuralFeature && annotation != null &&
+ Meta.CONTEXT.equals(annotation.getDetails().get(Meta.DEF_KEY))) {
+ EStructuralFeature sfeature = (EStructuralFeature)modelElement;
+
+ ContextProvider contextProvider = getContextClass(sfeature, context);
+ if(contextProvider != null) {
+ // check extended context environment
+ getEnvProvider(sfeature, context);
+ if(!contextProvider.getStatus().isOK()) {
+ DefUtils.mergeAndFlatten(contextProvider.getStatus(),
+ DIAGNOSTIC_SOURCE, annotation, diagnostics);
+ return false;
+ }
+ }
+ } else if(modelElement instanceof EClass) {
+ getDefinition((EClass)modelElement, modelElement, diagnostics, null, context);
+ }
+
+ return true;
+ }
+
+ public static ContextProvider getContextClass(EStructuralFeature bindFeature, final Map validationContext) {
+ IModelExpressionProvider oclExprProvider = new IModelExpressionProvider() {
+ public IModelExpression createExpression(String body, EClassifier contextClassifier) {
+ return getExpression(Annotations.Meta.OCL_KEY, body, contextClassifier, validationContext);
+ }
+ public IModelExpression createExpression(String body, EClassifier context, IParseEnvironment extEnv) {
+ // no custom env supported here, use ordinary createExpression
+ return createExpression(body, context);
+ }
+ };
+ EClass resolutionContext = bindFeature.getEContainingClass();
+ return DefUtils.getContextClass(resolutionContext, oclExprProvider, bindFeature,
+ ExternModelImport.getPackageRegistry(validationContext));
+ }
+
+ private ContextProvider createContextProvider(String ctxExpression, EClass contextClass, Map context) {
+ return new ExpressionContextProvider(getExpression(Meta.OCL_KEY, ctxExpression, contextClass, context));
+ }
+
+ public ValueSpecDef getDefinition(EClass metaClass, EObject modelElement, DiagnosticChain diagnostics, DefData data, Map context) {
+ ValueSpecDef definition = findDefinition(metaClass, context);
+ if(definition != null) {
+ return definition;
+ }
+
+ if(data == null) {
+ for (Iterator it = metaClass.getEAnnotations().iterator(); it.hasNext();) {
+ EAnnotation nextAnnotation = (EAnnotation) it.next();
+ if(Annotations.CONSTRAINTS_META_URI.equals(nextAnnotation.getSource())) {
+ String val = (String)nextAnnotation.getDetails().get(Meta.DEF_KEY);
+ if(val != null && (val.equals(Meta.VALUESPEC) ||
+ val.equals(Meta.CONSTRAINT))) {
+ data = new DefData();
+ data.metaKey = val;
+ data.defClass = metaClass;
+ break;
+ }
+ }
+ }
+ }
+
+ EList superTypes = metaClass.getESuperTypes();
+ if(data == null && superTypes.isEmpty()) {
+ return null;
+ }
+
+ if(data != null) {
+ for (Iterator it = metaClass.getEStructuralFeatures().iterator(); it.hasNext();) {
+ EStructuralFeature nextAttr = (EStructuralFeature) it.next();
+
+ for (Iterator annotationIt = nextAttr.getEAnnotations().iterator(); annotationIt.hasNext();) {
+ EAnnotation annotation = (EAnnotation)annotationIt.next();
+ if(!Annotations.CONSTRAINTS_META_URI.equals(annotation.getSource())) {
+ continue;
+ }
+ String metaValue = (String)annotation.getDetails().get(Meta.DEF_KEY);
+ if(data.body == null) {
+ if(Meta.BODY.equals(metaValue)) {
+ data.body = new DefUtils.FeatureValProvider(nextAttr);
+ checkAndReportProblems(data.body, annotation, diagnostics);
+ }
+ }
+
+ if(data.lang == null) {
+ if(Meta.LANG.equals(metaValue)) {
+ data.lang = new DefUtils.FeatureValProvider(nextAttr);
+ checkAndReportProblems(data.lang, annotation, diagnostics);
+ }
+ }
+
+ if(data.context == null) {
+ if(Meta.CONTEXT.equals(metaValue)) {
+ String ctxExpression = (String)annotation.getDetails().get(Meta.OCL_KEY);
+ if(ctxExpression != null) {
+ data.context = createContextProvider(ctxExpression, metaClass, null);
+ }
+ checkAndReportProblems(data.context, annotation, diagnostics);
+ }
+ }
+
+ if(data.type == null) {
+ if(Meta.TYPE.equals(metaValue)) {
+ String typeExpr = (String)annotation.getDetails().get(Meta.OCL_KEY);
+ if(typeExpr != null) {
+ data.type = new ExpresssionTypeProvider(getExpression(Meta.OCL_KEY, typeExpr, metaClass, context));
+ } else {
+ data.type = new TypedElementProvider(nextAttr);
+ }
+ checkAndReportProblems(data.type, annotation, diagnostics);
+ }
+ }
+ } // end of EAttribute annotations iteration
+ }
+
+ if(data.type == null) {
+ data.type = getTypeInfo(metaClass, metaClass, diagnostics, context);
+/* EAnnotation typeAnnotation = DefUtils.getAnnotationWithKey(metaClass, Annotations.CONSTRAINTS_META_URI, Annotations.Meta.OCL_KEY);
+ if(typeAnnotation != null && Meta.TYPE.equals(typeAnnotation.getDetails().get(Meta.DEF_KEY))) {
+ String typeExpr = (String)typeAnnotation.getDetails().get(Meta.OCL_KEY);
+ if(typeExpr != null) {
+ data.type = new ExpresssionTypeProvider(getExpression(Meta.OCL_KEY, typeExpr, metaClass, context));
+ checkAndReportProblems(data.type, typeAnnotation, diagnostics);
+ }
+ }*/
+ }
+
+ if(data.body != null) {
+ definition = createDefinition(data);
+ assert data.defClass != null;
+ registerDefinition(data.defClass, definition, context);
+ return definition;
+ }
+ }
+
+ for (Iterator it = superTypes.iterator(); it.hasNext();) {
+ EClass superClass = (EClass) it.next();
+ ValueSpecDef inheritedDef = getDefinition(superClass, modelElement, diagnostics, data, context);
+ if(inheritedDef != null) {
+ if(data == null) {
+ data = new DefData();
+ }
+ inheritDefinition(data, metaClass, inheritedDef);
+ registerDefinition(data.defClass, createDefinition(data), context);
+ return inheritedDef;
+ }
+ }
+
+ if(data != null) {
+ if(data.body == null) {
+ data.body = createMissingBodyProvider(LabelProvider.INSTANCE.getObjectLabel(modelElement));
+ // report missing body
+ checkAndReportProblems(data.body, modelElement, diagnostics);
+ return createDefinition(data);
+ }
+ }
+ return null;
+ }
+
+ private static TypeProvider getTypeInfo(EModelElement typeAnnotationSource, EClass resolutionContext, DiagnosticChain diagnostics, Map validationContext) {
+ TypeProvider typeProvider = null;
+ List annotations = DefUtils.getAnnotationsWithKeyAndValue(typeAnnotationSource, Annotations.CONSTRAINTS_META_URI, Annotations.Meta.DEF_KEY, Annotations.Meta.TYPE);
+
+ EAnnotation typeAnnotation = annotations.isEmpty() ? null : (EAnnotation)annotations.get(0);
+
+ if(typeAnnotation != null && Meta.TYPE.equals(typeAnnotation.getDetails().get(Meta.DEF_KEY))) {
+ String typeExprBody = (String)typeAnnotation.getDetails().get(Meta.OCL_KEY);
+ if(typeExprBody != null) {
+ IModelExpression typeExpr = getExpression(Meta.OCL_KEY, typeExprBody, resolutionContext, validationContext);
+ boolean usesTypeName = typeExpr.getStatus().isOK() && String.class.equals(typeExpr.getResultType().getInstanceClass());
+ typeProvider = (usesTypeName) ? (TypeProvider)
+ new ContextTypeAdapter(new LookupByNameContextProvider(
+ typeExpr, ExternModelImport.getPackageRegistry(validationContext))) :
+ new ExpresssionTypeProvider(typeExpr);
+ checkAndReportProblems(typeProvider, typeAnnotation, diagnostics);
+ }
+ }
+ return typeProvider;
+ }
+
+ private static void inheritDefinition(DefData data, EClass valueSpecEClass, ValueSpecDef superDef) {
+ data.defClass = valueSpecEClass;
+ if(data.body == null) {
+ data.body = superDef.getBody();
+ }
+ if(data.lang == null) {
+ data.lang = superDef.getLang();
+ }
+ if(data.type == null) {
+ data.type = superDef.getTypeRestriction();
+ }
+ }
+
+ private ValueSpecDef createDefinition(DefData data) {
+ assert data != null;
+ assert data.body != null;
+ ValueSpecDef valueSpecDef = Meta.CONSTRAINT.equals(data.metaKey) ?
+ new ConstraintDef(data.body, data.lang) :
+ new ValueSpecDef(data.body, data.lang, data.type);
+
+ if(Trace.shouldTrace(DebugOptions.META_DEFINITIONS)) {
+ String msgPtn = "[{0}] {1} type: {2}"; //$NON-NLS-1$
+ Trace.trace( MessageFormat.format(msgPtn, new Object[] { data.metaKey, data.defClass.getName(), data.type }));
+ }
+ return valueSpecDef;
+ }
+
+ private static boolean checkAndReportProblems(IDefElementProvider defElementProvider, EObject destination, DiagnosticChain diagnostics) {
+ if(!defElementProvider.getStatus().isOK()) {
+ diagnostics.add(DefUtils.statusToDiagnostic(defElementProvider.getStatus(), DIAGNOSTIC_SOURCE, destination));
+ return false;
+ }
+ return true;
+ }
+
+ private static ValueSpecDef findDefinition(EClass eClass, Map context) {
+ if(context != null) {
+ Map defMap = (Map)context.get(ValueSpecDef.class);
+ return (defMap != null) ? (ValueSpecDef)defMap.get(eClass) : null;
+ }
+ return null;
+ }
+
+ private static ContextData getCachedCtxBinding(EModelElement modelElement, Map context) {
+ if(context != null) {
+ Map bindMap = (Map)context.get(ContextProvider.class);
+ if(bindMap != null) {
+ return (ContextData)bindMap.get(modelElement);
+ }
+ }
+ if(Trace.shouldTrace(DebugOptions.DEBUG)) {
+ Trace.trace("Performance warning: Validation should run in a context for caching"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ private static Map getEnvProvider(EStructuralFeature contextBindFeature, Map context) {
+ List varDefs = DefUtils.getAnnotationsWithKeyAndValue(
+ contextBindFeature, Annotations.CONSTRAINTS_META_URI,
+ Annotations.Meta.DEF_KEY, Annotations.Meta.VARIABLE);
+ if(varDefs.isEmpty()) {
+ return null;
+ }
+
+ Map env = null;
+ for (Iterator it = varDefs.iterator(); it.hasNext();) {
+ EAnnotation nextVarAnnotation = (EAnnotation) it.next();
+
+ TypeProvider type = null;
+ String typePrefix = Annotations.Meta.TYPE + "."; //$NON-NLS-1$
+ Map.Entry typeExpression = DefUtils.getKeyPreffixAnnotation(nextVarAnnotation, typePrefix);
+ if(typeExpression != null) {
+ String body = (String)typeExpression.getValue();
+ if(body == null) {
+ // TODO - report missing var type status
+ } else {
+ IModelExpression expression = getExpression(Meta.OCL_KEY, body, contextBindFeature.getEContainingClass(), context);
+ type = new DefUtils.ExpresssionTypeProvider(expression);
+ }
+ } else {
+ // TODO - report missing var type status
+ }
+
+ String name = (String)nextVarAnnotation.getDetails().get(Annotations.Meta.NAME);
+ if(name == null) {
+ //TODO - report missing var name status
+ continue;
+ }
+ if(env == null) {
+ env = new HashMap();
+ }
+ env.put(name, type);
+ }
+ return env;
+ }
+
+ private static void registerCtxBinding(EStructuralFeature contextDefOwner, ContextData contextData, Map context) {
+ if(context != null) {
+ Map bindMap = (Map)context.get(ContextProvider.class);
+ if(bindMap == null) {
+ bindMap = new HashMap();
+ context.put(ContextProvider.class, bindMap);
+ }
+ bindMap.put(contextDefOwner, contextData);
+ }
+ }
+
+ private static void registerDefinition(EClass eClass, ValueSpecDef definition, Map context) {
+ assert definition != null;
+ assert eClass != null;
+
+ if(context != null) {
+ Map defMap = (Map)context.get(ValueSpecDef.class);
+ if(defMap == null) {
+ defMap = new HashMap();
+ context.put(ValueSpecDef.class, defMap);
+ }
+ defMap.put(eClass, definition);
+ }
+ }
+
+ private static class DefData {
+ String metaKey;
+ EClass defClass;
+ StringValProvider body;
+ StringValProvider lang;
+ TypeProvider type;
+ ContextProvider context;
+ public DefData() {}
+ }
+
+ private static class ContextData {
+ final ContextProvider contextClass;
+ final Map environment;
+ public ContextData(ContextProvider contextProvider, Map environment) {
+ this.contextClass = contextProvider;
+ this.environment = environment;
+ }
+ }
+
+ private static StringValProvider createMissingBodyProvider(final String elementLabel) {
+ return new StringValProvider() {
+ public IStatus getStatus() {
+ String message = MessageFormat.format(
+ Messages.def_MissingBodyAnnotation,
+ new Object[] { elementLabel });
+ return GMFValidationPlugin.createStatus(IStatus.ERROR,
+ StatusCodes.MISSING_VALUESPEC_BODY_ANNOTATION, message, null);
+ }
+ public String getValue(EObject contextInstance) {
+ return null;
+ }
+ };
+ }
+
+ private static IStatus getTypeConformancyStatus(EObject typeProviderContext, TypeProvider leftType, IModelExpression expression) {
+ assert leftType != null && leftType.getStatus().isOK();
+ if(leftType.hasTypedElement()) {
+ ETypedElement typedElement = leftType.getTypedElement(typeProviderContext);
+ if(typedElement == null) {
+ return GMFValidationPlugin.createStatus(IStatus.WARNING,
+ StatusCodes.VALUESPEC_TYPE_NOT_AVAILABLE,
+ Messages.def_NoTypeAvailable, null);
+ }
+ if(!expression.isAssignableToElement(typedElement)) {
+ return DefUtils.getIncompatibleTypesStatus(typedElement.getEType(), expression.getResultType());
+ }
+ } else {
+ EClassifier type = leftType.getType(typeProviderContext);
+ if(type == null) {
+ return GMFValidationPlugin.createStatus(IStatus.WARNING,
+ StatusCodes.VALUESPEC_TYPE_NOT_AVAILABLE,
+ Messages.def_NoTypeAvailable, null);
+ }
+
+ if(!expression.isAssignableTo(type)) {
+ return DefUtils.getIncompatibleTypesStatus(type, expression.getResultType());
+ }
+ }
+ return Status.OK_STATUS;
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedOclValidator.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedOclValidator.java
new file mode 100644
index 000000000..00e3e66c4
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/AnnotatedOclValidator.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.text.MessageFormat;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+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.common.util.EList;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.EObjectValidator;
+import org.eclipse.gmf.internal.validate.expressions.ExpressionProviderRegistry;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpression;
+
+/**
+ * This validator extends the checker for basic EObject constraints
+ * with validation of OCL constrain annotation.
+ *
+ * @author dvorak
+ */
+public class AnnotatedOclValidator extends AbstractValidator implements EValidator {
+
+ /**
+ * Handles elements related to OCL annotations
+ */
+ private static ConstraintHandler oclHandler = new ConstraintHandler();
+
+ /**
+ * Constructs validator
+ */
+ public AnnotatedOclValidator() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.emf.ecore.EValidator#validate(org.eclipse.emf.ecore.EDataType, java.lang.Object, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
+ */
+ public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map context) {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.emf.ecore.EValidator#validate(org.eclipse.emf.ecore.EObject, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
+ */
+ public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map context) {
+ return validate(eObject.eClass(), eObject, diagnostics, context);
+ }
+
+ /**
+ * @see EObjectValidator#validate(org.eclipse.emf.ecore.EClass, org.eclipse.emf.ecore.EObject, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
+ */
+ public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map context) {
+ return validateOCL(eObject, diagnostics, context);
+ }
+
+ /**
+ * Performs <code>OCL annotation checks on the given object</code>
+ * </p>
+ * @param eObject the subject for validation
+ * @param diagnostics diagnostics object to collect the results
+ * @param context the context of validation activity
+ * @return <code>true</code>if object is valid; <code>false</code> otherwise
+ */
+ protected boolean validateOCL(EObject eObject, final DiagnosticChain diagnostics, Map context) {
+ if(eObject instanceof EAnnotation) {
+ return oclHandler.handleEAnnotation((EAnnotation)eObject, diagnostics, context);
+ }
+ else if(eObject.eClass().getEPackage() != EcorePackage.eINSTANCE) {
+ return oclHandler.handleMetaModel(eObject.eClass(), eObject, diagnostics, context);
+ }
+
+ return true;
+ }
+
+ private static class ConstraintHandler {
+ public ConstraintHandler() {}
+
+ protected EClass getContextType(EModelElement constrainedElement) {
+ if(constrainedElement instanceof EClass) {
+ return (EClass)constrainedElement;
+ }
+ else if(constrainedElement instanceof EStructuralFeature) {
+ return ((EStructuralFeature)constrainedElement).getEContainingClass();
+ }
+ return null;
+ }
+
+ protected boolean handleEAnnotation(EAnnotation annotation, DiagnosticChain diagnostics, Map context) {
+ return handleEAnnotation(annotation, null /* no instance to evaluate against */, diagnostics, context);
+ }
+
+ protected boolean handleEAnnotation(EAnnotation annotation, EObject contextInstance, DiagnosticChain diagnostics, Map context) {
+ if(!Annotations.CONSTRAINTS_URI.equals(annotation.getSource())) {
+ return true;
+ }
+
+ boolean isValid = true;
+ for(Iterator it = annotation.getDetails().iterator(); it.hasNext();) {
+ Map.Entry nextDetail = (Map.Entry)it.next();
+ String key = String.valueOf(nextDetail.getKey());
+ if(ExpressionProviderRegistry.getInstance().getLanguages().contains(key)) {
+ String body = readBodyDetail(nextDetail, diagnostics);
+ if(body != null) {
+ EModelElement constrainedElement = annotation.getEModelElement();
+ EClass contextClass = getContextType(constrainedElement);
+ if(contextClass != null) {
+ IModelExpression expression = getExpression(key, body, contextClass, context);
+ assert expression != null;
+
+ ConstraintAdapter constraint = new ConstraintAdapter(expression);
+ if(contextInstance != null) {
+ isValid &= handleConstraintDefition(constraint, contextInstance, diagnostics);
+ isValid &= handleConstrainedElement(constraint, contextInstance,
+ getDescriptionDetail(annotation), diagnostics);
+ } else {
+ isValid &= handleConstraintDefition(constraint, nextDetail, diagnostics);
+ }
+ } else {
+ diagnostics.add(new BasicDiagnostic(
+ Diagnostic.WARNING, DIAGNOSTIC_SOURCE, StatusCodes.INVALID_CONSTRAINT_CONTEXT,
+ MessageFormat.format(Messages.validation_ConstraintInInvalidContext,
+ new Object[] { LabelProvider.INSTANCE.getObjectLabel(constrainedElement) }),
+ new Object[] { nextDetail }));
+ }
+ } // end of body processing
+ }
+ }
+ return isValid;
+ }
+
+
+ private static String getDescriptionDetail(EAnnotation annotation) {
+ Object val = annotation.getDetails().get(Annotations.DESCRIPTION);
+ return val != null ? String.valueOf(val) : null;
+ }
+
+ private static String readBodyDetail(Map.Entry bodyEntry, DiagnosticChain diagnostics) {
+ String body = (String)bodyEntry.getValue();
+ if(body != null && body.trim().length() > 0) {
+ return body;
+ }
+ diagnostics.add(new BasicDiagnostic(Diagnostic.WARNING,
+ DIAGNOSTIC_SOURCE, StatusCodes.EMPTY_CONSTRAINT_BODY,
+ Messages.validation_EmptyExpressionBody,
+ new Object[] { bodyEntry }));
+ return null;
+ }
+
+ protected boolean handleMetaModel(EClass eClass, EObject modelElement, DiagnosticChain diagnostics, Map context) {
+ boolean isValid = true;
+
+ for (Iterator it = eClass.getEAnnotations().iterator(); it.hasNext();) {
+ EAnnotation nextAnnocation = (EAnnotation) it.next();
+ if(Annotations.CONSTRAINTS_URI.equals(nextAnnocation.getSource())) {
+ handleEAnnotation(nextAnnocation, modelElement, diagnostics, context);
+ }
+ }
+
+ for (Iterator it = eClass.getEOperations().iterator(); it.hasNext();) {
+ EOperation nextOperation = (EOperation) it.next();
+ EAnnotation annotation = nextOperation.getEAnnotation(Annotations.CONSTRAINTS_URI);
+ if(annotation != null) {
+ isValid &= handleEAnnotation(annotation, modelElement, diagnostics, context);
+ }
+ }
+ for (Iterator it = eClass.getEStructuralFeatures().iterator(); it.hasNext();) {
+ EStructuralFeature nextFeature = (EStructuralFeature) it.next();
+ EAnnotation annotation = nextFeature.getEAnnotation(Annotations.CONSTRAINTS_URI);
+ if(annotation != null) {
+ isValid &= handleEAnnotation(annotation, modelElement, diagnostics, context);
+ }
+ }
+
+ EList superTypes = eClass.getESuperTypes();
+ for (Iterator it = superTypes.iterator(); it.hasNext();) {
+ EClass nextSuperType = (EClass) it.next();
+ isValid &= handleMetaModel(nextSuperType, modelElement, diagnostics, context);
+ }
+
+ return isValid;
+ }
+
+
+
+ protected boolean handleConstraintDefition(ConstraintAdapter constraintProxy, Object target, DiagnosticChain diagnostics) {
+ IStatus constraintStatus = constraintProxy.getStatus();
+
+ if(Trace.shouldTrace(DebugOptions.META_DEFINITIONS)) {
+ String msgPtn = "[metamodel-constraint] context={0} body={1}"; //$NON-NLS-1$
+ Trace.trace(MessageFormat.format(msgPtn, new Object[] {
+ LabelProvider.INSTANCE.getObjectLabel(constraintProxy.getContext()),
+ constraintProxy.getBody()
+ }));
+ }
+
+
+ if(!constraintStatus.isOK()) {
+ String message = MessageFormat.format(Messages.invalidExpressionBody,
+ new Object[] { constraintProxy.getBody(),
+ constraintStatus.getMessage() });
+ diagnostics.add(new BasicDiagnostic(
+ Diagnostic.ERROR, DIAGNOSTIC_SOURCE, constraintStatus.getCode(),
+ message, new Object[] { target }));
+ return false;
+ }
+
+ return true;
+ }
+
+ protected boolean handleConstrainedElement(ConstraintAdapter constraint, EObject constrainedElement, String description, DiagnosticChain diagnostics) {
+ if(!constraint.isSatisfied(constrainedElement)) {
+ String message = null;
+ if(description == null) {
+ message = MessageFormat.format(Messages.validation_ConstraintViolation, new Object[] {
+ constraint.getBody(),
+ LabelProvider.INSTANCE.getObjectLabel(constrainedElement) });
+ } else {
+ // TODO - user constraint ID as a key, support localication for messages
+ message = description;
+ }
+ diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, DIAGNOSTIC_SOURCE,
+ StatusCodes.CONSTRAINT_VIOLATION, message, new Object[] { constrainedElement }));
+ return false;
+ }
+
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Annotations.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Annotations.java
new file mode 100644
index 000000000..af054ae07
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Annotations.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+
+public final class Annotations {
+
+ /**
+ * The constraint URI which is used as the source of constraint annotations
+ */
+ public static final String CONSTRAINTS_URI = "http://www.eclipse.org/gmf/2005/constraints"; //$NON-NLS-1$
+
+ public static final String CONSTRAINTS_META_URI = CONSTRAINTS_URI + "/meta"; //$NON-NLS-1$
+
+ /**
+ * The key of annotation detail which represents OCL expression.
+ * Corresponding value is the expression body.
+ */
+ public static final String OCL_KEY = "ocl"; //$NON-NLS-1$
+
+ public static final String DESCRIPTION = "description"; //$NON-NLS-1$
+
+ public static final class Meta {
+ public static final String DEF_KEY = "def"; //$NON-NLS-1$
+ public static final String VALUESPEC = "ValueSpec"; //$NON-NLS-1$
+ public static final String CONSTRAINT = "Constraint"; //$NON-NLS-1$
+ public static final String TYPE = "type"; //$NON-NLS-1$
+ public static final String BODY = "body"; //$NON-NLS-1$
+ public static final String LANG = "lang"; //$NON-NLS-1$
+ public static final String CONTEXT = "context"; //$NON-NLS-1$
+ public static final String REF = "ref"; //$NON-NLS-1$
+ public static final String OCL_KEY = "ocl"; //$NON-NLS-1$
+ public static final String VARIABLE = "variable"; //$NON-NLS-1$
+ public static final String NAME = "name"; //$NON-NLS-1$
+
+ public static final String IMPORT = "import"; //$NON-NLS-1$
+ }
+
+ private Annotations() {
+ }
+}
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintAdapter.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintAdapter.java
new file mode 100644
index 000000000..65f288000
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintAdapter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ocl.parser.EcoreEnvironment;
+import org.eclipse.emf.ocl.types.TypesPackage;
+import org.eclipse.gmf.internal.validate.expressions.AbstractExpression;
+import org.eclipse.gmf.internal.validate.expressions.IEvaluationEnvironment;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpression;
+
+public class ConstraintAdapter extends AbstractExpression {
+ private IModelExpression expression;
+ private EClassifier resultType;
+
+ public ConstraintAdapter(IModelExpression expression) {
+ super(expression.getBody(), expression.getContext(), null);
+ this.expression = expression;
+ if(getStatus().isOK()) {
+ this.resultType = expression.getResultType();
+ if(this.resultType != null && !expression.isLooselyTyped()) {
+ Class resultClass = resultType.getInstanceClass();
+ if(!(Boolean.class.equals(resultClass) || boolean.class.equals(resultClass))) {
+ String msg = MessageFormat.format(
+ Messages.invalidConstraintExprType,
+ new Object[] { resultType.getName(), getBody() });
+ setStatus(new Status(IStatus.ERROR,
+ GMFValidationPlugin.getPluginId(),
+ StatusCodes.INVALID_EXPRESSION_TYPE, msg, null));
+ }
+ }
+ }
+ }
+
+
+ public IStatus getStatus() {
+ if(expression.getStatus().isOK()) {
+ return super.getStatus();
+ }
+ return expression.getStatus();
+ }
+
+ public String getLanguage() {
+ return expression.getLanguage();
+ }
+
+ public boolean isLooselyTyped() {
+ return expression.isLooselyTyped();
+ }
+
+ public boolean isAssignableToElement(ETypedElement typedElement) {
+ EClassifier classifier = EcoreEnvironment.getOCLType(typedElement);
+ return classifier != null ? classifier == TypesPackage.eINSTANCE.getPrimitiveBoolean() : false;
+ }
+
+ public boolean isAssignableTo(EClassifier ecoreType) {
+ EClassifier classifier = EcoreEnvironment.getOCLType(ecoreType);
+ return classifier != null ? classifier == TypesPackage.eINSTANCE.getPrimitiveBoolean() : false;
+ }
+
+ public EClassifier getResultType() {
+ return resultType;
+ }
+
+ protected Object doEvaluate(Object context) {
+ return expression.evaluate(context);
+ }
+
+ protected Object doEvaluate(Object context, IEvaluationEnvironment extEnvironment) {
+ return expression.evaluate(context, extEnvironment);
+ }
+
+ public boolean isSatisfied(EObject context) {
+ Object value = evaluate(context);
+ return (value instanceof Boolean) ? ((Boolean)value).booleanValue() : false;
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintDef.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintDef.java
new file mode 100644
index 000000000..aad57f209
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ConstraintDef.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.StringValProvider;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.TypeProvider;
+
+public class ConstraintDef extends ValueSpecDef {
+
+ private static final TypeProvider BOOLEAN_TYPE =
+ new TypeProvider() {
+ public IStatus getStatus() {
+ return Status.OK_STATUS;
+ }
+ public EClassifier getType(EObject context) {
+ return EcorePackage.eINSTANCE.getEBooleanObject();
+ }
+ public ETypedElement getTypedElement(EObject context) {
+ return null;
+ }
+ public boolean hasTypedElement() {
+ return false;
+ }
+ public String toString() {
+ return EcorePackage.eINSTANCE.getEBooleanObject().getName();
+ }
+ };
+
+ public ConstraintDef(StringValProvider body, StringValProvider lang) {
+ super(body, lang, BOOLEAN_TYPE);
+ }
+
+ public String getLabel() {
+ return Messages.def_ConstraintDefLabel;
+ }
+
+ public String toString() {
+ return "constraint: " + super.toString(); //$NON-NLS-1$
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DebugOptions.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DebugOptions.java
new file mode 100644
index 000000000..912d0f852
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DebugOptions.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+
+public class DebugOptions {
+ /**
+ * This class should not be instantiated because it has only static
+ * features.
+ */
+ private DebugOptions() {
+ super();
+ }
+
+ public static final String DEBUG = GMFValidationPlugin.getPluginId() + "/debug"; //$NON-NLS-1$
+
+ public static final String META_DEFINITIONS = DEBUG + "/meta/definitions"; //$NON-NLS-1$
+ public static final String CONSTRAINTS = DEBUG + "/constraints"; //$NON-NLS-1$
+
+
+ public static final String EXCEPTIONS_CATCHING = DEBUG + "/exceptions/catching"; //$NON-NLS-1$
+ public static final String EXCEPTIONS_THROWING = DEBUG + "/exceptions/throwing"; //$NON-NLS-1$
+
+ public static final String METHODS_ENTERING = DEBUG + "/methods/entering"; //$NON-NLS-1$
+ public static final String METHODS_EXITING = DEBUG + "/methods/exiting"; //$NON-NLS-1$
+
+ public static final String CACHE = DEBUG + "/cache"; //$NON-NLS-1$
+
+}
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DefUtils.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DefUtils.java
new file mode 100644
index 000000000..60eef774d
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/DefUtils.java
@@ -0,0 +1,688 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier;
+import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
+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.common.util.EMap;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ocl.parser.EcoreEnvironment;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.ContextProvider;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.StringValProvider;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.TypeProvider;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpression;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpressionProvider;
+import org.eclipse.osgi.util.NLS;
+
+public class DefUtils {
+
+ /**
+ * Prevent from instantation
+ */
+ private DefUtils() {
+ }
+
+ public static class FeatureValProvider extends AbstractProvider implements StringValProvider {
+ private EStructuralFeature feature;
+
+ public FeatureValProvider(EStructuralFeature feature) {
+ if(feature == null) {
+ throw new IllegalArgumentException("null feature passed"); //$NON-NLS-1$
+ }
+ this.feature = feature;
+ setStatus(validateFeature(feature));
+ }
+
+ public String getValue(EObject contextInstance) {
+ if(!feature.getEContainingClass().isSuperTypeOf(contextInstance.eClass())) {
+ throw new IllegalArgumentException("Invalid context instance"); //$NON-NLS-1$
+ }
+ if(!getStatus().isOK()) {
+ return null;
+ }
+ Object value = contextInstance.eGet(feature);
+ assert value == null || value instanceof String;
+ return (String)contextInstance.eGet(feature);
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("lang: ") //$NON-NLS-1$
+ .append(feature.getEContainingClass().getName())
+ .append("::").append(feature.getName()); //$NON-NLS-1$
+ return buf.toString();
+ }
+
+ private static IStatus validateFeature(EStructuralFeature feature) {
+ if(feature.getEType() == EcorePackage.eINSTANCE.getEString()) {
+ return Status.OK_STATUS;
+ }
+ String requiredType = LabelProvider.INSTANCE.getObjectLabel(
+ EcorePackage.eINSTANCE.getEString());
+ String foundType = LabelProvider.INSTANCE.getObjectLabel(feature.getEType());
+ String message = MessageFormat.format(
+ Messages.incompatibleTypes,
+ new Object[] { requiredType, foundType });
+ return GMFValidationPlugin.createStatus(IStatus.ERROR,
+ StatusCodes.INVALID_EXPRESSION_TYPE, message, null);
+ }
+ }
+
+
+ private abstract static class AbstractProvider implements IDefElementProvider {
+ private IStatus status = Status.OK_STATUS;
+
+ AbstractProvider() {}
+
+ protected void setStatus(IStatus status) {
+ if(status == null) {
+ throw new IllegalArgumentException("Null status"); //$NON-NLS-1$
+ }
+ this.status = status;
+ }
+ public IStatus getStatus() {
+ return status;
+ }
+ }
+
+
+ private static class ExpressionBasedProvider extends AbstractProvider implements IDefElementProvider {
+ private IModelExpression expression;
+ private EClassifier requiredType;
+
+ protected ExpressionBasedProvider(IModelExpression expression, EClassifier requiredType) {
+ this.expression = expression;
+ this.requiredType = requiredType;
+ if(!expression.getStatus().isOK()) {
+ setStatus(expression.getStatus());
+ } else {
+ EClassifier queryResultType = expression.getResultType();
+ assert queryResultType != null : "Expression must have type"; //$NON-NLS-1$
+ assert requiredType != null : "Required type must be defined"; //$NON-NLS-1$
+ if(!checkTypeAssignmentCompatibility(requiredType, queryResultType)) {
+ setStatus(getIncompatibleTypesStatus(requiredType, queryResultType));
+ }
+ }
+ }
+
+ protected IModelExpression getExpression() {
+ return expression;
+ }
+
+ protected EClassifier getRequiredType() {
+ return requiredType;
+ }
+
+ public Object evaluate(EObject resolutionContext) {
+ return expression.evaluate(resolutionContext);
+ }
+
+ public String toString() {
+ return expression.toString();
+ }
+ }
+
+ public static class LookupByNameContextProvider extends ExpressionBasedProvider implements ContextProvider {
+ private Map contextCache = new HashMap(5);
+ private EPackage.Registry registry;
+
+ public LookupByNameContextProvider(IModelExpression expression, EPackage.Registry registry) {
+ super(expression, EcorePackage.eINSTANCE.getEString());
+ this.registry = (registry != null) ? registry : EPackage.Registry.INSTANCE;
+ }
+
+ public EClassifier getContextClassifier(EObject resolutionContext) {
+ if(getStatus().isOK()) {
+ Object typeNameObj = evaluate(resolutionContext);
+ if(typeNameObj instanceof String) {
+ if(contextCache.containsKey(typeNameObj)) {
+ return (EClassifier)contextCache.get(typeNameObj);
+ }
+ String[] typeName = ((String)typeNameObj).split("::"); //$NON-NLS-1$
+ List nameSeq = new ArrayList(Arrays.asList(typeName));
+ if(typeName.length > 1) {
+ nameSeq.remove(typeName.length - 1);
+ EPackage ePackage = EcoreEnvironment.findPackage(nameSeq, registry);
+ if(ePackage != null) {
+ EClassifier contextClassifier = ePackage.getEClassifier(typeName[typeName.length - 1]);
+ contextCache.put(typeNameObj, contextClassifier);
+ return contextClassifier;
+ }
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+
+
+ public static class GenClassifierContextAdapter extends ExpressionBasedProvider implements ContextProvider {
+
+ public static boolean isGenClassifier(EClassifier eClassifier) {
+ if(eClassifier.getEPackage() == null ||
+ !GenModelPackage.eNS_URI.equals(eClassifier.getEPackage().getNsURI())) {
+ return false;
+ }
+ return GenModelPackage.eINSTANCE.getGenClass().getName().equals(eClassifier.getName()) ||
+ GenModelPackage.eINSTANCE.getGenClassifier().getName().equals(eClassifier.getName());
+ }
+
+ public GenClassifierContextAdapter(IModelExpression expression) {
+ super(expression, expression.getResultType());
+ if(!isGenClassifier(expression.getResultType())) {
+ getIncompatibleTypesStatus(GenModelPackage.eINSTANCE
+ .getGenClassifier(), expression.getResultType());
+ }
+ }
+
+ public EClassifier getContextClassifier(EObject resolutionContext) {
+ if(!getStatus().isOK()) {
+ return null;
+ }
+ GenClassifier genClassifier = (GenClassifier)super.evaluate(resolutionContext);
+ return genClassifier != null ? genClassifier.getEcoreClassifier() : null;
+ }
+ }
+
+
+ public static class ExpressionContextProvider extends ExpressionBasedProvider implements ContextProvider {
+
+ public ExpressionContextProvider(IModelExpression expression) {
+ super(expression, EcorePackage.eINSTANCE.getEClassifier());
+ }
+
+ public EClassifier getContextClassifier(EObject resolutionContext) {
+ return getStatus().isOK() ? (EClassifier)super.evaluate(resolutionContext) : null;
+ }
+ }
+
+
+ public static class ReferencedContextProvider extends AbstractProvider implements ContextProvider {
+ private EReference contextRef;
+ private Map/*<EClass, ContextProvider>*/ referencedContexts = Collections.EMPTY_MAP;
+
+ public ReferencedContextProvider(EClass context, String referenceName, IModelExpressionProvider oclExprProvider, EPackage.Registry registry) {
+ if(context == null) {
+ throw new IllegalArgumentException("null context EClass"); //$NON-NLS-1$
+ }
+ if(referenceName != null) {
+ EStructuralFeature eFeature = context.getEStructuralFeature(referenceName);
+ if(eFeature instanceof EReference) {
+ this.contextRef = (EReference) eFeature;
+ } else {
+ String message = NLS.bind(Messages.def_NoEReferenceFoundByName,
+ referenceName, LabelProvider.INSTANCE.getObjectLabel(context));
+ setStatus(GMFValidationPlugin.createStatus(IStatus.ERROR, -1, message, null));
+ }
+ } else {
+ String message = Messages.def_NoEReferenceInCtxBinding;
+ setStatus(GMFValidationPlugin.createStatus(IStatus.ERROR, -1, message, null));
+ }
+
+ if(contextRef != null) {
+ EClass referencedClass = contextRef.getEReferenceType();
+ List subTypes = getSubTypes(getRootEPackage(referencedClass.getEPackage()), referencedClass, new ArrayList());
+
+ referencedContexts = new HashMap(5);
+ for (Iterator it = subTypes.iterator(); it.hasNext();) {
+ EClass nextClass = (EClass) it.next();
+ ContextProvider referencedContext = DefUtils.getContextClass(nextClass, oclExprProvider, null, registry);
+ if(referencedContext != null) {
+ referencedContexts.put(nextClass, referencedContext);
+ it.remove();
+ }
+ }
+ // perform coverage check
+ List statuses = Collections.EMPTY_LIST;
+ for (Iterator it = subTypes.iterator(); it.hasNext();) {
+ EClass nextClass = (EClass) it.next();
+
+ if(getProvider(nextClass) == null && !(nextClass.isInterface() || nextClass.isAbstract())) {
+ String message = NLS.bind(Messages.def_NoCtxInProviderForCtxBinding,
+ LabelProvider.INSTANCE.getObjectLabel(nextClass),
+ LabelProvider.INSTANCE.getFeatureLabel(contextRef));
+ if(statuses.isEmpty()) {
+ statuses = new ArrayList();
+ }
+ statuses.add(GMFValidationPlugin.createStatus(IStatus.ERROR, -1, message, null));
+ }
+ }
+ if(statuses.size() == 1) {
+ setStatus((IStatus)statuses.get(0));
+ } else {
+ setStatus(new MultiStatus(GMFValidationPlugin.getPluginId(), -1,
+ (IStatus[])statuses.toArray(new IStatus[statuses.size()]),
+ Messages.def_MissingCtxDefInReferencedCtxProviders, null));
+ }
+ }
+ }
+
+ public EClassifier getContextClassifier(EObject resolutionContext) {
+ if(getStatus().isOK()) {
+ if(!contextRef.getEContainingClass().isSuperTypeOf(resolutionContext.eClass())) {
+ throw new IllegalArgumentException("Requires instance of :" + contextRef.getEContainingClass()); //$NON-NLS-1$
+ }
+ assert resolutionContext.eClass().getEStructuralFeature(contextRef.getName()) != null;
+
+ Object referencedEntity = resolutionContext.eGet(contextRef);
+ if(referencedEntity instanceof EObject) {
+ EObject eObject = (EObject)referencedEntity;
+ ContextProvider provider = getProvider(eObject.eClass());
+ return (provider != null && provider.getStatus().isOK()) ?
+ provider.getContextClassifier(eObject) : null;
+ }
+ }
+ return null;
+ }
+
+ private ContextProvider getProvider(EClass contextProviderEClass) {
+ ContextProvider provider = (ContextProvider)referencedContexts.get(contextProviderEClass);
+ if(provider == null) {
+ for(Iterator it = contextProviderEClass.getESuperTypes().iterator(); it.hasNext();) {
+ ContextProvider nextProvider = (ContextProvider)referencedContexts.get(it.next());
+ if(nextProvider != null) {
+ return nextProvider;
+ }
+ }
+ }
+ return provider;
+ }
+ }
+
+ public static class ExpresssionTypeProvider extends ExpressionBasedProvider implements TypeProvider {
+
+ public ExpresssionTypeProvider(IModelExpression expression) {
+ super(expression, getRequiredResultType(expression));
+ }
+
+ public boolean hasTypedElement() {
+ if(getStatus().isOK()) {
+ EClassifier requiredType = getCanonicalEClassifier(getRequiredType());
+ return requiredType instanceof EClass &&
+ EcorePackage.eINSTANCE.getETypedElement().isSuperTypeOf((EClass)requiredType);
+ }
+ return false;
+ }
+
+ public EClassifier getType(EObject context) {
+ if(!getStatus().isOK()) {
+ return null;
+ }
+ Object val = evaluate(context);
+ if(val instanceof ETypedElement) {
+ return ((ETypedElement)val).getEType();
+ } else if(val instanceof EClassifier) {
+ return (EClassifier)val;
+ }
+ assert false;
+ return null;
+ }
+
+ public ETypedElement getTypedElement(EObject context) {
+ if(!getStatus().isOK()) {
+ return null;
+ }
+ Object val = evaluate(context);
+ if(val instanceof ETypedElement) {
+ return (ETypedElement)val;
+ } else if(val instanceof EClassifier) {
+ return null;
+ }
+ assert false;
+ return null;
+ }
+
+ private static EClassifier getRequiredResultType(IModelExpression expression) {
+ EClassifier type = expression.getResultType();
+ if(type instanceof EClass) {
+ if(DefUtils.isEcorePackageClassifier(type)) {
+ EClassifier canonicalClassifier = DefUtils.getCanonicalEcorePackageClassifier(type);
+ assert canonicalClassifier instanceof EClass;
+ EClass canonicalClass = (EClass)canonicalClassifier;
+ if(EcorePackage.eINSTANCE.getETypedElement().isSuperTypeOf(canonicalClass) ||
+ EcorePackage.eINSTANCE.getEClassifier().isSuperTypeOf(canonicalClass)) {
+ return type;
+ }
+ }
+ }
+ return EcorePackage.eINSTANCE.getEClassifier();
+ }
+ }
+
+ public static class TypedElementProvider extends AbstractProvider implements TypeProvider {
+ private EStructuralFeature feature;
+
+ public TypedElementProvider(EStructuralFeature feature) {
+ this.feature = feature;
+ }
+
+ public boolean hasTypedElement() {
+ return true;
+ }
+
+ public EClassifier getType(EObject context) {
+ return getTypedElement(context).getEType();
+ }
+
+ public ETypedElement getTypedElement(EObject context) {
+ return (ETypedElement)context.eGet(feature);
+ }
+ }
+
+ public static class ContextTypeAdapter extends AbstractProvider implements TypeProvider {
+ private ContextProvider ctxProvider;
+
+ public ContextTypeAdapter(ContextProvider contextProvider) {
+ if(contextProvider == null) {
+ throw new IllegalArgumentException("null contextProvider"); //$NON-NLS-1$
+ }
+ this.ctxProvider = contextProvider;
+ }
+
+ public EClassifier getType(EObject resolutionContext) {
+ return ctxProvider.getContextClassifier(resolutionContext);
+ }
+
+ public boolean hasTypedElement() {
+ return false;
+ }
+
+ public ETypedElement getTypedElement(EObject context) {
+ return null;
+ }
+ }
+
+ public static Diagnostic statusToDiagnostic(IStatus status, String diagSource, Object destObj) {
+ return statusToDiagnostic(status, diagSource, destObj, null);
+ }
+
+ public static DiagnosticChain mergeAndFlatten(Diagnostic diagnostic, DiagnosticChain diagnosticChain) {
+ List children = diagnostic.getChildren();
+ if(children == null || children.isEmpty()) {
+ diagnosticChain.add(diagnostic);
+ } else {
+ for (Iterator it = children.iterator(); it.hasNext();) {
+ mergeAndFlatten((Diagnostic) it.next(), diagnosticChain);
+ }
+ }
+ return diagnosticChain;
+ }
+
+ public static DiagnosticChain mergeAndFlatten(IStatus status, String diagSource, Object destObj, DiagnosticChain diagnosticChain) {
+ Diagnostic diagnostic = statusToDiagnostic(status, diagSource, destObj);
+ return mergeAndFlatten(diagnostic, diagnosticChain);
+ }
+
+
+ public static Diagnostic statusToDiagnostic(IStatus status, String diagSource, Object destObj, String prefixMessage) {
+ int severity = IStatus.INFO;
+ switch (status.getSeverity()) {
+ case IStatus.ERROR:
+ severity = Diagnostic.ERROR;
+ break;
+ case IStatus.WARNING:
+ severity = Diagnostic.WARNING;
+ break;
+ case IStatus.INFO:
+ severity = Diagnostic.INFO;
+ break;
+ case IStatus.OK:
+ severity = Diagnostic.OK;
+ break;
+ case IStatus.CANCEL:
+ severity = Diagnostic.CANCEL;
+ break;
+ }
+ Object[] data = (destObj != null) ? new Object[] { destObj } : new Object[0];
+ String message = (prefixMessage != null) ? prefixMessage + status.getMessage() : status.getMessage();
+
+ BasicDiagnostic diagnostic = new BasicDiagnostic(severity, diagSource, status.getCode(), message, data);
+ if(status.isMultiStatus()) {
+ IStatus[] children = status.getChildren();
+ for (int i = 0; i < children.length; i++) {
+ diagnostic.add(statusToDiagnostic(children[i], diagSource, destObj, prefixMessage));
+ }
+ }
+ return diagnostic;
+ }
+
+
+ public static boolean checkTypeAssignmentCompatibility(EClassifier leftClassifier, EClassifier rightClassifier) {
+ EClassifier left = getCanonicalEClassifier(leftClassifier);
+ EClassifier right = getCanonicalEClassifier(rightClassifier);
+ if(left == right) {
+ return true;
+ }
+
+ if(left instanceof EClass) {
+ if(right instanceof EClass &&
+ ((EClass)left).isSuperTypeOf(((EClass)right))) {
+ return true;
+ }
+ } else {
+ Class rightClass = right.getInstanceClass();
+ Class leftClass = left.getInstanceClass();
+ if(leftClass != null && rightClass != null && leftClass.isAssignableFrom(rightClass)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static IStatus getIncompatibleTypesStatus(EClassifier leftClassifier, EClassifier rightClassifier) {
+ String message = MessageFormat.format(
+ Messages.incompatibleTypes,
+ new Object[] {
+ LabelProvider.INSTANCE.getObjectLabel(leftClassifier),
+ LabelProvider.INSTANCE.getObjectLabel(rightClassifier) } );
+
+ return GMFValidationPlugin.createStatus(IStatus.ERROR,
+ StatusCodes.INVALID_EXPRESSION_TYPE, message, null);
+ }
+
+ public static EClassifier emfToOclType(EClassifier type) {
+ return EcoreEnvironment.getOCLType(type);
+ }
+
+ public static EAnnotation getAnnotationWithKey(EModelElement eModelElement, String sourceURI, String key) {
+ for (Iterator it = eModelElement.getEAnnotations().iterator(); it.hasNext();) {
+ EAnnotation nextAnnotation = (EAnnotation) it.next();
+ if(sourceURI.equals(nextAnnotation.getSource()) && nextAnnotation.getDetails().containsKey(key)) {
+ return nextAnnotation;
+ }
+ }
+ return null;
+ }
+
+ public static Map.Entry findAnnotationDetailEntry(EModelElement eModelElement, String sourceURI, String key, String val) {
+ for (Iterator it = eModelElement.getEAnnotations().iterator(); it.hasNext();) {
+ EAnnotation nextAnnotation = (EAnnotation) it.next();
+ if(sourceURI.equals(nextAnnotation.getSource()) && nextAnnotation.getDetails().containsKey(key)) {
+ for (Iterator entryIt = nextAnnotation.getDetails().iterator(); entryIt.hasNext();) {
+ Map.Entry nextEntry = (Map.Entry)entryIt.next();
+ if(nextEntry.getValue() == val || nextEntry.getKey().equals(key)) {
+ return nextEntry;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+ public static Map.Entry getKeyPreffixAnnotation(EAnnotation annotation, String keyPrefix) {
+ for (Iterator it = annotation.getDetails().entrySet().iterator(); it.hasNext();) {
+ Map.Entry nextEntry = (Map.Entry)it.next();
+ if(((String)nextEntry.getKey()).startsWith(keyPrefix)) {
+ return nextEntry;
+ }
+ }
+ return null;
+ }
+
+ public static List getAnnotationsWithKeyAndValue(EModelElement eModelElement, String sourceURI, String key, String value) {
+ List annotations = null;
+ for (Iterator it = eModelElement.getEAnnotations().iterator(); it.hasNext();) {
+ EAnnotation nextAnnotation = (EAnnotation) it.next();
+ if(sourceURI.equals(nextAnnotation.getSource())) {
+ Object detailVal = nextAnnotation.getDetails().get(key);
+ if((value != null && value.equals(detailVal)) || value == detailVal) {
+ if(annotations == null) {
+ annotations = new ArrayList(eModelElement.getEAnnotations().size());
+ }
+ annotations.add(nextAnnotation);
+ }
+ }
+ }
+ return annotations != null ? annotations : Collections.EMPTY_LIST;
+ }
+
+ public static List getAnnotationValues(EModelElement eModelElement, String sourceURI, String key) {
+ List annotations = null;
+ for (Iterator it = eModelElement.getEAnnotations().iterator(); it.hasNext();) {
+ EAnnotation nextAnnotation = (EAnnotation) it.next();
+ if(sourceURI.equals(nextAnnotation.getSource())) {
+ Object detailVal = nextAnnotation.getDetails().get(key);
+ if((detailVal != null)) {
+ if(annotations == null) {
+ annotations = new ArrayList(eModelElement.getEAnnotations().size());
+ }
+ annotations.add(detailVal);
+ }
+ }
+ }
+ return annotations != null ? annotations : Collections.EMPTY_LIST;
+ }
+
+ public static boolean isEcorePackageClassifier(EClassifier classifier) {
+ EPackage classifierPackage = classifier.getEPackage();
+ return EcorePackage.eINSTANCE == classifierPackage ||
+ (classifierPackage != null && EcorePackage.eINSTANCE.getNsURI().equals(classifierPackage.getNsURI()));
+ }
+
+ public static EClassifier getCanonicalEcorePackageClassifier(EClassifier classifier) {
+ if(!isEcorePackageClassifier(classifier)) {
+ return null;
+ }
+ return EcorePackage.eINSTANCE.getEClassifier(classifier.getName());
+ }
+
+ static EClassifier getCanonicalEClassifier(EClassifier classifier) {
+ EClassifier eCoreCanonical = getCanonicalEcorePackageClassifier(classifier);
+ return (eCoreCanonical == null) ? classifier : eCoreCanonical;
+ }
+
+ /**
+ * @return String value associated with the given key in given detail map or
+ * <code>null</code> if not key is present in the value
+ */
+ public static String getAnnotationDetailValue(EMap detail, String key) {
+ if(detail == null || key == null) {
+ throw new IllegalArgumentException("null detail map or key"); //$NON-NLS-1$
+ }
+ Object val = detail.get(key);
+ return val instanceof String ? (String) val : null;
+ }
+
+
+ public static ContextProvider getContextClass(EClass resolutionContext, IModelExpressionProvider oclExprProvider, EStructuralFeature bindFeature, EPackage.Registry registry) {
+ assert bindFeature == null || bindFeature.getEContainingClass().isSuperTypeOf(resolutionContext);
+
+ EModelElement annotationTarget = (bindFeature != null) ? (EModelElement) bindFeature : resolutionContext;
+ EAnnotation ctxAnnotation = annotationTarget.getEAnnotation(Annotations.CONSTRAINTS_META_URI);
+
+ if (ctxAnnotation != null && Annotations.Meta.CONTEXT.equals(ctxAnnotation.getDetails().get(Annotations.Meta.DEF_KEY))) {
+ for (Iterator it = ctxAnnotation.getDetails().entrySet().iterator(); it.hasNext();) {
+ Map.Entry nextDetail = (Map.Entry) it.next();
+ Object key = nextDetail.getKey();
+ String value = nextDetail.getValue() instanceof String ? (String) nextDetail.getValue() : ""; //$NON-NLS-1$
+
+ if (Annotations.Meta.OCL_KEY.equals(key)) {
+ if (value != null) {
+ IModelExpression contextEpression = oclExprProvider.createExpression(value, resolutionContext);
+ EClassifier resultType = contextEpression.getResultType();
+ if (String.class.equals(resultType.getInstanceClass())) {
+ return new LookupByNameContextProvider(contextEpression, registry);
+ }
+ else if(GenClassifierContextAdapter.isGenClassifier(resultType)) {
+ return new GenClassifierContextAdapter(contextEpression);
+ }
+
+ // TODO - support in general EClassifier, GenClassifier, or String typeName
+ // report problem for expressions with any other result type
+ return new ExpressionContextProvider(contextEpression);
+ }
+ } else if (Annotations.Meta.REF.equals(key)) {
+ return new ReferencedContextProvider(resolutionContext, value, oclExprProvider, registry);
+ }
+ }
+ }
+
+ // no context found
+ return null;
+ }
+
+ /**
+ * @param ePackage
+ * scope for searching the sub-types, including sub-packages
+ * @param superType
+ * the type of which the sub-types are to be found
+ * @param foundSubTypes
+ * placeholder for the collected sub-types
+ * @return passed <code>foundSubTypes</code> list for convenience
+ */
+ static List getSubTypes(EPackage ePackage, EClass superType, List foundSubTypes) {
+ for (Iterator it = ePackage.getEClassifiers().iterator(); it.hasNext();) {
+ EClassifier classifier = (EClassifier) it.next();
+ if(classifier instanceof EClass && (superType).isSuperTypeOf((EClass)classifier)) {
+ foundSubTypes.add(classifier);
+ }
+ }
+ for (Iterator it = ePackage.getESubpackages().iterator(); it.hasNext();) {
+ getSubTypes((EPackage) it.next(), superType, foundSubTypes);
+ }
+ return foundSubTypes;
+ }
+
+ static EPackage getRootEPackage(EPackage ePackage) {
+ EPackage root = ePackage;
+ for (EPackage parent = ePackage; parent != null; parent = parent.getESuperPackage()) {
+ root = parent;
+ }
+ return root;
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/EDataTypeConversion.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/EDataTypeConversion.java
new file mode 100644
index 000000000..b9910e4dd
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/EDataTypeConversion.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+public class EDataTypeConversion {
+
+ private static final Class[][] integralsToFloatsArray = new Class[][] {
+ new Class[] { Byte.class, Float.class },
+ new Class[] { Short.class, Float.class },
+ new Class[] { Integer.class, Float.class },
+ new Class[] { Long.class, Double.class },
+ new Class[] { BigInteger.class, BigDecimal.class }
+ };
+
+ private static final List integrals = new ArrayList();
+ static {
+ for (int i = 0; i < integralsToFloatsArray.length; i++) {
+ integrals.add(integralsToFloatsArray[i][0]);
+ }
+ }
+
+ private static final List floats = Arrays.asList(new Class[] {
+ Float.class, Double.class, BigDecimal.class,
+ });
+
+
+ public static boolean isConvertable(EDataType leftDataType, EDataType rightDataType) {
+ if(leftDataType == null || rightDataType == null) {
+ throw new IllegalArgumentException("null data type"); //$NON-NLS-1$
+ }
+ if(leftDataType.getInstanceClass() == null || rightDataType.getInstanceClass() == null) {
+ return false;
+ }
+ Class leftClass = EcoreUtil.wrapperClassFor(leftDataType.getInstanceClass());
+ Class rightClass = EcoreUtil.wrapperClassFor(rightDataType.getInstanceClass());
+ if(Number.class.isAssignableFrom(leftClass) && Number.class.isAssignableFrom(leftClass)) {
+ return isConvertable(leftClass, rightClass);
+ }
+ return leftClass.equals(rightClass);
+ }
+
+ private static boolean isConvertable(Class left, Class right) {
+ if(left == null || right == null) {
+ throw new IllegalArgumentException("null Class argument"); //$NON-NLS-1$
+ }
+
+ int leftPos = integrals.indexOf(left);
+ int rightPos = integrals.indexOf(right);
+ if(leftPos >= 0) {
+ if(rightPos < 0) {
+ return false;
+ }
+ } else {
+ if((leftPos = floats.indexOf(left)) >= 0) {
+ // left is float
+ if(rightPos >= 0) {
+ // convert right int to float
+ rightPos = floats.indexOf(integralsToFloatsArray[rightPos][1]);
+ } else {
+ if((rightPos = floats.indexOf(right)) < 0) {
+ return false;
+ }
+ }
+ return leftPos >= rightPos;
+ }
+ }
+
+ return left.isAssignableFrom(right);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExpressionCache.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExpressionCache.java
new file mode 100644
index 000000000..c7e463c07
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExpressionCache.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.gmf.internal.validate.expressions.AbstractExpression;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpression;
+import org.eclipse.gmf.internal.validate.expressions.IParseEnvironment;
+
+/**
+ * Cache for parsed OCL expressions, to be reused in evaluation for different
+ * context instances.
+ *
+ * @author dvorak
+ */
+public abstract class ExpressionCache {
+ private Map body2Entries = new HashMap();
+
+ protected ExpressionCache() {
+ }
+
+ protected abstract IModelExpression createExpressionEntry(String body, EClassifier context, IParseEnvironment extEnv);
+
+ /**
+ * Gets expression object for the given context type and expression body.
+ * </p>
+ *
+ * @param body
+ * the expression body
+ * @param context
+ * the context type required for evaluation.
+ *
+ * @return the constraint proxy encapsulating the parsed constraint
+ * expression
+ */
+ public IModelExpression getExpression(String body, EClassifier context) {
+ return getExpression(body, context, null);
+ }
+
+ /**
+ * Gets expression object for the given context type and expression
+ * body.
+ * </p>
+ *
+ * @param body
+ * the expression body
+ * @param context
+ * the context type required for evaluation.
+ * @param env
+ * parsing environment providing custom variable definitions.
+ *
+ * @return the constraint proxy encapsulating the parsed constraint
+ * expression
+ */
+ public IModelExpression getExpression(String body, EClassifier context, IParseEnvironment env) {
+ if (body == null || context == null) {
+ throw new IllegalArgumentException("Null expression body or context"); //$NON-NLS-1$
+ }
+
+ IModelExpression resultEntry = null;
+
+ if (body2Entries.containsKey(body)) {
+ Object prev = body2Entries.get(body);
+ if (prev instanceof AbstractExpression) {
+ IModelExpression prevEntry = (AbstractExpression) prev;
+ if (prevEntry.getContext() == context) {
+ return prevEntry;
+ }
+ }
+ List cachedEntries = (prev instanceof List) ? (List) prev : new LinkedList();
+ if (cachedEntries.isEmpty()) {
+ // only one previous with not matching context class
+ // -> add previous and register the new one
+ cachedEntries.add(prev);
+ body2Entries.put(body, cachedEntries);
+ } else {
+ // try to find entry with appropriate context
+ for (Iterator it = cachedEntries.iterator(); it.hasNext();) {
+ AbstractExpression nextConstraint = (AbstractExpression) it.next();
+ if (nextConstraint.getContext() == context) {
+ return nextConstraint;
+ }
+ }
+ }
+ resultEntry = createExpressionEntry(body, context, env);
+ cachedEntries.add(resultEntry);
+ assert resultEntry != null;
+ return resultEntry;
+ }
+
+ resultEntry = createExpressionEntry(body, context, env);
+ body2Entries.put(body, resultEntry);
+ return resultEntry;
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExternModelImport.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExternModelImport.java
new file mode 100644
index 000000000..24fb89a4b
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ExternModelImport.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier;
+import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
+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.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.osgi.util.NLS;
+
+public class ExternModelImport {
+ private static final String DIAGNOSTIC_SOURCE = GMFValidationPlugin.getDefault().getBundle().getSymbolicName() + ".imports"; //$NON-NLS-1$
+
+ private static final EValidator VALIDATOR = new AbstractValidator() {
+
+ public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map context) {
+ super.validate(eClass, eObject, diagnostics, context);
+ ExternModelImport importer = getImporter(context, eObject);
+ if(eObject instanceof EAnnotation) {
+ return importer.processAnnotation((EAnnotation)eObject, diagnostics);
+ }
+
+ EPackage ePackage = eObject.eClass().getEPackage();
+ if(!importer.hasPackageImportsProcessed(ePackage)) {
+ return importer.processAnnotations(eObject.eClass().getEPackage(), diagnostics);
+ }
+ return true;
+ }
+ };
+
+ private ResourceSet importedModels;
+ private EPackage.Registry registry;
+ private HashSet processedPackages;
+
+
+ private ExternModelImport(EObject validatedObject) {
+ this.importedModels = new ResourceSetImpl();
+ Resource targetModel = validatedObject.eResource();
+ if(targetModel != null) {
+ this.importedModels.setURIConverter(targetModel.getResourceSet().getURIConverter());
+ }
+ this.processedPackages = new HashSet();
+ }
+
+ public static EValidator getImportValidator() {
+ return VALIDATOR;
+ }
+
+ public static ExternModelImport getImporter(Map context, EObject validatedEObject) {
+ if(context != null) {
+ Object value = context.get(ExternModelImport.class);
+ if(value == null) {
+ value = new ExternModelImport(validatedEObject);
+ context.put(ExternModelImport.class, value);
+ }
+ assert value instanceof ExternModelImport;
+ return (ExternModelImport)value;
+ }
+
+ return new ExternModelImport(validatedEObject);
+ }
+
+ /**
+ * @return The import package registry associated with the context or <code>null</code> if there is no such registry
+ */
+ public static EPackage.Registry getPackageRegistry(Map context) {
+ Object registry = context.get(EPackageRegistryImpl.class);
+ assert registry == null || registry instanceof EPackage.Registry : "registry must be EPackage.Registry"; //$NON-NLS-1$
+ return (EPackage.Registry)registry;
+ }
+
+ boolean hasPackageImportsProcessed(EPackage importingPackage) {
+ return processedPackages.contains(importingPackage);
+ }
+
+ private boolean processAnnotations(EPackage importingPackage, DiagnosticChain diagnostics) {
+ boolean result = true;
+ for (Iterator it = importingPackage.getEAnnotations().iterator(); it.hasNext();) {
+ result &= processAnnotation((EAnnotation) it.next(), diagnostics);
+ }
+ processedPackages.add(importingPackage);
+ return result;
+ }
+
+ private boolean processAnnotation(EAnnotation annotation, DiagnosticChain diagnostics) {
+ if(Annotations.CONSTRAINTS_URI.equals(annotation.getSource())) {
+ return processImportEAnnotation(annotation, diagnostics);
+ }
+ return true;
+ }
+
+ public void intializeExternPackages(EObject root) {
+ EPackage.Registry registryToInit = registry != null ? registry : EPackage.Registry.INSTANCE;
+ for (Iterator refIt = EcoreUtil.ExternalCrossReferencer.find(root).keySet().iterator(); refIt.hasNext();) {
+ Object next = refIt.next();
+ EPackage nextPackage = null;
+ if (next instanceof EClassifier) {
+ nextPackage = ((EClassifier) next).getEPackage();
+ registryToInit.getEPackage(((EClassifier) next).getEPackage().getNsURI());
+ }
+ else if(next instanceof EPackage) {
+ nextPackage = (EPackage)next;
+ }
+ else if(next instanceof GenPackage) {
+ nextPackage = ((GenPackage)next).getEcorePackage();
+ }
+ else if(next instanceof GenClassifier) {
+ nextPackage = ((GenClassifier) next).getGenPackage().getEcorePackage();
+ }
+
+ if(nextPackage != null) {
+ // force the package to be initialized in registry, in case a package descriptor is registered
+ // Note: this is required for successfull ocl environment lookup of EClassifiers from external meta-models
+ registryToInit.getEPackage(nextPackage.getNsURI());
+ }
+ }
+ }
+
+
+ private boolean processImportEAnnotation(EAnnotation annotation, DiagnosticChain diagnostics) {
+ boolean result = true;
+ for (Iterator it = annotation.getDetails().entrySet().iterator(); it.hasNext();) {
+ Map.Entry nextEntry = (Map.Entry)it.next();
+ if(!nextEntry.getKey().equals(Annotations.Meta.IMPORT)) {
+ continue;
+ }
+ String importVal = (String) nextEntry.getValue();
+ if(importVal != null) {
+ URI modelURI = null;
+ try {
+ modelURI = URI.createURI(importVal.trim());
+ try {
+ importModelFromResource(modelURI);
+ } catch (RuntimeException e) {
+ result = false;
+ reportModelLoadingError(importVal, annotation.getEModelElement(), diagnostics, e);
+ }
+ } catch (IllegalArgumentException e) {
+ result = false;
+ reportInvalidModelURI(importVal, annotation.getEModelElement(), diagnostics);
+ }
+ } else {
+ result = false;
+ reportInvalidModelURI(importVal, annotation.getEModelElement(), diagnostics);
+ }
+ }
+ return result;
+ }
+
+
+ private static void reportInvalidModelURI(String modelURIValue, EModelElement annotatedElement, DiagnosticChain diagnostics) {
+ Object destObj = DefUtils.findAnnotationDetailEntry(annotatedElement,
+ Annotations.CONSTRAINTS_URI, Annotations.Meta.IMPORT, modelURIValue);
+ assert destObj != null;
+
+ Diagnostic diagnostic = new BasicDiagnostic(Diagnostic.ERROR,
+ DIAGNOSTIC_SOURCE, StatusCodes.INVALID_MODEL_IMPORT_URI,
+ NLS.bind(Messages.invalidModelImportUri, modelURIValue), new Object[] { destObj });
+ diagnostics.add(diagnostic);
+ }
+
+ private static void reportModelLoadingError(String modelURIValue, EModelElement annotatedElement, DiagnosticChain diagnostics, RuntimeException error) {
+ Object destObj = DefUtils.findAnnotationDetailEntry(annotatedElement,
+ Annotations.CONSTRAINTS_URI, Annotations.Meta.IMPORT, modelURIValue);
+ assert destObj != null;
+
+ String message = NLS.bind(Messages.modelImportResourceLoadingError, modelURIValue, error.getLocalizedMessage());
+ Diagnostic diagnostic = new BasicDiagnostic(Diagnostic.ERROR,
+ DIAGNOSTIC_SOURCE, StatusCodes.INVALID_MODEL_IMPORT_URI,
+ message, new Object[] { destObj });
+ diagnostics.add(diagnostic);
+ GMFValidationPlugin.log(diagnostic.getSeverity(), message, error);
+ }
+
+ private boolean importModelFromResource(URI modelURI) throws RuntimeException {
+ EList contents = importedModels.getResource(modelURI, true).getContents();
+ for (Iterator it = contents.iterator(); it.hasNext();) {
+ EObject nextObj = (EObject) it.next();
+ if(nextObj instanceof EPackage) {
+ EPackage ePackage = (EPackage)nextObj;
+ if(ePackage.getNsURI() != null) {
+ // force package initialization
+ EPackage.Registry.INSTANCE.getEPackage(ePackage.getNsURI());
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/GMFValidationPlugin.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/GMFValidationPlugin.java
new file mode 100644
index 000000000..ce23d8390
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/GMFValidationPlugin.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The main plugin class to be used in the desktop.
+ */
+public class GMFValidationPlugin extends Plugin {
+
+ //The shared instance.
+ private static GMFValidationPlugin plugin;
+
+ /**
+ * The constructor.
+ */
+ public GMFValidationPlugin() {
+ plugin = this;
+ }
+
+ /**
+ * This method is called upon plug-in activation
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ }
+
+ /**
+ * This method is called when the plug-in is stopped
+ */
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ plugin = null;
+ }
+
+ /**
+ * Returns the shared instance.
+ */
+ public static GMFValidationPlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Creates a new status object for this plugin.
+ *
+ * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
+ * <code>INFO</code>, <code>WARNING</code>, or <code>CANCEL</code>
+ * @param code the plug-in-specific status code, or <code>OK</code>
+ * @param message a human-readable message, localized to the
+ * current locale
+ * @param exception a low-level exception, or <code>null</code> if not
+ * applicable
+ */
+ public static IStatus createStatus(int severity, int code, String message, Throwable exception) {
+ return new Status(severity, getPluginId(), code, message, exception);
+ }
+
+ public static void log(int severity, String message, Throwable exception) {
+ Status s = new Status(severity, getPluginId(),
+ 0, message != null ? message : "", exception); //$NON-NLS-1$
+ log(s);
+ }
+
+ public static void log(IStatus status) {
+ if(status.getSeverity() >= IStatus.WARNING && Trace.shouldTrace()) {
+ Trace.trace(status.getMessage());
+ }
+ getDefault().getLog().log(status);
+ }
+
+ public static String getPluginId() {
+ return getDefault().getBundle().getSymbolicName();
+ }
+}
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/IDefElementProvider.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/IDefElementProvider.java
new file mode 100644
index 000000000..2e89f1e47
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/IDefElementProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.ETypedElement;
+
+public interface IDefElementProvider {
+ IStatus getStatus();
+
+ public interface ContextProvider extends IDefElementProvider {
+ /**
+ * Gets context classifier.
+ *
+ * @param resolutionContext
+ * contextual instance to be used for resolving the resulting
+ * context classifier.
+ * @return classifer object or <code>null</code> is this provider was
+ * not able to find out suitable classifier in this
+ * <code>resolutionContext</code>.
+ * <p>
+ * Note: if this provider status is not <code>OK</code>, this
+ * method returns <code>null</code>.
+ */
+ EClassifier getContextClassifier(EObject resolutionContext);
+ }
+
+ public interface TypeProvider extends IDefElementProvider {
+ /**
+ * Gets typed element represented by this provider.
+ * <p>
+ *
+ * @return typed element or <code>null</code> if this provider
+ * represents only plain classifier without extra info on
+ * muliplicity, ordering, uniqueness which have impact on the
+ * resulting model type.
+ */
+ ETypedElement getTypedElement(EObject context);
+ EClassifier getType(EObject context);
+ boolean hasTypedElement();
+ }
+
+ public interface StringValProvider extends IDefElementProvider {
+ String getValue(EObject contextInstance);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/LabelProvider.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/LabelProvider.java
new file mode 100644
index 000000000..01374fe5a
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/LabelProvider.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.EValidator.SubstitutionLabelProvider;
+import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
+
+
+
+public class LabelProvider implements SubstitutionLabelProvider {
+ public static final SubstitutionLabelProvider INSTANCE = new LabelProvider();
+ private static final AdapterFactory ECORE_FACTORY = new EcoreItemProviderAdapterFactory();
+
+ private LabelProvider() {
+ super();
+ }
+
+ public String getFeatureLabel(EStructuralFeature eStructuralFeature) {
+ return eStructuralFeature.getName();
+ }
+
+ public String getObjectLabel(EObject eObject) {
+ if(eObject == null) {
+ return String.valueOf(eObject);
+ }
+ if(eObject instanceof EStructuralFeature) {
+ return getFeatureLabel((EStructuralFeature)eObject);
+ }
+ else if(eObject instanceof ENamedElement) {
+ return qualifiedName((ENamedElement)eObject, new StringBuffer()).toString();
+ }
+
+ String displayName = toDisplayName(eObject);
+ return (displayName != null) ? displayName : EcoreUtil.getIdentification(eObject);
+ }
+
+ public String getValueLabel(EDataType eDataType, Object value) {
+ return EcoreUtil.convertToString(eDataType, value);
+ }
+
+ private static StringBuffer qualifiedName(ENamedElement namedElement, StringBuffer buf) {
+ if(buf == null) {
+ buf = new StringBuffer();
+ }
+ EObject container = namedElement.eContainer();
+ if(container instanceof ENamedElement) {
+ ENamedElement owner = (ENamedElement)container;
+ qualifiedName(owner, buf);
+ buf.append("::"); //$NON-NLS-1$
+ }
+
+ buf.append(namedElement.getName());
+ return buf;
+ }
+
+ private static String toDisplayName(EObject eObject) {
+ IItemLabelProvider labelAdapter = (IItemLabelProvider)EcoreUtil.getRegisteredAdapter(EcorePackage.eINSTANCE.getEAnnotation(), IItemLabelProvider.class);
+ if(labelAdapter == null) {
+ labelAdapter = (IItemLabelProvider)ECORE_FACTORY.adapt(eObject, IItemLabelProvider.class);
+ }
+ return labelAdapter.getText(eObject);
+ }
+
+ public static final String getTextLabel(Object obj) {
+ return (obj instanceof EObject) ? INSTANCE.getObjectLabel((EObject)obj) : String.valueOf(obj);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Messages.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Messages.java
new file mode 100644
index 000000000..6823bd289
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Messages.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import org.eclipse.osgi.util.NLS;
+
+public final class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.gmf.internal.validate.messages";//$NON-NLS-1$
+
+ private Messages() {
+ // Do not instantiate
+ }
+
+ public static String validation_EmptyExpressionBody;
+ public static String validation_ConstraintInInvalidContext;
+ public static String validation_ConstraintViolation;
+ public static String def_InvalidContextDefinition;
+ public static String def_MissingBodyAnnotation;
+ public static String def_NoContextAvailable;
+ public static String def_NoTypeAvailable;
+ public static String def_ValueSpecDefLabel;
+ public static String def_ConstraintDefLabel;
+ public static String invalidExpressionBody;
+ public static String incompatibleTypes;
+ public static String unexpectedExprEvalError;
+ public static String invalidConstraintExprType;
+ public static String unexpectedValidationError;
+ public static String unexpectedExprParseError;
+ public static String invalidModelImportUri;
+ public static String modelImportResourceLoadingError;
+ public static String modelImportUriFallbackResolution;
+
+ public static String noExpressionProviderAvailable;
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+ public static String def_NoEReferenceFoundByName;
+ public static String def_NoEReferenceInCtxBinding;
+ public static String def_NoCtxInProviderForCtxBinding;
+ public static String def_MissingCtxDefInReferencedCtxProviders;
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/StatusCodes.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/StatusCodes.java
new file mode 100644
index 000000000..a2bd0365e
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/StatusCodes.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+public final class StatusCodes {
+
+ public static int INVALID_CONSTRAINT_EXPRESSION = 200;
+
+ /**
+ * Status code indicates the error status expression which failed to parse.
+ */
+ public static int INVALID_VALUE_EXPRESSION = 201;
+
+ /**
+ * Status code which indicates the error status for constraint having the expression type different from Boolean.
+ */
+ public static int INVALID_EXPRESSION_TYPE = 202;
+
+ public static int MISSING_VALUESPEC_BODY_ANNOTATION = 205;
+
+ public static int INVALID_VALUESPEC_DEF = 206;
+
+ public static int NO_VALUESPEC_CONTEXT_AVAILABLE = 207;
+
+ public static int NO_VALUESPEC_BODY_AVAILABLE = 208;
+
+ public static int INVALID_CONSTRAINT_CONTEXT = 209;
+
+ public static int EMPTY_CONSTRAINT_BODY = 210;
+
+ public static int UNEXPECTED_PARSE_ERROR = 215;
+
+ public static int UNEXPECTED_EVALUATION_ERROR = 220;
+
+ public static int INVALID_VALUESPEC_TYPE = 222;
+
+ public static int VALUESPEC_TYPE_NOT_AVAILABLE = 223;
+
+ /**
+ * The diagnostic code for constraint violations.
+ */
+ public static final int CONSTRAINT_VIOLATION = 225;
+
+ public static final int UNEXPECTED_VALIDATION_ERROR = 300;
+
+ public static final int INVALID_MODEL_IMPORT_URI = 305;
+
+ public static final int EXPRESSION_PROVIDER_NOT_AVAILABLE = 310;
+
+ private StatusCodes() {
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Trace.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Trace.java
new file mode 100644
index 000000000..f172fad5a
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/Trace.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+
+/**
+ * A utility for tracing debug information, filtering and generating trace output.
+ */
+public class Trace {
+
+ private static final Plugin plugin = GMFValidationPlugin.getDefault();
+
+ /**
+ * private constructor for the static class.
+ */
+ private Trace() {
+ super();
+ }
+
+ /**
+ * String containing an open parenthesis.
+ *
+ */
+ private static final String PARENTHESIS_OPEN = "("; //$NON-NLS-1$
+
+ /**
+ * String containing a close parenthesis.
+ *
+ */
+ private static final String PARENTHESIS_CLOSE = ")"; //$NON-NLS-1$
+
+ /**
+ * Prefix for tracing the catching of throwables.
+ *
+ */
+ private static final String PREFIX_CATCHING = "CAUGHT "; //$NON-NLS-1$
+
+ /**
+ * Separator containing a space.
+ *
+ */
+ private static final String SEPARATOR_SPACE = " "; //$NON-NLS-1$
+
+ /**
+ * The cached debug options (for optimization).
+ */
+ private static final Map cachedOptions = new HashMap();
+
+ /**
+ * Retrieves a Boolean value indicating whether tracing is enabled.
+ *
+ * @return Whether tracing is enabled.
+ */
+ protected static boolean shouldTrace() {
+ return plugin.isDebugging();
+ }
+
+ /**
+ * Retrieves a Boolean value indicating whether tracing is enabled for the
+ * specified debug option.
+ *
+ * @return Whether tracing is enabled for the debug option.
+ * @param option The debug option for which to determine trace enablement.
+ *
+ */
+ public static boolean shouldTrace(String option) {
+ if (shouldTrace()) {
+ Boolean value = null;
+
+ synchronized (cachedOptions) {
+ value = (Boolean) cachedOptions.get(option);
+
+ if (null == value) {
+ value = Boolean.valueOf(Platform.getDebugOption(option));
+
+ cachedOptions.put(option, value);
+ }
+ }
+
+ return value.booleanValue();
+ }
+
+ return false;
+ }
+
+ /**
+ * Traces the specified message from the specified plug-in.
+ *
+ * @param plugin The plug-in from which to trace.
+ * @param message The message to be traced.
+ */
+ public static void trace(String message) {
+ if (shouldTrace()) {
+ System.out.println(message);
+ }
+ }
+
+ /**
+ * Traces the specified message for the specified
+ * debug option.
+ *
+ * @param option The debug option for which to trace.
+ * @param message The message to be traced.
+ */
+ public static void trace(String option, String message) {
+ if (shouldTrace(option)) {
+ trace(message);
+ }
+ }
+
+ /**
+ * Traces the catching of the specified throwable.
+ *
+ * @param option The debug option for which to trace.
+ * @param throwable The throwable that is being caught.
+ */
+ public static void catching(
+ String option,
+ Throwable throwable) {
+
+ if (shouldTrace(option)) {
+
+ trace(
+ PREFIX_CATCHING
+ + SEPARATOR_SPACE
+ + PARENTHESIS_OPEN
+ + throwable.getMessage()
+ + PARENTHESIS_CLOSE);
+ throwable.printStackTrace(System.err);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValidatorChain.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValidatorChain.java
new file mode 100644
index 000000000..72623ec6d
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValidatorChain.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import java.text.MessageFormat;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+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.gmf.validate.ValidationOptions;
+
+public class ValidatorChain implements EValidator {
+ private static final String DIAGNOSTIC_SOURCE = "org.eclipse.gmf.validation.failure"; //$NON-NLS-1$
+
+ private EValidator[] validatorList;
+ private ValidationOptions options;
+
+ public ValidatorChain(EValidator[] validators) {
+ this(validators, null);
+ }
+
+ /**
+ *
+ * @param validators
+ * @param options validation optiond or <code>null</code> if default should be used
+ */
+ public ValidatorChain(EValidator[] validators, ValidationOptions options) {
+ if(validators == null || validators.length == 0) {
+ throw new IllegalArgumentException("No validators specified"); //$NON-NLS-1$
+ }
+
+ this.validatorList = new EValidator[validators.length];
+
+ for (int i = 0; i < validators.length; i++) {
+ EValidator nextValidator = validators[i];
+ if(nextValidator == null) {
+ throw new IllegalArgumentException("null validator passed"); //$NON-NLS-1$
+ }
+ validatorList[i] = nextValidator;
+ }
+
+ this.options = options;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.emf.ecore.EValidator#validate(org.eclipse.emf.ecore.EClass, org.eclipse.emf.ecore.EObject, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
+ */
+ public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map context) {
+ if(options != null && context != null) {
+ AbstractValidator.setOptions(options, context);
+ }
+
+ boolean result = true;
+ for (int i = 0; i < validatorList.length; i++) {
+ EValidator nextValidator = validatorList[i];
+ try {
+ result &= nextValidator.validate(eClass, eObject, diagnostics, context);
+ } catch (Exception e) {
+ reportValidationFailure(eObject, diagnostics, e);
+ }
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.emf.ecore.EValidator#validate(org.eclipse.emf.ecore.EDataType, java.lang.Object, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
+ */
+ public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map context) {
+ if(options != null && context != null) {
+ AbstractValidator.setOptions(options, context);
+ }
+
+ boolean result = true;
+ for (int i = 0; i < validatorList.length; i++) {
+ EValidator nextValidator = validatorList[i];
+ try {
+ result &= nextValidator.validate(eDataType, value, diagnostics, context);
+ } catch (Exception e) {
+ reportValidationFailure(value, diagnostics, e);
+ }
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.emf.ecore.EValidator#validate(org.eclipse.emf.ecore.EObject, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
+ */
+ public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map context) {
+ if(options != null && context != null) {
+ AbstractValidator.setOptions(options, context);
+ }
+
+ boolean result = true;
+ for (int i = 0; i < validatorList.length; i++) {
+ EValidator nextValidator = validatorList[i];
+ try {
+ result &= nextValidator.validate(eObject, diagnostics, context);
+ } catch (Exception e) {
+ reportValidationFailure(eObject, diagnostics, e);
+ }
+ }
+ return result;
+ }
+
+ private static void reportValidationFailure(Object objFailedToValidate, DiagnosticChain diagnostics, Exception failure) {
+ String messagePtn = Messages.unexpectedValidationError;
+ String objLabel = null;
+ try {
+ // safe check because of ItemProviders possibly throwing exceptions
+ objLabel = LabelProvider.getTextLabel(objFailedToValidate);
+ } catch(Exception e) {
+ objLabel = String.valueOf(objFailedToValidate);
+ Trace.catching(DebugOptions.EXCEPTIONS_CATCHING, e);
+ }
+
+ IStatus status = GMFValidationPlugin.createStatus(
+ IStatus.ERROR, StatusCodes.UNEXPECTED_VALIDATION_ERROR,
+ MessageFormat.format(messagePtn, new Object[] { objLabel }), failure);
+
+ diagnostics.add(DefUtils.statusToDiagnostic(status, DIAGNOSTIC_SOURCE, objFailedToValidate));
+ GMFValidationPlugin.log(status);
+ Trace.catching(DebugOptions.EXCEPTIONS_CATCHING, failure);
+ }
+}
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValueSpecDef.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValueSpecDef.java
new file mode 100644
index 000000000..54ad822e3
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ValueSpecDef.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.StringValProvider;
+import org.eclipse.gmf.internal.validate.IDefElementProvider.TypeProvider;
+
+
+public class ValueSpecDef {
+ private StringValProvider body;
+ private StringValProvider lang;
+ private TypeProvider type;
+
+
+ public ValueSpecDef(StringValProvider body, StringValProvider lang) {
+ if(body == null) {
+ throw new IllegalArgumentException();
+ }
+ this.body = body;
+ this.lang = lang;
+ }
+
+ public ValueSpecDef(StringValProvider body, StringValProvider lang, TypeProvider typeRestriction) {
+ this(body, lang);
+ this.type = typeRestriction;
+ }
+
+ public boolean isOK() {
+ return body.getStatus().isOK() &&
+ (lang == null || lang.getStatus().isOK()) &&
+ (type == null || type.getStatus().isOK());
+ }
+
+ public TypeProvider getTypeRestriction() {
+ return type;
+ }
+
+ public String createBody(EObject contextInstance) {
+ return body.getValue(contextInstance);
+ }
+
+ public String createLanguage(EObject contextInstance) {
+ if(lang == null) {
+ return Annotations.OCL_KEY;
+ }
+ return lang.getValue(contextInstance);
+ }
+
+ public StringValProvider getBody() {
+ return body;
+ }
+
+ public StringValProvider getLang() {
+ return lang;
+ }
+
+ public String getLabel() {
+ return Messages.def_ValueSpecDefLabel;
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("body: ").append(body); //$NON-NLS-1$
+ buf.append(" lang: ").append(lang); //$NON-NLS-1$
+ return buf.toString();
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/AbstractExpression.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/AbstractExpression.java
new file mode 100644
index 000000000..3d6eed0f3
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/AbstractExpression.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.gmf.internal.validate.DebugOptions;
+import org.eclipse.gmf.internal.validate.GMFValidationPlugin;
+import org.eclipse.gmf.internal.validate.LabelProvider;
+import org.eclipse.gmf.internal.validate.Messages;
+import org.eclipse.gmf.internal.validate.StatusCodes;
+import org.eclipse.gmf.internal.validate.Trace;
+
+/**
+ * This class represents the base for expression. Clients providing new types
+ * of expression should sublass this class.
+ */
+public abstract class AbstractExpression implements IModelExpression {
+ private IStatus status;
+ private String body;
+ private EClassifier contextClassifier;
+ private Map extEnv;
+
+ /**
+ * Constructs expression from its body, with specified context.
+ *
+ * @param body
+ * specifies the evaluation logic in the language recognized by
+ * this expression.
+ * @param context
+ * the class in which context the expression is to be parsed
+ * @param extendedEnv
+ * additional parsing context information, can be
+ * <code>null</code>
+ * @throws IllegalArgumentException
+ * if any of the passed <code>body</code>,
+ * <code>contextClassifier</code> is <code>null</code>
+ */
+ protected AbstractExpression(String body, EClassifier context, IParseEnvironment extendedEnv) {
+ if(body == null || context == null) {
+ throw new IllegalArgumentException("null body or context-class"); //$NON-NLS-1$
+ }
+ this.body = body;
+ this.contextClassifier = context;
+ this.status = Status.OK_STATUS;
+ if(extendedEnv != null) {
+ this.extEnv = new HashMap(5);
+ for (Iterator it = extendedEnv.getVariableNames().iterator(); it.hasNext();) {
+ String nextVar = (String) it.next();
+ extEnv.put(nextVar, extendedEnv.getTypeOf(nextVar));
+ }
+ } else {
+ this.extEnv = Collections.EMPTY_MAP;
+ }
+ }
+
+ protected Map getExtEnvironment() {
+ return extEnv;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#isLooselyTyped()
+ */
+ public boolean isLooselyTyped() {
+ return true;
+ }
+
+ protected void setStatus(IStatus status) {
+ this.status = status;
+ }
+
+ /**
+ * Performs evaluation of this expression in the context.
+ * <p>
+ * This method gets called by {@link #evaluate(Object) } only if this
+ * expression has <code>OK</code> status and the passed context is valid
+ *
+ * @param context
+ * the context instance for evaluation.
+ *
+ * @return result of this expression evalutation. In case this expression
+ * status is not <code>OK</code> status, <code>null</code> is
+ * returned.
+ */
+ protected abstract Object doEvaluate(Object context);
+
+ /**
+ * Performs evaluation of this expression in the extended context.
+ * <p>
+ * This method gets called by {@link #evaluate(Object) } only if this
+ * expression has <code>OK</code> status and the passed context is valid
+ *
+ * @param context
+ * the context instance for evaluation.
+ * @param extendedEnv
+ * the environment with custom variables intialized for
+ * evaluation
+ *
+ * @return result of this expression evalutation. In case this expression
+ * status is not <code>OK</code> status, <code>null</code> is
+ * returned.
+ */
+ protected abstract Object doEvaluate(Object context, IEvaluationEnvironment extendedEnv);
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#getResultType()
+ */
+ public EClassifier getResultType() {
+ return EcorePackage.eINSTANCE.getEJavaObject();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#isConformantTo(org.eclipse.emf.ecore.EClassifier)
+ */
+ public abstract boolean isAssignableTo(EClassifier ecoreType);
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#isConformantTo(org.eclipse.emf.ecore.ETypedElement)
+ */
+ public abstract boolean isAssignableToElement(ETypedElement typedElement);
+
+ public abstract String getLanguage();
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#evaluate(org.eclipse.emf.ecore.EObject)
+ */
+ public final Object evaluate(Object context) {
+ return evaluate(context, null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#evaluate(org.eclipse.emf.ecore.EObject, org.eclipse.gmf.validate.expressions.IEvaluationEnvironment)
+ */
+ public final Object evaluate(Object contextInstance, IEvaluationEnvironment extendedEnv) {
+ if(contextInstance == null || !hasCompatibleContext(contextInstance)) {
+ throw new IllegalArgumentException("Invalid evaluation context:" + contextInstance); //$NON-NLS-1$
+ }
+ if(getStatus().isOK()) {
+ try {
+ if(extendedEnv != null) {
+ return doEvaluate(contextInstance, extendedEnv);
+ }
+ return doEvaluate(contextInstance);
+ } catch (RuntimeException e) {
+ IStatus status = GMFValidationPlugin.createStatus(
+ IStatus.ERROR, StatusCodes.UNEXPECTED_EVALUATION_ERROR,
+ Messages.unexpectedExprEvalError, e);
+ GMFValidationPlugin.log(status);
+ Trace.catching(DebugOptions.EXCEPTIONS_CATCHING, e);
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#getStatus()
+ */
+ public IStatus getStatus() {
+ return status;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#getBody()
+ */
+ public String getBody() {
+ return body;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.validate.expressions.IModelExpression#getContextClass()
+ */
+ public EClassifier getContext() {
+ return contextClassifier;
+ }
+
+ public String toString() {
+ return body + "context:[" + LabelProvider.INSTANCE.getObjectLabel(contextClassifier) + "] "; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private boolean hasCompatibleContext(Object ctxInstance) {
+ if(contextClassifier instanceof EClass) {
+ EClass contextClass = (EClass)contextClassifier;
+ return (ctxInstance instanceof EObject) ?
+ contextClass.isSuperTypeOf(((EObject)ctxInstance).eClass()) : false;
+ }
+
+ return contextClassifier.isInstance(ctxInstance);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/EnvironmentProvider.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/EnvironmentProvider.java
new file mode 100644
index 000000000..9eea7b139
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/EnvironmentProvider.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import java.util.HashMap;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EPackage;
+
+/**
+ * This class provides the client with parsing and evaluation environments.
+ */
+public class EnvironmentProvider {
+
+ // no instances
+ private EnvironmentProvider() {
+ }
+
+ /**
+ * Creates environment for parsing an expression.
+ * @return the empty environment instance
+ */
+ public static IParseEnvironment createParseEnv() {
+ return new EnvImpl();
+ }
+
+ /**
+ * Creates environment for evaluating an expression.
+ * @return the empty evaluation environment instance
+ */
+ public static IEvaluationEnvironment createEvaluationEnv() {
+ return new EvalEnvImpl();
+ }
+
+
+ private static class EnvImpl extends HashMap implements IParseEnvironment {
+ private EPackage.Registry importReg;
+ EnvImpl() {
+ super(5);
+ }
+
+ public void setVariable(String name, EClassifier type) {
+ if(type == null || type.getName() == null) {
+ throw new IllegalArgumentException("Invalid EClassifier passed:" + type); //$NON-NLS-1$
+ }
+ if(name == null) {
+ throw new IllegalArgumentException("null variable name passed"); //$NON-NLS-1$
+ }
+
+ put(name, type);
+ }
+
+ public EClassifier getTypeOf(String name) {
+ return (EClassifier)get(name);
+ }
+
+ public Set getVariableNames() {
+ return keySet();
+ }
+
+ public void clear() {
+ super.clear();
+ importReg = null;
+ }
+
+ public EPackage.Registry getImportRegistry() {
+ return importReg;
+ }
+
+ public void setImportRegistry(EPackage.Registry importReg) {
+ this.importReg = importReg;
+ }
+ }
+
+ private static class EvalEnvImpl extends HashMap implements IEvaluationEnvironment {
+ EvalEnvImpl() {
+ super(5);
+ }
+
+ public void setVariable(String name, Object value) {
+ put(name, value);
+ }
+
+ public Object getValueOf(String name) {
+ return get(name);
+ }
+
+ public Set getVariableNames() {
+ return keySet();
+ }
+
+ public void clear() {
+ super.clear();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/ExpressionProviderRegistry.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/ExpressionProviderRegistry.java
new file mode 100644
index 000000000..e055210fc
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/ExpressionProviderRegistry.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.InvalidRegistryObjectException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.gmf.internal.validate.GMFValidationPlugin;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * This class maintains all contribution to
+ * <code>org.eclipse.gmf.validate.expressions</code> extension point.
+ * <p>
+ * It collects all contributions of all providers at this class initialization
+ * time. It only creates and caches only descriptors of provider implementations.
+ * A provider itself is initialized lazily on demand.
+ */
+public class ExpressionProviderRegistry {
+ private static final ExpressionProviderRegistry INSTANCE = new ExpressionProviderRegistry();
+
+ private Map registry;
+
+ private ExpressionProviderRegistry() {
+ registry = new HashMap();
+ initialiaze();
+ }
+
+ /**
+ * Gets the instance of providers registry.
+ */
+ public static ExpressionProviderRegistry getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Gets the provider for the given language.
+ *
+ * @param language
+ * the identifier of the language
+ * @return the provider supporting expressions in the given language or
+ * <code>null</code> if no such provider is found
+ */
+ public IModelExpressionProvider getProvider(String language) {
+ Descriptor descriptor = getDescriptor(language);
+ if(descriptor != null && descriptor.getStatus().isOK()) {
+ return descriptor.getProvider();
+ }
+ return null;
+ }
+
+ /**
+ * Gets supported expression languages by providers in this registry.
+ * @return set of language identifiers strings, never <code>null</code>
+ */
+ public Set getLanguages() {
+ return registry.keySet();
+ }
+
+ /**
+ * Gets descriptor of the provider supporting the given language.
+ *
+ * @param language
+ * the identifier of the expression language whose provider is to
+ * be retrieved
+ * @return corresponding provider descriptor or <code>null</code> if no
+ * such provider is found.
+ */
+ public Descriptor getDescriptor(String language) {
+ return (Descriptor)registry.get(language);
+ }
+
+
+ private void initialiaze() {
+ IConfigurationElement[] configs = Platform.getExtensionRegistry().getConfigurationElementsFor(
+ Descriptor.GLOBAL_EXTENSION_ID);
+ for (int i = 0; i < configs.length; i++) {
+ IConfigurationElement element = configs[i];
+ Descriptor descriptor = new Descriptor(element);
+ if(descriptor.getStatus().isOK()) {
+ String lang = descriptor.getLanguage();
+ assert lang != null;
+ Descriptor currentDsc = (Descriptor)registry.get(lang);
+ if(currentDsc == null) {
+ registry.put(lang, descriptor);
+ } else {
+ String message = NLS.bind(Messages.providerAlreadyExistsIgnore, new Object[] {
+ currentDsc.getProviderClassName(), lang,
+ descriptor.getProviderClassName()
+ });
+ GMFValidationPlugin.log(GMFValidationPlugin.createStatus(IStatus.ERROR, 0, message, null));
+ }
+ }
+ }
+ registry = Collections.unmodifiableMap(registry);
+ }
+
+ static class Descriptor {
+ static final String EXTENSION_ID = "expressionProviders"; //$NON-NLS-1$
+ static final String GLOBAL_EXTENSION_ID = GMFValidationPlugin.getPluginId() + "." + EXTENSION_ID; //$NON-NLS-1$
+
+ public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+ public static final String ATTR_LANGUAGE = "language"; //$NON-NLS-1$
+ public static final String ATTR_REQUIRES_MODEL_CLASS = "requiresModelClass"; //$NON-NLS-1$
+ public static final String ATTR_NAME = "name"; //$NON-NLS-1$
+ public static final String ATTR_DESCRIPTION = "description"; //$NON-NLS-1$
+ public static final String ATTR_LOOSELY_TYPED = "isLooselyTyped"; //$NON-NLS-1$
+
+ private IConfigurationElement configElement;
+ private String language;
+ private String className;
+ private boolean modelReflection;
+ private boolean isLooselyTyped;
+ private String name;
+ private String description;
+ private IStatus status;
+ private IModelExpressionProvider provider;
+
+ Descriptor(IConfigurationElement config) {
+ this.status = Status.OK_STATUS;
+ try {
+ configure(config);
+ } catch (InvalidRegistryObjectException e) {
+ GMFValidationPlugin.log(IStatus.ERROR, Messages.initDescriptorFailure, e);
+ }
+ }
+
+ public IStatus getStatus() {
+ return status;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public boolean supportsModelReflection() {
+ return modelReflection;
+ }
+
+ public boolean isLooselyTyped() {
+ return isLooselyTyped;
+ }
+
+ public String getProviderClassName() {
+ return className;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ IModelExpressionProvider getProvider() {
+ if(provider == null && getStatus().isOK()) {
+ try {
+ provider = (IModelExpressionProvider)configElement.createExecutableExtension(ATTR_CLASS);
+ } catch(CoreException e) {
+ String message = NLS.bind(Messages.providerCreationFailure, getProviderClassName());
+ GMFValidationPlugin.log(IStatus.ERROR, message, e);
+ }
+ }
+ return provider;
+ }
+
+ private void configure(IConfigurationElement config) {
+ this.configElement = config;
+ language = configElement.getAttribute(ATTR_LANGUAGE);
+ if(language == null || language.trim().length() == 0) {
+ this.status = GMFValidationPlugin.createStatus(IStatus.ERROR, 0,
+ Messages.missingProviderLanguage, null);
+ }
+ className = config.getAttribute(ATTR_CLASS);
+ if(className == null || className.trim().length() == 0) {
+ this.status = GMFValidationPlugin.createStatus(IStatus.ERROR, 0,
+ Messages.missingProviderClass, null);
+ }
+
+ modelReflection = "true".equals(config.getAttribute(ATTR_REQUIRES_MODEL_CLASS)); //$NON-NLS-1$
+ isLooselyTyped = "true".equals(config.getAttribute(ATTR_LOOSELY_TYPED)); //$NON-NLS-1$
+ name = config.getAttribute(ATTR_NAME);
+ description = config.getAttribute(ATTR_DESCRIPTION);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IEvaluationEnvironment.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IEvaluationEnvironment.java
new file mode 100644
index 000000000..3e7637a98
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IEvaluationEnvironment.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import java.util.Set;
+
+/**
+ * The evaluation environment maintains current values of variables
+ * for the evaluation of an expression. Variables are maintained as
+ * key-value pairs with variable name as the key and its value object
+ * as the value part in the pair.
+ */
+public interface IEvaluationEnvironment {
+ /**
+ * Sets variable value in this environment.
+ * If a variable of the given name already exists, the old value
+ * is replaced.
+ *
+ * @param name the name which uniquely identifies the variable
+ * @param value the value to which the given variable is to be initialized.
+ * Can be <code>null</code>
+ */
+ void setVariable(String name, Object value);
+ /**
+ * Gets variable value set in this environment.
+ * @param name the name of the variable to query for value
+ * @return the value of the given variable, or <code>null</code> if no
+ * such variable is set in this environment.
+ * Remark: Use {@link #getVariableNames()} in order to detect if the
+ * variable is present in the environment or has <code>null</code> value.
+ */
+ Object getValueOf(String name);
+
+ /**
+ * Gets the names of all variables currently set in this environments.
+ * @return set of String objects representing the names, never <code>null</code>
+ */
+ Set/*String*/ getVariableNames();
+
+ /**
+ * Removes all variables set in this environment
+ */
+ void clear();
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpression.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpression.java
new file mode 100644
index 000000000..69447df89
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpression.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.ETypedElement;
+
+/**
+ * This interface replesents a general expression resulting in a value when it
+ * gets evaluated.
+ * <p>
+ * The evaluation logic is expressed by the body defined in the language
+ * recognized by this expression. The expression is parased in the context of
+ * specified EClass. The way how the context instance is references is
+ * expression provider specific and should be described by the provider.
+ */
+public interface IModelExpression {
+
+ /**
+ * Gets the body representing the evaluation logic of this expression.
+ *
+ * @return the body text, never <code>null</code>
+ */
+ public String getBody();
+
+ /**
+ * Gets the context class which was used for parsing of this expression.
+ *
+ * @return the context class, never <code>null</code>
+ */
+ public EClassifier getContext();
+
+ /**
+ * Gets the status of this expression.
+ *
+ * @return The status with severity of <code>IStatus.OK</code> if this
+ * expression has been succesfully parsed and is ready for
+ * evaluation. Other severity levels indicate problems and this
+ * expression is not evaluated.
+ */
+ public IStatus getStatus();
+
+ /**
+ * Evaluates this expression in the given context.
+ *
+ * @param context
+ * The contextual instance for evaluation. It must be the same or
+ * sub-class of the context class used for parsing of this
+ * expression
+ * @result the object resulting from evaluation
+ * @throws IllegalArgumentException
+ * if the context object is invalid for this expression
+ * @throws IllegalArgumentException
+ * if either the context object or the extended environment is
+ * invalid for this expression
+ * @see #getContext()
+ * @see #evaluate(Object, IEvaluationEnvironment)
+ */
+ public Object evaluate(Object context);
+
+ /**
+ * Evaluates this expression in extended context.
+ *
+ * @param context
+ * The contextual instance for evaluation. It must be the same or
+ * sub-class of the context class used for parsing of this
+ * expression
+ * @param extendedEnv
+ * environment with custom variables
+ * @result the object resulting from evaluation or <code>null</code> in
+ * case this expression is not in <code>OK</code> status.
+ * @throws IllegalArgumentException
+ * if either the context object or the extended environment is
+ * invalid for this expression
+ * @see #evaluate(Object)
+ */
+ public Object evaluate(Object context, IEvaluationEnvironment extendedEnv);
+
+ /**
+ * Gets the type of the object which would be the result of this expression
+ * evaluation
+ *
+ * @return the type classifier
+ */
+ public EClassifier getResultType();
+
+ /**
+ * Indicates whether this expression is loosely typed. Loosely typed means
+ * the parsed expression result type <code>java.lang.Object</code>. More
+ * concrete types can only be detected from the evaluation result.
+ *
+ * @return <code>true</code> in case is loosely typed; otherwise
+ * <code>false</code>
+ */
+ public boolean isLooselyTyped();
+
+ /**
+ * Checks whether the given ecore type is compatible for the asssignment
+ * to the given type.
+ * @param ecoreType ecore type
+ */
+ public boolean isAssignableTo(EClassifier ecoreType);
+
+ /**
+ * Checks whether the given ecore type is compatible for the asssignment
+ * to the given typed element.<p>
+ * This type check takes into account multiplicities.
+ *
+ * @param ecoreType ecore type
+ * @return <code>true</code> if any result of this expression evaluation can
+ * be assigned to feature represented by the given element type.
+ */
+ public boolean isAssignableToElement(ETypedElement typedElement);
+
+ /**
+ * Gets the identifier of the language in which this expression is defined.
+ *
+ * @return string representing the language identifier.
+ *
+ * @see ExpressionProviderRegistry#getProvider(String)
+ */
+ public String getLanguage();
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpressionProvider.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpressionProvider.java
new file mode 100644
index 000000000..3e07fbd06
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IModelExpressionProvider.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import org.eclipse.emf.ecore.EClassifier;
+
+/**
+ * This interface represents implements language specific expression provider.
+ * The implementations are registered through
+ * <code>org.eclipse.gmf.validate.expressions</code> extension point.
+ *
+ * @see ExpressionProviderRegistry
+ */
+public interface IModelExpressionProvider {
+
+ /**
+ * Creates expression from body in the specified context.
+ * <p>
+ * The context is represented by EClass referenceable from the expression
+ * body. Its instance passed at evalution time provides the evalution
+ * context.
+ *
+ * @param body
+ * definition of the evaluation logic in the language of this
+ * expression provider
+ * @param context
+ * the context classifier for parsing
+ * @return parsed model expression instance with the status indicating
+ * success or possible failure.
+ */
+ IModelExpression createExpression(String body, EClassifier context);
+
+ /**
+ * Creates expression from body in the specified context class and extended environment.
+ * <p>
+ * In addition to the context EClass, extended environment with custom variables
+ * is passed. The variable are referencable in the
+ *
+ * @param body
+ * definition of the evaluation logic in the language of this
+ * expression provider
+ * @param context
+ * the context classifier for parsing
+ * @return parsed model expression instance with the status indicating
+ * success or possible failure.
+ *
+ * @see EnvironmentProvider#createParseEnv()
+ */
+ IModelExpression createExpression(String body, EClassifier context, IParseEnvironment extEnv);
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IParseEnvironment.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IParseEnvironment.java
new file mode 100644
index 000000000..1b8c536fe
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/IParseEnvironment.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EPackage;
+
+/**
+ * The parse environment maintains declarations of variables
+ * reuired for successful parsing of an expression. Variables are maintained as
+ * key-value pairs with variable name as the key and type as the value.
+ */
+public interface IParseEnvironment {
+ /**
+ * Gets the names of all variables currently set in this environments.
+ * @return set of String objects representing the names, never <code>null</code>
+ */
+ Set/*String*/ getVariableNames();
+
+ /**
+ * Declare variable in this environment.
+ * If a variable of the given name already exists, the old entry is
+ * is replaced.
+ *
+ * @param name <code>non-null</code> name which uniquely identifies the variable
+ * @param type <code>non-null</code> type of the declared variable.</p>
+ * For non-model types (plain java classes) the client can pass {@link EDataType}
+ * classifiers encapsulating the instance class.
+ * @throws IllegalArgumentException if <code>name</code> is not a valid variable name or
+ * <code>type</code> is not a valid type classifier.
+ */
+ void setVariable(String name, EClassifier type);
+
+ /**
+ * Gets the type of the given variable.
+ *
+ * @param name the name of the variable declared in this environment
+ * @return
+ */
+ EClassifier getTypeOf(String name);
+
+ /**
+ * Gets package registry to be used for external model import.
+ * @return the registry or <code>null</code> of no registry is set in this environment.
+ * @see #setImportRegistry(org.eclipse.emf.ecore.EPackage.Registry)
+ */
+ EPackage.Registry getImportRegistry();
+
+ /**
+ * Sets optional package registry with pre-initialized model packages to be
+ * available in this environment.
+ */
+ void setImportRegistry(EPackage.Registry registry);
+
+ /**
+ * Removes all variables set in this environment and sets the import registry to <code>null</code>
+ */
+ void clear();
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/Messages.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/Messages.java
new file mode 100644
index 000000000..852ad244c
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/Messages.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.expressions;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.gmf.internal.validate.expressions.messages"; //$NON-NLS-1$
+
+ private Messages() {
+ }
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ public static String providerAlreadyExistsIgnore;
+
+ public static String missingProviderLanguage;
+
+ public static String missingProviderClass;
+
+ public static String providerCreationFailure;
+
+ public static String initDescriptorFailure;
+}
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/messages.properties b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/messages.properties
new file mode 100644
index 000000000..cae53f2d3
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/expressions/messages.properties
@@ -0,0 +1,5 @@
+providerAlreadyExistsIgnore=Expression provider ''{0}'' already registered for language ''{1}''. Ignoring ''{2}'' provider
+missingProviderLanguage=Missing expression provider language
+missingProviderClass=Missing expression provider class
+providerCreationFailure=Expression provider creation failed, class= {0}
+initDescriptorFailure=Expression provider descriptor intialization failed.
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/messages.properties b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/messages.properties
new file mode 100644
index 000000000..0d322016f
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/messages.properties
@@ -0,0 +1,26 @@
+validation_ConstraintInInvalidContext=Constraint placed in invalid context ''{0}''
+validation_EmptyExpressionBody=Empty expression body.
+validation_ConstraintViolation=Constraint violation ''{0}'' in ''{1}''
+
+def_ValueSpecDefLabel=ValueSpec Definition
+def_NoTypeAvailable=The type specification of expression produces no type
+def_ConstraintDefLabel=Constraint Definition
+def_InvalidContextDefinition=Invalid context definition.
+def_NoEReferenceFoundByName=No EReference with name '{0}' found in '{1}'
+def_NoEReferenceInCtxBinding=No reference specified for context binding
+def_MissingBodyAnnotation=Missing expression 'body' annotation in ''{0}''
+def_NoContextAvailable=No evaluation context available for value-spec or constraint ''{0}''
+
+invalidExpressionBody=Invalid expression body ''{0}''. Cause: {1}
+invalidConstraintExprType=Invalid expression type ''{0}'' in constraint ''{1}''. Boolean is required.
+incompatibleTypes=Incompatible types. Required ''{0}'', found ''{1}''
+unexpectedExprEvalError=Unexpected error during expression evalutation. See log for details.
+unexpectedExprParseError=Unexpected error during expression parsing. See log for details.
+unexpectedValidationError=Validation failed unexpectedly for {0}. See log for details.
+invalidModelImportUri=Invalid URI in model import. URI:{0}
+modelImportResourceLoadingError=Imported model resource ''{0}'' loading error. Cause:{1}
+modelImportUriFallbackResolution=Model import from ''{0}'' failed, using fall-back resolution from ''{1}''
+
+noExpressionProviderAvailable=No expression provider available for language={0}
+def_NoCtxInProviderForCtxBinding=Class ''{0}'' provides no context definiton for context binding reference ''{1}''
+def_MissingCtxDefInReferencedCtxProviders=Referenced context provider entities define no context
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionAdapter.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionAdapter.java
new file mode 100644
index 000000000..8e9f05dc9
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionAdapter.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.ocl;
+
+import java.text.MessageFormat;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ocl.expressions.ExpressionsFactory;
+import org.eclipse.emf.ocl.expressions.OCLExpression;
+import org.eclipse.emf.ocl.expressions.Variable;
+import org.eclipse.emf.ocl.expressions.util.ExpressionsUtil;
+import org.eclipse.emf.ocl.parser.EcoreEnvironment;
+import org.eclipse.emf.ocl.parser.EcoreEnvironmentFactory;
+import org.eclipse.emf.ocl.parser.Environment;
+import org.eclipse.emf.ocl.parser.EnvironmentFactory;
+import org.eclipse.emf.ocl.parser.ParserException;
+import org.eclipse.emf.ocl.query.Query;
+import org.eclipse.emf.ocl.query.QueryFactory;
+import org.eclipse.emf.ocl.types.util.Types;
+import org.eclipse.gmf.internal.validate.DebugOptions;
+import org.eclipse.gmf.internal.validate.DefUtils;
+import org.eclipse.gmf.internal.validate.EDataTypeConversion;
+import org.eclipse.gmf.internal.validate.GMFValidationPlugin;
+import org.eclipse.gmf.internal.validate.Messages;
+import org.eclipse.gmf.internal.validate.StatusCodes;
+import org.eclipse.gmf.internal.validate.Trace;
+import org.eclipse.gmf.internal.validate.expressions.AbstractExpression;
+import org.eclipse.gmf.internal.validate.expressions.IEvaluationEnvironment;
+import org.eclipse.gmf.internal.validate.expressions.IParseEnvironment;
+
+public class OCLExpressionAdapter extends AbstractExpression {
+ /**
+ * The OCL language identifier.
+ */
+ public static final String OCL = "ocl"; //$NON-NLS-1$
+
+ private Query query;
+
+ public OCLExpressionAdapter(String body, EClassifier context, IParseEnvironment extEnv) {
+ super(body, context, extEnv);
+
+ try {
+ if(extEnv == null) {
+ this.query = QueryFactory.eINSTANCE.createQuery(body, context);
+ } else {
+ EnvironmentFactory factory = extEnv.getImportRegistry() == null ?
+ EnvironmentFactory.ECORE_INSTANCE : new EcoreEnvironmentFactory(extEnv.getImportRegistry());
+ Environment env = factory.createClassifierContext(context);
+
+ for (Iterator it = extEnv.getVariableNames().iterator(); it.hasNext();) {
+ String varName = (String)it.next();
+ EClassifier type = extEnv.getTypeOf(varName);
+
+ Variable varDecl = ExpressionsFactory.eINSTANCE.createVariable();
+ varDecl.setName(varName);
+ varDecl.setType(type);
+ env.addElement(varDecl.getName(), varDecl, false);
+ }
+ OCLExpression oclExpression = ExpressionsUtil.createQuery(env, body, true);
+ this.query = QueryFactory.eINSTANCE.createQuery(oclExpression);
+ }
+ } catch (ParserException e) {
+ setInvalidOclExprStatus(e);
+ } catch (IllegalArgumentException e) {
+ setInvalidOclExprStatus(e);
+ } catch(RuntimeException e) {
+ setStatus(GMFValidationPlugin.createStatus(
+ IStatus.ERROR, StatusCodes.UNEXPECTED_PARSE_ERROR,
+ Messages.unexpectedExprParseError, e));
+ GMFValidationPlugin.log(getStatus());
+ Trace.catching(DebugOptions.EXCEPTIONS_CATCHING, e);
+ }
+ }
+
+ public String getLanguage() {
+ return OCL;
+ }
+
+ public boolean isLooselyTyped() {
+ return false;
+ }
+
+ public boolean isAssignableTo(EClassifier ecoreType) {
+ EClassifier oclType = EcoreEnvironment.getOCLType(ecoreType);
+ if(oclType == null) {
+ return false;
+ }
+ return isOclConformantTo(oclType);
+ }
+
+ public boolean isAssignableToElement(ETypedElement typedElement) {
+ EClassifier oclType = EcoreEnvironment.getOCLType(typedElement);
+ if(oclType == null) {
+ return false;
+ }
+ return isOclConformantTo(oclType);
+ }
+
+ public EClassifier getResultType() {
+ return (query != null) ? query.getExpression().getType() : super.getResultType();
+ }
+
+ protected Object doEvaluate(Object context) {
+ return filterOCLInvalid((query != null) ? query.evaluate(context) : null);
+ }
+
+ protected Object doEvaluate(Object context, IEvaluationEnvironment extEnvironment) {
+ // TODO - add custom variables !!!
+ return doEvaluate(context);
+ }
+
+ private static Object filterOCLInvalid(Object object) {
+ return object == Types.OCL_INVALID ? null : object;
+ }
+
+ boolean isOclConformantTo(EClassifier oclType) {
+ EClassifier thisOclType = getResultType();
+ // Note: in OCL, Double extends Integer
+ if ((oclType.getInstanceClass() == Integer.class ||
+ oclType.getInstanceClass() == int.class) &&
+ (thisOclType.getInstanceClass() == Double.class ||
+ thisOclType.getInstanceClass() == double.class)) {
+ return true;
+ }
+
+ if(thisOclType instanceof EDataType && oclType instanceof EDataType) {
+ if(EDataTypeConversion.isConvertable((EDataType)oclType, (EDataType)thisOclType)) {
+ return true;
+ }
+ }
+ return DefUtils.checkTypeAssignmentCompatibility(oclType, thisOclType);
+ }
+
+ void setInvalidOclExprStatus(Exception exception) {
+ String message = MessageFormat.format(
+ Messages.invalidExpressionBody,
+ new Object[] { getBody(), exception.getLocalizedMessage() });
+
+ setStatus(GMFValidationPlugin.createStatus(
+ IStatus.ERROR, StatusCodes.INVALID_VALUE_EXPRESSION, message, exception));
+ Trace.catching(DebugOptions.EXCEPTIONS_CATCHING, exception);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionProvider.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionProvider.java
new file mode 100644
index 000000000..2e33af76a
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/internal/validate/ocl/OCLExpressionProvider.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.internal.validate.ocl;
+
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpression;
+import org.eclipse.gmf.internal.validate.expressions.IModelExpressionProvider;
+import org.eclipse.gmf.internal.validate.expressions.IParseEnvironment;
+
+public class OCLExpressionProvider implements IModelExpressionProvider {
+
+ public OCLExpressionProvider() {
+ }
+
+ public IModelExpression createExpression(String body, EClassifier context) {
+ return createExpression(body, context, null);
+ }
+
+ public IModelExpression createExpression(String body, EClassifier context, IParseEnvironment extEnv) {
+ return new OCLExpressionAdapter(body, context, extEnv);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/GMFValidator.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/GMFValidator.java
new file mode 100644
index 000000000..a6b170198
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/GMFValidator.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.validate;
+
+import java.util.HashMap;
+
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.util.Diagnostician;
+import org.eclipse.emf.ecore.util.EObjectValidator;
+import org.eclipse.gmf.internal.validate.AnnotatedDefinitionValidator;
+import org.eclipse.gmf.internal.validate.AnnotatedOclValidator;
+import org.eclipse.gmf.internal.validate.ExternModelImport;
+import org.eclipse.gmf.internal.validate.ValidatorChain;
+
+/**
+ * Validator of GMF constraint annotations.
+ */
+public class GMFValidator extends ValidatorChain {
+
+ private static EValidator[] GMF_VALIDATORS = new EValidator[] {
+ ExternModelImport.getImportValidator(),
+ new AnnotatedOclValidator(),
+ new AnnotatedDefinitionValidator()
+ };
+
+ private static final EValidator NO_ECORE_INSTANCE = new ValidatorChain(GMF_VALIDATORS);
+
+ private static EValidator[] ALL_VALIDATORS = new EValidator[] {
+ EObjectValidator.INSTANCE,
+ NO_ECORE_INSTANCE };
+
+ /**
+ * Ecore compliant validator instance.
+ */
+ public static final EValidator INSTANCE = new ValidatorChain(ALL_VALIDATORS);
+
+ private GMFValidator() {
+ super(GMF_VALIDATORS);
+ }
+
+ /**
+ * Validates the given object using its registered EValidator and
+ * additionally performs validation of <code>OCL constraints annotations</code>,
+ * value-spec and constraint definitions.
+ * </p>
+ *
+ * @param eObject the subject for validation
+ * @return resulting root diagnostic object containing the children diagnostic elements representing
+ * the concrete constraint validation results
+ */
+ public static Diagnostic validate(EObject eObject) {
+ Diagnostician diagnostician = new Diagnostician(new DelegateRegistry());
+ return diagnostician.validate(eObject);
+ }
+
+ /**
+ * Validates the given object using its registered EValidator and
+ * additionally performs validation of <code>OCL constraints annotations</code>,
+ * value-spec and constraint definitions.
+ * </p>
+ *
+ * @param eObject the subject for validation
+ * @param options validation options
+ * @return resulting root diagnostic object containing the children diagnostic elements representing
+ * the concrete constraint validation results
+ */
+ public static Diagnostic validate(EObject eObject, ValidationOptions options) {
+ Diagnostician diagnostician = new Diagnostician(new DelegateRegistry(options));
+ return diagnostician.validate(eObject);
+ }
+
+ private static class DelegateRegistry extends HashMap implements Registry {
+ private ValidationOptions options;
+ private EValidator gmfValidator;
+ private EValidator noEcoreValidator;
+
+ DelegateRegistry() {
+ this(null);
+ gmfValidator = GMFValidator.INSTANCE;
+ noEcoreValidator = GMFValidator.NO_ECORE_INSTANCE;
+ }
+
+ DelegateRegistry(ValidationOptions options) {
+ this.options = options;
+ }
+
+ private EValidator getGmfValidator() {
+ if(gmfValidator == null) {
+ gmfValidator = new ValidatorChain(ALL_VALIDATORS, options);
+ }
+ return gmfValidator;
+ }
+
+ private EValidator getNoEcoreValidator() {
+ if(noEcoreValidator == null) {
+ noEcoreValidator = new ValidatorChain(GMF_VALIDATORS, options);
+ }
+ return noEcoreValidator;
+ }
+
+ public EValidator getEValidator(EPackage ePackage) {
+ if(containsKey(ePackage)) {
+ return (EValidator)super.get(ePackage);
+ }
+ EValidator delegateValidator = Registry.INSTANCE.getEValidator(ePackage);
+ if(delegateValidator == null || delegateValidator.getClass().equals(EObjectValidator.class)) {
+ return getGmfValidator();
+ }
+ return createDelegator(ePackage, delegateValidator);
+ }
+
+ private EValidator createDelegator(Object key, EValidator delegate) {
+ // extend custom validator retrieved from the registry only with GMF validators
+ EValidator delegatingValidator = new ValidatorChain(new EValidator[] { delegate, getNoEcoreValidator() });
+ put(key, delegatingValidator);
+ return delegatingValidator;
+ }
+
+ public Object get(Object key) {
+ Object provider = super.get(key);
+ if(provider != null) {
+ return provider;
+ }
+ provider = Registry.INSTANCE.get(key);
+ if(provider != null && provider instanceof EValidator) {
+ if(provider.getClass().equals(EObjectValidator.class)) {
+ return getGmfValidator();
+ }
+ provider = createDelegator(key, (EValidator)provider);
+ }
+ return provider;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/ValidationOptions.java b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/ValidationOptions.java
new file mode 100644
index 000000000..73cfe626c
--- /dev/null
+++ b/plugins/org.eclipse.gmf.validate/src/org/eclipse/gmf/validate/ValidationOptions.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2005 Borland Software Corporation
+ *
+ * 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:
+ * Radek Dvorak (Borland) - initial API and implementation
+ */
+package org.eclipse.gmf.validate;
+
+/**
+ * Holds GMF specific options to be used in validation
+ */
+public class ValidationOptions {
+ private boolean reportSuccess;
+ private boolean useGmfLabelSubtitution;
+
+ public static ValidationOptions getDefault() {
+ ValidationOptions options = new ValidationOptions();
+ options.setReportSuccess(false);
+ options.setReportSuccess(false);
+ return options;
+ }
+
+ public boolean isReportSuccess() {
+ return reportSuccess;
+ }
+
+ public void setReportSuccess(boolean reportSuccess) {
+ this.reportSuccess = reportSuccess;
+ }
+
+ public boolean isUseGmfLabelSubtitution() {
+ return useGmfLabelSubtitution;
+ }
+
+ public void setUseGmfLabelSubtitution(boolean useGmfLabelSubtituion) {
+ this.useGmfLabelSubtitution = useGmfLabelSubtituion;
+ }
+} \ No newline at end of file

Back to the top