Package org.openiaml.model.drools

Source Code of org.openiaml.model.drools.DroolsInsertionQueue$MyPropogationContext

package org.openiaml.model.drools;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.drools.FactHandle;
import org.drools.WorkingMemory;
import org.drools.event.ObjectInsertedEvent;
import org.drools.event.WorkingMemoryEventListener;
import org.drools.reteoo.ReteTuple;
import org.drools.rule.Rule;
import org.drools.spi.Activation;
import org.drools.spi.KnowledgeHelper;
import org.drools.spi.PropagationContext;
import org.eclipse.emf.ecore.EObject;
import org.openiaml.model.drools.DroolsInferenceEngine.InferenceQueueLog;

/**
* <p>To support the iterative way of adding new elements to the
* model, this class supports the queueing up of elements for
* addition later.</p>
*
* <p>Essentially, instead of using
* <code>insert(object);</code>,
* the Drools rule must instead use
* <code>queue.add(object, drools);</code>,
* where <code>drools</code> is an automatically populated
* object referring to the Drools instance.</p>
*
* <p>Once the queue has been completely populated, the
* apply() method must be called to insert the queued elements.</p>
*
* <p>It also deals with throwing {@link ObjectInsertionEvent}s when
* adding the queued elements, to allow for other listeners in the system
* to function as normal.</p>
*
* @author jmwright
*/
public class DroolsInsertionQueue {

  /**
   * This is a bit of a hack to a real {@link PropogationContext}, because
   * the default one we get is not actually populated properly (elements
   * remain null; I think they are being reset to help GC).
   *
   * Essentially it's only real use is {@link #getRuleOrigin()}; most
   * of the other methods throw an {@link UnsupportedOperationException}.
   *
   * @author jmwright
   *
   */
  public class MyPropogationContext implements PropagationContext {

    private static final long serialVersionUID = 1L;
   
    private Activation activation;

    /**
     * Initialise this with a given activation. This activation
     * will contain the actual rule origin.
     *
     * @param activation
     */
    public MyPropogationContext(Activation activation) {
      this.activation = activation;
    }

    /**
     * Not supported.
     *
     * @throws UnsupportedOperationException
     * @see org.drools.spi.PropagationContext#addRetractedTuple(org.drools.rule.Rule, org.drools.spi.Activation)
     */
    @Override
    public void addRetractedTuple(Rule rule, Activation activation) {
      throw new UnsupportedOperationException("addRetractedTuple() is not supported");
    }

    /**
     * Not supported.
     *
     * @throws UnsupportedOperationException
     * @see org.drools.spi.PropagationContext#clearRetractedTuples()
     */
    @Override
    public void clearRetractedTuples() {
      throw new UnsupportedOperationException("clearRetractedTuples() is not supported");
    }

    /* (non-Javadoc)
     * @see org.drools.spi.PropagationContext#getActivationOrigin()
     */
    @Override
    public Activation getActivationOrigin() {
      return activation;
    }

    /**
     * Not supported.
     *
     * @throws UnsupportedOperationException
     * @see org.drools.spi.PropagationContext#getActiveActivations()
     */
    @Override
    public int getActiveActivations() {
      throw new UnsupportedOperationException("getActiveActivations() is not supported");
    }

    /**
     * Not supported.
     *
     * @throws UnsupportedOperationException
     * @see org.drools.spi.PropagationContext#getDormantActivations()
     */
    @Override
    public int getDormantActivations() {
      throw new UnsupportedOperationException("getDormantActivations() is not supported");
    }

    /**
     * Not supported.
     *
     * @throws UnsupportedOperationException
     * @see org.drools.spi.PropagationContext#getPropagationNumber()
     */
    @Override
    public long getPropagationNumber() {
      throw new UnsupportedOperationException("getDormantActivations() is not supported");
    }

    /* (non-Javadoc)
     * @see org.drools.spi.PropagationContext#getRuleOrigin()
     */
    @Override
    public Rule getRuleOrigin() {
      return activation.getRule();
    }

    /**
     * Not sure what this should actually be, but this returns
     * a type ASSERTION.
     *
     * @see org.drools.spi.PropagationContext#getType()
     */
    @Override
    public int getType() {
      return PropagationContext.ASSERTION;
    }

    /**
     * Does nothing.
     *
     * @see org.drools.spi.PropagationContext#releaseResources()
     */
    @Override
    public void releaseResources() {
      // does nothing
    }

    /**
     * Not supported.
     *
     * @throws UnsupportedOperationException
     * @see org.drools.spi.PropagationContext#removeRetractedTuple(org.drools.rule.Rule, org.drools.reteoo.ReteTuple)
     */
    @Override
    public Activation removeRetractedTuple(Rule rule, ReteTuple tuple) {
      throw new UnsupportedOperationException("removeRetractedTuple() is not supported");
    }

  }
 
  public List<EObject> objects = new ArrayList<EObject>();
  public List<KnowledgeHelper> helpers = new ArrayList<KnowledgeHelper>();
  public List<Activation> activations = new ArrayList<Activation>();
 
  private boolean trackInsertions;
  // data storage structures
  private Map<EObject,Activation> tracked = new HashMap<EObject,Activation>();
  private Map<Activation,List<EObject>> activationObjects = new HashMap<Activation,List<EObject>>();
 
