blob: 16d4c8fd7def72345c2d6defd4b9c94b1749a352 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2012 E.D.Willink 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:
* E.D.Willink - Initial API and implementation
* E.D.Willink - Bug 360072
*******************************************************************************/
package org.eclipse.ocl.ecore.delegate;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EStructuralFeature.Internal.SettingDelegate;
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 SettingBehavior extends AbstractDelegatedBehavior<EStructuralFeature, SettingDelegate.Factory.Registry, SettingDelegate.Factory>
{
public static final SettingBehavior INSTANCE = new SettingBehavior();
public static final String DERIVATION_CONSTRAINT_KEY = "derivation"; //$NON-NLS-1$
public static final String INITIAL_CONSTRAINT_KEY = "initial"; //$NON-NLS-1$
public static final String NAME = "settingDelegates"; //$NON-NLS-1$
/**
* Creates an {@link org.eclipse.ocl.ecore.delegate.AbstractDelegatedBehavior.ExpressionCacheAdapter ExpressionCacheAdapter} for expression <code>e</code> and adds
* it to <code>property</code>'s adapter list so that {@link #getCachedOCLExpression(EStructuralFeature)}
* will return <code>e</code> when called for <code>property</code>. To achieve this, any other
* {@link org.eclipse.ocl.ecore.delegate.AbstractDelegatedBehavior.ExpressionCacheAdapter ExpressionCacheAdapter} in <code>property</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(EStructuralFeature)} will then return <code>null</code>.
*
* @since 3.1
*/
public void cacheOCLExpression(EStructuralFeature property, OCLExpression e) {
ExpressionCacheAdapter.cacheOCLExpression(property, e);
}
/**
* Looks for an {@link org.eclipse.ocl.ecore.delegate.AbstractDelegatedBehavior.ExpressionCacheAdapter ExpressionCacheAdapter} attached to <code>property</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(EStructuralFeature property) {
return ExpressionCacheAdapter.getCachedOCLExpression(property);
}
public SettingDelegate.Factory getDefaultFactory() {
return SettingDelegate.Factory.Registry.INSTANCE.getFactory(getName());
}
public SettingDelegate.Factory.Registry getDefaultRegistry() {
return SettingDelegate.Factory.Registry.INSTANCE;
}
public EPackage getEPackage(EStructuralFeature eStructuralFeature) {
return eStructuralFeature.getEContainingClass().getEPackage();
}
public SettingDelegate.Factory getFactory(DelegateDomain delegateDomain, EStructuralFeature eStructuralFeature) {
SettingDelegate.Factory.Registry registry = DelegateResourceSetAdapter.getRegistry(
eStructuralFeature, getRegistryClass(), getDefaultRegistry());
return registry.getFactory(delegateDomain.getURI());
}
public Class<SettingDelegate.Factory> getFactoryClass() {
return SettingDelegate.Factory.class;
}
/**
* Return the feature body associated with structuralFeature, if necessary using ocl to
* create the relevant parsing environment for a textual definition..
*/
public OCLExpression getFeatureBody(OCL ocl, EStructuralFeature structuralFeature) {
OCLExpression result = ExpressionCacheAdapter.getCachedOCLExpression(structuralFeature);
if (result != null){
return result != NO_OCL_DEFINITION ? result : null;
}
EAnnotation eAnnotation = OCLCommon.getDelegateAnnotation(structuralFeature);
if (eAnnotation == null) {
cacheOCLExpression(structuralFeature, NO_OCL_DEFINITION);
return null;
}
EMap<String, String> details = eAnnotation.getDetails();
String expr = details.get(DERIVATION_CONSTRAINT_KEY);
if (expr == null) {
expr = details.get(INITIAL_CONSTRAINT_KEY);
if (expr == null) {
return null;
}
}
EClass context = structuralFeature.getEContainingClass();
OCL.Helper helper = ocl.createOCLHelper();
helper.setAttributeContext(context, structuralFeature);
Constraint constraint;
try {
constraint = helper.createDerivedValueExpression(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();
cacheOCLExpression(structuralFeature, body);
return body;
}
public String getName() {
return NAME;
}
public Class<SettingDelegate.Factory.Registry> getRegistryClass() {
return SettingDelegate.Factory.Registry.class;
}
/**
* Tells if there is a textual expression for the <code>structuralFeature</code> in an
* annotation that can be compiled by {@link #getFeatureBody(OCL, EStructuralFeature)}. Probing
* this saves callers the more expensive construction of an {@link OCL} object.
* @since 3.1
*/
public boolean hasCompileableFeatureBody(EStructuralFeature structuralFeature) {
return OCLCommon.getDelegateAnnotation(structuralFeature) != null;
}
}