From: <jbo...@li...> - 2006-05-02 12:36:06
|
Author: bagerman Date: 2006-05-02 08:35:52 -0400 (Tue, 02 May 2006) New Revision: 4039 Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/util/BaseTableReverseOrderIterator.java Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/LeapsTest.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactHandleImpl.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactTable.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/Handle.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/HandleFactory.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/LeapsTuple.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleBaseImpl.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleHandle.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/TokenEvaluator.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/WorkingMemoryImpl.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/util/BaseTableIterator.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/util/ConstrainedFactTableIterator.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/util/Table.java labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/util/TokenStack.java Log: 1. Modify Leaps locking strategy to follow RETEoo 2. Iterate facts for not and exists in reverse order Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -1,5 +1,4 @@ package org.drools.compiler; - /* * Copyright 2005 JBoss Inc * @@ -16,10 +15,11 @@ * limitations under the License. */ + + import java.io.IOException; import java.io.Reader; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -27,8 +27,8 @@ import org.apache.commons.jci.compilers.CompilationResult; import org.apache.commons.jci.compilers.JavaCompiler; import org.apache.commons.jci.compilers.JavaCompilerFactory; -import org.apache.commons.jci.readers.ResourceReader; import org.apache.commons.jci.readers.MemoryResourceReader; +import org.apache.commons.jci.readers.ResourceReader; import org.apache.commons.jci.stores.ResourceStore; import org.drools.lang.descr.FunctionDescr; import org.drools.lang.descr.PackageDescr; @@ -45,15 +45,15 @@ import org.xml.sax.SAXException; public class PackageBuilder { - private JavaCompiler compiler; + private JavaCompiler compiler; - private Package pkg; + private Package pkg; - private List results; + private List results; - private PackageStore packageStoreWrapper; + private PackageStore packageStoreWrapper; - private MemoryResourceReader src; + private MemoryResourceReader src; private PackageBuilderConfiguration configuration; @@ -72,20 +72,21 @@ if ( configuration == null ) { configuration = new PackageBuilderConfiguration(); } - - this.compiler = getCompiler( configuration.getCompiler() ); - - this.configuration = configuration; - + + this.compiler = JavaCompilerFactory.getInstance().createCompiler( configuration.getCompiler() ); + + this.configuration = configuration; + this.src = new MemoryResourceReader(); this.results = new ArrayList(); this.pkg = pkg; + if ( pkg != null ) { this.packageStoreWrapper = new PackageStore( pkg.getPackageCompilationData() ); - } + } } /** @@ -94,22 +95,20 @@ * @throws DroolsParserException * @throws IOException */ - public void addPackageFromDrl(Reader reader) throws DroolsParserException, - IOException { + public void addPackageFromDrl(Reader reader) throws DroolsParserException, IOException { DrlParser parser = new DrlParser(); PackageDescr pkg = parser.parse( reader ); this.results.addAll( parser.getErrors() ); addPackage( pkg ); } - + /** * Load a rule package from XML source. * @param reader * @throws DroolsParserException * @throws IOException */ - public void addPackageFromXml(Reader reader) throws DroolsParserException, - IOException { + public void addPackageFromXml(Reader reader) throws DroolsParserException, IOException { XmlPackageReader xmlReader = new XmlPackageReader(); try { @@ -119,7 +118,7 @@ } addPackage( xmlReader.getPackageDescr() ); - } + } /** * Load a rule package from DRL source using the supplied DSL configuration. @@ -129,22 +128,20 @@ * @throws IOException */ public void addPackageFromDrl(Reader source, - Reader dsl) throws DroolsParserException, - IOException { + Reader dsl) throws DroolsParserException, IOException { DrlParser parser = new DrlParser(); - PackageDescr pkg = parser.parse( source, - dsl ); + PackageDescr pkg = parser.parse( source, dsl ); this.results.addAll( parser.getErrors() ); addPackage( pkg ); - } - + } + public void addPackage(PackageDescr packageDescr) { - if ( packageDescr.getName() == null || "".equals( packageDescr.getName() ) ) { - - throw new MissingPackageNameException( "Missing package name for rule package." ); + if (packageDescr.getName() == null || "".equals(packageDescr.getName())) { + + throw new MissingPackageNameException("Missing package name for rule package."); } - + if ( this.pkg != null ) { //mergePackage( packageDescr ) ; mergePackage( this.pkg, @@ -195,7 +192,7 @@ try { clazz = typeResolver.resolveType( className ); pkg.addGlobal( identifier, - clazz ); + clazz ); } catch ( ClassNotFoundException e ) { new GlobalError( identifier ); } @@ -206,9 +203,9 @@ String text, MemoryResourceReader src, ResourceStore dst) { - src.add( className.replace( '.', - '/' ) + ".java", - text.getBytes() ); + src.addFile( className.replace( '.', + '/' ) + ".java", + text.toCharArray() ); CompilationResult result = compiler.compile( new String[]{className}, src, dst, @@ -220,16 +217,15 @@ private void addFunction(FunctionDescr functionDescr) { FunctionBuilder buidler = new FunctionBuilder(); CompilationResult result = compile( this.pkg.getName() + "." + ucFirst( functionDescr.getName() ), - buidler.build( this.pkg, - functionDescr ), + buidler.build( this.pkg, functionDescr ), src, this.packageStoreWrapper ); - + if ( result.getErrors().length > 0 ) { this.results.add( new FunctionError( functionDescr, result.getErrors(), "Function Compilation error" ) ); - } + } } private void addRule(RuleDescr ruleDescr) { @@ -251,17 +247,16 @@ // Check if there is any code to compile. If so compile it. if ( builder.getRuleClass() != null ) { - compileRule( builder, - rule, + compileRule( builder, + rule, ruleDescr ); } + this.pkg.addRule( rule ); } - - public void compileRule(RuleBuilder builder, - Rule rule, - RuleDescr ruleDescr) { + + public void compileRule(RuleBuilder builder, Rule rule, RuleDescr ruleDescr) { // The compilation result is for th entire rule, so difficult to associate with any descr CompilationResult result = compile( this.pkg.getName() + "." + ruleDescr.getClassName(), builder.getRuleClass(), @@ -274,10 +269,10 @@ result.getErrors(), "Rule Compilation error" ) ); } else { - + for ( Iterator it = builder.getInvokers().keySet().iterator(); it.hasNext(); ) { String className = (String) it.next(); - + // Check if an invoker - returnvalue, predicate, eval or consequence has been associated // If so we add it to the PackageCompilationData as it will get wired up on compilation Object invoker = builder.getInvokerLookups().get( className ); @@ -286,14 +281,14 @@ invoker ); } String text = (String) builder.getInvokers().get( className ); - + //System.out.println( className + ":\n" + text ); - + result = compile( className, text, src, this.packageStoreWrapper ); - + if ( result.getErrors().length > 0 ) { PatternDescr descr = (PatternDescr) builder.getDescrLookups().get( className ); this.results.add( new RuleError( rule, @@ -301,8 +296,8 @@ result.getErrors(), "Rule Compilation error for Invoker" ) ); } - } - } + } + } } /** @@ -313,7 +308,7 @@ * Compiled packages are serializable. */ public Package getPackage() { - if ( hasErrors() ) { + if (hasErrors()) { this.pkg.setError( this.printErrors() ); } return this.pkg; @@ -339,12 +334,12 @@ StringBuffer buf = new StringBuffer(); for ( Iterator iter = this.results.iterator(); iter.hasNext(); ) { DroolsError err = (DroolsError) iter.next(); - buf.append( err.getMessage() ); + buf.append(err.getMessage()); buf.append( "\n" ); } return buf.toString(); } - + /** * Takes a given name and makes sure that its legal and doesn't already exist. If the file exists it increases counter appender untill it is unique. * @@ -358,8 +353,7 @@ String ext, ResourceReader src) { // replaces all non alphanumeric or $ chars with _ - String newName = "Rule_" + name.replaceAll( "[^\\w$]", - "_" ); + String newName = "Rule_" + name.replaceAll( "[^\\w$]", "_" ); // make sure the class name does not exist, if it does increase the counter int counter = -1; @@ -380,16 +374,6 @@ return newName; } - private JavaCompiler getCompiler(int compiler) { - switch ( compiler ) { - case PackageBuilderConfiguration.JANINO : - return JavaCompilerFactory.getInstance().createCompiler( "janino" ); - case PackageBuilderConfiguration.ECLIPSE : - default : - return JavaCompilerFactory.getInstance().createCompiler( "eclipse" ); - } - } - private String ucFirst(String name) { return name.toUpperCase().charAt( 0 ) + name.substring( 1 ); } @@ -397,8 +381,9 @@ public static class MissingPackageNameException extends IllegalArgumentException { public MissingPackageNameException(String message) { - super( message ); + super(message); } - + } + } \ No newline at end of file Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/LeapsTest.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/LeapsTest.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/LeapsTest.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -22,10 +22,8 @@ import java.util.List; import org.drools.Cheese; -import org.drools.FactHandle; import org.drools.QueryResults; import org.drools.RuleBase; -import org.drools.Sensor; import org.drools.WorkingMemory; import org.drools.compiler.PackageBuilder; import org.drools.rule.Package; @@ -128,7 +126,4 @@ public void testLogicalAssertions2() throws Exception { // Not working in leaps } - - public void testEmptyColumn() throws Exception { - } } Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -0,0 +1,354 @@ +package org.drools.common; + +/* + * Copyright 2005 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import org.drools.FactException; +import org.drools.PackageIntegrationException; +import org.drools.RuleBase; +import org.drools.RuleIntegrationException; +import org.drools.WorkingMemory; +import org.drools.rule.CompositePackageClassLoader; +import org.drools.rule.InvalidPatternException; +import org.drools.rule.Package; +import org.drools.rule.PackageCompilationData; +import org.drools.rule.Rule; +import org.drools.spi.FactHandleFactory; + +/** + * Implementation of <code>RuleBase</code>. + * + * @author <a href="mailto:bo...@we...">bob mcwhirter</a> + * @author <a href="mailto:mar...@jb...">Mark Proctor</a> + * + * @version $Id: RuleBaseImpl.java,v 1.5 2005/08/14 22:44:12 mproctor Exp $ + */ +abstract public class AbstractRuleBase + implements + RuleBase, + Externalizable { + // ------------------------------------------------------------ + // Instance members + // ------------------------------------------------------------ + + private Map pkgs; + + private transient CompositePackageClassLoader packageClassLoader; + + /** The fact handle factory. */ + private FactHandleFactory factHandleFactory; + + private Map globals; + + // @todo: replace this with a weak HashSet + /** + * WeakHashMap to keep references of WorkingMemories but allow them to be + * garbage collected + */ + private transient Map workingMemories; + + /** Special value when adding to the underlying map. */ + private static final Object PRESENT = new Object(); + + // ------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------ + + /** + * Construct. + * + * @param rete + * The rete network. + */ + public AbstractRuleBase(FactHandleFactory factHandleFactory) { + this.factHandleFactory = factHandleFactory; + + this.packageClassLoader = new CompositePackageClassLoader( Thread.currentThread().getContextClassLoader() ); + this.pkgs = new HashMap(); + this.globals = new HashMap(); + this.workingMemories = new WeakHashMap(); + } + + /** + * Handles the write serialization of the Package. Patterns in Rules may + * reference generated data which cannot be serialized by default methods. + * The Package uses PackageCompilationData to hold a reference to the + * generated bytecode. The generated bytecode must be restored before any + * Rules. + * + */ + public void writeExternal(ObjectOutput stream) throws IOException { + stream.writeObject( this.pkgs ); + + // Rules must be restored by an ObjectInputStream that can resolve using a given ClassLoader to handle seaprately by storing as + // a byte[] + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutput out = new ObjectOutputStream( bos ); + out.writeObject( this.factHandleFactory ); + out.writeObject( this.globals ); + + stream.writeObject( bos.toByteArray() ); + } + /** + * Handles the read serialization of the Package. Patterns in Rules may + * reference generated data which cannot be serialized by default methods. + * The Package uses PackageCompilationData to hold a reference to the + * generated bytecode; which must be restored before any Rules. A custom + * ObjectInputStream, able to resolve classes against the bytecode in the + * PackageCompilationData, is used to restore the Rules. + * + */ + public void readExternal( ObjectInput stream ) throws IOException, + ClassNotFoundException { + // PackageCompilationData must be restored before Rules as it has the + // ClassLoader needed to resolve the generated code references in Rules + this.pkgs = (Map) stream.readObject( ); + + this.packageClassLoader = new CompositePackageClassLoader( Thread.currentThread( ) + .getContextClassLoader( ) ); + for (Iterator it = this.pkgs.values( ).iterator( ); it.hasNext( );) { + this.packageClassLoader.addClassLoader( ( (Package) it.next( ) ).getPackageCompilationData( ) + .getClassLoader( ) ); + } + + // Return the rules stored as a byte[] + byte[] bytes = (byte[]) stream.readObject( ); + + // Use a custom ObjectInputStream that can resolve against a given + // classLoader + ObjectInputStreamWithLoader streamWithLoader = new ObjectInputStreamWithLoader( new ByteArrayInputStream( bytes ), + this.packageClassLoader ); + + this.factHandleFactory = (FactHandleFactory) streamWithLoader.readObject( ); + this.globals = (Map) streamWithLoader.readObject( ); + + this.workingMemories = new WeakHashMap( ); + } + + // ------------------------------------------------------------ + // Instance methods + // ------------------------------------------------------------ + + /** + * @see RuleBase + */ + public WorkingMemory newWorkingMemory() { + return newWorkingMemory( true ); + } + + /** + * @see RuleBase + */ + abstract public WorkingMemory newWorkingMemory(boolean keepReference); + + public void disposeWorkingMemory(WorkingMemory workingMemory) { + this.workingMemories.remove( workingMemory ); + } + + /** + * @see RuleBase + */ + public FactHandleFactory getFactHandleFactory() { + return this.factHandleFactory; + } + + public FactHandleFactory newFactHandleFactory() { + return this.factHandleFactory.newInstance(); + } + + public Package[] getPackages() { + return (Package[]) this.pkgs.values().toArray( new Package[this.pkgs.size()] ); + } + + public Map getGlobals() { + return this.globals; + } + + /** + * Add a <code>Package</code> to the network. Iterates through the + * <code>Package</code> adding Each individual <code>Rule</code> to the + * network. Before update network each referenced <code>WorkingMemory</code> + * is locked. + * + * @param pkg + * The package to add. + * @throws PackageIntegrationException + * + * @throws RuleIntegrationException + * if an error prevents complete construction of the network for + * the <code>Rule</code>. + * @throws FactException + * @throws InvalidPatternException + */ + public void addPackage(Package newPkg) throws PackageIntegrationException { + newPkg.checkValidity(); + Package pkg = (Package) this.pkgs.get( newPkg.getName() ); + + // Iterate each workingMemory and lock it + // This is so we don't update the Rete network during propagation + for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) it.next(); + workingMemory.getLock().lock(); + } + + if ( pkg != null ) { + mergePackage( pkg, + newPkg ); + } else { + this.pkgs.put( newPkg.getName(), + newPkg ); + } + + Map newGlobals = newPkg.getGlobals(); + + // Check that the global data is valid, we cannot change the type + // of an already declared global variable + for ( Iterator it = newGlobals.keySet().iterator(); it.hasNext(); ) { + String identifier = (String) it.next(); + Class type = (Class) newGlobals.get( identifier ); + if ( this.globals.containsKey( identifier ) && !this.globals.get( identifier ).equals( type ) ) { + throw new PackageIntegrationException( pkg ); + } + } + this.globals.putAll( newGlobals ); + + Rule[] rules = newPkg.getRules(); + + for ( int i = 0; i < rules.length; ++i ) { + addRule( rules[i] ); + } + + this.packageClassLoader.addClassLoader( newPkg.getPackageCompilationData().getClassLoader() ); + + // Iterate each workingMemory and attempt to fire any rules, that were activated as a result + // of the new rule addition. Unlock after fireAllRules(); + for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) it.next(); + + workingMemory.fireAllRules(); + workingMemory.getLock().unlock(); + } + } + + private void mergePackage(Package pkg, + Package newPkg) throws PackageIntegrationException { + Map globals = pkg.getGlobals(); + List imports = pkg.getImports(); + + // First update the binary files + // @todo: this probably has issues if you add classes in the incorrect order - functions, rules, invokers. + PackageCompilationData compilationData = pkg.getPackageCompilationData(); + PackageCompilationData newCompilationData = newPkg.getPackageCompilationData(); + String[] files = newCompilationData.list(); + for ( int i = 0, length = files.length; i < length; i++ ) { + compilationData.write( files[i], + newCompilationData.read( files[i] ) ); + } + + // Merge imports + imports.addAll( newPkg.getImports() ); + + // Add invokers + compilationData.putAllInvokers( newCompilationData.getInvokers() ); + + // Add globals + for ( Iterator it = globals.keySet().iterator(); it.hasNext(); ) { + String identifier = (String) it.next(); + Class type = (Class) globals.get( identifier ); + if ( globals.containsKey( identifier ) && !globals.get( identifier ).equals( type ) ) { + throw new PackageIntegrationException( "Unable to merge new Package", + newPkg ); + } + } + } + + protected void addRule(Rule rule) throws InvalidPatternException { + if ( !rule.isValid() ) { + throw new IllegalArgumentException( "The rule called " + rule.getName() + " is not valid. Check for compile errors reported." ); + } + } + + public void removePackage(String packageName) { + Package pkg = (Package) this.pkgs.get( packageName ); + // Iterate each workingMemory and lock it + // This is so we don't update the Rete network during propagation + for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) it.next(); + workingMemory.getLock().lock(); + } + + Rule[] rules = pkg.getRules(); + + for ( int i = 0; i < rules.length; ++i ) { + removeRule( rules[i] ); + } + + this.packageClassLoader.removeClassLoader( pkg.getPackageCompilationData().getClassLoader() ); + + pkg.clear(); + + // Iterate and unlock + for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) it.next(); + workingMemory.getLock().unlock(); + } + } + + public void removeRule(String packageName, + String ruleName) { + Package pkg = (Package) this.pkgs.get( packageName ); + Rule rule = pkg.getRule( ruleName ); + // Iterate each workingMemory and lock it + // This is so we don't update the Rete network during propagation + for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) it.next(); + workingMemory.getLock().lock(); + } + removeRule( rule ); + pkg.removeRule( rule ); + + // Iterate and unlock + for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) it.next(); + workingMemory.getLock().unlock(); + } + } + + abstract protected void removeRule(Rule rule); + + protected void addWorkingMemory( WorkingMemory workingMemory, boolean keepReference ) { + if (keepReference) { + this.workingMemories.put( workingMemory, PRESENT ); + } + } + public Set getWorkingMemories() { + return this.workingMemories.keySet(); + } +} Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -47,6 +47,8 @@ import org.drools.util.IdentityMap; import org.drools.util.PrimitiveLongMap; import org.drools.util.PrimitiveLongStack; +import org.drools.util.concurrent.locks.Lock; +import org.drools.util.concurrent.locks.ReentrantLock; /** * Implementation of <code>WorkingMemory</code>. @@ -55,43 +57,45 @@ * @author <a href="mailto:si...@re...">Simon Harris </a> * @author <a href="mailto:bag...@gm...">Alexander Bagerman </a> */ -abstract public class AbstractWorkingMemory - implements - WorkingMemory, - InternalWorkingMemoryActions, - EventSupport, - PropertyChangeListener { +abstract public class AbstractWorkingMemory implements WorkingMemory, + InternalWorkingMemoryActions, EventSupport, PropertyChangeListener { // ------------------------------------------------------------ // Constants // ------------------------------------------------------------ - private static final Class[] ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES = new Class[]{PropertyChangeListener.class}; + private static final Class[] ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES = new Class[] { PropertyChangeListener.class }; // ------------------------------------------------------------ // Instance members // ------------------------------------------------------------ /** The arguments used when adding/removing a property change listener. */ - protected final Object[] addRemovePropertyChangeListenerArgs = new Object[]{this}; + protected final Object[] addRemovePropertyChangeListenerArgs = new Object[] { this }; /** Global values which are associated with this memory. */ - private final Map globals = new HashMap(); + private final Map globals = new HashMap( ); /** Object-to-handle mapping. */ - protected final Map identityMap = new IdentityMap(); - protected final Map equalsMap = new HashMap(); + protected final Map identityMap = new IdentityMap( ); + protected final Map equalsMap = new HashMap( ); + protected final PrimitiveLongMap justified = new PrimitiveLongMap( 8, 32 ); - private final PrimitiveLongStack factHandlePool = new PrimitiveLongStack(); + private final PrimitiveLongStack factHandlePool = new PrimitiveLongStack( ); + protected static final String STATED = "STATED"; + protected static final String JUSTIFIED = "JUSTIFIED"; + protected static final String NEW = "NEW"; + protected static final FactStatus STATUS_NEW = new FactStatus( NEW, - 0 ); + 0 ); /** The eventSupport */ protected final WorkingMemoryEventSupport workingMemoryEventSupport = new WorkingMemoryEventSupport( this ); + protected final AgendaEventSupport agendaEventSupport = new AgendaEventSupport( this ); /** The <code>RuleBase</code> with which this memory is associated. */ @@ -100,12 +104,14 @@ protected final FactHandleFactory handleFactory; /** Rule-firing agenda. */ - // protected final Agenda agenda; + // protected final Agenda agenda; /** Flag to determine if a rule is currently being fired. */ protected boolean firing; protected long propagationIdCounter; + private ReentrantLock lock = new ReentrantLock( ); + public AbstractWorkingMemory(RuleBase ruleBase, FactHandleFactory handleFactory) { this.ruleBase = ruleBase; @@ -421,6 +427,10 @@ } } + public Lock getLock() { + return this.lock; + } + protected static class FactStatus { private int counter; private String status; Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactHandleImpl.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactHandleImpl.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactHandleImpl.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -15,11 +15,9 @@ * limitations under the License. */ -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Set; import org.drools.FactHandle; import org.drools.common.InternalFactHandle; @@ -33,62 +31,56 @@ public class FactHandleImpl extends Handle implements InternalFactHandle { - private Set activatedTuples = null; + private List activatedTuples = null; - private List notTuples = null; + private List notTuples = null; - private List existsTuples = null; + private List existsTuples = null; /** * actual object that is asserted to the system no getters just a direct * access to speed things up */ - public FactHandleImpl(long id, - Object object) { - super( id, - object ); + public FactHandleImpl(long id, Object object) { + super( id, object ); } - protected final void addActivatedTuple(LeapsTuple tuple) { - if ( this.activatedTuples == null ) { - this.activatedTuples = new HashSet(); + protected void addActivatedTuple( LeapsTuple tuple ) { + if (this.activatedTuples == null) { + this.activatedTuples = new LinkedList( ); } this.activatedTuples.add( tuple ); } - protected final void addNotTuple(LeapsTuple tuple, - int index) { - if ( this.notTuples == null ) { - this.notTuples = new LinkedList(); + protected void addNotTuple( LeapsTuple tuple, int index ) { + if (this.notTuples == null) { + this.notTuples = new LinkedList( ); } - this.notTuples.add( new FactHandleTupleAssembly( tuple, - index ) ); + this.notTuples.add( new FactHandleTupleAssembly( tuple, index ) ); } - protected final void addExistsTuple(LeapsTuple tuple, - int index) { - if ( this.existsTuples == null ) { - this.existsTuples = new LinkedList(); + protected void addExistsTuple( LeapsTuple tuple, int index ) { + if (this.existsTuples == null) { + this.existsTuples = new LinkedList( ); } - this.existsTuples.add( new FactHandleTupleAssembly( tuple, - index ) ); + this.existsTuples.add( new FactHandleTupleAssembly( tuple, index ) ); } - protected final Iterator getActivatedTuples() { + protected Iterator getActivatedTuples() { if ( this.activatedTuples != null ) { return this.activatedTuples.iterator(); } return null; } - protected final Iterator getNotTupleAssemblies() { + protected Iterator getNotTupleAssemblies() { if ( this.notTuples != null ) { return this.notTuples.iterator(); } return null; } - protected final Iterator getExistsTupleAssemblies() { + protected Iterator getExistsTupleAssemblies() { if ( this.existsTuples != null ) { return this.existsTuples.iterator(); } Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactTable.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactTable.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/FactTable.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -15,9 +15,8 @@ * limitations under the License. */ -import java.util.HashSet; import java.util.Iterator; -import java.util.Set; +import java.util.LinkedList; import org.drools.common.PropagationContextImpl; import org.drools.leaps.util.Table; @@ -47,7 +46,7 @@ * Tuples that are either already on agenda or are very close (missing * exists or have not facts matching) */ - private final Set tuples; + private final LinkedList tuples; /** * initializes base LeapsTable with appropriate Comparator and positive and @@ -59,7 +58,7 @@ public FactTable(ConflictResolver conflictResolver) { super( conflictResolver.getFactConflictResolver() ); this.rules = new RuleTable( conflictResolver.getRuleConflictResolver() ); - this.tuples = new HashSet(); + this.tuples = new LinkedList(); } /** @@ -165,15 +164,11 @@ return ret.toString(); } - Iterator getTuplesIterator() { + protected Iterator getTuplesIterator() { return this.tuples.iterator(); } - boolean addTuple(LeapsTuple tuple) { - return this.tuples.add( tuple ); + protected void addTuple(LeapsTuple tuple) { + this.tuples.add( tuple ); } - - void removeTuple(LeapsTuple tuple) { - this.tuples.remove( tuple ); - } } \ No newline at end of file Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/Handle.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/Handle.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/Handle.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -26,9 +26,7 @@ * @author Alexander Bagerman * */ -public class Handle - implements - Serializable { +public class Handle implements Serializable { private static final long serialVersionUID = 1L; // object to handle Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/HandleFactory.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/HandleFactory.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/HandleFactory.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -22,14 +22,12 @@ * @author Alexander Bagerman * */ -class HandleFactory - implements - FactHandleFactory { +class HandleFactory implements FactHandleFactory { private static final long serialVersionUID = 8510623248591449450L; private long counter; - HandleFactory() { + protected HandleFactory() { this.counter = 0L; } @@ -49,9 +47,8 @@ * @param object * @return leaps handle */ - public final FactHandle newFactHandle(Object object) { - return new FactHandleImpl( this.getNextId(), - object ); + public final FactHandle newFactHandle( Object object ) { + return new FactHandleImpl( this.getNextId( ), object ); } /** Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/LeapsTuple.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/LeapsTuple.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/LeapsTuple.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -20,12 +20,10 @@ import org.drools.FactHandle; import org.drools.common.InternalFactHandle; -import org.drools.common.LogicalDependency; import org.drools.rule.Declaration; import org.drools.spi.Activation; import org.drools.spi.PropagationContext; import org.drools.spi.Tuple; -import org.drools.util.LinkedList; /** * Leaps Tuple implementation @@ -49,8 +47,6 @@ private final LeapsRule leapsRule; - private LinkedList justified; - /** * agendaItem parts */ @@ -83,7 +79,7 @@ * * @return rule */ - LeapsRule getLeapsRule() { + protected LeapsRule getLeapsRule() { return this.leapsRule; } @@ -141,11 +137,11 @@ * * @return indicator if agendaItem was null'ed */ - boolean isActivationNull() { + protected boolean isActivationNull() { return this.activation == null; } - Activation getActivation() { + protected Activation getActivation() { return this.activation; } @@ -184,7 +180,7 @@ * * @return */ - boolean isReadyForActivation() { + protected boolean isReadyForActivation() { return this.readyForActivation; } @@ -214,31 +210,32 @@ return buffer.toString(); } - void setBlockingNotFactHandle(FactHandleImpl factHandle, + protected void setBlockingNotFactHandle(FactHandleImpl factHandle, int index) { this.readyForActivation = false; this.blockingNotFactHandles[index] = factHandle; } - boolean isBlockingNotFactHandle(int index ) { + protected boolean isBlockingNotFactHandle(int index ) { return this.blockingNotFactHandles[index] != null; } - void removeBlockingNotFactHandle(int index) { + + protected void removeBlockingNotFactHandle(int index) { this.blockingNotFactHandles[index] = null; this.setReadyForActivation(); } - void setExistsFactHandle(FactHandleImpl factHandle, + protected void setExistsFactHandle(FactHandleImpl factHandle, int index) { this.existsFactHandles[index] = factHandle; this.setReadyForActivation(); } - boolean isExistsFactHandle(int index) { + protected boolean isExistsFactHandle(int index) { return this.existsFactHandles[index] != null; } - void removeExistsFactHandle(int index) { + protected void removeExistsFactHandle(int index) { this.existsFactHandles[index] = null; this.setReadyForActivation(); } @@ -265,22 +262,10 @@ } } - PropagationContext getContext() { + protected PropagationContext getContext() { return this.context; } - public void addLogicalDependency(LogicalDependency node) { - if ( this.justified == null ) { - this.justified = new LinkedList(); - } - - this.justified.add( node ); - } - - public LinkedList getLogicalDependencies() { - return this.justified; - } - protected void setContext( PropagationContext context ) { this.context = context; } Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleBaseImpl.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleBaseImpl.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleBaseImpl.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -16,21 +16,18 @@ */ import java.io.IOException; -import java.io.ObjectInputStream; +import java.io.ObjectInput; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; import org.drools.FactException; import org.drools.PackageIntegrationException; import org.drools.RuleBase; import org.drools.WorkingMemory; +import org.drools.common.AbstractRuleBase; import org.drools.rule.InvalidPatternException; -import org.drools.rule.Package; -import org.drools.rule.PackageCompilationData; import org.drools.rule.Rule; import org.drools.spi.FactHandleFactory; @@ -41,32 +38,12 @@ * @author Alexander Bagerman * */ -public class RuleBaseImpl - implements - RuleBase { - private static final long serialVersionUID = 1487738104393155409L; +public class RuleBaseImpl extends AbstractRuleBase { + private static final long serialVersionUID = 1487738104393155409L; - private transient Map leapsRules; + private Map leapsRules; /** - * The fact handle factory. - */ - private final FactHandleFactory factHandleFactory; - - private transient Map globalDeclarations; - - private final Map rulesPackages; - - /** - * WeakHashMap to keep references of WorkingMemories but allow them to be - * garbage collected - */ - private transient Map workingMemories; - - /** Special value when adding to the underlying map. */ - private static final Object PRESENT = new Object(); - - /** * Construct. * * @param rete @@ -92,12 +69,7 @@ * @throws Exception */ public RuleBaseImpl(FactHandleFactory factHandleFactory) { - // casting to make sure that it's leaps handle factory - this.factHandleFactory = (HandleFactory) factHandleFactory; - this.globalDeclarations = new HashMap(); - this.workingMemories = new WeakHashMap(); - - this.rulesPackages = new HashMap(); + super (factHandleFactory); this.leapsRules = new HashMap(); } @@ -111,130 +83,19 @@ /** * @see RuleBase */ - public WorkingMemory newWorkingMemory(boolean keepReference) { + public WorkingMemory newWorkingMemory( boolean keepReference ) { WorkingMemoryImpl workingMemory = new WorkingMemoryImpl( this ); // add all rules added so far - for ( Iterator it = this.leapsRules.values().iterator(); it.hasNext(); ) { - workingMemory.addLeapsRules( (List) it.next() ); + for (Iterator it = this.leapsRules.values( ).iterator( ); it.hasNext( );) { + workingMemory.addLeapsRules( (List) it.next( ) ); } // - if ( keepReference ) { - this.workingMemories.put( workingMemory, - RuleBaseImpl.PRESENT ); - } + super.addWorkingMemory( workingMemory, keepReference ); + return workingMemory; } - void disposeWorkingMemory(WorkingMemory workingMemory) { - this.workingMemories.remove( workingMemory ); - } - /** - * @see RuleBase - */ - public FactHandleFactory getFactHandleFactory() { - return this.factHandleFactory; - } - - /** - * returns NEW fact handle factory because each working memory needs the new - * one - * - * @see RuleBase - */ - public FactHandleFactory newFactHandleFactory() { - return this.factHandleFactory.newInstance(); - } - - /** - * @see RuleBase - */ - - public Package[] getPackages() { - return (Package[]) this.rulesPackages.values().toArray( new Package[this.rulesPackages.size()] ); - } - - public Map getGlobalDeclarations() { - return this.globalDeclarations; - } - - /** - * Add a <code>Package</code> to the network. Iterates through the - * <code>Package</code> adding Each individual <code>Rule</code> to the - * network. - * - * @param rulesPackage - * The rule-set to add. - * @throws PackageIntegrationException - * - * @throws FactException - * @throws InvalidPatternException - */ - public void addPackage(Package newPackage) throws PackageIntegrationException { - newPackage.checkValidity(); - Package pkg = (Package) this.rulesPackages.get( newPackage.getName() ); - if ( pkg != null ) { - mergePackage( pkg, - newPackage ); - } else { - this.rulesPackages.put( newPackage.getName(), - newPackage ); - } - - Map newGlobals = newPackage.getGlobals(); - - // Check that the global data is valid, we cannot change the type - // of an already declared global variable - for ( Iterator it = newGlobals.keySet().iterator(); it.hasNext(); ) { - String identifier = (String) it.next(); - Class type = (Class) newGlobals.get( identifier ); - if ( this.globalDeclarations.containsKey( identifier ) && !this.globalDeclarations.get( identifier ).equals( type ) ) { - throw new PackageIntegrationException( pkg ); - } - } - this.globalDeclarations.putAll( newGlobals ); - - Rule[] rules = newPackage.getRules(); - - for ( int i = 0; i < rules.length; ++i ) { - addRule( rules[i] ); - } - } - - public void mergePackage(Package existingPackage, - Package newPackage) throws PackageIntegrationException { - Map globals = existingPackage.getGlobals(); - List imports = existingPackage.getImports(); - - // First update the binary files - // @todo: this probably has issues if you add classes in the incorrect - // order - functions, rules, invokers. - PackageCompilationData compilationData = existingPackage.getPackageCompilationData(); - PackageCompilationData newCompilationData = newPackage.getPackageCompilationData(); - String[] files = newCompilationData.list(); - for ( int i = 0, length = files.length; i < length; i++ ) { - compilationData.write( files[i], - newCompilationData.read( files[i] ) ); - } - - // Merge imports - imports.addAll( newPackage.getImports() ); - - // Add invokers - compilationData.putAllInvokers( newCompilationData.getInvokers() ); - - // Add globals - for ( Iterator it = globals.keySet().iterator(); it.hasNext(); ) { - String identifier = (String) it.next(); - Class type = (Class) globals.get( identifier ); - if ( globals.containsKey( identifier ) && !globals.get( identifier ).equals( type ) ) { - throw new PackageIntegrationException( "Unable to merge new Package", - newPackage ); - } - } - } - - /** * Creates leaps rule wrappers and propagate rule to the working memories * * @param rule @@ -243,57 +104,46 @@ */ public void addRule(Rule rule) throws FactException, InvalidPatternException { - if ( !rule.isValid() ) { - throw new IllegalArgumentException( "The rule called " + rule.getName() + " is not valid. Check for compile errors reported." ); - } + super.addRule(rule); + List rules = Builder.processRule( rule ); this.leapsRules.put( rule, rules ); - for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + for ( Iterator it = this.getWorkingMemories().iterator(); it.hasNext(); ) { ((WorkingMemoryImpl) it.next()).addLeapsRules( rules ); } // Iterate each workingMemory and attempt to fire any rules, that were // activated as a result of the new rule addition - for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + for ( Iterator it = this.getWorkingMemories().iterator(); it.hasNext(); ) { WorkingMemoryImpl workingMemory = (WorkingMemoryImpl) it.next(); workingMemory.fireAllRules(); } } public void removeRule(Rule rule) { - for ( Iterator it = this.workingMemories.keySet().iterator(); it.hasNext(); ) { + for ( Iterator it = this.getWorkingMemories().iterator(); it.hasNext(); ) { ((WorkingMemoryImpl) it.next()).removeRule( (List) this.leapsRules.remove( rule ) ); } } - public Set getWorkingMemories() { - return this.workingMemories.keySet(); - } - /** - * This is to allow the RuleBase to be serializable. + * Handles the read serialization of the Package. Patterns in Rules may reference generated data which cannot be serialized by default methods. + * The Package uses PackageCompilationData to hold a reference to the generated bytecode; which must be restored before any Rules. + * A custom ObjectInputStream, able to resolve classes against the bytecode in the PackageCompilationData, is used to restore the Rules. + * */ - private void readObject(ObjectInputStream is) throws ClassNotFoundException, - IOException, - Exception { - //always perform the default de-serialization first - is.defaultReadObject(); + public void readExternal(ObjectInput stream) throws IOException, + ClassNotFoundException { + super.readExternal(stream); - this.leapsRules = new HashMap(); - this.globalDeclarations = new HashMap(); - this.workingMemories = new WeakHashMap(); + for (int i = 0; i < this.getPackages( ).length; i++) { + Rule[] rules = this.getPackages( )[i].getRules(); - Package[] packages = this.getPackages(); - this.rulesPackages.clear(); - for ( int i = 0; i < packages.length; i++ ) { - this.addPackage( packages[i] ); - Rule[] rules = packages[i].getRules(); - - for ( int k = 0; k < rules.length; k++ ) { - addRule( rules[k] ); + for ( int j = 0; j < rules.length; ++j ) { + addRule( rules[j] ); } } } Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleHandle.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleHandle.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/RuleHandle.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -28,11 +28,8 @@ // ce position for which handle is created private final int dominantPosition; - public RuleHandle(long id, - LeapsRule rule, - int dominantPosition) { - super( id, - rule ); + public RuleHandle(long id, LeapsRule rule, int dominantPosition) { + super( id, rule ); this.dominantPosition = dominantPosition; } @@ -67,14 +64,16 @@ /** * @see java.lang.Object */ - public boolean equals(Object that) { - return super.equals( that ) && (this.getDominantPosition() == ((RuleHandle) that).getDominantPosition()); + public boolean equals( Object that ) { + return super.equals( that ) + && ( this.getDominantPosition( ) == ( (RuleHandle) that ).getDominantPosition( ) ); } /** * @see java.lang.Object */ public String toString() { - return "R-" + this.getId() + " \"" + this.getLeapsRule().toString() + "\" [pos - " + this.dominantPosition + "]"; + return "R-" + this.getId( ) + " \"" + this.getLeapsRule( ).toString( ) + + "\" [pos - " + this.dominantPosition + "]"; } -} \ No newline at end of file +} Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/TokenEvaluator.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/TokenEvaluator.java 2006-05-02 09:42:31 UTC (rev 4038) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/leaps/TokenEvaluator.java 2006-05-02 12:35:52 UTC (rev 4039) @@ -181,37 +181,33 @@ * @return * @throws Exception */ - final static boolean processAfterAllPositiveConstraintOk(LeapsTuple tuple, + final static boolean processAfterAllPositiveConstraintOk( LeapsTuple tuple, LeapsRule leapsRule, - WorkingMemoryImpl workingMemory) { - if ( leapsRule.containsEvalConditions() && !TokenEvaluator.evaluateEvalConditions( leapsRule, - tuple, - workingMemory ) ) { + WorkingMemoryImpl workingMemory ) { + if (leapsRule.containsEvalConditions( ) + && !TokenEvaluator.evaluateEvalConditions( leapsRule, tuple, workingMemory )) { return false; } - if ( leapsRule.containsExistsColumns() ) { - TokenEvaluator.evaluateExistsConditions( tuple, - leapsRule, - workingMemory ); + if (leapsRule.containsExistsColumns( )) { + TokenEvaluator.evaluateExistsConditions( tuple, leapsRule, workingMemory ); } - if ( leapsRule.containsNotColumns() ) { - TokenEvaluator.evaluateNotConditions( tuple, - leapsRule, - workingMemory ); + if (leapsRule.containsNotColumns( )) { + TokenEvaluator.evaluateNotConditions( tuple, leapsRule, workingMemory ); } // put tuple onto fact tables that might affect activation status // via exists or not conditions - Class[] classes = leapsRule.getExistsNotColumnsClasses(); - for ( int i = 0, length = classes.length; i < length; i++ ) { + Class[] classes = leapsRule.getExistsNotColumnsClasses( ); + for (int i = 0, length = classes.length; i < length; i++) { workingMemory.getFactTable( classes[i] ).addTuple( tuple ); } // - if ( tuple.isReadyForActivation() ) { + if (tuple.isReadyForActivation( )) { // let agenda to do its work ... [truncated message content] |