Impact Analysis

From Furcas Wiki

Jump to: navigation, search

Introduction

The effort for re-evaluating OCL expressions over a set of model elements grows with the number of elements, the complexity of the expressions, and the number of model changes. Techniques to reduce this effort have been presented in previous work but do not cover the full range of OCL expressions, in particular calls to operations defined in OCL, including recursive operations. The approach described here that based on ideas from related work is applicable to the full range of OCL expressions. We further increase the number of elements for which we can prove that the model change does not affect an expression's value by using partial evaluation and delta propagation.

Interface

To create an Impact Analyzer for a specific expression you should use the ImpactAnalyzerFactory:

public interface ImpactAnalyzerFactory {
    ImpactAnalyzerFactory eINSTANCE = …;

    /**
     * Constructs an impact analyzer for the expression specified with an explicit context type
     * specification. Use this factory method if <code>expression</code> does not contain any
     * reference to <code>self</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.
     * @param oppositeEndFinder
     *            used to perform {@link OppositePropertyCallExp} when evaluating (parts of)
     *            <code>expression</code> and for evaluating <code>allInstances()</code> calls
     */
    ImpactAnalyzer createImpactAnalyzer(OCLExpression expression, EClass context,
                           boolean notifyOnNewContextElements, OppositeEndFinder oppositeEndFinder);
    ImpactAnalyzer createImpactAnalyzer(OCLExpression expression, boolean notifyOnNewContextElements,
            OppositeEndFinder oppositeEndFinder);
    ImpactAnalyzer createImpactAnalyzer(OCLExpression expression, boolean notifyOnNewContextElements);
}

The resulting instance of ImpactAnalyzer is given by the following interface:

public interface ImpactAnalyzer {

  /**
   * Creates a filter for the given OCL expression, which matches at least all events
   * that cause the expression to change its value on one or more context elements.
   * Note that also events may be matched that don't actually lead to a change. The
   * filter synthesis is "conservative" in this sense.
   * @return the filter matching all relevant events
   */
  EventFilter createFilterForExpression();

  /**
   * For a change notification <tt>event</tt> calculates a superset of the set of context objects
   * for which <tt>expression</tt> may have changed its value due to the changed indicated by the event.
   * As implies by "superset," the result set may contain context elements for which the expression's
   * value may happen to not have changed.
   *
   * @param event
   *            the event to calculate for
   * @return all relevant context objects
   */
  Collection<EObject> getContextObjects(Notification event);
}

Example

To be notified when the expression "self.signature.parameters->size()=self.arguments->size()" changes its result the following code can be used:

EventManager eventManager =
   EventManagerFactory.eINSTANCE.createEventManagerFor(
   editingDomain.getResourceSet());
final OCLExpression invariant = OCL.newInstance().createOCLHelper().
		createQuery("self.signature.parameters->size()=self.arguments->size()");
final ImpactAnalyzer impactAnalyzer =
		ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(invariant,
        		/* notifyOnNewContextElements */ true, oppositeEndFinder);
Adapter adapter = new AdapterImpl() {
   @Override
   public void notifyChanged(Notification msg) {
      // revalidate invariant on context objects delivered by impact analysis:
      Collection<EObject> revalidateOn = impactAnalyzer.getContextObjects(msg);
      if (revalidateOn != null && !revalidateOn.isEmpty()) {
          revalidate(invariant, revalidateOn);
      }
   }
};
eventManager.subscribe(impactAnalyzer.createFilterForExpression(), adapter);
Personal tools