blob: 4ec48dfef48a728c6cacade8376dcb543c5ee4ff [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation
* E.D.Willink - Bug 360072
*******************************************************************************/
package org.eclipse.ocl.ecore.delegate;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EOperation.Internal.InvocationDelegate;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.common.OCLCommon;
import org.eclipse.ocl.common.delegate.DelegateResourceSetAdapter;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.ExpressionInOCL;
import org.eclipse.ocl.ecore.OCL;
import org.eclipse.ocl.ecore.OCLExpression;
/**
* @since 3.0
*/
public class InvocationBehavior extends AbstractDelegatedBehavior<EOperation, InvocationDelegate.Factory.Registry, InvocationDelegate.Factory>
{
public static final InvocationBehavior INSTANCE = new InvocationBehavior();
public static final String BODY_CONSTRAINT_KEY = "body"; //$NON-NLS-1$
public static final String NAME = "invocationDelegates"; //$NON-NLS-1$
public boolean appliesTo(EOperation operation) {
String annotation = OCLCommon.getDelegateAnnotation(operation, BODY_CONSTRAINT_KEY);
return annotation != null;
}
/**
* Creates an {@link org.eclipse.ocl.ecore.delegate.AbstractDelegatedBehavior.ExpressionCacheAdapter ExpressionCacheAdapter} for expression <code>e</code> and adds
* it to <code>operation</code>'s adapter list so that {@link #getCachedOCLExpression(EOperation)}
* will return <code>e</code> when called for <code>operation</code>. To achieve this, any other
* {@link org.eclipse.ocl.ecore.delegate.AbstractDelegatedBehavior.ExpressionCacheAdapter ExpressionCacheAdapter} in <code>operation</code>'s adapter list is removed.
*
* @param e if <code>null</code>, any existing cache entry is removed and no new entry
* is created. {@link #getCachedOCLExpression(EOperation)} will then return <code>null</code>.
*
* @since 3.1
*/
public void cacheOCLExpression(EOperation operation, OCLExpression e) {
ExpressionCacheAdapter.cacheOCLExpression(operation, e);
}
/**
* Looks for an {@link org.eclipse.ocl.ecore.delegate.AbstractDelegatedBehavior.ExpressionCacheAdapter ExpressionCacheAdapter} attached to <code>operation</code>.
* If such an adapter is found, its cached expression is returned. The cached expression
* may be a reserved expression indicating that no OCL expression exists and that an
* unsuccessful attempt to obtain one has been made before.
* {@link #isNoOCLDefinition(OCLExpression)} should be used to check for the reserved expression.
* null is returned if no cached expression is available.
*
* @since 3.1
*/
public OCLExpression getCachedOCLExpression(EOperation operation) {
return ExpressionCacheAdapter.getCachedOCLExpression(operation);
}
public InvocationDelegate.Factory getDefaultFactory() {
return InvocationDelegate.Factory.Registry.INSTANCE.getFactory(getName());
}
public InvocationDelegate.Factory.Registry getDefaultRegistry() {
return InvocationDelegate.Factory.Registry.INSTANCE;
}
public EPackage getEPackage(EOperation eOperation) {
return eOperation.getEContainingClass().getEPackage();
}
public InvocationDelegate.Factory getFactory(DelegateDomain delegateDomain, EOperation eOperation) {
InvocationDelegate.Factory.Registry registry = DelegateResourceSetAdapter.getRegistry(
eOperation, getRegistryClass(), getDefaultRegistry());
return registry.getFactory(delegateDomain.getURI());
}
public Class<InvocationDelegate.Factory> getFactoryClass() {
return InvocationDelegate.Factory.class;
}
public String getName() {
return NAME;
}
/**
* Return the operation body associated with operation, if necessary using
* <code>ocl</code> to create the relevant parsing environment for a textual
* definition.
*/
public OCLExpression getOperationBody(OCL ocl, EOperation operation) {
OCLExpression result = ExpressionCacheAdapter.getCachedOCLExpression(operation);
if (result != null) {
return result != NO_OCL_DEFINITION ? result : null;
}
String expr = OCLCommon.getDelegateAnnotation(operation, BODY_CONSTRAINT_KEY);
if (expr == null) {
ExpressionCacheAdapter.cacheOCLExpression(operation, NO_OCL_DEFINITION);
return null;
}
EClass context = operation.getEContainingClass();
OCL.Helper helper = ocl.createOCLHelper();
helper.setOperationContext(context, operation);
Constraint constraint;
try {
constraint = helper.createBodyCondition(expr);
} catch (ParserException e) {
throw new org.eclipse.ocl.ecore.delegate.OCLDelegateException(e.getLocalizedMessage(), e);
}
if (constraint == null) {
return null;
}
ExpressionInOCL specification = (ExpressionInOCL) constraint.getSpecification();
if (specification == null) {
return null;
}
OCLExpression body = (OCLExpression) specification.getBodyExpression();
ExpressionCacheAdapter.cacheOCLExpression(operation, body);
return body;
}
public Class<InvocationDelegate.Factory.Registry> getRegistryClass() {
return InvocationDelegate.Factory.Registry.class;
}
/**
* Tells if there is a textual expression for the <code>operation</code> in an
* annotation that can be compiled by {@link #getOperationBody(OCL, EOperation)}. Probing
* this saves callers the more expensive construction of an {@link OCL} object.
* @since 3.1
*/
public boolean hasCompileableOperationBody(EOperation operation) {
return OCLCommon.getDelegateAnnotation(operation, BODY_CONSTRAINT_KEY) != null;
}
}