package org.drools.integrationtests;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import junit.framework.TestCase;

import org.drools.Address;
import org.drools.Cheese;
import org.drools.Person;
import org.drools.Primitives;
import org.drools.RuleBase;
import org.drools.RuleBaseConfiguration;
import org.drools.RuleBaseFactory;
import org.drools.StatefulSession;
import org.drools.WorkingMemory;
import org.drools.common.InternalFactHandle;
import org.drools.compiler.PackageBuilder;
import org.drools.rule.Package;
import org.drools.rule.Rule;

public class MarshallingTest extends TestCase {
    public void testSerializable() throws Exception {

        final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_Serializable.drl" ) );

        final PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( reader );
        final Package pkg = serialisePackage( builder.getPackage() );

        assertEquals( 0,
                      builder.getErrors().getErrors().length );

        RuleBase ruleBase = getRuleBase();// RuleBaseFactory.newRuleBase();

        ruleBase.addPackage( pkg );

        Map map = new HashMap();
        map.put( "x",
                 ruleBase );
        final byte[] ast = serializeOut( map );
        map = (Map) serializeIn( ast );
        ruleBase = (RuleBase) map.get( "x" );
        final Rule[] rules = ruleBase.getPackages()[0].getRules();
        assertEquals( 4,
                      rules.length );

        assertEquals( "match Person 1",
                      rules[0].getName() );
        assertEquals( "match Person 2",
                      rules[1].getName() );
        assertEquals( "match Person 3",
                      rules[2].getName() );
        assertEquals( "match Integer",
                      rules[3].getName() );

        WorkingMemory workingMemory = ruleBase.newStatefulSession();

        workingMemory.setGlobal( "list",
                                 new ArrayList() );

        final Person bob = new Person( "bob" );
        workingMemory.insert( bob );

        final byte[] wm = serializeOut( workingMemory );

        workingMemory = ruleBase.newStatefulSession( new ByteArrayInputStream( wm ) );

        assertEquals( 1,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertEquals( bob,
                      IteratorToList.convert( workingMemory.iterateObjects() ).get( 0 ) );

        assertEquals( 2,
                      workingMemory.getAgenda().agendaSize() );

        workingMemory.fireAllRules();

        final List list = (List) workingMemory.getGlobal( "list" );

        assertEquals( 3,
                      list.size() );
        // because of agenda-groups
        assertEquals( new Integer( 4 ),
                      list.get( 0 ) );

        assertEquals( 2,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( bob ) );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( new Person( "help" ) ) );
    }

    public void testSerializeWorkingMemoryAndRuleBase1() throws Exception {
        // has the first newStatefulSession before the ruleBase is serialised
        final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_Serializable.drl" ) );

        final PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( reader );
        final Package pkg = serialisePackage( builder.getPackage() );

        assertEquals( 0,
                      builder.getErrors().getErrors().length );

        RuleBase ruleBase = getRuleBase();// RuleBaseFactory.newRuleBase();

        WorkingMemory workingMemory = ruleBase.newStatefulSession();

        Map map = new HashMap();
        map.put( "x",
                 ruleBase );
        final byte[] ast = serializeOut( map );
        map = (Map) serializeIn( ast );
        ruleBase = (RuleBase) map.get( "x" );

        final byte[] wm = serializeOut( workingMemory );

        workingMemory = ruleBase.newStatefulSession( new ByteArrayInputStream( wm ) );

        ruleBase.addPackage( pkg );

        workingMemory.setGlobal( "list",
                                 new ArrayList() );

        final Person bob = new Person( "bob" );
        workingMemory.insert( bob );

        final Rule[] rules = ruleBase.getPackages()[0].getRules();

        assertEquals( 4,
                      rules.length );

        assertEquals( "match Person 1",
                      rules[0].getName() );
        assertEquals( "match Person 2",
                      rules[1].getName() );
        assertEquals( "match Person 3",
                      rules[2].getName() );
        assertEquals( "match Integer",
                      rules[3].getName() );

        assertEquals( 1,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertEquals( bob,
                      IteratorToList.convert( workingMemory.iterateObjects() ).get( 0 ) );

        assertEquals( 2,
                      workingMemory.getAgenda().agendaSize() );

        workingMemory.fireAllRules();

        final List list = (List) workingMemory.getGlobal( "list" );

        assertEquals( 3,
                      list.size() );
        // because of agenda-groups
        assertEquals( new Integer( 4 ),
                      list.get( 0 ) );

        assertEquals( 2,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( bob ) );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( new Person( "help" ) ) );

    }

