Clover coverage report - Drools - 2.0-rc2
Coverage timestamp: Wed May 11 2005 07:12:26 BST
file stats: LOC: 411   Methods: 12
NCLOC: 218   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Agenda.java 63.9% 67.5% 83.3% 67.9%
coverage coverage
 1    package org.drools.reteoo;
 2   
 3    /*
 4    * $Id: Agenda.java,v 1.54.2.1 2005/04/15 01:14:19 mproctor Exp $
 5    *
 6    * Copyright 2001-2003 (C) The Werken Company. All Rights Reserved.
 7    *
 8    * Redistribution and use of this software and associated documentation
 9    * ("Software"), with or without modification, are permitted provided that the
 10    * following conditions are met:
 11    *
 12    * 1. Redistributions of source code must retain copyright statements and
 13    * notices. Redistributions must also contain a copy of this document.
 14    *
 15    * 2. Redistributions in binary form must reproduce the above copyright notice,
 16    * this list of conditions and the following disclaimer in the documentation
 17    * and/or other materials provided with the distribution.
 18    *
 19    * 3. The name "drools" must not be used to endorse or promote products derived
 20    * from this Software without prior written permission of The Werken Company.
 21    * For written permission, please contact bob@werken.com.
 22    *
 23    * 4. Products derived from this Software may not be called "drools" nor may
 24    * "drools" appear in their names without prior written permission of The Werken
 25    * Company. "drools" is a trademark of The Werken Company.
 26    *
 27    * 5. Due credit should be given to The Werken Company. (http://werken.com/)
 28    *
 29    * THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS ``AS IS''
 30    * AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 31    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 32    * ARE DISCLAIMED. IN NO EVENT SHALL THE WERKEN COMPANY OR ITS CONTRIBUTORS BE
 33    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 34    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 35    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 36    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 37    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 38    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 39    * POSSIBILITY OF SUCH DAMAGE.
 40    *
 41    */
 42   
 43    import java.io.Serializable;
 44    import java.util.HashMap;
 45    import java.util.Iterator;
 46    import java.util.Map;
 47   
 48    import org.drools.rule.Rule;
 49    import org.drools.spi.AgendaFilter;
 50    import org.drools.spi.AsyncExceptionHandler;
 51    import org.drools.spi.ConflictResolver;
 52    import org.drools.spi.ConsequenceException;
 53    import org.drools.spi.Duration;
 54    import org.drools.spi.Tuple;
 55    import org.drools.util.PriorityQueue;
 56   
 57    /**
 58    * Rule-firing Agenda.
 59    *
 60    * <p>
 61    * Since many rules may be matched by a single assertObject(...) all scheduled
 62    * actions are placed into the <code>Agenda</code>.
 63    * </p>
 64    *
 65    * <p>
 66    * While processing a scheduled action, it may modify or retract objects in
 67    * other scheduled actions, which must then be removed from the agenda.
 68    * Non-invalidated actions are left on the agenda, and are executed in turn.
 69    * </p>
 70    *
 71    * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter </a>
 72    * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris </a>
 73    */
 74    class Agenda
 75    implements
 76    Serializable
 77    {
 78    // ------------------------------------------------------------
 79    // Instance members
 80    // ------------------------------------------------------------
 81   
 82    public static int NONE = 0;
 83    public static int ASSERT = 1;
 84    public static int MODIFY = 2;
 85    public static int RETRACT = 3;
 86   
 87    /** Working memory of this Agenda. */
 88    private final WorkingMemoryImpl workingMemory;
 89   
 90    /** Items in the agenda. */
 91    private final PriorityQueue activationQueue;
 92   
 93    /** Items time-delayed. */
 94    private final Map scheduledItems;
 95   
 96    private final Map itemsToRetract;
 97   
 98    private final Map scheduledItemsToRetract;
 99   
 100    /** The current agenda item being fired; or null if none. */
 101    private AgendaItem item;
 102   
 103    private int mode = 0;
 104   
 105    // ------------------------------------------------------------
 106    // Constructors
 107    // ------------------------------------------------------------
 108   
 109    /**
 110    * Construct.
 111    *
 112    * @param workingMemory
 113    * The <code>WorkingMemory</code> of this agenda.
 114    * @param conflictResolver
 115    * The conflict resolver.
 116    */
 117  73 public Agenda(WorkingMemoryImpl workingMemory,
 118    ConflictResolver conflictResolver)
 119    {
 120  73 this.workingMemory = workingMemory;
 121  73 this.activationQueue = new PriorityQueue( conflictResolver );
 122  73 this.scheduledItems = new HashMap( );
 123  73 this.itemsToRetract = new HashMap( );
 124  73 this.scheduledItemsToRetract = new HashMap( );
 125    }
 126   
 127    // ------------------------------------------------------------
 128    // Instance methods
 129    // ------------------------------------------------------------
 130   
 131    /**
 132    * Schedule a rule action invokation on this <code>Agenda</code>. Rules
 133    * specified with noNoop=true that are active should not be added to the
 134    * agenda
 135    *
 136    * @param tuple
 137    * The matching <code>Tuple</code>.
 138    * @param rule
 139    * The rule to fire.
 140    */
 141  6156 void addToAgenda(ReteTuple tuple,
 142    Rule rule)
 143    {
 144    /*
 145    * if no-loop is true for this rule and the current rule is active then
 146    * do not not re-add to the agenda
 147    */
 148   
 149  6156 if ( this.item != null && rule.getNoLoop( ) && rule.equals( this.item.getRule( ) ) )
 150    {
 151  1 return;
 152    }
 153   
 154  6155 Duration dur = rule.getDuration( );
 155   
 156  6155 if ( dur != null && dur.getDuration( tuple ) > 0 )
 157    {
 158    // check if item has been retracted as part of a modify
 159  0 AgendaItem item = null;
 160  0 if ( !this.itemsToRetract.isEmpty( ) )
 161    {
 162  0 item = (AgendaItem) this.scheduledItems.get( tuple.getKey( ) );
 163    }
 164   
 165  0 if ( item == null )
 166    {
 167  0 item = new AgendaItem( tuple,
 168    rule );
 169  0 this.scheduledItems.put( item.getKey( ),
 170    item );
 171  0 scheduleItem( item );
 172  0 this.workingMemory.getEventSupport( ).fireActivationCreated( rule,
 173    tuple );
 174    }
 175    }
 176    else
 177    {
 178    // check if item has been retracted as part of a modify
 179  6155 AgendaItem item = null;
 180  6155 if ( !this.itemsToRetract.isEmpty( ) )
 181    {
 182  12 item = (AgendaItem) this.itemsToRetract.remove( tuple.getKey( ) );
 183    }
 184   
 185  6155 if ( item == null )
 186    {
 187  6152 item = new AgendaItem( tuple,
 188    rule );
 189  6152 this.activationQueue.add( item );
 190  6152 this.workingMemory.getEventSupport( ).fireActivationCreated( rule,
 191    tuple );
 192    }
 193    else
 194    {
 195  3 this.activationQueue.add( item );
 196    }
 197    }
 198    }
 199   
 200    /**
 201    * Remove a tuple from the agenda.
 202    *
 203    * @param key
 204    * The key to the tuple to be removed.
 205    * @param rule
 206    * The rule to remove.
 207    */
 208  931 void removeFromAgenda(TupleKey key,
 209    Rule rule)
 210    {
 211  931 AgendaItem eachItem;
 212  931 Tuple tuple;
 213  931 Iterator itemIter = this.activationQueue.iterator( );
 214   
 215  931 while ( itemIter.hasNext( ) )
 216    {
 217  22308 eachItem = (AgendaItem) itemIter.next( );
 218   
 219  22308 if ( eachItem.getRule( ) == rule && eachItem.getKey( ).containsAll( key ) )
 220    {
 221  5761 itemIter.remove( );
 222    // need to restart iterator as heap could place elements before
 223    // current iterator position
 224  5761 itemIter = this.activationQueue.iterator( );
 225   
 226  5761 if ( (this.mode == Agenda.MODIFY) && !this.workingMemory.getEventSupport( ).isEmpty( ) )
 227    {
 228  83 this.itemsToRetract.put( eachItem.getKey( ),
 229    eachItem );
 230    }
 231    else
 232    {
 233  5678 this.workingMemory.getEventSupport( ).fireActivationCancelled( rule,
 234    eachItem.getTuple( ) );
 235    }
 236    }
 237    }
 238   
 239  931 itemIter = this.scheduledItems.values( ).iterator( );
 240   
 241  931 while ( itemIter.hasNext( ) )
 242    {
 243  0 eachItem = (AgendaItem) itemIter.next( );
 244   
 245  0 if ( eachItem.getRule( ) == rule && eachItem.getKey( ).containsAll( key ) )
 246    {
 247  0 if ( (this.mode == Agenda.MODIFY) && !this.workingMemory.getEventSupport( ).isEmpty( ) )
 248    {
 249  0 this.scheduledItemsToRetract.put( eachItem.getKey( ),
 250    eachItem );
 251    }
 252    else
 253    {
 254  0 tuple = eachItem.getTuple( );
 255   
 256  0 cancelItem( eachItem );
 257   
 258  0 itemIter.remove( );
 259   
 260  0 this.workingMemory.getEventSupport( ).fireActivationCancelled( rule,
 261    tuple );
 262    }
 263    }
 264    }
 265    }
 266   
 267  316 void removeMarkedItemsFromAgenda()
 268    {
 269  316 AgendaItem eachItem;
 270   
 271  316 Iterator itemIter = this.itemsToRetract.values( ).iterator( );
 272  316 while ( itemIter.hasNext( ) )
 273    {
 274  80 eachItem = (AgendaItem) itemIter.next( );
 275  80 this.workingMemory.getEventSupport( ).fireActivationCancelled( eachItem.getRule( ),
 276    eachItem.getTuple( ) );
 277  80 itemIter.remove( );
 278    }
 279   
 280  316 itemIter = this.scheduledItemsToRetract.values( ).iterator( );
 281  316 while ( itemIter.hasNext( ) )
 282    {
 283  0 eachItem = (AgendaItem) itemIter.next( );
 284   
 285  0 cancelItem( eachItem );
 286   
 287  0 this.workingMemory.getEventSupport( ).fireActivationCancelled( eachItem.getRule( ),
 288    eachItem.getTuple( ) );
 289  0 itemIter.remove( );
 290    }
 291    }
 292   
 293    /**
 294    * Clears all Activations from the Agenda
 295    *
 296    */
 297  5 void clearAgenda()
 298    {
 299  5 AgendaItem eachItem;
 300   
 301    // Remove all items in the Agenda and fire a Cancelled event for each
 302  5 Iterator iter = this.activationQueue.iterator( );
 303  5 while ( iter.hasNext( ) )
 304    {
 305  7 eachItem = (AgendaItem) iter.next( );
 306   
 307  7 iter.remove( );
 308   
 309  7 this.workingMemory.getEventSupport( ).fireActivationCancelled( eachItem.getRule( ),
 310    eachItem.getTuple( ) );
 311    }
 312   
 313  5 iter = this.scheduledItems.values( ).iterator( );
 314   
 315    // Cancel all items in the Schedule and fire a Cancelled event for each
 316  5 while ( iter.hasNext( ) )
 317    {
 318  0 eachItem = (AgendaItem) iter.next( );
 319   
 320  0 cancelItem( eachItem );
 321   
 322  0 iter.remove( );
 323   
 324  0 this.workingMemory.getEventSupport( ).fireActivationCancelled( eachItem.getRule( ),
 325    eachItem.getTuple( ) );
 326    }
 327    }
 328   
 329    /**
 330    * Schedule an agenda item for delayed firing.
 331    *
 332    * @param item
 333    * The item to schedule.
 334    */
 335  0 void scheduleItem(AgendaItem item)
 336    {
 337  0 Scheduler.getInstance( ).scheduleAgendaItem( item,
 338    this.workingMemory );
 339    }
 340   
 341    /**
 342    * Cancel a scheduled agenda item for delayed firing.
 343    *
 344    * @param item
 345    * The item to cancel.
 346    */
 347  0 void cancelItem(AgendaItem item)
 348    {
 349  0 Scheduler.getInstance( ).cancelAgendaItem( item );
 350    }
 351   
 352    /**
 353    * Determine if this <code>Agenda</code> has any scheduled items.
 354    *
 355    * @return <code>true<code> if the agenda is empty, otherwise
 356    * <code>false</code>.
 357    */
 358  778 public boolean isEmpty()
 359    {
 360  778 return this.activationQueue.isEmpty( );
 361    }
 362   
 363  18 public int size()
 364    {
 365  18 return activationQueue.size( );
 366    }
 367   
 368    /**
 369    * Fire the next scheduled <code>Agenda</code> item.
 370    *
 371    * @throws ConsequenceException
 372    * If an error occurs while firing an agenda item.
 373    */
 374  384 public void fireNextItem(AgendaFilter filter) throws ConsequenceException
 375    {
 376  384 if ( isEmpty( ) )
 377    {
 378  0 return;
 379    }
 380   
 381  384 item = (AgendaItem) this.activationQueue.remove( );
 382   
 383  384 try
 384    {
 385  384 if ( filter == null || filter.accept( item ) )
 386    {
 387  383 item.fire( this.workingMemory );
 388    }
 389    }
 390    finally
 391    {
 392  384 item = null;
 393    }
 394    }
 395   
 396    /**
 397    * Sets the AsyncExceptionHandler to handle exceptions thrown by the Agenda
 398    * Scheduler used for duration rules.
 399    *
 400    * @param handler
 401    */
 402  1 void setAsyncExceptionHandler(AsyncExceptionHandler handler)
 403    {
 404  1 Scheduler.getInstance( ).setAsyncExceptionHandler( handler );
 405    }
 406   
 407  2484 void setMode(int mode)
 408    {
 409  2484 this.mode = mode;
 410    }
 411    }