Clover coverage report - Drools - 2.0-rc2
Coverage timestamp: Wed May 11 2005 07:12:26 BST
file stats: LOC: 619   Methods: 32
NCLOC: 372   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
WorkingMemoryImpl.java 50% 68.4% 84.4% 68.4%
coverage coverage
 1    package org.drools.reteoo;
 2   
 3    /*
 4    * $Id: WorkingMemoryImpl.java,v 1.62.2.2 2005/04/26 02:43:49 mproctor Exp $
 5    *
 6    * Copyright 2001-2004 (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.beans.PropertyChangeEvent;
 44    import java.beans.PropertyChangeListener;
 45    import java.lang.reflect.InvocationTargetException;
 46    import java.lang.reflect.Method;
 47    import java.util.ArrayList;
 48    import java.util.HashMap;
 49    import java.util.Iterator;
 50    import java.util.LinkedList;
 51    import java.util.List;
 52    import java.util.Map;
 53   
 54    import org.drools.FactException;
 55    import org.drools.FactHandle;
 56    import org.drools.NoSuchFactHandleException;
 57    import org.drools.NoSuchFactObjectException;
 58    import org.drools.RuleBase;
 59    import org.drools.WorkingMemory;
 60    import org.drools.event.WorkingMemoryEventListener;
 61    import org.drools.event.WorkingMemoryEventSupport;
 62    import org.drools.spi.AgendaFilter;
 63    import org.drools.spi.AsyncExceptionHandler;
 64    import org.drools.util.IdentityMap;
 65    import org.drools.util.PrimitiveLongMap;
 66    import org.drools.util.PrimitiveLongStack;
 67   
 68    /**
 69    * Implementation of <code>WorkingMemory</code>.
 70    *
 71    * @author <a href="mailto:bob@werken.com">bob mcwhirter </a>
 72    * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris </a>
 73    */
 74    class WorkingMemoryImpl
 75    implements
 76    WorkingMemory,
 77    PropertyChangeListener
 78    {
 79    // ------------------------------------------------------------
 80    // Constants
 81    // ------------------------------------------------------------
 82    private static final Class[] ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES = new Class[]{PropertyChangeListener.class};
 83   
 84    // ------------------------------------------------------------
 85    // Instance members
 86    // ------------------------------------------------------------
 87   
 88    /** The arguments used when adding/removing a property change listener. */
 89    private final Object[] addRemovePropertyChangeListenerArgs = new Object[]{this};
 90   
 91    /** The actual memory for the <code>JoinNode</code>s. */
 92    private final Map joinMemories = new HashMap( );
 93   
 94    /** Application data which is associated with this memory. */
 95    private final Map applicationData = new HashMap( );
 96   
 97    /** Handle-to-object mapping. */
 98    private final PrimitiveLongMap objects = new PrimitiveLongMap( 32,
 99    8 );
 100   
 101    /** Object-to-handle mapping. */
 102    private final Map handles = new IdentityMap( );
 103    private final PrimitiveLongStack factHandlePool = new PrimitiveLongStack( );
 104   
 105    /** The eventSupport */
 106    private final WorkingMemoryEventSupport eventSupport = new WorkingMemoryEventSupport( this );
 107   
 108    /** The <code>RuleBase</code> with which this memory is associated. */
 109    private final RuleBaseImpl ruleBase;
 110   
 111    /** Rule-firing agenda. */
 112    private final Agenda agenda;
 113   
 114    /** Flag to determine if a rule is currently being fired. */
 115    private boolean firing;
 116   
 117    // ------------------------------------------------------------
 118    // Constructors
 119    // ------------------------------------------------------------
 120   
 121    /**
 122    * Construct.
 123    *
 124    * @param ruleBase
 125    * The backing rule-base.
 126    */
 127  71 public WorkingMemoryImpl(RuleBaseImpl ruleBase)
 128    {
 129  71 this.ruleBase = ruleBase;
 130  71 this.agenda = new Agenda( this,
 131    ruleBase.getConflictResolver( ) );
 132    }
 133   
 134    // ------------------------------------------------------------
 135    // Instance methods
 136    // ------------------------------------------------------------
 137   
 138  3 public void addEventListener(WorkingMemoryEventListener listener)
 139    {
 140  3 this.eventSupport.addEventListener( listener );
 141    }
 142   
 143  0 public void removeEventListener(WorkingMemoryEventListener listener)
 144    {
 145  0 this.eventSupport.removeEventListener( listener );
 146    }
 147   
 148  2 public List getEventListeners()
 149    {
 150  2 return eventSupport.getEventListeners( );
 151    }
 152   
 153    /**
 154    * Create a new <code>FactHandle</code>.
 155    *
 156    * @return The new fact handle.
 157    */
 158  872 FactHandle newFactHandle()
 159    {
 160  872 if ( !this.factHandlePool.isEmpty( ) )
 161    {
 162  0 return this.ruleBase.getFactHandleFactory( ).newFactHandle( this.factHandlePool.pop( ) );
 163    }
 164    else
 165    {
 166  872 return this.ruleBase.getFactHandleFactory( ).newFactHandle( );
 167    }
 168    }
 169   
 170    /**
 171    * @see WorkingMemory
 172    */
 173  39488 public Map getApplicationDataMap()
 174    {
 175  39488 return this.applicationData;
 176    }
 177   
 178    /**
 179    * @see WorkingMemory
 180    */
 181  1 public void setApplicationData(String name,
 182    Object value)
 183    {
 184    // Make sure the application data has been declared in the RuleBase
 185  1 Map applicationDataDefintions = this.ruleBase.getApplicationData( );
 186  1 Class type = (Class) applicationDataDefintions.get( name );
 187  1 if ( ( type == null ) )
 188    {
 189  0 throw new RuntimeException( "Unexpected application data [" + name + "]" );
 190    }
 191  1 else if ( !type.isInstance( value ) )
 192    {
 193  0 throw new RuntimeException( "Illegal class for application data. " +
 194    "Expected [" + type.getName() + "], " +
 195    "found [" + value.getClass().getName() + "]." );
 196   
 197    }
 198    else
 199    {
 200  1 this.applicationData.put( name,
 201    value );
 202    }
 203    }
 204   
 205    /**
 206    * @see WorkingMemory
 207    */
 208  51 public Object getApplicationData(String name)
 209    {
 210  51 return this.applicationData.get( name );
 211    }
 212   
 213    /**
 214    * Retrieve the rule-firing <code>Agenda</code> for this
 215    * <code>WorkingMemory</code>.
 216    *
 217    * @return The <code>Agenda</code>.
 218    */
 219  7080 protected Agenda getAgenda()
 220    {
 221  7080 return this.agenda;
 222    }
 223   
 224    /**
 225    * Clear the Agenda
 226    */
 227  2 public void clearAgenda()
 228    {
 229  2 this.agenda.clearAgenda( );
 230    }
 231   
 232    /**
 233    * @see WorkingMemory
 234    */
 235  2 public RuleBase getRuleBase()
 236    {
 237  2 return this.ruleBase;
 238    }
 239   
 240  16 public synchronized void fireAllRules(AgendaFilter agendaFilter) throws FactException
 241    {
 242    // If we're already firing a rule, then it'll pick up
 243    // the firing for any other assertObject(..) that get
 244    // nested inside, avoiding concurrent-modification
 245    // exceptions, depending on code paths of the actions.
 246   
 247  16 if ( !firing )
 248    {
 249  16 try
 250    {
 251  16 firing = true;
 252   
 253  16 while ( !agenda.isEmpty( ) )
 254    {
 255  378 agenda.fireNextItem( agendaFilter );
 256    }
 257    }
 258    finally
 259    {
 260  16 firing = false;
 261    }
 262    }
 263    }
 264   
 265    /**
 266    * @see WorkingMemory
 267    */
 268  16 public void fireAllRules() throws FactException
 269    {
 270  16 fireAllRules( null );
 271    }
 272   
 273    /**
 274    * @see WorkingMemory
 275    */
 276  84673 public Object getObject(FactHandle handle) throws NoSuchFactObjectException
 277    {
 278  84673 Object object = this.objects.get( ((FactHandleImpl) handle).getId( ) );
 279   
 280  84673 if ( object == null )
 281    {
 282  0 throw new NoSuchFactObjectException( handle );
 283    }
 284   
 285  84673 return object;
 286    }
 287   
 288    /**
 289    * @see WorkingMemory
 290    */
 291  361 public FactHandle getFactHandle(Object object) throws NoSuchFactHandleException
 292    {
 293  361 FactHandle factHandle = (FactHandle) this.handles.get( object );
 294   
 295  361 if ( factHandle == null )
 296    {
 297  0 throw new NoSuchFactHandleException( object );
 298    }
 299   
 300  361 return factHandle;
 301    }
 302   
 303  1 public List getFactHandles()
 304    {
 305  1 return new ArrayList( this.handles.values( ) );
 306    }
 307   
 308    /**
 309    * @see WorkingMemory
 310    */
 311  23 public List getObjects()
 312    {
 313  23 return new ArrayList( this.objects.values( ) );
 314    }
 315   
 316  0 public List getObjects(Class objectClass)
 317    {
 318  0 List matching = new LinkedList( );
 319  0 Iterator objIter = this.objects.values( ).iterator( );
 320  0 Object obj;
 321  0 while ( objIter.hasNext( ) )
 322    {
 323  0 obj = objIter.next( );
 324   
 325  0 if ( objectClass.isInstance( obj ) )
 326    {
 327  0 matching.add( obj );
 328    }
 329    }
 330   
 331  0 return matching;
 332    }
 333   
 334    /**
 335    * @see WorkingMemory
 336    */
 337  8 public boolean containsObject(FactHandle handle)
 338    {
 339  8 return this.objects.containsKey( ((FactHandleImpl) handle).getId( ) );
 340    }
 341   
 342    /**
 343    * @see WorkingMemory
 344    */
 345  873 public FactHandle assertObject(Object object) throws FactException
 346    {
 347  873 return assertObject( object, /* Not-Dynamic */
 348    false );
 349    }
 350   
 351  873 public synchronized FactHandle assertObject(Object object,
 352    boolean dynamic) throws FactException
 353    {
 354  873 FactHandle handle = (FactHandle) handles.get( object );
 355   
 356  873 if ( handle != null )
 357    {
 358  1 return handle;
 359    }
 360   
 361  872 handle = newFactHandle( );
 362   
 363  872 putObject( handle,
 364    object );
 365   
 366  872 if ( dynamic )
 367    {
 368  0 addPropertyChangeListener( object );
 369    }
 370   
 371  872 this.agenda.setMode( Agenda.ASSERT );
 372  872 ruleBase.assertObject( handle,
 373    object,
 374    this );
 375   
 376  872 eventSupport.fireObjectAsserted( handle,
 377    object );
 378  872 this.agenda.setMode( Agenda.NONE );
 379  872 return handle;
 380    }
 381   
 382  0 private void addPropertyChangeListener(Object object)
 383    {
 384  0 try
 385    {
 386  0 Method method = object.getClass( ).getMethod( "addPropertyChangeListener",
 387    ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES );
 388   
 389  0 method.invoke( object,
 390    addRemovePropertyChangeListenerArgs );
 391    }
 392    catch ( NoSuchMethodException e )
 393    {
 394  0 System.err.println( "Warning: Method addPropertyChangeListener not found"
 395    + " on the class " + object.getClass( )
 396    + " so Drools will be unable to process JavaBean"
 397    + " PropertyChangeEvents on the asserted Object" );
 398    }
 399    catch ( IllegalArgumentException e )
 400    {
 401  0 System.err.println( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass( ) + " does not take" + " a simple PropertyChangeListener argument" + " so Drools will be unable to process JavaBean"
 402    + " PropertyChangeEvents on the asserted Object" );
 403    }
 404    catch ( IllegalAccessException e )
 405    {
 406  0 System.err.println( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass( ) + " is not public" + " so Drools will be unable to process JavaBean" + " PropertyChangeEvents on the asserted Object" );
 407    }
 408    catch ( InvocationTargetException e )
 409    {
 410  0 System.err.println( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass( ) + " threw an InvocationTargetException" + " so Drools will be unable to process JavaBean"
 411    + " PropertyChangeEvents on the asserted Object: " + e.getMessage( ) );
 412    }
 413    catch ( SecurityException e )
 414    {
 415  0 System.err.println( "Warning: The SecurityManager controlling the class " + object.getClass( ) + " did not allow the lookup of a" + " addPropertyChangeListener method" + " so Drools will be unable to process JavaBean"
 416    + " PropertyChangeEvents on the asserted Object: " + e.getMessage( ) );
 417    }
 418    }
 419   
 420  54 private void removePropertyChangeListener(FactHandle handle) throws NoSuchFactObjectException
 421    {
 422  54 Object object = null;
 423  54 try
 424    {
 425  54 object = getObject( handle );
 426   
 427  54 Method mehod = handle.getClass( ).getMethod( "removePropertyChangeListener",
 428    ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES );
 429   
 430  0 mehod.invoke( handle,
 431    addRemovePropertyChangeListenerArgs );
 432    }
 433    catch ( NoSuchMethodException e )
 434    {
 435    // The removePropertyChangeListener method on the class
 436    // was not found so Drools will be unable to
 437    // stop processing JavaBean PropertyChangeEvents
 438    // on the retracted Object
 439    }
 440    catch ( IllegalArgumentException e )
 441    {
 442  0 System.err.println( "Warning: The removePropertyChangeListener method" + " on the class " + object.getClass( ) + " does not take" + " a simple PropertyChangeListener argument" + " so Drools will be unable to stop processing JavaBean"
 443    + " PropertyChangeEvents on the retracted Object" );
 444    }
 445    catch ( IllegalAccessException e )
 446    {
 447  0 System.err.println( "Warning: The removePropertyChangeListener method" + " on the class " + object.getClass( ) + " is not public" + " so Drools will be unable to stop processing JavaBean" + " PropertyChangeEvents on the retracted Object" );
 448    }
 449    catch ( InvocationTargetException e )
 450    {
 451  0 System.err.println( "Warning: The removePropertyChangeL istener method" + " on the class " + object.getClass( ) + " threw an InvocationTargetException" + " so Drools will be unable to stop processing JavaBean"
 452    + " PropertyChangeEvents on the retracted Object: " + e.getMessage( ) );
 453    }
 454    catch ( SecurityException e )
 455    {
 456  0 System.err.println( "Warning: The SecurityManager controlling the class " + object.getClass( ) + " did not allow the lookup of a" + " removePropertyChangeListener method" + " so Drools will be unable to stop processing JavaBean"
 457    + " PropertyChangeEvents on the retracted Object: " + e.getMessage( ) );
 458    }
 459    }
 460   
 461    /**
 462    * Associate an object with its handle.
 463    *
 464    * @param handle
 465    * The handle.
 466    * @param object
 467    * The object.
 468    */
 469  1193 Object putObject(FactHandle handle,
 470    Object object)
 471    {
 472  1193 Object oldValue = this.objects.put( ((FactHandleImpl) handle).getId( ),
 473    object );
 474   
 475  1193 this.handles.put( object,
 476    handle );
 477   
 478  1193 return oldValue;
 479    }
 480   
 481  370 Object removeObject(FactHandle handle)
 482    {
 483  370 Object object = this.objects.remove( ((FactHandleImpl) handle).getId( ) );
 484   
 485  370 this.handles.remove( object );
 486   
 487  370 return object;
 488    }
 489   
 490    /**
 491    * @see WorkingMemory
 492    */
 493  54 public synchronized void retractObject(FactHandle handle) throws FactException
 494    {
 495  54 removePropertyChangeListener( handle );
 496   
 497  54 this.agenda.setMode( Agenda.RETRACT );
 498   
 499  54 ruleBase.retractObject( handle,
 500    this );
 501   
 502  54 Object oldObject = removeObject( handle );
 503   
 504  54 factHandlePool.push( ((FactHandleImpl) handle).getId( ) );
 505   
 506  54 eventSupport.fireObjectRetracted( handle,
 507    oldObject );
 508  54 this.agenda.setMode( Agenda.NONE );
 509   
 510  54 ((FactHandleImpl) handle).invalidate( );
 511    }
 512   
 513    /**
 514    * @see WorkingMemory
 515    */
 516  316 public synchronized void modifyObject(FactHandle handle,
 517    Object object) throws FactException
 518    {
 519  316 Object originalObject = removeObject( handle );
 520   
 521  316 if ( originalObject == null )
 522    {
 523  0 throw new NoSuchFactObjectException( handle );
 524    }
 525   
 526  316 putObject( handle,
 527    object );
 528   
 529  316 this.agenda.setMode( Agenda.MODIFY );
 530   
 531  316 this.ruleBase.retractObject( handle,
 532    this );
 533   
 534  316 this.ruleBase.assertObject( handle,
 535    object,
 536    this );
 537   
 538  316 this.agenda.removeMarkedItemsFromAgenda( );
 539   
 540  316 this.agenda.setMode( Agenda.NONE );
 541   
 542    /*
 543    * this.ruleBase.modifyObject( handle, object, this );
 544    */
 545  316 this.eventSupport.fireObjectModified( handle,
 546    originalObject,
 547    object );
 548    }
 549   
 550    /**
 551    * Retrieve the <code>JoinMemory</code> for a particular
 552    * <code>JoinNode</code>.
 553    *
 554    * @param node
 555    * The <code>JoinNode</code> key.
 556    *
 557    * @return The node's memory.
 558    */
 559  3557 public JoinMemory getJoinMemory(JoinNode node)
 560    {
 561  3557 JoinMemory memory = (JoinMemory) this.joinMemories.get( node );
 562   
 563  3557 if ( memory == null )
 564    {
 565  52 memory = new JoinMemory( node.getTupleDeclarations( ),
 566    node.getCommonDeclarations( ) );
 567   
 568  52 this.joinMemories.put( node,
 569    memory );
 570    }
 571   
 572  3557 return memory;
 573    }
 574   
 575  59894 public WorkingMemoryEventSupport getEventSupport()
 576    {
 577  59894 return eventSupport;
 578    }
 579   
 580    /**
 581    * Sets the AsyncExceptionHandler to handle exceptions thrown by the Agenda
 582    * Scheduler used for duration rules.
 583    *
 584    * @param handler
 585    */
 586  1 public void setAsyncExceptionHandler(AsyncExceptionHandler handler)
 587    {
 588  1 this.agenda.setAsyncExceptionHandler( handler );
 589    }
 590   
 591  0 public void dumpMemory()
 592    {
 593  0 Iterator it = this.joinMemories.keySet( ).iterator( );
 594  0 while ( it.hasNext( ) )
 595    {
 596  0 ((JoinMemory) this.joinMemories.get( it.next( ) )).dump( );
 597    }
 598   
 599    }
 600   
 601  0 public void propertyChange(PropertyChangeEvent event)
 602    {
 603  0 Object object = event.getSource( );
 604   
 605  0 try
 606    {
 607  0 modifyObject( getFactHandle( object ),
 608    object );
 609    }
 610    catch ( NoSuchFactHandleException e )
 611    {
 612    // Not a fact so unable to process the chnage event
 613    }
 614    catch ( FactException e )
 615    {
 616  0 throw new RuntimeException( e.getMessage( ) );
 617    }
 618    }
 619    }