    public void testSerializeWorkingMemoryAndRuleBase2() throws Exception {
        // has the first newStatefulSession after the ruleBase is serialised
        final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_Serializable.drl" ) );

        final PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( reader );
        final Package pkg = serialisePackage( builder.getPackage() );

        assertEquals( 0,
                      builder.getErrors().getErrors().length );

        RuleBase ruleBase = getRuleBase();// RuleBaseFactory.newRuleBase();   

        // serialise a hashmap with the RuleBase as a key
        Map map = new HashMap();
        map.put( "x",
                 ruleBase );
        final byte[] ast = serializeOut( map );
        map = (Map) serializeIn( ast );
        ruleBase = (RuleBase) map.get( "x" );

        WorkingMemory workingMemory = ruleBase.newStatefulSession();

        // serialise the working memory before population
        final byte[] wm = serializeOut( workingMemory );
        workingMemory = ruleBase.newStatefulSession( new ByteArrayInputStream( wm ) );

        ruleBase.addPackage( pkg );

        workingMemory.setGlobal( "list",
                                 new ArrayList() );

        final Person bob = new Person( "bob" );
        workingMemory.insert( bob );

        final Rule[] rules = ruleBase.getPackages()[0].getRules();

        assertEquals( 4,
                      rules.length );

        assertEquals( "match Person 1",
                      rules[0].getName() );
        assertEquals( "match Person 2",
                      rules[1].getName() );
        assertEquals( "match Person 3",
                      rules[2].getName() );
        assertEquals( "match Integer",
                      rules[3].getName() );

        assertEquals( 1,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertEquals( bob,
                      IteratorToList.convert( workingMemory.iterateObjects() ).get( 0 ) );

        assertEquals( 2,
                      workingMemory.getAgenda().agendaSize() );

        workingMemory.fireAllRules();

        final List list = (List) workingMemory.getGlobal( "list" );

        assertEquals( 3,
                      list.size() );
        // because of agenda-groups
        assertEquals( new Integer( 4 ),
                      list.get( 0 ) );

        assertEquals( 2,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( bob ) );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( new Person( "help" ) ) );
    }

