/******************************************************************************* * Copyright (c) 2005, 2010 IBM Corporation, Borland Software Corp., 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: * IBM - Initial API and implementation * E.D.Willink - Refactoring to support extensibility and flexible error handling * Borland - Bug 265066 * Adolfo Sanchez-Barbudo Herrera (Open Canarias) - Bug 333032 *******************************************************************************/ package org.eclipse.ocl; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.ocl.expressions.Variable; import org.eclipse.ocl.helper.OCLSyntaxHelper; import org.eclipse.ocl.internal.evaluation.TracingEvaluationVisitor; import org.eclipse.ocl.parser.AbstractOCLParser; import org.eclipse.ocl.parser.OCLAnalyzer; import org.eclipse.ocl.parser.OCLFactoryWithHistory; import org.eclipse.ocl.parser.ValidationVisitor; import org.eclipse.ocl.util.Adaptable; import org.eclipse.ocl.util.TypeUtil; import org.eclipse.ocl.utilities.OCLFactory; import org.eclipse.ocl.utilities.UMLReflection; import org.eclipse.ocl.utilities.Visitor; /** * Partial implementation of the {@link EnvironmentFactory} interface, useful * for subclassing to define the OCL binding for a metamodel. This abstract * class takes care of some of the more common (and mundane) chores, such as: * <ul> * <li>defining the "self" variable in the classifier context</li> * <li>creating variables for operation parameters in an operation context</li> * </ul> * <p> * The subclass's responsibility (in addition to implementing any other * interface methods not implemented here) is to define how to: * </p> * <ul> * <li>{@linkplain #getClassifier obtain} the classifier in the * user model of an input element (which may already be a classifier * or an may be an M0 instance)</li> * <li>{@linkplain #lookupPackage lookup} a package in the model associated * with this environment factory</li> * </ul> * <p> * This class is intended to be extended by clients, for the purpose of * implementing metamodel-specific environment factories. * </p> * <p> * See the {@link EnvironmentFactory} class for a description of the * generic type parameters of this class. * </p> * * @author Christian W. Damus (cdamus) */ public abstract class AbstractEnvironmentFactory<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> implements EnvironmentFactory<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>, Adaptable { private boolean traceEvaluation; /** * Initializes me. */ protected AbstractEnvironmentFactory() { super(); } /** * Creates an environment for the specified package context. * * @param parent the parent environment of the environment to be created * @param context the package context (must not be <code>null</code>) * @return the new nested environment */ protected Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createPackageContext( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> parent, PK context) { Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> result = createEnvironment(parent); if (result instanceof AbstractEnvironment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>) { ((AbstractEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>) result) .setContextPackage(context); } return result; } // implements the interface method public Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createPackageContext( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> parent, List<String> pathname) { PK contextPackage = lookupPackage(pathname); return (contextPackage == null)? null : createPackageContext(parent, contextPackage); } /** * Looks up the package identified by the specified qualified name by * whatever means is appropriate to the particular environment implementation. * * @param pathname the qualified name of the package to find * @return the matching package, or <code>null</code> if none is found */ protected abstract PK lookupPackage(List<String> pathname); // implements the interface method public Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createClassifierContext( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> parent, C context) { Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> result = createEnvironment(parent); // in case it corresponds to an OCL primitive type UMLReflection<PK, C, O, P, EL, PM, S, COA, SSA, CT> uml = parent.getUMLReflection(); context = uml.asOCLType(context); Variable<C, PM> self = parent.getOCLFactory().createVariable(); uml.setName(self, Environment.SELF_VARIABLE_NAME); uml.setType(self, context); result.addElement(self.getName(), self, true); result.setSelfVariable(self); return result; } // implements the interface method public Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createInstanceContext( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> parent, Object context) { return createClassifierContext(parent, getClassifier(context)); } // implements the interface method public Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createOperationContext( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> parent, O operation) { Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> result = createEnvironment(parent); if (result instanceof AbstractEnvironment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>) { ((AbstractEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>) result) .setContextOperation(operation); } UMLReflection<PK, C, O, P, EL, PM, S, COA, SSA, CT> uml = parent.getUMLReflection(); OCLFactory oclFactory = parent.getOCLFactory(); for (PM next : parent.getUMLReflection().getParameters(operation)) { // ensure that we use the OCL primitive types wherever possible Variable<C, PM> var = oclFactory.createVariable(); uml.setName(var, uml.getName(next)); uml.setType(var, TypeUtil.resolveType(result, uml.getOCLType(next))); var.setRepresentedParameter(next); result.addElement(var.getName(), var, true); } return result; } // implements the interface method public Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createAttributeContext( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> parent, P property) { Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> result = createEnvironment(parent); if (result instanceof AbstractEnvironment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>) { ((AbstractEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>) result) .setContextProperty(property); } return result; } // implements the interface method public EvaluationVisitor<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createEvaluationVisitor( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> env, EvaluationEnvironment<C, O, P, CLS, E> evalEnv, Map<? extends CLS, ? extends Set<? extends E>> extentMap) { EvaluationVisitor<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> result = new EvaluationVisitorImpl<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>( env, evalEnv, extentMap); if (isEvaluationTracingEnabled()) { // decorate the evaluation visitor with tracing support result = new TracingEvaluationVisitor<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>( result); } return result; } /** * @since 3.1 */ public OCLAnalyzer<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createOCLAnalyzer( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> env, String input) { return new OCLAnalyzer<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>(env, input); } /** * @since 3.1 */ public OCLAnalyzer<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> createOCLAnalyzer( AbstractOCLParser parser) { return new OCLAnalyzer<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>(parser); } /** * @since 3.1 */ public OCLFactoryWithHistory createOCLFactoryWithHistory( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> env) { return new OCLFactoryWithHistory(env.getOCLFactory()); } /** * @since 3.1 */ public OCLSyntaxHelper createOCLSyntaxHelper( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> env) { return new org.eclipse.ocl.internal.helper.OCLSyntaxHelper<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>(env); } /** * @since 3.1 */ public Visitor<Boolean, C, O, P, EL, PM, S, COA, SSA, CT> createValidationVisitor( Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> env) { return new ValidationVisitor<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>(env); } /** * Obtains client metamodel's classifier for the specified * <code>context</code> object, which may be an instance of a classifier * in the user model or may actually be a classifier in the user model. * * @param context a context object or classifier * @return the user model's classifier for this context object, or the * context itself if it is a classifier */ protected abstract C getClassifier(Object context); /** * Queries whether tracing of evaluation is enabled. Tracing * logs the progress of evaluation to the console, which may * be of use in diagnosing problems. * <p> * In an Eclipse environment, tracing is also enabled by turning on the * <tt>org.eclipse.ocl/debug/evaluation</tt> debug option. * </p> * * @return whether evaluation tracing is enabled * * @see #setEvaluationTracingEnabled(boolean) */ protected boolean isEvaluationTracingEnabled() { return traceEvaluation; } /** * Sets whether tracing of evaluation is enabled. Tracing logs * the progress of parsing to the console, which may be of use in diagnosing * problems. * <p> * In an Eclipse environment, tracing is also enabled by turning on the * <tt>org.eclipse.ocl/debug/evaluation</tt> debug option. * </p> * * param b whether evaluation tracing is enabled * * @see #isEvaluationTracingEnabled() */ protected void setEvaluationTracingEnabled(boolean b) { traceEvaluation = b; } /** * The abstract environment factory implementation is adaptable. The * default implementation adapts to and interface actually implemented by * the receiver. * <p> * Subclasses may override or extend this implementation. * </p> * * @since 1.2 */ @SuppressWarnings("unchecked") public <T> T getAdapter(Class<T> adapterType) { T result; if (adapterType.isAssignableFrom(getClass())) { result = (T) this; } else { result = null; } return result; } }