  private static final long serialVersionUID = 1L;

  /**
   * @param trackInsertions should we keep track of which activations
   *   various elements were added?
   *
   * @see #getActivationFor(EObject)
   */
  public DroolsInsertionQueue(boolean trackInsertions) {
    super();
    this.trackInsertions = trackInsertions;
  }
 
  /**
   * Load additional information from the drools object.
   * This is the method called from the Drools rules to
   * add it to the insertion queue.
   *
   * @param e
   * @param drools
   * @return
   */
  public void add(EObject e, KnowledgeHelper drools) {
    objects.add(e);
    helpers.add(drools);
    Activation a = drools.getActivation();
    activations.add(a);
   
    // should we track the insertions for each activation?
    if (trackInsertions) {
      // map from EObject to Activation
      tracked.put(e, a);
      // list map from Activation to EObject
      if (activationObjects.get(a) == null) {
        activationObjects.put(a, new ArrayList<EObject>());
      }
      activationObjects.get(a).add(e);
    }
  }
 
  /**
   * Is this queue empty?
   *
   * @return
   */
  public boolean isEmpty() {
    return objects.isEmpty();
  }

  /**
   * The number of objects queued in here.
   *
   * @return
   */
  public int size() {
    return objects.size();
  }
 
  /**
   * Remove the existing WorkingMemoryEventListeners from the
   * WorkingMemory, so that these are not called while we insert
   * objects.
   *
   * @param memory
   * @return
   */
  private List<WorkingMemoryEventListener> removeExistingListeners(WorkingMemory memory) {
    List<WorkingMemoryEventListener> listeners = new ArrayList<WorkingMemoryEventListener>();
    List<?> oldListeners = memory.getWorkingMemoryEventListeners();
    for (Object obj : oldListeners) {
      listeners.add((WorkingMemoryEventListener) obj);
    }
   
    for (WorkingMemoryEventListener listener : listeners) {
      memory.removeEventListener((WorkingMemoryEventListener) listener);
    }

    return listeners;
  }
 
  private void addExistingListeners(List<WorkingMemoryEventListener> listeners, WorkingMemory memory) {
    for (WorkingMemoryEventListener listener : listeners) {
      memory.addEventListener(listener);
    }
  }

  /**
   * Apply all the new objects to the given working memory.
   * Also throws WorkingMemoryEvents for each added event.
   *
   * @param memory
   * @param log
   */
  public void apply(WorkingMemory memory, int step, InferenceQueueLog log) {
    assert(objects.size() == helpers.size());
   
    // first, remove all WorkingMemoryEventListeners
    // (or else memory.insert() below will still call them)
    List<WorkingMemoryEventListener> listeners = removeExistingListeners(memory);
   
    for (int i = 0; i < objects.size(); i++) {
      FactHandle handle = memory.insert(objects.get(i));

      // log it
      log.increment("step " + step + " type " + objects.get(i).eClass().getName(), 1);

      // throw a new event for all listeners
      KnowledgeHelper drools = helpers.get(i);
      for (WorkingMemoryEventListener listener : listeners) {
        listener.objectInserted(new ObjectInsertedEvent(
            drools.getWorkingMemory(),
            new MyPropogationContext(activations.get(i)),
            handle,
            objects.get(i)
          ));
      }
    }
   
    // add all the listeners back again
    addExistingListeners(listeners, memory);
  }
 
  /**
   * If we have been tracking activation insertions, this will get the
   * activation for a particular object insertion, or null if none
   * was found.
   *
   * @param object
   */
  public Object getActivationFor(EObject object) {
    return tracked.get(object);
  }
 
  /**
   * If we have been tracking activation insertions, this will get all
   * of the objects that were inserted for a particular activation, or
   * null if this activation was not found.
   *
   * @param object
   */
  public List<EObject> getInsertedObjectsForActivation(Object a) {
    if (!(a instanceof Activation)) {
      throw new IllegalArgumentException("Expected object type '" + a + "' to be an Activation, was: " + a.getClass().getSimpleName());
    }
    return activationObjects.get(a);
  }

  /**
   * Since we create a new queue for each iteration step, this will
   * add all the activations and EObjects from the old queue.
   *
   * @throws IllegalArugmentException if we are not tracking insertions
   * @throws IllegalStateException if the current tracking queues aren't empty
   *
   * @param oldQueue
   */
  public void addPreviousInsertions(DroolsInsertionQueue oldQueue) {
    if (!trackInsertions) {
      throw new IllegalArgumentException("Cannot add previous insertions - tracking is not enabled.");
    }
    if (!tracked.isEmpty()) {
      throw new IllegalStateException("The tracking map is not empty; this method should be called before any element insertion occurs.");
    }
    if (!activationObjects.isEmpty()) {
      throw new IllegalStateException("The activation objects map is not empty; this method should be called before any element insertion occurs.");
    }
    // we don't really need to copy them all; just assigning them will be enough
    tracked = oldQueue.tracked;
    activationObjects = oldQueue.activationObjects;
   
  }

}
TOP

Related Classes of org.openiaml.model.drools.DroolsInsertionQueue$MyPropogationContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.