    public void FIXME_testSerializeWorkingMemoryAndRuleBase3() throws Exception {
        // has the first newStatefulSession after the ruleBase is serialised
        final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_Serializable.drl" ) );

        final PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( reader );
        final Package pkg = serialisePackage( builder.getPackage() );

        assertEquals( 0,
                      builder.getErrors().getErrors().length );

        RuleBase ruleBase = getRuleBase();
        WorkingMemory workingMemory = ruleBase.newStatefulSession();

        ruleBase.addPackage( pkg );

        workingMemory.setGlobal( "list",
                                 new ArrayList() );

        final Person bob = new Person( "bob" );
        workingMemory.insert( bob );

        // serialise a hashmap with the RuleBase as a key, after WM population
        Map map = new HashMap();
        map.put( "x",
                 ruleBase );
        final byte[] ast = serializeOut( map );
        map = (Map) serializeIn( ast );
        ruleBase = (RuleBase) map.get( "x" );

        // now try serialising with a fully populated wm from a serialised rulebase
        final byte[] wm = serializeOut( workingMemory );
        workingMemory = ruleBase.newStatefulSession( new ByteArrayInputStream( wm ) );

        final Rule[] rules = ruleBase.getPackages()[0].getRules();

        assertEquals( 4,
                      rules.length );

        assertEquals( "match Person 1",
                      rules[0].getName() );
        assertEquals( "match Person 2",
                      rules[1].getName() );
        assertEquals( "match Person 3",
                      rules[2].getName() );
        assertEquals( "match Integer",
                      rules[3].getName() );

        assertEquals( 1,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertEquals( bob,
                      IteratorToList.convert( workingMemory.iterateObjects() ).get( 0 ) );

        assertEquals( 2,
                      workingMemory.getAgenda().agendaSize() );

        workingMemory.fireAllRules();

        final List list = (List) workingMemory.getGlobal( "list" );

        assertEquals( 3,
                      list.size() );
        // because of agenda-groups
        assertEquals( new Integer( 4 ),
                      list.get( 0 ) );

        assertEquals( 2,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( bob ) );
        assertTrue( IteratorToList.convert( workingMemory.iterateObjects() ).contains( new Person( "help" ) ) );
    }

    public void testSerializeAdd() throws Exception {

        //Create a rulebase, a session, and test it
        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
        PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic1.drl" ) ) );
        Package pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );

        StatefulSession session = ruleBase.newStatefulSession();
        List list = new ArrayList();
        session.setGlobal( "list",
                           list );

        InternalFactHandle stilton = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                                                                      10 ) );
        InternalFactHandle brie = (InternalFactHandle) session.insert( new Cheese( "brie",
                                                                                   10 ) );
        session.fireAllRules();

        assertEquals( list.size(),
                      1 );
        assertEquals( "stilton",
                      list.get( 0 ) );

        byte[] serializedSession = serializeOut( session );
        session.dispose();

        byte[] serializedRulebase = serializeOut( ruleBase );

        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );

        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        list = (List) session.getGlobal( "list" );

        assertNotNull( list );
        assertEquals( list.size(),
                      1 );
        assertEquals( "stilton",
                      list.get( 0 ) );

        builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic3.drl" ) ) );
        pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );

        InternalFactHandle stilton2 = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                                                                       10 ) );
        InternalFactHandle brie2 = (InternalFactHandle) session.insert( new Cheese( "brie",
                                                                                    10 ) );
        InternalFactHandle bob = (InternalFactHandle) session.insert( new Person( "bob",
                                                                                  30 ) );
        session.fireAllRules();

        assertEquals( list.size(),
                      3 );
        assertEquals( bob.getObject(),
                      list.get( 1 ) );
        assertEquals( "stilton",
                      list.get( 2 ) );

        session.dispose();

    }

    public void testSerializationOfIndexedWM() throws Exception {
        final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_Serializable2.drl" ) );

        final PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( reader );
        final Package pkg = builder.getPackage();

        assertEquals( builder.getErrors().toString(),
                      0,
                      builder.getErrors().getErrors().length );

        RuleBase ruleBase = getRuleBase();// RuleBaseFactory.newRuleBase();

        ruleBase.addPackage( pkg );

        Map map = new HashMap();
        map.put( "x",
                 ruleBase );
        final byte[] ast = serializeOut( map );
        map = (Map) serializeIn( ast );
        ruleBase = (RuleBase) map.get( "x" );
        final Rule[] rules = ruleBase.getPackages()[0].getRules();
        assertEquals( 3,
                      rules.length );

        WorkingMemory workingMemory = ruleBase.newStatefulSession();

        workingMemory.setGlobal( "list",
                                 new ArrayList() );

        final Primitives p = new Primitives();
        p.setBytePrimitive( (byte) 1 );
        p.setShortPrimitive( (short) 2 );
        p.setIntPrimitive( (int) 3 );
        workingMemory.insert( p );

        final byte[] wm = serializeOut( workingMemory );

        workingMemory = ruleBase.newStatefulSession( new ByteArrayInputStream( wm ) );

        assertEquals( 1,
                      IteratorToList.convert( workingMemory.iterateObjects() ).size() );
        assertEquals( p,
                      IteratorToList.convert( workingMemory.iterateObjects() ).get( 0 ) );

        assertEquals( 3,
                      workingMemory.getAgenda().agendaSize() );

        workingMemory.fireAllRules();

        final List list = (List) workingMemory.getGlobal( "list" );

        assertEquals( 3,
                      list.size() );
        // because of agenda-groups
        assertEquals( "1",
                      list.get( 0 ) );
        assertEquals( "2",
                      list.get( 1 ) );
        assertEquals( "3",
                      list.get( 2 ) );

    }

    /*
     *  Here I am inserting data points which are not used by any rule (e.g Person).
     *  Later adding rule (e.g. Rule: 'match Person') for those data points.
     *  
     *  Result: Pkg/Rule addition is failing with ClassCastException
     */
    public void testSerializeAdd2() throws Exception {

        //Create a rulebase, a session, and test it
        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
        PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic1_0.drl" ) ) );
        Package pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );

        List results = new ArrayList();
        StatefulSession session = ruleBase.newStatefulSession();
        session.setGlobal( "results",
                           results );

        InternalFactHandle stilton1 = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                                                                       10 ) );
        session.insert( new Cheese( "brie",
                                    10 ) );
        InternalFactHandle bob = (InternalFactHandle) session.insert( new Person( "bob",
                                                                                  10 ) );

        // fire rules
        session.fireAllRules();
        // check the results are correct
        assertEquals( 1,
                      results.size() );
        assertEquals( stilton1.getObject(),
                      results.get( 0 ) );

        // serialize session and rulebase out
        byte[] serializedSession = serializeOut( session );
        byte[] serializedRulebase = serializeOut( ruleBase );
        session.dispose();

        // now deserialize the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );

        // dynamically add a new package
        builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic3_0.drl" ) ) );
        pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );

        InternalFactHandle stilton2 = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                                                                       20 ) );
        session.insert( new Cheese( "brie",
                                    20 ) );
        InternalFactHandle mark = (InternalFactHandle) session.insert( new Person( "mark",
                                                                                   20 ) );
        session.fireAllRules();

        results = (List) session.getGlobal( "results" );
        assertEquals( 4,
                      results.size() );
        assertEquals( bob.getObject(),
                      results.get( 1 ) );
        assertEquals( stilton2.getObject(),
                      results.get( 2 ) );
        assertEquals( mark.getObject(),
                      results.get( 3 ) );

        serializedSession = null;
        serializedRulebase = null;

        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );

        // dispose session
        session.dispose();

    }

    /*
     *  Here I am inserting data points(e.g. Cheese) with  'stilton' / 'brie' as type value.
     *  Initially I had only 1 rule ('like stilton') for data points(e.g. Cheese) having type as 'stilton'.
     *
     *  Later added new rule ('like brie')  for data points(e.g. Cheese) having type as 'brie'. 
     *  
     *  Result: new rule is not getting fired for new data points having type as 'brie'.
     *          Only for old data points having type as 'brie' the new rule got fired.
     */
    public void testSerializeAdd_newRuleNotFiredForNewData() throws Exception {
        //Create a rulebase, a session, and test it
        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
        PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic1_0.drl" ) ) );
        Package pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );

        List results = new ArrayList();
        StatefulSession session = ruleBase.newStatefulSession();
        session.setGlobal( "results",
                           results );

        InternalFactHandle stilton1 = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                                                                       10 ) );
        InternalFactHandle brie1 = (InternalFactHandle) session.insert( new Cheese( "brie",
                                                                                    10 ) );
        session.fireAllRules();

        byte[] serializedSession = serializeOut( session );
        byte[] serializedRulebase = serializeOut( ruleBase );

        session.dispose();

        assertEquals( 1,
                      results.size() );
        assertEquals( stilton1.getObject(),
                      results.get( 0 ) );

        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        results = (List) session.getGlobal( "results" );

        builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic1_1.drl" ) ) );
        pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );
        
        InternalFactHandle stilton2 = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                    20 ) );
        InternalFactHandle brie2 = (InternalFactHandle) session.insert( new Cheese( "brie",
                                    20 ) );
        InternalFactHandle brie3 = (InternalFactHandle) session.insert( new Cheese( "brie",
                                    30 ) );
        session.fireAllRules();
        assertEquals( 5,
                      results.size() );
        assertEquals( brie1.getObject(),
                      results.get( 1 ) );
        assertEquals( stilton2.getObject(),
                      results.get( 2 ) );
        assertEquals( brie2.getObject(),
                      results.get( 4 ) );
        assertEquals( brie3.getObject(),
                      results.get( 3 ) );

        serializedSession = null;
        serializedRulebase = null;

        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );

        session.dispose();
    }

    /*
     *  Works Fine if both the scenarios mentioned above are skipped. 
     */
    public void testSerializeAdd3() throws Exception {
        //Create a rulebase, a session, and test it
        RuleBase ruleBase = RuleBaseFactory.newRuleBase( );
        PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic1_0.drl" ) ) );
        Package pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );
        
        List results = new ArrayList();
        StatefulSession session = ruleBase.newStatefulSession();
        session.setGlobal( "results",
                           results );

        InternalFactHandle stilton1 = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                                                                       10 ) );
        InternalFactHandle brie1 = (InternalFactHandle) session.insert( new Cheese( "brie",
                                                                                    10 ) );
        session.fireAllRules();

        byte[] serializedSession = serializeOut( session );
        byte[] serializedRulebase = serializeOut( ruleBase );

        session.dispose();

        assertEquals( 1,
                      results.size() );
        assertEquals( stilton1.getObject(),
                      results.get( 0 ) );

        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        results = (List) session.getGlobal( "results" );
        
        builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic3_0.drl" ) ) );
        pkg = serialisePackage( builder.getPackage() );
        
        ruleBase.addPackage( pkg );
        
        InternalFactHandle stilton2 = (InternalFactHandle) session.insert( new Cheese( "stilton", 20 ) );
        InternalFactHandle brie2 = (InternalFactHandle) session.insert( new Cheese( "brie", 20 ) );
        InternalFactHandle bob1 = (InternalFactHandle) session.insert( new Person( "bob", 20 ) );
        InternalFactHandle bob2 = (InternalFactHandle) session.insert( new Person( "bob", 30 ) );
        session.fireAllRules();
 
        assertEquals( 4,
                      results.size() );
        assertEquals( stilton2.getObject(),
                      results.get( 1 ) );
        assertEquals( bob2.getObject(),
                      results.get( 2 ) );
        assertEquals( bob1.getObject(),
                      results.get( 3 ) );

        serializedSession = null;
        serializedRulebase = null;
        
        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );
        
        session.dispose();
        
        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        results = (List) session.getGlobal( "results" );
        
        builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic1_2.drl" ) ) );
        pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );
        
        InternalFactHandle stilton3 = (InternalFactHandle) session.insert( new Cheese( "stilton", 40 ) );
        InternalFactHandle brie3 = (InternalFactHandle) session.insert( new Cheese( "brie", 40 ) );
        InternalFactHandle bob3 = (InternalFactHandle) session.insert( new Person( "bob", 40 ) );
        InternalFactHandle bob4 = (InternalFactHandle) session.insert( new Person( "bob", 40 ) );
        InternalFactHandle addr1 = (InternalFactHandle) session.insert( new Address( "bangalore" ) );
        InternalFactHandle addr2 = (InternalFactHandle) session.insert( new Address( "India" ) );
        
        session.fireAllRules();
 
        assertEquals( 9,
                      results.size() );
        assertEquals( stilton3.getObject(),
                      results.get( 4 ) );
        assertEquals( bob4.getObject(),
                      results.get( 5 ) );
        assertEquals( bob3.getObject(),
                      results.get( 6 ) );
        assertEquals( addr2.getObject(),
                      results.get( 7 ) );
        assertEquals( addr1.getObject(),
                      results.get( 8 ) );

        serializedSession = null;
        serializedRulebase = null;
        
        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );
        
        session.dispose();
        
        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        results = (List) session.getGlobal( "results" );
        
        InternalFactHandle stilton4 = (InternalFactHandle) session.insert( new Cheese( "stilton", 50 ) );
        InternalFactHandle brie4 = (InternalFactHandle) session.insert( new Cheese( "brie", 50 ) );
        InternalFactHandle bob5 = (InternalFactHandle) session.insert( new Person( "bob", 50 ) );
        InternalFactHandle bob6 = (InternalFactHandle) session.insert( new Person( "bob", 50 ) );
        InternalFactHandle addr3 = (InternalFactHandle) session.insert( new Address( "Tripura" ) );
        InternalFactHandle addr4 = (InternalFactHandle) session.insert( new Address( "Agartala" ) );
        
        session.fireAllRules();
 
        assertEquals( 14,
                      results.size() );
        assertEquals( stilton4.getObject(),
                      results.get( 9 ) );
        assertEquals( bob6.getObject(),
                      results.get( 10 ) );
        assertEquals( bob5.getObject(),
                      results.get( 11 ) );
        assertEquals( addr4.getObject(),
                      results.get( 12 ) );
        assertEquals( addr3.getObject(),
                      results.get( 13 ) );

        serializedSession = null;
        serializedRulebase = null;
        
        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );
        
        session.dispose();
       
    }
    
    /*
     * I have tried both the scenarios
     * 1. Remove a rule from a pkg.
     * 2. Remove a pkg
     * 
     * But both cases after inserting associated data points (i.e data points which are used to fire/activate the removed rule)
     * session.fireAllRules() is throwing NoClassDefFoundError
     * 
     */
    public void testSerializeAddRemove_NoClassDefFoundError() throws Exception {

        //Create a rulebase, a session, and test it
        RuleBase ruleBase = RuleBaseFactory.newRuleBase( );
        PackageBuilder builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic1_0.drl" ) ) );
        Package pkg = serialisePackage( builder.getPackage() );
        ruleBase.addPackage( pkg );
        
        List results = new ArrayList();
        StatefulSession session = ruleBase.newStatefulSession();
        session.setGlobal( "results",
                           results );

        InternalFactHandle stilton1 = (InternalFactHandle) session.insert( new Cheese( "stilton",
                                                                                       10 ) );
        InternalFactHandle brie1 = (InternalFactHandle) session.insert( new Cheese( "brie",
                                                                                    10 ) );
        session.fireAllRules();

        byte[] serializedSession = serializeOut( session );
        byte[] serializedRulebase = serializeOut( ruleBase );

        session.dispose();

        assertEquals( 1,
                      results.size() );
        assertEquals( stilton1.getObject(),
                      results.get( 0 ) );

        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        results = (List) session.getGlobal( "results" );
        
        builder = new PackageBuilder();
        builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Dynamic3_0.drl" ) ) );
        pkg = serialisePackage( builder.getPackage() );
        
        ruleBase.addPackage( pkg );
        
        InternalFactHandle stilton2 = (InternalFactHandle) session.insert( new Cheese( "stilton", 20 ) );
        InternalFactHandle brie2 = (InternalFactHandle) session.insert( new Cheese( "brie", 20 ) );
        InternalFactHandle bob1 = (InternalFactHandle) session.insert( new Person( "bob", 20 ) );
        InternalFactHandle bob2 = (InternalFactHandle) session.insert( new Person( "bob", 30 ) );
        session.fireAllRules();
 
        assertEquals( 4,
                      results.size() );
        assertEquals( stilton2.getObject(),
                      results.get( 1 ) );
        assertEquals( bob2.getObject(),
                      results.get( 2 ) );
        assertEquals( bob1.getObject(),
                      results.get( 3 ) );

        serializedSession = null;
        serializedRulebase = null;
        
        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );
        
        session.dispose();
        
        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        results = (List) session.getGlobal( "results" );
       
        // CASE 1: remove rule
        ruleBase.removeRule("org.drools.test", "like stilton");
        
        InternalFactHandle stilton3 = (InternalFactHandle) session.insert( new Cheese( "stilton", 20 ) );
        InternalFactHandle brie3 = (InternalFactHandle) session.insert( new Cheese( "brie", 20 ) );
        InternalFactHandle bob3 = (InternalFactHandle) session.insert( new Person( "bob", 20 ) );
        InternalFactHandle bob4 = (InternalFactHandle) session.insert( new Person( "bob", 30 ) );
        session.fireAllRules();
 
        assertEquals( 6,
                      results.size() );
        assertEquals( bob4.getObject(),
                      results.get( 4 ) );
        assertEquals( bob3.getObject(),
                      results.get( 5 ) );


        // now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) );
        results = (List) session.getGlobal( "results" );
       
        // CASE 2: remove pkg
        ruleBase.removePackage("org.drools.test");
        
        InternalFactHandle stilton4 = (InternalFactHandle) session.insert( new Cheese( "stilton", 20 ) );
        InternalFactHandle brie4 = (InternalFactHandle) session.insert( new Cheese( "brie", 20 ) );
        InternalFactHandle bob5 = (InternalFactHandle) session.insert( new Person( "bob", 20 ) );
        InternalFactHandle bob6 = (InternalFactHandle) session.insert( new Person( "bob", 30 ) );
        session.fireAllRules();
 
        assertEquals( 6,
                      results.size() );
        assertEquals( bob6.getObject(),
                      results.get( 4 ) );
        assertEquals( bob5.getObject(),
                      results.get( 5 ) );
        
        serializedSession = null;
        serializedRulebase = null;
        
        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );
        
        session.dispose();
        
        //=====================  Error Scenario ========================================
        
