package com.sap.emf.ocl.trigger.impl; import java.util.Collection; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.ocl.ecore.OCLExpression; import org.eclipse.ocl.ecore.opposites.OppositeEndFinder; import org.eclipse.ocl.examples.eventmanager.EventFilter; import org.eclipse.ocl.examples.impactanalyzer.ImpactAnalyzer; import org.eclipse.ocl.examples.impactanalyzer.ImpactAnalyzerFactory; import org.eclipse.ocl.examples.impactanalyzer.configuration.ActivationOption; import org.eclipse.ocl.examples.impactanalyzer.util.OCLFactory; import com.sap.emf.ocl.trigger.Triggerable; /** * Acts as change listener specific to one {@link OCLExpression}, knowing which {@link Triggerable} to inform after * having computed the affected elements. * * @author Axel Uhl (D043530) * */ public class AdapterForExpression extends AdapterImpl { private final Triggerable triggerableToNotify; private final OCLExpression expression; private final ImpactAnalyzer impactAnalyzer; private final OppositeEndFinder oppositeEndFinder; /** * With this constructor, the expression must contain a <code>self</code> occurrence that allows us to infer the context type. * * @param notifyNewContextElements * The analyzer can be parameterized during construction such that it either registers for creation events on the * context type or not. Registering for element creation on the context type is useful for invariants / constraints * because when a new element is created, validating the constraint may be useful. For other use cases, registering * for element creation may not be so useful. For example, when a type inferencer defines its rules using OCL, it * only wants to receive <em>update</em> events after the element has been fully initialized from those OCL * expressions. In those cases, some framework may be responsible for the initial evaluation of those OCL * expressions on new element, and therefore, context element creation events are not of interest. */ public AdapterForExpression(Triggerable triggerableToNotify, OCLExpression expression, boolean notifyOnNewContextElements, OppositeEndFinder oppositeEndFinder, ActivationOption configuration) { this.triggerableToNotify = triggerableToNotify; this.expression = expression; this.impactAnalyzer = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, notifyOnNewContextElements, oppositeEndFinder, configuration, OCLFactory.getInstance()); this.oppositeEndFinder = oppositeEndFinder; } /** * A non-<code>null</code> context must be provided if this constructor is used. Should the <code>expression</code> contain an * occurrence of <code>self</code>, its type must be the same as <code>context</code>. * * @param notifyNewContextElements * The analyzer can be parameterized during construction such that it either registers for creation events on the * context type or not. Registering for element creation on the context type is useful for invariants / constraints * because when a new element is created, validating the constraint may be useful. For other use cases, registering * for element creation may not be so useful. For example, when a type inferencer defines its rules using OCL, it * only wants to receive <em>update</em> events after the element has been fully initialized from those OCL * expressions. In those cases, some framework may be responsible for the initial evaluation of those OCL * expressions on new element, and therefore, context element creation events are not of interest. */ public AdapterForExpression(Triggerable triggerableToNotify, OCLExpression expression, EClass context, boolean notifyOnNewContextElements, OppositeEndFinder oppositeEndFinder, ActivationOption configuration) { if (context == null) { throw new IllegalArgumentException("This constructor expects a non-null context type for expression "+expression); } this.triggerableToNotify = triggerableToNotify; this.expression = expression; this.impactAnalyzer = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, context, notifyOnNewContextElements, oppositeEndFinder, configuration, OCLFactory.getInstance()); this.oppositeEndFinder = oppositeEndFinder; } private ImpactAnalyzer getImpactAnalyzer() { return impactAnalyzer; } public EventFilter getEventFilter() { return impactAnalyzer.createFilterForExpression(); } @Override public void notifyChanged(Notification msg) { ImpactAnalyzer ia = getImpactAnalyzer(); Collection<EObject> affectedContextObjects = ia.getContextObjects(msg); if (!affectedContextObjects.isEmpty()) { triggerableToNotify.notify(expression, affectedContextObjects, oppositeEndFinder, msg); } } }