//      now recreate the rulebase, deserialize the session and test it
        ruleBase = (RuleBase) serializeIn( serializedRulebase );
        session = ruleBase.newStatefulSession( new ByteArrayInputStream( serializedSession ) ); // ClassNotFound Exception
        results = (List) session.getGlobal( "results" );
       
       
        
        InternalFactHandle stilton5 = (InternalFactHandle) session.insert( new Cheese( "stilton", 30 ) );
        InternalFactHandle brie5 = (InternalFactHandle) session.insert( new Cheese( "brie", 30 ) );
        InternalFactHandle bob7 = (InternalFactHandle) session.insert( new Person( "bob", 30 ) );
        InternalFactHandle bob8 = (InternalFactHandle) session.insert( new Person( "bob", 40 ) );
        session.fireAllRules();
 
        assertEquals( 8,
                      results.size() );
        assertEquals( bob7.getObject(),
                      results.get( 6 ) );
        assertEquals( bob8.getObject(),
                      results.get( 7 ) );
        
        serializedSession = null;
        serializedRulebase = null;
        
        serializedSession = serializeOut( session );
        serializedRulebase = serializeOut( ruleBase );
        
        session.dispose();
       
    }
    
    protected RuleBase getRuleBase() throws Exception {

        return RuleBaseFactory.newRuleBase( RuleBase.RETEOO,
                                            null );
    }

    protected RuleBase getRuleBase(final RuleBaseConfiguration config) throws Exception {

        return RuleBaseFactory.newRuleBase( RuleBase.RETEOO,
                                            config );
    }

    protected Package serialisePackage(Package pkg) {
        try {
            byte[] bytes = serializeOut( pkg );
            return (Package) serializeIn( bytes );
        } catch ( Exception e ) {
            throw new RuntimeException( "trouble serialising package.",
                                        e );
        }
    }

    protected Object serializeIn(final byte[] bytes) throws IOException,
                                                    ClassNotFoundException {
        final ObjectInput in = new ObjectInputStream( new ByteArrayInputStream( bytes ) );
        final Object obj = in.readObject();
        in.close();
        return obj;
    }

    protected byte[] serializeOut(final Object obj) throws IOException {
        // Serialize to a byte array
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        final ObjectOutput out = new ObjectOutputStream( bos );
        out.writeObject( obj );
        out.close();

        // Get the bytes of the serialized object
        final byte[] bytes = bos.toByteArray();
        return bytes;
    }
}