Package org.drools.compiler.factmodel.traits

Source Code of org.drools.compiler.factmodel.traits.TraitTest

/*
* Copyright 2011 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.
*/

package org.drools.compiler.factmodel.traits;

import org.drools.compiler.CommonTestMethodBase;
import org.drools.compiler.Person;
import org.drools.core.RuleBaseConfiguration;
import org.drools.core.common.InternalFactHandle;
import org.drools.core.common.InternalWorkingMemoryEntryPoint;
import org.drools.core.common.ObjectTypeConfigurationRegistry;
import org.drools.core.factmodel.traits.Entity;
import org.drools.core.factmodel.traits.LogicalTypeInconsistencyException;
import org.drools.core.factmodel.traits.MapWrapper;
import org.drools.core.factmodel.traits.Thing;
import org.drools.core.factmodel.traits.Trait;
import org.drools.core.factmodel.traits.TraitFactory;
import org.drools.core.factmodel.traits.TraitProxy;
import org.drools.core.factmodel.traits.TraitRegistry;
import org.drools.core.factmodel.traits.TraitTypeMap;
import org.drools.core.factmodel.traits.Traitable;
import org.drools.core.factmodel.traits.TraitableBean;
import org.drools.core.factmodel.traits.TripleBasedBean;
import org.drools.core.factmodel.traits.TripleBasedStruct;
import org.drools.core.factmodel.traits.VirtualPropertyMode;
import org.drools.core.impl.KnowledgeBaseImpl;
import org.drools.core.io.impl.ByteArrayResource;
import org.drools.core.io.impl.ClassPathResource;
import org.drools.core.reteoo.ObjectTypeConf;
import org.drools.core.util.CodedHierarchyImpl;
import org.drools.core.util.HierarchyEncoder;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.command.Command;
import org.kie.api.definition.type.FactType;
import org.kie.api.event.rule.AfterMatchFiredEvent;
import org.kie.api.event.rule.AgendaEventListener;
import org.kie.api.event.rule.DebugAgendaEventListener;
import org.kie.api.event.rule.RuleRuntimeEventListener;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.ClassObjectFilter;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.command.CommandFactory;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.runtime.StatefulKnowledgeSession;
import org.kie.internal.runtime.StatelessKnowledgeSession;
import org.mockito.ArgumentCaptor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.*;

@RunWith(Parameterized.class)
public class TraitTest extends CommonTestMethodBase {

    private static long t0;


    public VirtualPropertyMode mode;

    @Parameterized.Parameters
    public static Collection modes() {
        return Arrays.asList( new VirtualPropertyMode[][]
                                      {
                                              { VirtualPropertyMode.MAP },
                                              { VirtualPropertyMode.TRIPLES }
                                      } );
    }

    public TraitTest( VirtualPropertyMode m ) {
        this.mode = m;
    }





    private StatefulKnowledgeSession getSession( String... ruleFiles ) {
        KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        for (String file : ruleFiles) {
            knowledgeBuilder.add( ResourceFactory.newClassPathResource( file ),
                                  ResourceType.DRL );
        }
        if (knowledgeBuilder.hasErrors()) {
            throw new RuntimeException( knowledgeBuilder.getErrors().toString() );
        }

        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages( knowledgeBuilder.getKnowledgePackages() );

        StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession();
        return session;
    }

    private StatefulKnowledgeSession getSessionFromString( String drl ) {
        KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        knowledgeBuilder.add( ResourceFactory.newByteArrayResource( drl.getBytes() ),
                              ResourceType.DRL );
        if (knowledgeBuilder.hasErrors()) {
            throw new RuntimeException( knowledgeBuilder.getErrors().toString() );
        }

        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages( knowledgeBuilder.getKnowledgePackages() );

        StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession();
        return session;
    }

    private KnowledgeBase getKieBaseFromString( String drl, RuleBaseConfiguration... conf ) {
        KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        knowledgeBuilder.add( ResourceFactory.newByteArrayResource( drl.getBytes() ),
                              ResourceType.DRL );
        if (knowledgeBuilder.hasErrors()) {
            throw new RuntimeException( knowledgeBuilder.getErrors().toString() );
        }

        KnowledgeBase kbase = conf.length > 0 ? KnowledgeBaseFactory.newKnowledgeBase( conf[0] ) : KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages( knowledgeBuilder.getKnowledgePackages() );

        return kbase;
    }




    @Test
    public void testTraitWrapGetAndSet() {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kb );
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();

        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            Class trait = kb.getFactType( "org.drools.compiler.trait.test",
                                          "Student" ).getFactClass();

            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );

            Map<String, Object> virtualFields = imp._getDynamicProperties();
            Map<String, Object> wrapper = proxy.getFields();

            wrapper.put( "name",
                         "john" );

            wrapper.put( "virtualField",
                         "xyz" );

            wrapper.entrySet();
            assertEquals( 4,
                          wrapper.size() );
            assertEquals( 2,
                          virtualFields.size() );

            assertEquals( "john",
                          wrapper.get( "name" ) );
            assertEquals( "xyz",
                          wrapper.get( "virtualField" ) );

            assertEquals( "john",
                          impClass.get( imp,
                                        "name" ) );

        } catch (Exception e) {
            e.printStackTrace();
            fail( e.getMessage() );
        }

    }



    @Test
    public void testTraitShed() {
        String source = "org/drools/compiler/factmodel/traits/testTraitShed.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );


        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        assertTrue( info.isEmpty() );

        ks.fireAllRules();

        assertTrue( info.contains( "Student" ) );
        assertEquals( 1,
                      info.size() );

        ks.insert( "hire" );
        ks.fireAllRules();

        Collection c = ks.getObjects();

        assertTrue( info.contains( "Worker" ) );
        assertEquals( 2,
                      info.size() );

        ks.insert( "check" );
        ks.fireAllRules();

        assertEquals( 4,
                      info.size() );
        assertTrue( info.contains( "Conflict" ) );
        assertTrue( info.contains( "Nothing" ) );

    }



    @Test
    public void testTraitDon() {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();

        Collection<? extends Object> wm = ks.getObjects();

        ks.insert( "go" );
        ks.fireAllRules();

        assertTrue( info.contains( "DON" ) );
        assertTrue( info.contains( "SHED" ) );

        Iterator it = wm.iterator();
        Object x = it.next();
        if ( x instanceof String ) {
            x = it.next();
        }

        System.out.println( x.getClass() );
        System.out.println( x.getClass().getSuperclass() );
        System.out.println( Arrays.asList( x.getClass().getInterfaces() ));
    }





    @Test
    public void testMixin() {
        String source = "org/drools/compiler/factmodel/traits/testTraitMixin.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();

        assertTrue( info.contains( "27" ) );

    }


    @Test
    public void traitMethodsWithObjects() {
        String source = "org/drools/compiler/factmodel/traits/testTraitWrapping.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List errors = new ArrayList();
        ks.setGlobal( "list",
                      errors );

        ks.fireAllRules();

        if (!errors.isEmpty()) {
            System.err.println( errors.toString() );
        }
        Assert.assertTrue( errors.isEmpty() );

    }


    @Test
    public void traitMethodsWithPrimitives() {
        String source = "org/drools/compiler/factmodel/traits/testTraitWrappingPrimitives.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List errors = new ArrayList();
        ks.setGlobal( "list",
                      errors );

        ks.fireAllRules();

        if (!errors.isEmpty()) {
            System.err.println( errors );
        }
        Assert.assertTrue( errors.isEmpty() );

    }


    @Test
    public void testTraitProxy() {

        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );
        TraitFactory.setMode( mode, kb );
        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();

        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            impClass.set( imp,
                          "name",
                          "aaa" );

            Class trait = kb.getFactType( "org.drools.compiler.trait.test",
                                          "Student" ).getFactClass();
            Class trait2 = kb.getFactType( "org.drools.compiler.trait.test",
                                           "Role" ).getFactClass();

            assertNotNull( trait );
            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );
            proxy.getFields().put( "field",
                                   "xyz" );
            //            proxy.getFields().put("name", "aaa");

            assertNotNull( proxy );

            TraitProxy proxy2 = (TraitProxy) tFactory.getProxy( imp,
                                                                trait );
            assertSame( proxy2,
                        proxy );

            TraitProxy proxy3 = (TraitProxy) tFactory.getProxy( imp,
                                                                trait2 );
            assertNotNull( proxy3 );
            assertEquals( "xyz",
                          proxy3.getFields().get( "field" ) );
            assertEquals( "aaa",
                          proxy3.getFields().get( "name" ) );

            TraitableBean imp2 = (TraitableBean) impClass.newInstance();
            impClass.set( imp2,
                          "name",
                          "aaa" );
            TraitProxy proxy4 = (TraitProxy) tFactory.getProxy( imp2,
                                                                trait );
            //            proxy4.getFields().put("name", "aaa");
            proxy4.getFields().put( "field",
                                    "xyz" );

            Assert.assertEquals( proxy2,
                                 proxy4 );

        } catch (InstantiationException e) {
            e.printStackTrace();
            fail( e.getMessage() );
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            fail( e.getMessage() );
        } catch ( LogicalTypeInconsistencyException e ) {
            e.printStackTrace();
            fail( e.getMessage() );
        }
    }


    @Test
    public void testWrapperSize() {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        TraitFactory.setMode( mode, kb );
        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();


        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            FactType traitClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                  "Student" );
            Class trait = traitClass.getFactClass();
            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );

            Map<String, Object> virtualFields = imp._getDynamicProperties();
            Map<String, Object> wrapper = proxy.getFields();
            assertEquals( 3,
                          wrapper.size() );
            assertEquals( 1,
                          virtualFields.size() );

            impClass.set(imp,
                         "name",
                         "john");
            assertEquals( 3,
                          wrapper.size() );
            assertEquals( 1,
                          virtualFields.size() );

            proxy.getFields().put( "school",
                                   "skol" );
            assertEquals( 3,
                          wrapper.size() );
            assertEquals( 1,
                          virtualFields.size() );

            proxy.getFields().put( "surname",
                                   "xxx" );
            assertEquals( 4,
                          wrapper.size() );
            assertEquals( 2,
                          virtualFields.size() );

            //            FactType indClass = kb.getFactType("org.drools.compiler.trait.test","Entity");
            //            TraitableBean ind = (TraitableBean) indClass.newInstance();
            TraitableBean ind = new Entity();

            TraitProxy proxy2 = (TraitProxy) tFactory.getProxy( ind,
                                                                trait );

            Map virtualFields2 = ind._getDynamicProperties();
            Map wrapper2 = proxy2.getFields();
            assertEquals( 3,
                          wrapper2.size() );
            assertEquals( 3,
                          virtualFields2.size() );

            traitClass.set( proxy2,
                            "name",
                            "john" );
            assertEquals( 3,
                          wrapper2.size() );
            assertEquals( 3,
                          virtualFields2.size() );

            proxy2.getFields().put( "school",
                                    "skol" );
            assertEquals( 3,
                          wrapper2.size() );
            assertEquals( 3,
                          virtualFields2.size() );

            proxy2.getFields().put( "surname",
                                    "xxx" );
            assertEquals( 4,
                          wrapper2.size() );
            assertEquals( 4,
                          virtualFields2.size() );

            FactType traitClass2 = kb.getFactType( "org.drools.compiler.trait.test",
                                                   "Role" );
            Class trait2 = traitClass2.getFactClass();
            //            TraitableBean ind2 = (TraitableBean) indClass.newInstance();
            TraitableBean ind2 = new Entity();

            TraitProxy proxy99 = (TraitProxy) tFactory.getProxy( ind2,
                                                                 trait2 );

            proxy99.getFields().put( "surname",
                                     "xxx" );
            proxy99.getFields().put( "name",
                                     "xyz" );
            proxy99.getFields().put( "school",
                                     "skol" );

            assertEquals( 3,
                          proxy99.getFields().size() );

            TraitProxy proxy100 = (TraitProxy) tFactory.getProxy( ind2,
                                                                  trait );

            assertEquals( 4,
                          proxy100.getFields().size() );

        } catch ( Exception e ) {
            e.printStackTrace();
            fail( e.getMessage() );
        }

    }



    @Test
    public void testWrapperEmpty() {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );
        TraitFactory.setMode( mode, kb );

        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();

        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();

            FactType studentClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                    "Student" );
            Class trait = studentClass.getFactClass();
            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );

            Map<String, Object> virtualFields = imp._getDynamicProperties();
            Map<String, Object> wrapper = proxy.getFields();
            assertFalse( wrapper.isEmpty() );

            studentClass.set( proxy,
                              "name",
                              "john" );
            assertFalse( wrapper.isEmpty() );
            studentClass.set( proxy,
                              "name",
                              null );
            assertFalse( wrapper.isEmpty() );

            studentClass.set( proxy,
                              "age",
                              32 );
            assertFalse( wrapper.isEmpty() );

            studentClass.set( proxy,
                              "age",
                              null );
            assertFalse( wrapper.isEmpty() );

            //            FactType indClass = kb.getFactType("org.drools.compiler.trait.test","Entity");
            TraitableBean ind = new Entity();

            FactType RoleClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                 "Role" );
            Class trait2 = RoleClass.getFactClass();
            TraitProxy proxy2 = (TraitProxy) tFactory.getProxy( ind,
                                                                trait2 );

            Map<String, Object> wrapper2 = proxy2.getFields();
            assertTrue( wrapper2.isEmpty() );

            proxy2.getFields().put( "name",
                                    "john" );
            assertFalse( wrapper2.isEmpty() );

            proxy2.getFields().put( "name",
                                    null );
            assertFalse( wrapper2.isEmpty() );

        } catch (Exception e) {
            e.printStackTrace();
            fail( e.getMessage() );
        }

    }



    @Test
    public void testWrapperContainsKey() {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );


        TraitFactory.setMode( mode, kb );
        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();

        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            impClass.set( imp,
                          "name",
                          "john" );

            FactType traitClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                  "Student" );
            Class trait = traitClass.getFactClass();
            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );

            Map<String, Object> virtualFields = imp._getDynamicProperties();
            Map<String, Object> wrapper = proxy.getFields();

            assertTrue( wrapper.containsKey( "name" ) );
            assertTrue( wrapper.containsKey( "school" ) );
            assertTrue( wrapper.containsKey( "age" ) );
            assertFalse( wrapper.containsKey( "surname" ) );

            proxy.getFields().put( "school",
                                   "skol" );
            proxy.getFields().put( "surname",
                                   "xxx" );
            assertTrue( wrapper.containsKey( "surname" ) );

            //            FactType indClass = kb.getFactType("org.drools.compiler.trait.test","Entity");
            TraitableBean ind = new Entity();

            TraitProxy proxy2 = (TraitProxy) tFactory.getProxy( ind,
                                                                trait );

            Map virtualFields2 = ind._getDynamicProperties();
            Map wrapper2 = proxy2.getFields();
            assertTrue( wrapper2.containsKey( "name" ) );
            assertTrue( wrapper2.containsKey( "school" ) );
            assertTrue( wrapper2.containsKey( "age" ) );
            assertFalse( wrapper2.containsKey( "surname" ) );

            traitClass.set( proxy2,
                            "name",
                            "john" );
            proxy2.getFields().put( "school",
                                    "skol" );
            proxy2.getFields().put( "surname",
                                    "xxx" );
            assertTrue( wrapper2.containsKey( "surname" ) );

            FactType traitClass2 = kb.getFactType( "org.drools.compiler.trait.test",
                                                   "Role" );
            Class trait2 = traitClass2.getFactClass();
            TraitableBean ind2 = new Entity();

            TraitProxy proxy99 = (TraitProxy) tFactory.getProxy( ind2,
                                                                 trait2 );
            Map<String, Object> wrapper99 = proxy99.getFields();

            assertFalse( wrapper99.containsKey( "name" ) );
            assertFalse( wrapper99.containsKey( "school" ) );
            assertFalse( wrapper99.containsKey( "age" ) );
            assertFalse( wrapper99.containsKey( "surname" ) );

            proxy99.getFields().put( "surname",
                                     "xxx" );
            proxy99.getFields().put( "name",
                                     "xyz" );
            proxy99.getFields().put( "school",
                                     "skol" );

            assertTrue( wrapper99.containsKey( "name" ) );
            assertTrue( wrapper99.containsKey( "school" ) );
            assertFalse( wrapper99.containsKey( "age" ) );
            assertTrue( wrapper99.containsKey( "surname" ) );
            assertEquals( 3,
                          proxy99.getFields().size() );

            TraitableBean ind0 = new Entity();

            TraitProxy proxy100 = (TraitProxy) tFactory.getProxy( ind0,
                                                                  trait2 );
            Map<String, Object> wrapper100 = proxy100.getFields();
            assertFalse( wrapper100.containsKey( "name" ) );
            assertFalse( wrapper100.containsKey( "school" ) );
            assertFalse( wrapper100.containsKey( "age" ) );
            assertFalse( wrapper100.containsKey( "surname" ) );

            TraitProxy proxy101 = (TraitProxy) tFactory.getProxy( ind0,
                                                                  trait );
            // object gains properties by virtue of another trait
            // so new props are accessible even using the old proxy
            assertTrue( wrapper100.containsKey( "name" ) );
            assertTrue( wrapper100.containsKey( "school" ) );
            assertTrue( wrapper100.containsKey( "age" ) );
            assertFalse( wrapper100.containsKey( "surname" ) );

        } catch (Exception e) {
            e.printStackTrace();
            fail( e.getMessage() );
        }

    }


    @Test
    public void testInternalComponents1(  ) {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        TraitFactory.setMode( mode, kb );
        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();


        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            FactType traitClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                  "Student" );
            Class trait = traitClass.getFactClass();
            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );
            Object proxyFields = proxy.getFields();
            Object coreTraits = imp._getTraitMap();
            Object coreProperties = imp._getDynamicProperties();

            assertTrue( proxy.getObject() instanceof TraitableBean );

            assertNotNull( proxyFields );
            assertNotNull( coreTraits );
            assertNotNull( coreProperties );

            if ( mode == VirtualPropertyMode.MAP ) {
                assertTrue( proxyFields instanceof MapWrapper );
                assertTrue( coreTraits instanceof TraitTypeMap );
                assertTrue( coreProperties instanceof HashMap );
            } else {
                assertEquals( "org.drools.compiler.trait.test.Student.org.drools.compiler.trait.test.Imp_ProxyWrapper", proxyFields.getClass().getName() );

                assertTrue(proxyFields instanceof TripleBasedStruct );
                assertTrue( coreTraits instanceof TraitTypeMap);
                assertTrue( coreProperties instanceof TripleBasedBean );
            }


            StudentProxy2 sp2 = new StudentProxy2( new Imp2(), null );
            System.out.println( sp2.toString() );

        } catch ( Exception e ) {
            e.printStackTrace();
            fail( e.getMessage() );
        }
    }




    @Test
    public void testWrapperKeySetAndValues() {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );
        TraitFactory.setMode( mode, kb );

        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();

        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            FactType traitClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                  "Student" );
            Class trait = traitClass.getFactClass();
            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );

            impClass.set( imp,
                          "name",
                          "john" );
            proxy.getFields().put( "surname",
                                   "xxx" );
            proxy.getFields().put( "name2",
                                   "john" );
            proxy.getFields().put( "nfield",
                                   null );

            Set set = new HashSet();
            set.add( "name" );
            set.add( "surname" );
            set.add( "age" );
            set.add( "school" );
            set.add( "name2" );
            set.add( "nfield" );

            assertEquals( 6,
                          proxy.getFields().keySet().size() );
            assertEquals( set,
                          proxy.getFields().keySet() );

            Collection col1 = proxy.getFields().values();
            Collection col2 = Arrays.asList( "john",
                                             null,
                                             0,
                                             "xxx",
                                             "john",
                                             null );

            Comparator comp = new Comparator() {

                public int compare( Object o1, Object o2 ) {
                    if (o1 == null && o2 != null) {
                        return 1;
                    }
                    if (o1 != null && o2 == null) {
                        return -1;
                    }
                    if (o1 == null && o2 == null) {
                        return 0;
                    }
                    return o1.toString().compareTo( o2.toString() );
                }
            };

            Collections.sort( (List) col1,
                              comp );
            Collections.sort( (List) col2,
                              comp );
            assertEquals( col1,
                          col2 );

            assertTrue( proxy.getFields().containsValue( null ) );
            assertTrue( proxy.getFields().containsValue( "john" ) );
            assertTrue( proxy.getFields().containsValue( 0 ) );
            assertTrue( proxy.getFields().containsValue( "xxx" ) );
            assertFalse( proxy.getFields().containsValue( "randomString" ) );
            assertFalse( proxy.getFields().containsValue( -96 ) );

        } catch (Exception e) {
            e.printStackTrace();
            fail( e.getMessage() );
        }

    }



    @Test
    public void testWrapperClearAndRemove() {
        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull( res );
        kbuilder.add( res,
                      ResourceType.DRL );
        if (kbuilder.hasErrors()) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages( kbuilder.getKnowledgePackages() );
        TraitFactory.setMode( mode, kb );
        TraitFactory tFactory = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();

        try {
            FactType impClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                "Imp" );
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            impClass.set( imp,
                          "name",
                          "john" );
            FactType traitClass = kb.getFactType( "org.drools.compiler.trait.test",
                                                  "Student" );
            Class trait = traitClass.getFactClass();
            TraitProxy proxy = (TraitProxy) tFactory.getProxy( imp,
                                                               trait );

            proxy.getFields().put( "surname",
                                   "xxx" );
            proxy.getFields().put( "name2",
                                   "john" );
            proxy.getFields().put( "nfield",
                                   null );

            Set set = new HashSet();
            set.add( "name" );
            set.add( "surname" );
            set.add( "age" );
            set.add( "school" );
            set.add( "name2" );
            set.add( "nfield" );

            assertEquals( 6,
                          proxy.getFields().keySet().size() );
            assertEquals( set,
                          proxy.getFields().keySet() );

            proxy.getFields().clear();

            Map<String, Object> fields = proxy.getFields();
            assertEquals( 3,
                          fields.size() );
            assertTrue( fields.containsKey( "age" ) );
            assertTrue( fields.containsKey( "school" ) );
            assertTrue( fields.containsKey( "name" ) );

            assertEquals( 0,
                          fields.get( "age" ) );
            assertNull( fields.get( "school" ) );
            assertNotNull( fields.get( "name" ) );

            proxy.getFields().put( "surname",
                                   "xxx" );
            proxy.getFields().put( "name2",
                                   "john" );
            proxy.getFields().put( "nfield",
                                   null );
            proxy.getFields().put( "age",
                                   24 );

            assertEquals( "john",
                          proxy.getFields().get( "name" ) );
            assertEquals( "xxx",
                          proxy.getFields().get( "surname" ) );
            assertEquals( "john",
                          proxy.getFields().get( "name2" ) );
            assertEquals( null,
                          proxy.getFields().get( "nfield" ) );
            assertEquals( 24,
                          proxy.getFields().get( "age" ) );
            assertEquals( null,
                          proxy.getFields().get( "school" ) );

            proxy.getFields().remove( "surname" );
            proxy.getFields().remove( "name2" );
            proxy.getFields().remove( "age" );
            proxy.getFields().remove( "school" );
            proxy.getFields().remove( "nfield" );
            assertEquals( 3,
                          proxy.getFields().size() );

            assertEquals( 0,
                          proxy.getFields().get( "age" ) );
            assertEquals( null,
                          proxy.getFields().get( "school" ) );
            assertEquals( "john",
                          proxy.getFields().get( "name" ) );

            assertEquals( null,
                          proxy.getFields().get( "nfield" ) );
            assertFalse( proxy.getFields().containsKey( "nfield" ) );

            assertEquals( null,
                          proxy.getFields().get( "name2" ) );
            assertFalse( proxy.getFields().containsKey( "name2" ) );

            assertEquals( null,
                          proxy.getFields().get( "surname" ) );
            assertFalse( proxy.getFields().containsKey( "surname" ) );

        } catch (Exception e) {
            e.printStackTrace();
            fail( e.getMessage() );
        }

    }





    @Test
    public void testIsAEvaluator( ) {
        String source = "package org.drools.compiler.trait.test;\n" +
                        "\n" +
                        "import org.drools.core.factmodel.traits.Traitable;\n" +
                        "import org.drools.core.factmodel.traits.Entity;\n" +
                        "import org.drools.core.factmodel.traits.Thing;\n" +
                        "\n" +
                        "global java.util.List list;\n" +
                        "\n" +
                        "\n" +
                        "declare Imp\n" +
                        "    @Traitable\n" +
                        "    name    : String        @key\n" +
                        "end\n" +
                        "\n" +
                        "declare trait Person\n" +
                        "    name    : String \n" +
                        "    age     : int   \n" +
                        "end\n" +
                        "  \n" +
                        "declare trait Worker\n" +
                        "    job     : String\n" +
                        "end\n" +
                        " \n" +
                        "\n" +
                        " \n" +
                        " \n" +
                        "rule \"Init\"\n" +
                        "when\n" +
                        "then\n" +
                        "    Imp core = new Imp( \"joe\" );\n" +
                        "    insert( core );\n" +
                        "    don( core, Person.class );\n" +
                        "    don( core, Worker.class );\n" +
                        "\n" +
                        "    Imp core2 = new Imp( \"adam\" );\n" +
                        "    insert( core2 );\n" +
                        "    don( core2, Worker.class );\n" +
                        "end\n" +
                        "\n" +
                        "rule \"Mod\"\n" +
                        "when\n" +
                        "    $p : Person( name == \"joe\" )\n" +
                        "then\n" +
                        "    modify ($p) { setName( \"john\" ); }\n" +
                        "end\n" +
                        "\n" +
                        "rule \"Worker Students v6\"\n" +
                        "when\n" +
                        "    $x2 := Person( name == \"john\" )\n" +
                        "    $x1 := Worker( core != $x2.core, this not isA $x2 )\n" +
                        "then\n" +
                        "    list.add( \"ok\" );\n" +
                        "end\n" +
                        "\n" +
                        "\n";

        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();

        System.out.println( info );
        assertTrue( info.contains( "ok" ) );
    }



    @Test
    public void testIsA() {
        String source = "org/drools/compiler/factmodel/traits/testTraitIsA.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();


        int num = 10;

        System.out.println( info );
        assertEquals( num,
                      info.size() );
        for (int j = 0; j < num; j++) {
            assertTrue( info.contains( "" + j ) );
        }

    }



    @Test
    public void testOverrideType() {
        String source = "org/drools/compiler/factmodel/traits/testTraitOverride.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        try {
            ks.fireAllRules();
            fail( "An exception was expected since a trait can't override the type of a core class field with these settings " );
        } catch ( Throwable rde ) {
            assertTrue( rde.getCause() instanceof UnsupportedOperationException );
        }
    }




    @Test
    public void testOverrideType2( ) {
        String drl = "package org.drools.compiler.trait.test; \n" +
                     "import org.drools.core.factmodel.traits.Traitable; \n" +
                     "" +
                     "declare Foo @Traitable end\n" +
                     "declare trait Bar end \n" +
                     "" +
                     "declare trait Mask fld : Foo end \n" +
                     "declare Face @Traitable fld : Bar end \n" +
                     "" +
                     "rule Don when then\n" +
                     "  Face face = new Face(); \n" +
                     "  don( face, Mask.class ); \n" +
                     "end\n";

        StatefulKnowledgeSession ks = getSessionFromString( drl );
        TraitFactory.setMode( mode, ks.getKieBase() );

        try {
            ks.fireAllRules();
            fail( "An exception was expected since a trait can't override the type of a core class field with these settings " );
        } catch ( Throwable rde ) {
            assertTrue( rde.getCause() instanceof UnsupportedOperationException );
        }
    }



    @Test
    public void testOverrideType3( ) {
        String drl = "package org.drools.compiler.trait.test; \n" +
                     "import org.drools.core.factmodel.traits.Traitable; \n" +
                     "" +
                     "declare trait Foo end\n" +
                     "declare trait Bar end \n" +
                     "" +
                     "declare trait Mask fld : Foo end \n" +
                     "declare Face @Traitable fld : Bar end \n" +
                     "" +
                     "rule Don when then\n" +
                     "  Face face = new Face(); \n" +
                     "  don( face, Mask.class ); \n" +
                     "end\n";

        StatefulKnowledgeSession ks = getSessionFromString( drl );
        TraitFactory.setMode( mode, ks.getKieBase() );

        try {
            ks.fireAllRules();
            fail( "An exception was expected since a trait can't override the type of a core class field with these settings " );
        } catch ( Throwable rde ) {
            assertTrue( rde.getCause() instanceof UnsupportedOperationException );
        }
    }





    @Test
    public void testTraitLegacy() {
        String source = "org/drools/compiler/factmodel/traits/testTraitLegacyTrait.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );


        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();

        System.err.println( " -------------- " + ks.getObjects().size() + " ---------------- " );
        for (Object o : ks.getObjects()) {
            System.err.println( "\t\t" + o );
        }
        System.err.println( " --------------  ---------------- " );
        System.err.println( info );
        System.err.println( " --------------  ---------------- " );

        assertEquals( 5,
                      info.size() );
        assertTrue( info.contains( "OK" ) );
        assertTrue( info.contains( "OK2" ) );
        assertTrue( info.contains( "OK3" ) );
        assertTrue( info.contains( "OK4" ) );
        assertTrue( info.contains( "OK5" ) );

    }




    @Test
    public void testTraitCollections() {
        String source = "org/drools/compiler/factmodel/traits/testTraitCollections.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );


        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();

        System.err.println( " -------------- " + ks.getObjects().size() + " ---------------- " );
        for (Object o : ks.getObjects()) {
            System.err.println( "\t\t" + o );
        }
        System.err.println( " --------------  ---------------- " );
        System.err.println( info );
        System.err.println( " --------------  ---------------- " );

        assertEquals( 1,
                      info.size() );
        assertTrue( info.contains( "OK" ) );

    }




    @Test
    public void testTraitCore() {
        String source = "org/drools/compiler/factmodel/traits/testTraitLegacyCore.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();

        System.err.println( " -------------- " + ks.getObjects().size() + " ---------------- " );
        for (Object o : ks.getObjects()) {
            System.err.println( "\t\t" + o );
        }
        System.err.println( " --------------  ---------------- " );
        System.err.println( info );
        System.err.println( " --------------  ---------------- " );

        assertTrue( info.contains( "OK" ) );
        assertTrue( info.contains( "OK2" ) );
        assertEquals( 2,
                      info.size() );

    }




    @Test
    public void traitWithEquality() {
        String source = "org/drools/compiler/factmodel/traits/testTraitWithEquality.drl";

        StatefulKnowledgeSession ks = getSession( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List info = new ArrayList();
        ks.setGlobal( "list",
                      info );

        ks.fireAllRules();

        Assert.assertTrue( info.contains( "DON" ) );
        Assert.assertTrue( info.contains( "EQUAL" ) );

    }



    @Test
    public void traitDeclared() {

        List<Integer> trueTraits = new ArrayList<Integer>();
        List<Integer> untrueTraits = new ArrayList<Integer>();

        StatefulKnowledgeSession ks = getSession( "org/drools/compiler/factmodel/traits/testDeclaredFactTrait.drl" );
        TraitFactory.setMode( mode, ks.getKieBase() );

        ks.setGlobal( "trueTraits",
                      trueTraits );
        ks.setGlobal( "untrueTraits",
                      untrueTraits );

        ks.fireAllRules();
        ks.dispose();

        assertTrue( trueTraits.contains( 1 ) );
        assertFalse( trueTraits.contains( 2 ) );
        assertTrue( untrueTraits.contains( 2 ) );
        assertFalse( untrueTraits.contains( 1 ) );
    }



    @Test
    public void traitPojo() {

        List<Integer> trueTraits = new ArrayList<Integer>();
        List<Integer> untrueTraits = new ArrayList<Integer>();

        StatefulKnowledgeSession session = getSession( "org/drools/compiler/factmodel/traits/testPojoFactTrait.drl" );
        TraitFactory.setMode( mode, session.getKieBase() );

        session.setGlobal( "trueTraits",
                           trueTraits );
        session.setGlobal( "untrueTraits",
                           untrueTraits );

        session.fireAllRules();
        session.dispose();

        assertTrue( trueTraits.contains( 1 ) );
        assertFalse( trueTraits.contains( 2 ) );
        assertTrue( untrueTraits.contains( 2 ) );
        assertFalse( untrueTraits.contains( 1 ) );
    }




    @Test
    public void testIsAOperator() {
        String source = "org/drools/compiler/factmodel/traits/testTraitIsA2.drl";
        StatefulKnowledgeSession ksession = getSession( source );
        TraitFactory.setMode( mode, ksession.getKieBase() );


        AgendaEventListener ael = mock( AgendaEventListener.class );
        ksession.addEventListener( ael );

        Person student = new Person( "student", 18 );
        ksession.insert( student );

        ksession.fireAllRules();

        ArgumentCaptor<AfterMatchFiredEvent> cap = ArgumentCaptor.forClass( AfterMatchFiredEvent.class );
        verify( ael,
                times( 3 ) ).afterMatchFired( cap.capture() );

        List<AfterMatchFiredEvent> values = cap.getAllValues();

        assertThat( values.get( 0 ).getMatch().getRule().getName(),
                    is( "create student" ) );
        assertThat( values.get( 1 ).getMatch().getRule().getName(),
                    is( "print student" ) );
        assertThat( values.get( 2 ).getMatch().getRule().getName(),
                    is( "print school" ) );

    }



    @Test
    public void testManyTraits() {
        String source = "" +
                        "import org.drools.compiler.Message;" +
                        "" +
                        "global java.util.List list; \n" +
                        "" +
                        "declare Message\n" +
                        "      @Traitable\n" +
                        "    end\n" +
                        "\n" +
                        "    declare trait NiceMessage\n" +
                        "       message : String\n" +
                        "    end\n" +
                        "" +
                        "rule \"Nice\"\n" +
                        "when\n" +
                        "  $n : NiceMessage( $m : message )\n" +
                        "then\n" +
                        "  System.out.println( $m );\n" +
                        "end" +
                        "\n" +
                        "    rule load\n" +
                        "        when\n" +
                        "\n" +
                        "        then\n" +
                        "            Message message = new Message();\n" +
                        "            message.setMessage(\"Hello World\");\n" +
                        "            insert(message);\n" +
                        "            don( message, NiceMessage.class );\n" +
                        "\n" +
                        "            Message unreadMessage = new Message();\n" +
                        "            unreadMessage.setMessage(\"unread\");\n" +
                        "            insert(unreadMessage);\n" +
                        "            don( unreadMessage, NiceMessage.class );\n" +
                        "\n" +
                        "            Message oldMessage = new Message();\n" +
                        "            oldMessage.setMessage(\"old\");\n" +
                        "            insert(oldMessage);\n" +
                        "            don( oldMessage, NiceMessage.class );" +

                        "            list.add(\"OK\");\n" +
                        "    end";
        StatefulKnowledgeSession ksession = getSessionFromString( source );
        TraitFactory.setMode( mode, ksession.getKieBase() );


        List list = new ArrayList();
        ksession.setGlobal( "list", list );

        Person student = new Person( "student", 18 );
        ksession.insert( student );

        ksession.fireAllRules();

        assertEquals( 1, list.size() );
        assertTrue( list.contains( "OK" ) );

    }


    @Test
    public void traitManyTimes() {

        StatefulKnowledgeSession ksession = getSession( "org/drools/compiler/factmodel/traits/testTraitDonMultiple.drl" );
        TraitFactory.setMode( mode, ksession.getKieBase() );

        List list = new ArrayList();
        ksession.setGlobal( "list", list );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }
        Collection x = ksession.getObjects();
        assertEquals( 2, ksession.getObjects().size() );

        assertEquals( 5, list.size() );
        assertEquals( 0, list.get( 0 ) );
        assertTrue( list.contains( 1 ) );
        assertTrue( list.contains( 2 ) );
        assertTrue( list.contains( 3 ) );
        assertTrue( list.contains( 4 ) );


    }



    // BZ #748752
    @Test
    public void traitsInBatchExecution() {
        String str = "package org.jboss.qa.brms.traits\n" +
                     "import org.drools.compiler.Person;\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "" +
                     "global java.util.List list;" +
                     "" +
                     "declare Person \n" +
                     "  @Traitable \n" +
                     "end \n" +
                     "" +
                     "declare trait Student\n" +
                     "  school : String\n" +
                     "end\n" +
                     "\n" +
                     "rule \"create student\" \n" +
                     "  when\n" +
                     "    $student : Person( age < 26 )\n" +
                     "  then\n" +
                     "    Student s = don( $student, Student.class );\n" +
                     "    s.setSchool(\"Masaryk University\");\n" +
                     "end\n" +
                     "\n" +
                     "rule \"print student\"\n" +
                     "  when\n" +
                     "    student : Person( this isA Student )\n" +
                     "  then" +
                     "    list.add( 1 );\n" +
                     "    System.out.println(\"Person is a student: \" + student);\n" +
                     "end\n" +
                     "\n" +
                     "rule \"print school\"\n" +
                     "  when\n" +
                     "    Student( $school : school )\n" +
                     "  then\n" +
                     "    list.add( 2 );\n" +
                     "    System.out.println(\"Student is attending \" + $school);\n" +
                     "end";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( str.getBytes() ), ResourceType.DRL );

        if (kbuilder.hasErrors()) {
            throw new RuntimeException(kbuilder.getErrors().toString());
        }

        List list = new ArrayList();

        KnowledgeBase kbase = kbuilder.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase );

        StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();


        ksession.setGlobal( "list", list );

        List<Command<?>> commands = new ArrayList<Command<?>>();
        Person student = new Person("student", 18);
        commands.add( CommandFactory.newInsert( student ));

        System.out.println("Starting execution...");
        commands.add(CommandFactory.newFireAllRules());
        ksession.execute(CommandFactory.newBatchExecution(commands));

        System.out.println("Finished...");

        assertEquals( 2, list.size() );
        assertTrue( list.contains( 1 ) );
        assertTrue( list.contains( 2 ) );
    }





    @Test
    public void testManyTraitsStateless() {
        String source = "" +
                        "import org.drools.compiler.Message;" +
                        "" +
                        "global java.util.List list; \n" +
                        "" +
                        "declare Message\n" +
                        "      @Traitable\n" +
                        "    end\n" +
                        "\n" +
                        "    declare trait NiceMessage\n" +
                        "       message : String\n" +
                        "    end\n" +
                        "" +
                        "rule \"Nice\"\n" +
                        "when\n" +
                        "  $n : NiceMessage( $m : message )\n" +
                        "then\n" +
                        "  System.out.println( $m );\n" +
                        "end" +
                        "\n" +
                        "    rule load\n" +
                        "        when\n" +
                        "\n" +
                        "        then\n" +
                        "            Message message = new Message();\n" +
                        "            message.setMessage(\"Hello World\");\n" +
                        "            insert(message);\n" +
                        "            don( message, NiceMessage.class );\n" +
                        "\n" +
                        "            Message unreadMessage = new Message();\n" +
                        "            unreadMessage.setMessage(\"unread\");\n" +
                        "            insert(unreadMessage);\n" +
                        "            don( unreadMessage, NiceMessage.class );\n" +
                        "\n" +
                        "            Message oldMessage = new Message();\n" +
                        "            oldMessage.setMessage(\"old\");\n" +
                        "            insert(oldMessage);\n" +
                        "            don( oldMessage, NiceMessage.class );" +

                        "            list.add(\"OK\");\n" +
                        "    end";
        KnowledgeBase kb = getKieBaseFromString( source );
        TraitFactory.setMode( mode, kb );

        StatelessKnowledgeSession ksession = kb.newStatelessKnowledgeSession();

        List list = new ArrayList();
        ksession.setGlobal( "list", list );

        ksession.execute( CommandFactory.newFireAllRules() );

        assertEquals( 1, list.size() );
        assertTrue( list.contains( "OK" ) );

    }



    @Test
    public void testAliasing() {
        String drl = "package org.drools.traits\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "import org.drools.core.factmodel.traits.Alias;\n" +
                     "" +
                     "global java.util.List list;" +
                     "" +
                     "declare Person \n" +
                     "  @Traitable \n" +
                     "  nomen     : String  @key @Alias(\"fld1\") \n" +
                     "  workPlace : String \n" +
                     "  address   : String \n" +
                     "  serviceYrs: int \n" +
                     "end \n" +
                     "" +
                     "declare trait Student\n" +
                     // this alias maps to the hard field
                     "  name      : String @Alias(\"fld1\") \n" +
                     // this alias works, binding school to workPlace
                     "  school    : String  @Alias(\"workPlace\") \n" +
                     // soft field, will use name 'level'
                     "  grade     : int @Alias(\"level\") \n" +
                     // this will try to bind rank to address
                     "  rank      : int @Alias(\"serviceYrs\") \n" +
                     "end \n" +
                     "\n" +
                     "rule \"create student\" \n" +
                     "  when\n" +
                     "  then\n" +
                     "    Person p = new Person( \"davide\", \"UniBoh\", \"Floor84\", 1 ); \n" +
                     "    Student s = don( p, Student.class );\n" +
                     "end\n" +
                     "\n" +
                     "rule \"print school\"\n" +
                     "  when\n" +
                     "    $student : Student( $school : school == \"UniBoh\",  $f : fields, fields[ \"workPlace\" ] == \"UniBoh\" )\n" +
                     "  then \n " +
                     "    $student.setRank( 99 ); \n" +
                     "    System.out.println( $student ); \n" +
                     "    $f.put( \"school\", \"Skool\" ); \n" +

                     "    list.add( $school );\n" +
                     "    list.add( $f.get( \"school\" ) );\n" +
                     "    list.add( $student.getSchool() );\n" +
                     "    list.add( $f.keySet() );\n" +
                     "    list.add( $f.entrySet() );\n" +
                     "    list.add( $f.values() );\n" +
                     "    list.add( $f.containsKey( \"school\" ) );\n" +
                     "    list.add( $student.getRank() );\n" +
                     "    list.add( $f.get( \"address\" ) );\n" +
                     "end";

        StatefulKnowledgeSession ksession = getSessionFromString( drl );
        TraitFactory.setMode( mode, ksession.getKieBase() );

        List list = new ArrayList();
        ksession.setGlobal( "list", list );

        ksession.fireAllRules();

        assertEquals( 9, list.size() );
        assertTrue( list.contains( "UniBoh" ) );
        assertTrue( list.contains( "Skool" ) );
        assertTrue( ( (Collection) list.get(3) ).containsAll( Arrays.asList( "workPlace", "nomen", "level" ) ) );
        assertTrue( ( (Collection) list.get(5) ).containsAll( Arrays.asList( "davide", "Skool", 0 ) ) );
        assertTrue( list.contains( true ) );
        assertTrue( list.contains( "Floor84" ) );
        assertTrue( list.contains( 99 ) );

    }



    @Test
    public void testTraitLogicalRemoval() {
        String drl = "package org.drools.trait.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "\n" +
                     "global java.util.List list;\n" +
                     "\n" +
                     "declare trait Student\n" +
                     "  age  : int\n" +
                     "  name : String\n" +
                     "end\n" +
                     "\n" +
                     "declare trait Worker\n" +
                     "  wage  : int\n" +
                     "  name : String\n" +
                     "end\n" +
                     "declare Person\n" +
                     "  @Traitable\n" +
                     "  name : String \n" +
                     "end\n" +
                     "\n" +
                     "\n" +
                     "rule \"Don Logical\"\n" +
                     "when\n" +
                     "  $s : String( this == \"trigger\" )\n" +
                     "then\n" +
                     "  Person p = new Person( \"john\" );\n" +
                     "  insertLogical( p ); \n" +
                     "  don( p, Student.class, true );\n" +
                     "end\n" +
                     " " +
                     "rule \"Don Logical 2\"\n" +
                     "when\n" +
                     "  $s : String( this == \"trigger2\" )\n" +
                     "  $p : Person( name == \"john\" )" +
                     "then\n" +
                     "  don( $p, Worker.class, true );\n" +
                     "end";


        StatefulKnowledgeSession ksession = getSessionFromString(drl);
        TraitFactory.setMode( mode, ksession.getKieBase() );

        List list = new ArrayList();
        ksession.setGlobal( "list", list );

        FactHandle h = ksession.insert( "trigger" );
        ksession.fireAllRules();
        assertEquals( 3, ksession.getObjects().size() );

        ksession.delete( h );
        ksession.fireAllRules();

        assertEquals( 0, ksession.getObjects().size() );

        FactHandle h1 = ksession.insert( "trigger" );
        FactHandle h2 = ksession.insert( "trigger2" );
        ksession.fireAllRules();

        assertEquals( 5, ksession.getObjects().size() );

        ksession.delete( h2 );
        ksession.fireAllRules();

        assertEquals( 3, ksession.getObjects().size() );

        ksession.delete( h1 );
        ksession.fireAllRules();

        assertEquals( 0, ksession.getObjects().size() );

    }


    @Test
    public void testTMSConsistencyWithNonTraitableBeans() {

        String s1 = "package org.drools.test;\n" +
                    "import org.drools.compiler.Person; \n" +
                    "import org.drools.core.factmodel.traits.Traitable; \n" +
                    "" +
                    "declare Person @Traitable end \n" +
                    "" +
                    "rule \"Init\"\n" +
                    "when\n" +
                    "then\n" +
                    "  insertLogical( new Person( \"x\", 18 ) );\n" +
                    "end\n" +
                    "\n" +
                    "declare trait Student\n" +
                    "  age  : int\n" +
                    "  name : String\n" +
                    "end\n" +
                    "\n" +
                    "rule \"Trait\"\n" +
                    "when\n" +
                    "    $p : Person( )\n" +
                    "then\n" +
                    "    don( $p, Student.class, true );\n" +
                    "end\n";


        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        TraitFactory.setMode( mode, ksession.getKieBase() );

        ksession.fireAllRules();

        FactHandle personHandle = ksession.getFactHandles( new ClassObjectFilter( Person.class ) ).iterator().next();
        InternalFactHandle h = ((InternalFactHandle) personHandle);
        ObjectTypeConfigurationRegistry reg = ((InternalWorkingMemoryEntryPoint) h.getEntryPoint()).getObjectTypeConfigurationRegistry();
        ObjectTypeConf conf = reg.getObjectTypeConf( ((InternalWorkingMemoryEntryPoint) h.getEntryPoint()).getEntryPoint(), ((InternalFactHandle) personHandle).getObject() );
        assertTrue( conf.isTMSEnabled() );

        ksession.dispose();
    }






    public static class TBean {
        private String fld;
        public String getFld() { return fld; }
        public void setFld( String fld ) { this.fld = fld; }
        public TBean( String fld ) { this.fld = fld; }
    }



    @Test
    public void testTraitsLegacyWrapperCoherence() {
        String str = "package org.drools.trait.test; \n" +
                     "global java.util.List list; \n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "import org.drools.compiler.factmodel.traits.TraitTest.TBean;\n" +
                     "" +                "" +
                     "declare TBean \n" +
                     "@Traitable \n" +
                     "end \n " +
                     "" +
                     "declare trait Mask \n" +
                     "  fld : String \n" +
                     "  xyz : int  \n" +
                     "end \n" +
                     "\n " +
                     "rule Init \n" +
                     "when \n" +
                     "then \n" +
                     "  insert( new TBean(\"abc\") ); \n" +
                     "end \n" +
                     "" +
                     "rule Don \n" +
                     "no-loop \n" +
                     "when \n" +
                     "  $b : TBean( ) \n" +
                     "then \n" +
                     "  Mask m = don( $b, Mask.class ); \n" +
                     "  modify (m) { setXyz( 10 ); } \n" +
                     "  list.add( m ); \n" +
                     "  System.out.println( \"Don result : \" + m ); \n " +
                     "end \n" +
                     "\n" +
                     "";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( ResourceFactory.newByteArrayResource( str.getBytes() ),
                      ResourceType.DRL );
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();

        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        TraitFactory.setMode( mode, ksession.getKieBase() );
        List<?> list = new ArrayList<Object>();

        ksession.setGlobal("list",
                           list);

        ksession.fireAllRules();


        Collection yOld = ksession.getObjects();
        assertEquals( 2, yOld.size() );

        TraitableBean coreOld = null;
        for ( Object o : yOld ) {
            if ( o instanceof TraitableBean ) {
                coreOld = (TraitableBean) o;
                break;
            }
        }
        assertNotNull( coreOld );

        assertSame( TBean.class, coreOld.getClass().getSuperclass() );

        assertEquals( "abc", ((TBean) coreOld).getFld() );
        assertEquals( 1, coreOld._getDynamicProperties().size() );
        assertEquals( 1, coreOld._getTraitMap().size() );
    }



    @Test
    public void testHasTypes() {

        String source = "org/drools/compiler/factmodel/traits/testTraitDon.drl";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        Resource res = ResourceFactory.newClassPathResource( source );
        assertNotNull(res);
        kbuilder.add(res, ResourceType.DRL);
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
        kb.addKnowledgePackages(kbuilder.getKnowledgePackages());
        TraitFactory traitBuilder = ((KnowledgeBaseImpl) kb).getConfiguration().getComponentFactory().getTraitFactory();
        TraitFactory.setMode( mode, kb );

        try {
            FactType impClass = kb.getFactType("org.drools.compiler.trait.test","Imp");
            TraitableBean imp = (TraitableBean) impClass.newInstance();
            impClass.set(imp, "name", "aaabcd");

            Class trait = kb.getFactType("org.drools.compiler.trait.test","Student").getFactClass();
            Class trait2 = kb.getFactType("org.drools.compiler.trait.test","Role").getFactClass();

            assertNotNull( trait);

            TraitProxy proxy = (TraitProxy) traitBuilder.getProxy(imp, trait);
            Thing thing = traitBuilder.getProxy(imp, Thing.class);

            TraitableBean core = (TraitableBean) proxy.getObject();


            TraitProxy proxy2 = (TraitProxy) traitBuilder.getProxy(imp, trait);
            Thing thing2 = traitBuilder.getProxy(imp, Thing.class);

            assertSame(proxy,proxy2);
            assertSame(thing,thing2);

            assertEquals(2, core.getTraits().size());


        } catch ( Exception e ) {
            e.printStackTrace();
            fail( e.getMessage() );
        }
    }






    @Test
    public void testTraitRedundancy() {
        String str = "package org.drools.compiler.factmodel.traits; \n" +
                     "global java.util.List list; \n" +
                     "" +
                     "declare trait IStudent end \n" +
                     "" +
                     "declare org.drools.compiler.factmodel.traits.IPerson @typesafe(false) end \n" +
                     "" +
                     "rule \"Students\" \n" +
                     "salience -10" +
                     "when \n" +
                     "   $s : IStudent() \n" +
                     "then \n" +
                     "   System.out.println( \"Student in \" + $s ); \n" +
                     "end \n" +
                     "" +
                     "rule \"Don\" \n" +
                     "no-loop  \n" +
                     "when \n" +
                     "  $p : IPerson( age < 30 ) \n" +
                     "then \n" +
                     "   System.out.println( \"Candidate student \" + $p ); \n" +
                     "   don( $p, IStudent.class );\n" +
                     "end \n" +
                     "" +
                     "rule \"Check\" \n" +
                     "no-loop \n" +
                     "when \n" +
                     "  $p : IPerson( this isA IStudent ) \n" +
                     "then \n" +
                     "   System.out.println( \"Known student \" + $p ); " +
                     "   modify ($p) { setAge( 37 ); } \n" +
                     "   shed( $p, IStudent.class );\n" +
                     "end \n";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( ResourceFactory.newByteArrayResource( str.getBytes() ),
                      ResourceType.DRL );
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();

        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        TraitFactory.setMode( mode, ksession.getKieBase() );
        List<?> list = new ArrayList<Object>();

        ksession.setGlobal("list",
                           list);

        ksession.insert( new StudentImpl( "skool", "john", 27 ) );


        assertEquals( 3, ksession.fireAllRules() );

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }

    }


    @Test
    public void traitSimpleTypes() {

        String s1 = "package org.drools.factmodel.traits;\n" +
                    "\n" +
                    "import org.drools.core.factmodel.traits.Traitable;\n" +
                    "" +
                    "declare trait PassMark\n" +
                    "end\n" +
                    "\n" +
                    "declare ExamMark \n" +
                    "@Traitable\n" +
                    "value : long \n" +
                    "end\n" +
                    "" +
                    "rule \"testTraitFieldTypePrimitive\"\n" +
                    "when\n" +
                    "    $mark : ExamMark()\n" +
                    "then\n" +
                    "    don($mark, PassMark.class);\n" +
                    "end\n" +
                    "" +
                    "rule \"Init\" when then insert( new ExamMark() ); end \n";



        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase );

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.fireAllRules();


    }



    @Test
    public void testTraitEncoding() {
        String s1 = "package org.drools.core.factmodel.traits;\n" +
                    "declare trait A end\n" +
                    "declare trait B extends A end\n" +
                    "declare trait C extends A end\n" +
                    "declare trait D extends A end\n" +
                    "declare trait E extends B end\n" +
                    "declare trait F extends C end\n" +
                    "declare trait G extends D end\n" +
                    "declare trait H extends D end\n" +
                    "declare trait I extends E end\n" +
                    "declare trait J extends F end\n" +
                    "declare trait K extends G, H end\n" +
                    "declare trait L extends G, H end\n" +
                    "declare trait M extends I, J end\n" +
                    "declare trait N extends K, L end\n" +
                    "" +
                    "rule \"donOneThing\"\n" +
                    "when\n" +
                    "    $x : Entity()\n" +
                    "then\n" +
                    "    don( $x, A.class );\n" +
                    "end\n" +
                    "" +
                    "rule \"donManyThing\"\n" +
                    "when\n" +
                    "    String( this == \"y\" ) \n" +
                    "    $x : Entity()\n" +
                    "then\n" +
                    "    don( $x, B.class );\n" +
                    "    don( $x, D.class );\n" +
                    "    don( $x, F.class );\n" +
                    "    don( $x, E.class );\n" +
                    "    don( $x, I.class );\n" +
                    "    don( $x, K.class );\n" +
                    "    don( $x, J.class );\n" +
                    "    don( $x, C.class );\n" +
                    "    don( $x, H.class );\n" +
                    "    don( $x, G.class );\n" +
                    "    don( $x, L.class );\n" +
                    "    don( $x, M.class );\n" +
                    "    don( $x, N.class );\n" +
                    "end\n"
                ;

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase );

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        TraitRegistry tr = ((KnowledgeBaseImpl) kbase).getConfiguration().getComponentFactory().getTraitRegistry();
        System.out.println( tr.getHierarchy() );


        Entity ent = new Entity( "x" );
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.insert( ent );
        ksession.fireAllRules();

        assertEquals( 1, ent.getMostSpecificTraits().size() );

        ksession.insert( "y" );
        ksession.fireAllRules();

        System.out.println( ent.getMostSpecificTraits() );
        assertEquals( 2, ent.getMostSpecificTraits().size() );

    }



    @Test
    public void testTraitActualTypeCodeWithEntities() {
        testTraitActualTypeCodeWithEntities( "ent", mode );
    }

    @Test
    public void testTraitActualTypeCodeWithCoreMap() {
        testTraitActualTypeCodeWithEntities( "kor", mode );
    }


    void testTraitActualTypeCodeWithEntities( String trig, VirtualPropertyMode mode ) {
        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ClassPathResource( "org/drools/compiler/factmodel/traits/testComplexDonShed.drl" ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase );

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

        ksession.insert( trig );
        ksession.fireAllRules();

        TraitableBean ent = (TraitableBean) ksession.getGlobal( "core" );

        assertEquals( CodedHierarchyImpl.stringToBitSet( "1" ), ent.getCurrentTypeCode( ) );

        ksession.insert( "b" );
        ksession.fireAllRules();
        assertEquals( CodedHierarchyImpl.stringToBitSet( "11" ), ent.getCurrentTypeCode( ) );

        ksession.insert( "c" );
        ksession.fireAllRules();
        assertEquals( CodedHierarchyImpl.stringToBitSet( "1011" ), ent.getCurrentTypeCode( ) );

        ksession.insert( "e" );
        ksession.fireAllRules();
        assertEquals( CodedHierarchyImpl.stringToBitSet( "11011" ), ent.getCurrentTypeCode( ) );

        ksession.insert( "-c" );
        ksession.fireAllRules();
        assertEquals( CodedHierarchyImpl.stringToBitSet( "11" ), ent.getCurrentTypeCode( ) );

        ksession.insert( "dg" );
        ksession.fireAllRules();
        assertEquals( CodedHierarchyImpl.stringToBitSet( "111111" ), ent.getCurrentTypeCode( ) );

        ksession.insert( "-f" );
        ksession.fireAllRules();
        assertEquals( CodedHierarchyImpl.stringToBitSet( "111" ), ent.getCurrentTypeCode( ) );

    }




    @Test
    public void testTraitModifyCore() {
        String s1 = "package test;\n" +
                    "import org.drools.core.factmodel.traits.*;\n" +
                    "" +
                    "declare trait Student name : String end\n" +
                    "declare trait Worker name : String end\n" +
                    "declare trait StudentWorker extends Student, Worker name : String end\n" +
                    "declare trait Assistant extends Student, Worker name : String end\n" +
                    "declare Person @Traitable name : String end\n" +
                    "" +
                    "rule \"Init\" \n" +
                    "when \n" +
                    "then \n" +
                    "  Person p = new Person( \"john\" ); \n" +
                    "  insert( p ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Don\" \n" +
                    "no-loop\n " +
                    "when \n" +
                    "  $p : Person( name == \"john\" ) \n" +
                    "then \n" +
                    "  System.out.println( $p ); \n" +
                    "" +
                    "  System.out.println( \" ----------------------------------------------------------------------------------- Don student\" ); \n" +
                    "  don( $p, Student.class ); \n" +
                    "  System.out.println( \" ----------------------------------------------------------------------------------- Don worker\" ); \n" +
                    "  don( $p, Worker.class ); \n" +
                    "  System.out.println( \" ----------------------------------------------------------------------------------- Don studentworker\" ); \n" +
                    "  don( $p, StudentWorker.class ); \n" +
                    "  System.out.println( \" ----------------------------------------------------------------------------------- Don assistant\" ); \n" +
                    "  don( $p, Assistant.class ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Log S\" \n" +
                    "when \n" +
                    "  $t : Student() \n" +
                    "then \n" +
                    "  System.out.println( \"Student >> \" +  $t ); \n" +
                    "end \n" +
                    "rule \"Log W\" \n" +
                    "when \n" +
                    "  $t : Worker() \n" +
                    "then \n" +
                    "  System.out.println( \"Worker >> \" + $t ); \n" +
                    "end \n" +
                    "rule \"Log SW\" \n" +
                    "when \n" +
                    "  $t : StudentWorker() \n" +
                    "then \n" +
                    "  System.out.println( \"StudentWorker >> \" + $t ); \n" +
                    "end \n" +
                    "rule \"Log RA\" \n" +
                    "when \n" +
                    "  $t : Assistant() \n" +
                    "then \n" +
                    "  System.out.println( \"Assistant >> \" + $t ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Mod\" \n" +
                    "salience -10 \n" +
                    "when \n" +
                    "  $p : Person( name == \"john\" ) \n" +
                    "then \n" +
                    "   System.out.println( \"-----------------------------\" );\n" +
                    "   modify ( $p ) { setName( \"alan\" ); } " +
                    "end \n" +
                    "";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase );

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

        int k = ksession.fireAllRules();

        assertEquals( 13, k );

    }




    @Test
    public void testTraitModifyCore2() {
        String s1 = "package test;\n" +
                    "import org.drools.core.factmodel.traits.*;\n" +
                    "" +
                    "declare trait Student @propertyReactive name : String end\n" +
                    "declare trait Worker @propertyReactive name : String end\n" +
                    "declare trait StudentWorker extends Student, Worker @propertyReactive name : String end\n" +
                    "declare trait StudentWorker2 extends StudentWorker @propertyReactive name : String end\n" +
                    "declare trait Assistant extends Student, Worker @propertyReactive name : String end\n" +
                    "declare Person @Traitable @propertyReactive name : String end\n" +
                    "" +
                    "rule \"Init\" \n" +
                    "when \n" +
                    "then \n" +
                    "  Person p = new Person( \"john\" ); \n" +
                    "  insert( p ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Don\" \n" +
                    "when \n" +
                    "  $p : Person( name == \"john\" ) \n" +
                    "then \n" +
                    "  System.out.println( \">>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DON WORKER \" + $p  ); \n" +
                    "  don( $p, Worker.class ); \n" +
                    "  System.out.println( \">>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DON STUDWORKER \" + $p ); \n" +
                    "  don( $p, StudentWorker2.class ); \n" +
                    "  System.out.println( \">>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DON ASSISTANT \" + $p ); \n" +
                    "  don( $p, Assistant.class ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Log S\" \n" +
                    "when \n" +
                    "  $t : Student() @watch( name ) \n" +
                    "then \n" +
                    "  System.out.println( \"@@Student >> \" +  $t ); \n" +
                    "end \n" +
                    "rule \"Log W\" \n" +
                    "when \n" +
                    "  $t : Worker() @watch( name ) \n" +
                    "then \n" +
                    "  System.out.println( \"@@Worker >> \" + $t ); \n" +
                    "end \n" +
                    "rule \"Log SW\" \n" +
                    "when \n" +
                    "  $t : StudentWorker() @watch( name ) \n" +
                    "then \n" +
                    "  System.out.println( \"@@StudentWorker >> \" + $t ); \n" +
                    "end \n" +
                    "rule \"Log RA\" \n" +
                    "when \n" +
                    "  $t : Assistant() @watch( name ) \n" +
                    "then \n" +
                    "  System.out.println( \"@@Assistant >> \" + $t ); \n" +
                    "end \n" +
                    "rule \"Log Px\" \n" +
                    "salience -1 \n" +
                    "when \n" +
                    "  $p : Person() @watch( name ) \n" +
                    "then \n" +
                    "  System.out.println( \"Poor Core Person >> \" + $p ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Mod\" \n" +
                    "salience -10 \n" +
                    "when \n" +
                    "  String( this == \"go\" ) \n" +
                    "  $p : Student( name == \"john\" ) \n" +
                    "then \n" +
                    "  System.out.println( \" ------------------------------------------------------------------------------ \" + $p ); \n" +
                    "  modify ( $p ) { setName( \"alan\" ); } " +
                    "end \n" +
                    "";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase ); // not relevant

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        int k = ksession.fireAllRules();

        assertEquals( 7, k );

        ksession.insert( "go" );
        k = ksession.fireAllRules();

        assertEquals( 6, k );

    }

    @Test
    public void testTraitModifyCore2a() {
        String s1 = "package test;\n" +
                    "import org.drools.core.factmodel.traits.*;\n" +
                    "global java.util.List list; \n" +
                    "" +
                    "declare trait Student @propertyReactive name : String end\n" +
                    "declare trait Worker @propertyReactive name : String end\n" +
                    "declare trait StudentWorker extends Student, Worker @propertyReactive name : String end\n" +
                    "declare trait Assistant extends Student, Worker @propertyReactive name : String end\n" +
                    "declare Person @Traitable @propertyReactive name : String end\n" +
                    "" +
                    "rule \"Init\" \n" +
                    "when \n" +
                    "then \n" +
                    "  Person p = new Person( \"john\" ); \n" +
                    "  insert( p ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Don\" \n" +
                    "when \n" +
                    "  $p : Person( name == \"john\" ) \n" +
                    "then \n" +
                    "  System.out.println( \">>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DON WORKER \" + $p  ); \n" +
                    "  don( $p, Worker.class ); \n" +
                    "  System.out.println( \">>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DON STUDWORKER \" + $p ); \n" +
                    "  don( $p, StudentWorker.class ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Log W\" \n" +
                    "when \n" +
                    "  $t : Worker( this isA StudentWorker ) @watch( name ) \n" +
                    "then \n" +
                    "  System.out.println( \"@@Worker >> \" + $t ); \n" +
                    "  list.add( true ); \n" +
                    "end \n" +
                    "rule \"Log SW\" \n" +
                    "when \n" +
                    "  $t : StudentWorker() @watch( name ) \n" +
                    "then \n" +
                    "  System.out.println( \"@@StudentWorker >> \" + $t ); \n" +
                    "end \n" +
                    "";
        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase ); // not relevant
        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

        ArrayList list = new ArrayList(  );
        ksession.setGlobal( "list", list );

        int k = ksession.fireAllRules();

        assertTrue( list.contains( true ) );
        assertEquals( 1, list.size() );
    }




    @Test
    public void testTraitModifyCore3() {
        String s1 = "package test;\n" +
                    "import org.drools.core.factmodel.traits.*;\n" +
                    "global java.util.List list; \n" +
                    "" +
                    "declare trait A id : int end\n" +
                    "declare trait B extends A end\n" +
                    "declare trait C extends A end\n" +
                    "declare trait D extends A end\n" +
                    "declare trait E extends B end\n" +
                    "declare trait F extends C end\n" +
                    "declare trait G extends D end\n" +
                    "declare trait H extends D end\n" +
                    "declare trait I extends E end\n" +
                    "declare trait J extends F end\n" +
                    "declare trait K extends G, H end\n" +
                    "declare trait L extends G, H end\n" +
                    "declare trait M extends I, J end\n" +
                    "declare trait N extends K, L end\n" +
                    "" +
                    "declare Core @Traitable id : int = 0 end \n" +
                    "" +
                    "rule \"Init\" when \n" +
                    "then \n" +
                    "   insert( new Core() );" +
                    "end \n" +
                    "" +
                    "rule \"donManyThing\"\n" +
                    "when\n" +
                    "    $x : Core( id == 0 )\n" +
                    "then\n" +
                    "    don( $x, A.class );\n" +
                    "    don( $x, B.class );\n" +
                    "    don( $x, D.class );\n" +
                    "    don( $x, F.class );\n" +
                    "    don( $x, E.class );\n" +
                    "    don( $x, I.class );\n" +
                    "    don( $x, K.class );\n" +
                    "    don( $x, J.class );\n" +
                    "    don( $x, C.class );\n" +
                    "    don( $x, H.class );\n" +
                    "    don( $x, G.class );\n" +
                    "    don( $x, L.class );\n" +
                    "    don( $x, M.class );\n" +
                    "    don( $x, N.class );\n" +
                    "end\n" +
                    "\n" +
                    "\n" +
                    "\n" +
                    "rule \"Log A\" when $x : A( id == 1 ) then System.out.println( \"A >> \" +  $x ); list.add( 1 ); end \n" +
                    "rule \"Log B\" when $x : B( id == 1 ) then System.out.println( \"B >> \" +  $x ); list.add( 2 ); end \n" +
                    "rule \"Log C\" when $x : C( id == 1 ) then System.out.println( \"C >> \" +  $x ); list.add( 3 ); end \n" +
                    "rule \"Log D\" when $x : D( id == 1 ) then System.out.println( \"D >> \" +  $x ); list.add( 4 ); end \n" +
                    "rule \"Log E\" when $x : E( id == 1 ) then System.out.println( \"E >> \" +  $x ); list.add( 5 ); end \n" +
                    "rule \"Log F\" when $x : F( id == 1 ) then System.out.println( \"F >> \" +  $x ); list.add( 6 ); end \n" +
                    "rule \"Log G\" when $x : G( id == 1 ) then System.out.println( \"G >> \" +  $x ); list.add( 7 ); end \n" +
                    "rule \"Log H\" when $x : H( id == 1 ) then System.out.println( \"H >> \" +  $x ); list.add( 8 ); end \n" +
                    "rule \"Log I\" when $x : I( id == 1 ) then System.out.println( \"I >> \" +  $x ); list.add( 9 ); end \n" +
                    "rule \"Log J\" when $x : J( id == 1 ) then System.out.println( \"J >> \" +  $x ); list.add( 10 ); end \n" +
                    "rule \"Log K\" when $x : K( id == 1 ) then System.out.println( \"K >> \" +  $x ); list.add( 11 ); end \n" +
                    "rule \"Log L\" when $x : L( id == 1 ) then System.out.println( \"L >> \" +  $x ); list.add( 12 ); end \n" +
                    "rule \"Log M\" when $x : M( id == 1 ) then System.out.println( \"M >> \" +  $x ); list.add( 13 ); end \n" +
                    "rule \"Log N\" when $x : N( id == 1 ) then System.out.println( \"N >> \" +  $x ); list.add( 14 ); end \n" +
                    "" +
                    "rule \"Log Core\" when $x : Core( $id : id ) then System.out.println( \"Core >>>>>> \" +  $x ); end \n" +
                    "" +
                    "rule \"Mod\" \n" +
                    "salience -10 \n" +
                    "when \n" +
                    "  String( this == \"go\" ) \n" +
                    "  $x : Core( id == 0 ) \n" +
                    "then \n" +
                    "  System.out.println( \" ------------------------------------------------------------------------------ \" ); \n" +
                    "  modify ( $x ) { setId( 1 ); }" +
                    "end \n" +
                    "";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase ); // not relevant

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        List list = new ArrayList();
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.setGlobal( "list", list );

        ksession.fireAllRules();

        ksession.insert( "go" );
        ksession.fireAllRules();

        assertEquals( 14, list.size() );
        for ( int j = 1; j <= 14; j++ ) {
            assertTrue( list.contains( j ) );
        }


    }







    @Test
    public void testTraitModifyCoreWithPropertyReactivity() {
        String s1 = "package test;\n" +
                    "import org.drools.core.factmodel.traits.*;\n" +
                    "global java.util.List list;\n" +
                    "" +
                    "declare trait Student @propertyReactive " +
                    "   name : String " +
                    "   age : int " +
                    "   grades : double " +
                    "   school : String " +
                    "   aaa : boolean " +
                    "end\n" +
                    "declare trait Worker @propertyReactive " +
                    "   name : String " +
                    "   wage : double " +
                    "end\n" +
                    "declare trait StudentWorker extends Student, Worker @propertyReactive " +
                    "   hours : int " +
                    "end\n" +
                    "declare trait Assistant extends Student, Worker @propertyReactive " +
                    "   address : String " +
                    "end\n" +
                    "declare Person @propertyReactive @Traitable " +
                    "   wage : double " +
                    "   name : String " +
                    "   age : int  " +
                    "end\n" +
                    "" +
                    "rule \"Init\" \n" +
                    "when \n" +
                    "then \n" +
                    "  Person p = new Person( 109.99, \"john\", 18 ); \n" +
                    "  insert( p ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Don\" \n" +
                    "when \n" +
                    "  $p : Person( name == \"john\" ) \n" +
                    "then \n" +
                    "  System.out.println( $p ); \n" +
                    "  don( $p, StudentWorker.class ); \n" +
                    "  don( $p, Assistant.class ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Log S\" \n" +
                    "when \n" +
                    "  $t : Student( age == 44 ) \n" +
                    "then \n" +
                    "  list.add( 1 );\n " +
                    "  System.out.println( \"Student >> \" +  $t ); \n" +
                    "end \n" +
                    "rule \"Log W\" \n" +
                    "when \n" +
                    "  $t : Worker( name == \"alan\" ) \n" +
                    "then \n" +
                    "  list.add( 2 );\n " +
                    "  System.out.println( \"Worker >> \" + $t ); \n" +
                    "end \n" +
                    "rule \"Log SW\" \n" +
                    "when \n" +
                    "  $t : StudentWorker( age == 44 ) \n" +
                    "then \n" +
                    "  list.add( 3 );\n " +
                    "  System.out.println( \"StudentWorker >> \" + $t ); \n" +
                    "end \n" +
                    "rule \"Log Pers\" \n" +
                    "when \n" +
                    "  $t : Person( age == 44 ) \n" +
                    "then \n" +
                    "  list.add( 4 );\n " +
                    "  System.out.println( \"Person >> \" + $t ); \n" +
                    "end \n" +
                    "" +
                    "rule \"Mod\" \n" +
                    "salience -10 \n" +
                    "when \n" +
                    "  String( this == \"go\" ) \n" +
                    "  $p : Student( name == \"john\" ) \n" +
                    "then \n" +
                    "  System.out.println( \" ------------------------------------------------------------------------------ \" + $p ); \n" +
                    "  modify ( $p ) { setSchool( \"myschool\" ), setAge( 44 ), setName( \"alan\" ); } " +
                    "end \n" +
                    "";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase ); // not relevant

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        List<Integer> list = new ArrayList<Integer>();
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.setGlobal( "list", list );
        int k = ksession.fireAllRules();

        ksession.insert( "go" );
        k = ksession.fireAllRules();

        assertEquals( 5, k );

        assertEquals( 4, list.size() );
        assertTrue( list.contains( 1 ) );
        assertTrue( list.contains( 2 ) );
        assertTrue( list.contains( 3 ) );
        assertTrue( list.contains( 4 ) );

    }




    public static interface IntfParent {}

    @Test
    public void testTraitEncodeExtendingNonTrait() {

        String s1 = "package test;\n" +
                    "import org.drools.compiler.factmodel.traits.TraitTest.IntfParent;\n" +
                    "" +
                    "declare IntfParent end\n" +
                    "" +
                    "declare trait TChild extends IntfParent end \n" +
                    "";

        String s2 = "package test; declare trait SomeThing end \n";


        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s2.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase );

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        KnowledgeBuilder kbuilder2 = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder2.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder2.hasErrors() ) {
            fail( kbuilder2.getErrors().toString() );
        }

        kbase.addKnowledgePackages( kbuilder2.getKnowledgePackages() );

    }



    @Test
    public void isAWithBackChaining() {

        String source = "org/drools/compiler/factmodel/traits/testTraitIsAWithBC.drl";
        StatefulKnowledgeSession ksession = getSession( source );
        TraitFactory.setMode( mode, ksession.getKieBase() );

        List list = new ArrayList();
        ksession.setGlobal( "list", list );

        ksession.fireAllRules();

        ksession.insert( "Como" );

        ksession.fireAllRules();

        assertTrue( list.contains( "Italy" ) );
    }




    @Test
    public void testIsAEvaluatorOnClassification( ) {
        String source = "package t.x \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "import org.drools.core.factmodel.traits.Thing\n" +
                        "import org.drools.core.factmodel.traits.Entity\n" +
                        "\n" +
                        "declare trait t.x.D\n" +
                        "    @propertyReactive\n" +
                        "\n" +
                        "end\n" +
                        "" +
                        "declare trait t.x.E\n" +
                        "    @propertyReactive\n" +
                        "\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Entity o = new Entity();\n" +
                        "   insert(o);\n" +
                        "   don( o, D.class ); \n" +
                        "end\n" +
                        "" +
                        "rule Don when\n" +
                        " $o : Entity() \n" +
                        "then \n" +
                        "end \n" +
                        "" +
                        "rule \"Rule 0 >> http://t/x#D\"\n" +
                        "when\n" +
                        "   $t : org.drools.core.factmodel.traits.Thing( $c : core, this not isA t.x.E.class, this isA t.x.D.class ) " +
                        "then\n" +
                        "   list.add( \"E\" ); \n" +
                        "   don( $t, E.class ); \n" +
                        "end\n" +
                        "" +
                        "rule React \n" +
                        "when E() then \n" +
                        "   list.add( \"X\" ); \n" +
                        "end \n"
                ;

        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        assertEquals( 2, list.size() );
        assertTrue( list.contains( "E" ) );
        assertTrue( list.contains( "X" ) );

    }



    @Test
    public void testShedWithTMS( ) {
        String source = "package t.x \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "import org.drools.core.factmodel.traits.Thing\n" +
                        "import org.drools.core.factmodel.traits.Entity\n" +
                        "\n" +
                        "declare trait t.x.D\n" +
                        "    @propertyReactive\n" +
                        "\n" +
                        "end\n" +
                        "" +
                        "declare trait t.x.E\n" +
                        "    @propertyReactive\n" +
                        "\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Entity o = new Entity();\n" +
                        "   insert(o);\n" +
                        "   don( o, Thing.class ); \n" +
                        "   don( o, D.class ); \n" +
                        "end\n" +
                        "" +
                        "rule Don when\n" +
                        " $o : Entity() \n" +
                        "then \n" +
                        "end \n" +
                        "" +
                        "rule \"Rule 0 >> http://t/x#D\"\n" +
                        "when\n" +
                        "   $t : org.drools.core.factmodel.traits.Thing( $c : core, top == true, this not isA t.x.E.class, this isA t.x.D.class ) " +
                        "then\n" +
                        "   list.add( \"E\" ); \n" +
                        "   System.out.println( \"E due to \" + $t); \n" +
                        "   don( $t, E.class ); \n" +
                        "end\n" +
                        "" +
                        "rule React \n" +
                        "when $x : E() then \n" +
                        "   list.add( \"X\" ); \n" +
                        "end \n" +
                        "" +
                        "rule Shed \n" +
                        "when \n" +
                        "   $s : String() \n" +
                        "   $d : Entity() \n" +
                        "then \n" +
                        "   delete( $s ); \n" +
                        "   shed( $d, D.class );\n" +
                        "end \n" +
                        ""
                ;

        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        System.out.println( list );
        assertEquals( 2, list.size() );
        assertTrue( list.contains( "E" ) );
        assertTrue( list.contains( "X" ) );

        ks.insert( "shed" );
        ks.fireAllRules();

        for ( Object o : ks.getObjects() ) {
            System.out.println( o );
        }
        assertEquals( 3, ks.getObjects().size() );

    }



    @Test
    public void testTraitInitialization() {
        String source = "package t.x \n" +
                        "import java.util.*; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "declare trait Foo\n" +
                        "   hardList : List = new ArrayList() \n" +
                        "   softList : List = new ArrayList() \n" +
                        "   moreList : List = new ArrayList() \n" +
                        "   otraList : List = new ArrayList() \n" +
                        "   primFld  : int = 3 \n" +
                        "   primDbl  : double = 0.421 \n" +
                        "\n" +
                        "end\n" +
                        "" +
                        "declare Bar\n" +
                        "   @Traitable()\n" +
                        "   hardList : List \n" +
                        "   moreList : List = Arrays.asList( 1, 2, 3 ) \n" +
                        "\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Bar o = new Bar();\n" +
                        "   insert(o);\n" +
                        "   Thing t = don( o, Thing.class ); \n" +
                        "   t.getFields().put( \"otraList\", Arrays.asList( 42 ) ); \n" +
                        "   don( o, Foo.class ); \n" +
                        "end\n" +
                        "" +
                        "rule Don when\n" +
                        "   $x : Foo( $h : hardList, $s : softList, $o : otraList, $m : moreList, $i : primFld, $d : primDbl ) \n" +
                        "then \n" +
                        "   list.add( $h ); \n" +
                        "   list.add( $s ); \n" +
                        "   list.add( $o ); \n" +
                        "   list.add( $m ); \n" +
                        "   list.add( $i ); \n" +
                        "   list.add( $d ); \n" +
                        "   System.out.println( $x ); \n" +
                        "end\n" +
                        ""
                ;

        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        assertEquals( 6, list.size() );
        assertFalse( list.contains( null ) );

        List hard = (List) list.get( 0 );
        List soft = (List) list.get( 1 );
        List otra = (List) list.get( 2 );
        List more = (List) list.get( 3 );

        assertTrue( hard.isEmpty() );
        assertTrue( soft.isEmpty() );
        assertEquals( more, Arrays.asList( 1, 2, 3 ) );
        assertEquals( otra, Arrays.asList( 42 ) );

        assertTrue( list.contains( 3 ) );
        assertTrue( list.contains( 0.421 ) );
    }




    @Test
    public void testUnTraitedBean() {
        String source = "package t.x \n" +
                        "import java.util.*; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "" +
                        "declare trait Foo end\n" +
                        "" +
                        "declare Bar\n" +
                        "   @Traitable\n" +
                        "end\n" +
                        "declare Bar2\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Bar o = new Bar();\n" +
                        "   insert(o);\n" +
                        "   Bar2 o2 = new Bar2();\n" +
                        "   insert(o2);\n" +
                        "end\n" +
                        "" +
                        "rule Check when\n" +
                        "   $x : Bar( this not isA Foo ) \n" +
                        "then \n" +
                        "   System.out.println( $x ); \n" +
                        "end\n" +
                        "rule Check2 when\n" +
                        "   $x : Bar2( this not isA Foo ) \n" +
                        "then \n" +
                        "   System.out.println( $x ); \n" +
                        "end\n" +
                        "";


        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

    }



    @Test
    public void testIsAOptimization(  ) {
        String source = "package t.x \n" +
                        "import java.util.*; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "" +
                        "declare trait A end\n" +
                        "declare trait B extends A end\n" +
                        "declare trait C extends B end\n" +
                        "declare trait D extends A end\n" +
                        "declare trait E extends C, D end\n" +
                        "declare trait F extends E end\n" +
                        "" +
                        "declare Kore\n" +
                        "   @Traitable\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Kore k = new Kore();\n" +
                        "   don( k, E.class ); \n" +
                        "end\n" +
                        "" +
                        "rule Check_1 when\n" +
                        "   $x : Kore( this isA [ B, D ]  ) \n" +
                        "then \n" +
                        "   list.add( \" B+D \" ); \n" +
                        "end\n" +
                        "" +
                        "rule Check_2 when\n" +
                        "   $x : Kore( this isA [ A ]  ) \n" +
                        "then \n" +
                        "   list.add( \" A \" ); \n" +
                        "end\n" +

                        "rule Check_3 when\n" +
                        "   $x : Kore( this not isA [ F ]  ) \n" +
                        "then \n" +
                        "   list.add( \" F \" ); \n" +
                        "end\n" +
                        "";


        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        assertEquals( 3, list.size() );

    }



    @Test
    public void testTypeRefractionOnInsert(  ) {
        String source = "package t.x \n" +
                        "import java.util.*; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "" +
                        "declare trait A @propertyReactive end\n" +
                        "declare trait B extends A @propertyReactive end\n" +
                        "declare trait C extends B @propertyReactive end\n" +
                        "declare trait D extends A @propertyReactive end\n" +
                        "declare trait E extends C, D @propertyReactive end\n" +
                        "declare trait F extends E @propertyReactive end\n" +
                        "" +
                        "declare Kore\n" +
                        "   @Traitable\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Kore k = new Kore();\n" +
                        "   System.out.println( \"-----------------------------------------------------------------------\" ); \n " +
                        "   don( k, B.class ); \n" +

                        "   System.out.println( \"-----------------------------------------------------------------------\" ); \n " +
                        "   don( k, C.class ); \n" +

                        "   System.out.println( \"-----------------------------------------------------------------------\" ); \n " +
                        "   don( k, D.class ); \n" +

                        "   System.out.println( \"-----------------------------------------------------------------------\" ); \n " +
                        "   don( k, E.class ); \n" +

                        "   System.out.println( \"-----------------------------------------------------------------------\" ); \n " +
                        "   don( k, A.class ); \n" +

                        "   System.out.println( \"-----------------------------------------------------------------------\" ); \n " +
                        "   don( k, F.class ); \n" +
                        "end\n" +
                        "" +
                        "rule Check_1 when\n" +
                        "   $x : A( ) \n" +
                        "then \n" +
                        "   list.add( $x ); \n" +
                        "   System.out.println( \" A by \" + $x ); \n" +
                        "end\n" +
                        "";


        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        assertEquals( 1, list.size() );

    }



    @Test
    public void testTypeRefractionOnQuery(  ) {
        String source = "declare BaseObject\n" +
                        "@Traitable\n" +
                        "id : String @key\n" +
                        "end\n" +
                        "\n" +
                        "declare trait A\n" +
                        "id : String @key\n" +
                        "end\n" +
                        "\n" +
                        "declare trait B extends A\n" +
                        "end\n" +
                        "\n" +
                        "declare trait C extends A\n" +
                        "end\n" +
                        "\n" +
                        "rule \"init\"\n" +
                        "when\n" +
                        "then\n" +
                        "BaseObject $obj = new BaseObject(\"testid123\");\n" +
                        "insert ($obj);\n" +
                        "don($obj, B.class, true);\n" +
                        "don($obj, C.class, true);\n" +
                        "end\n" +
                        "\n" +
                        "query \"QueryTraitA\"\n" +
                        "a : A()\n" +
                        "end";


        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        ks.fireAllRules();

        QueryResults res = ks.getQueryResults( "QueryTraitA" );

        assertEquals( 1, res.size() );

    }


    @Test
    public void testTypeRefractionOnQuery2(  ) {
        String source = "package t.x \n" +
                        "import java.util.*; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "" +
                        "declare trait A end\n" +
                        "declare trait B extends A end\n" +
                        "declare trait C extends B end\n" +
                        "declare trait D extends A end\n" +
                        "declare trait E extends C, D end\n" +
                        "declare trait F extends E end\n" +
                        "declare trait G extends A end\n" +
                        "" +
                        "declare Kore\n" +
                        "   @Traitable\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Kore k = new Kore();\n" +
                        "   don( k, C.class ); \n" +
                        "   don( k, D.class ); \n" +
                        "   don( k, E.class ); \n" +
                        "   don( k, B.class ); \n" +
                        "   don( k, A.class ); \n" +
                        "   don( k, F.class ); \n" +
                        "   don( k, G.class ); \n" +
                        "   shed( k, B.class ); \n" +
                        "end\n" +
                        "" +
                        "rule RuleA\n" +
                        "when \n" +
                        "   $x : A(  ) \n" +
                        "then \n" +
                        "   System.out.println( $x ); \n " +
                        "end\n" +
                        " \n" +
                        "query queryA1\n" +
                        "   $x := A(  ) \n" +
                        "end\n" +
                        "";


        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        QueryResults res;
        res = ks.getQueryResults( "queryA1" );
        assertEquals( 1, res.size() );
    }



    @Test
    public void testTypeRefractionOnQueryWithIsA(  ) {
        String source = "package t.x \n" +
                        "import java.util.*; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "" +
                        "declare trait A @propertyReactive end\n" +
                        "declare trait B extends A @propertyReactive end\n" +
                        "declare trait C extends B @propertyReactive end\n" +
                        "declare trait D extends A @propertyReactive end\n" +
                        "declare trait E extends C, D @propertyReactive end\n" +
                        "declare trait F extends E @propertyReactive end\n" +
                        "" +
                        "declare Kore\n" +
                        "   @Traitable\n" +
                        "end\n" +
                        "" +
                        "rule Init when\n" +
                        "then\n" +
                        "   Kore k = new Kore();\n" +
                        "   don( k, C.class ); \n" +
                        "   don( k, D.class ); \n" +
                        "   don( k, E.class ); \n" +
                        "   don( k, B.class ); \n" +
                        "   don( k, A.class ); \n" +
                        "   don( k, F.class ); \n" +
                        "   shed( k, B.class ); \n" +
                        "end\n" +
                        "" +
                        " \n" +
                        "query queryA\n" +
                        "   $x := Kore( this isA A ) \n" +
                        "end\n" +
                        "";


        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        QueryResults res = ks.getQueryResults( "queryA" );
        Iterator<QueryResultsRow> iter = res.iterator();
        Object a = iter.next().get( "$x" );
        assertFalse( iter.hasNext() );

        assertEquals( 1, res.size() );

    }



    @Test
    public void testCoreUpdate4(  ) {
        String source = "package t.x \n" +
                        "import java.util.*; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "" +
                        "declare trait A " +
                        "   age : int \n" +
                        "end\n" +
                        "" +
                        "declare Kore\n" +
                        "   @Traitable\n" +
                        "   @propertyReactive" +
                        "   age : int\n" +
                        "end\n" +
                        "" +
                        "rule Init \n" +
                        "when\n" +
                        "then\n" +
                        "   Kore k = new Kore( 44 );\n" +
                        "   insert( k ); \n" +
                        "end\n" +
                        "" +
                        "" +
                        "rule Don \n" +
                        "no-loop \n" +
                        "when\n" +
                        "   $x : Kore() \n" +
                        "then \n" +
                        "   System.out.println( \"Donning\" ); \n" +
                        "   don( $x, A.class ); \n" +
                        "end\n" +
                        "rule React \n" +
                        "salience 1" +
                        "when\n" +
                        "   $x : Kore( this isA A.class ) \n" +
                        "then \n" +
                        "   System.out.println( \"XXXXXXXXXXXXXXXXXXXXXX \" + $x ); \n" +
                        "   list.add( $x ); \n" +
                        "end\n" +
                        "";
        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );
        ks.fireAllRules();

        for ( Object o : ks.getObjects() ) {
            System.err.println( o );
        }
        assertEquals( 1, list.size() );
    }



    @Test
    public void traitLogicalSupportAnddelete() {
        String drl = "package org.drools.trait.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "\n" +
                     "global java.util.List list;\n" +
                     "\n" +
                     "declare trait Student\n" +
                     "  age  : int\n" +
                     "  name : String\n" +
                     "end\n" +
                     "\n" +
                     "declare Person\n" +
                     "  @Traitable\n" +
                     "  name : String\n" +
                     "end\n" +
                     "\n" +
                     "rule Init when then insert( new Person( \"john\" ) ); end \n" +
                     "" +
                     "rule \"Don Logical\"\n" +
                     "when\n" +
                     "  $s : String( this == \"trigger1\" )\n" +
                     "  $p : Person() \n" +
                     "then\n" +
                     "  don( $p, Student.class, true );\n" +
                     "end\n" +
                     "" +
                     "rule \"Don Logical2\"\n" +
                     "when\n" +
                     "  $s : String( this == \"trigger2\" )\n" +
                     "  $p : Person() \n" +
                     "then\n" +
                     "  don( $p, Student.class, true );\n" +
                     "end\n" +
                     "" +
                     "rule \"Undon \"\n" +
                     "when\n" +
                     "  $s : String( this == \"trigger3\" )\n" +
                     "  $p : Person() \n" +
                     "then\n" +
                     "  shed( $p, org.drools.core.factmodel.traits.Thing.class ); " +
                     "  delete( $s ); \n" +
                     "end\n" +
                     " " +
                     "rule \"Don Logical3\"\n" +
                     "when\n" +
                     "  $s : String( this == \"trigger4\" )\n" +
                     "  $p : Person() \n" +
                     "then\n" +
                     "  don( $p, Student.class, true );" +
                     "end\n" +
                     " " +
                     "rule \"Undon 2\"\n" +
                     "when\n" +
                     "  $s : String( this == \"trigger5\" )\n" +
                     "  $p : Person() \n" +
                     "then\n" +
                     "  delete( $s ); \n" +
                     "  delete( $p ); \n" +
                     "end\n" +
                     "";


        StatefulKnowledgeSession ksession = getSessionFromString(drl);
        TraitFactory.setMode( mode, ksession.getKieBase() );

        List list = new ArrayList();
        ksession.setGlobal( "list", list );

        FactHandle h1 = ksession.insert( "trigger1" );
        FactHandle h2 = ksession.insert( "trigger2" );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }
        System.err.println( "---------------------------------" );

        assertEquals( 4, ksession.getObjects().size() );

        ksession.delete( h1 );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }
        System.err.println( "---------------------------------" );

        assertEquals( 3, ksession.getObjects().size() );

        ksession.delete( h2 );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }
        System.err.println( "---------------------------------" );

        assertEquals( 1, ksession.getObjects().size() );

        ksession.insert( "trigger3" );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }
        System.err.println( "---------------------------------" );

        assertEquals( 1, ksession.getObjects().size() );

        ksession.insert( "trigger4" );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }
        System.err.println( "---------------------------------" );

        assertEquals( 3, ksession.getObjects().size() );

        ksession.insert( "trigger5" );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.err.println( o );
        }
        System.err.println( "---------------------------------" );

        assertEquals( 1, ksession.getObjects().size() );
    }



    @Test
    public void testShedThing() {
        String s1 = "package test;\n" +
                    "import org.drools.core.factmodel.traits.*;\n" +
                    "global java.util.List list; \n" +
                    "" +
                    "declare trait A id : int end\n" +
                    "declare trait B extends A end\n" +
                    "declare trait C extends A end\n" +
                    "declare trait D extends A end\n" +
                    "declare trait E extends B end\n" +
                    "" +
                    "declare Core @Traitable id : int = 0 end \n" +
                    "" +
                    "rule \"Init\" when \n" +
                    "then \n" +
                    "   insert( new Core() );" +
                    "end \n" +
                    "" +
                    "rule \"donManyThing\"\n" +
                    "when\n" +
                    "    $x : Core( id == 0 )\n" +
                    "then\n" +
                    "    don( $x, A.class );\n" +
                    "    don( $x, B.class );\n" +
                    "    don( $x, C.class );\n" +
                    "    don( $x, D.class );\n" +
                    "    don( $x, E.class );\n" +
                    "end\n" +
                    "\n" +
                    "\n" +
                    "" +
                    "rule \"Mod\" \n" +
                    "salience -10 \n" +
                    "when \n" +
                    "  $g : String( this == \"go\" ) \n" +
                    "  $x : Core( id == 0 ) \n" +
                    "then \n" +
                    "  shed( $x, Thing.class ); " +
                    "  delete( $g ); \n\n" +
                    "end \n" +
                    "";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase ); // not relevant

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        List list = new ArrayList();
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.setGlobal( "list", list );

        ksession.fireAllRules();

        ksession.insert( "go" );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.out.println( o );
        }

        assertEquals( 1, ksession.getObjects().size() );
    }


    @Test
    public void testdeleteThings() {
        String s1 = "package test;\n" +
                    "import org.drools.core.factmodel.traits.*;\n" +
                    "global java.util.List list; \n" +
                    "" +
                    "declare trait A id : int end\n" +
                    "declare trait B extends A end\n" +
                    "declare trait C extends A end\n" +
                    "declare trait D extends A end\n" +
                    "declare trait E extends B end\n" +
                    "" +
                    "declare Core @Traitable id : int = 0 end \n" +
                    "" +
                    "rule \"Init\" when \n" +
                    "then \n" +
                    "   insert( new Core() );" +
                    "end \n" +
                    "" +
                    "rule \"donManyThing\"\n" +
                    "when\n" +
                    "    $x : Core( id == 0 )\n" +
                    "then\n" +
                    "    don( $x, A.class );\n" +
                    "    don( $x, B.class );\n" +
                    "    don( $x, C.class );\n" +
                    "    don( $x, D.class );\n" +
                    "    don( $x, E.class );\n" +
                    "end\n" +
                    "\n" +
                    "\n" +
                    "" +
                    "rule \"Mod\" \n" +
                    "salience -10 \n" +
                    "when \n" +
                    "  $g : String( this == \"go\" ) \n" +
                    "  $x : Core( id == 0 ) \n" +
                    "then \n" +
                    "  delete( $x ); \n\n" +
                    "  delete( $g ); \n\n" +
                    "end \n" +
                    "";

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add( new ByteArrayResource( s1.getBytes() ), ResourceType.DRL );
        if ( kbuilder.hasErrors() ) {
            fail( kbuilder.getErrors().toString() );
        }
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, kbase );

        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

        List list = new ArrayList();
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.setGlobal( "list", list );

        ksession.fireAllRules();

        ksession.insert( "go" );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.out.println( o );
        }

        assertEquals( 0, ksession.getObjects().size() );
    }

    @Test
    public void traitLogicalRemovalSimple( ) {
        String drl = "package org.drools.compiler.trait.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "\n" +
                     "global java.util.List list;\n" +
                     "\n" +
                     "declare trait Student\n" +
                     " age : int\n" +
                     " name : String\n" +
                     "end\n" +
                     "declare trait Worker\n" +
                     " wage : int\n" +
                     "end\n" +
                     "" +
                     "declare trait Scholar extends Student\n" +
                     "end\n" +
                     "\n" +
                     "declare Person\n" +
                     " @Traitable\n" +
                     " name : String\n" +
                     "end\n" +
                     "\n" +
                     "\n" +
                     "rule \"Don Logical\"\n" +
                     "when\n" +
                     " $s : String( this == \"trigger\" )\n" +
                     "then\n" +
                     " Person p = new Person( \"john\" );\n" +
                     " insert( p ); \n" +
                     " don( p, Student.class, true );\n" +
                     " don( p, Worker.class );\n" +
                     " don( p, Scholar.class );\n" +
                     "end";


        StatefulKnowledgeSession ksession = getSessionFromString(drl);
        TraitFactory.setMode( mode, ksession.getKieBase() );

        List list = new ArrayList();
        ksession.setGlobal( "list", list );

        FactHandle h = ksession.insert( "trigger" );
        ksession.fireAllRules();
        assertEquals( 5, ksession.getObjects().size() );

        ksession.delete( h );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            // lose the string and the Student proxy
            System.out.println( o );
        }
        assertEquals( 3, ksession.getObjects().size() );

    }



    @Traitable
    public static class TraitableFoo {

        private String id;

        public TraitableFoo( String id, int x, Object k ) {
            setId( id );
        }

        public String getId() {
            return id;
        }

        public void setId( String id ) {
            this.id = id;
        }
    }

    @Traitable
    public static class XYZ extends TraitableFoo {

        public XYZ() {
            super( null, 0, null );
        }

    }


    @Test
    public void testTraitDonLegacyClassWithoutEmptyConstructor( ) {
        String drl = "package org.drools.compiler.trait.test;\n" +
                     "\n" +
                     "import org.drools.compiler.factmodel.traits.TraitTest.TraitableFoo;\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "\n" +
                     "" +
                     "declare trait Bar\n" +
                     "end\n" +
                     "\n" +
                     "rule \"Don\"\n" +
                     "no-loop \n" +
                     "when\n" +
                     " $f : TraitableFoo( )\n" +
                     "then\n" +
                     "  Bar b = don( $f, Bar.class );\n" +
                     "end";


        StatefulKnowledgeSession ksession = getSessionFromString(drl);
        TraitFactory.setMode( mode, ksession.getKieBase() );
        ksession.addEventListener( new DebugAgendaEventListener(  ) );

        ksession.insert( new TraitableFoo( "xx", 0, null ) );
        ksession.fireAllRules();

        for ( Object o : ksession.getObjects() ) {
            System.out.println( o );
        }

        assertEquals( 2, ksession.getObjects().size() );
    }



    @Test
    public void testdeleteCoreObjectChained(  ) {
        String source = "package org.drools.test;\n" +
                        "import java.util.List; \n" +
                        "import org.drools.core.factmodel.traits.Thing \n" +
                        "import org.drools.core.factmodel.traits.Traitable \n" +
                        "\n" +
                        "global java.util.List list; \n" +
                        "\n" +
                        "" +
                        "declare trait A " +
                        "   age : int \n" +
                        "end\n" +
                        "" +
                        "declare Kore\n" +
                        "   @Traitable\n" +
                        "   age : int\n" +
                        "end\n" +
                        "" +
                        "rule Init \n" +
                        "when\n" +
                        "   $s : String() \n" +
                        "then\n" +
                        "   Kore k = new Kore( 44 );\n" +
                        "   insertLogical( k ); \n" +
                        "end\n" +
                        "" +
                        "" +
                        "rule Don \n" +
                        "no-loop \n" +
                        "when\n" +
                        "   $x : Kore() \n" +
                        "then \n" +
                        "   System.out.println( \"Donning\" ); \n" +
                        "   don( $x, A.class ); \n" +
                        "end\n" +
                        "" +
                        "" +
                        "rule delete \n" +
                        "salience -99 \n" +
                        "when \n" +
                        "   $x : String() \n" +
                        "then \n" +
                        "   System.out.println( \"deleteing\" ); \n" +
                        "   delete( $x ); \n" +
                        "end \n" +
                        "\n";

        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );

        ks.insert( "go" );

        ks.fireAllRules();

        for ( Object o : ks.getObjects() ) {
            System.out.println( o );
        }

        assertEquals( 0, ks.getObjects().size() );

        ks.dispose();
    }


    @Test
    public void testUpdateLegacyClass(  ) {
        String source = "package org.drools.text;\n" +
                        "\n" +
                        "global java.util.List list;\n" +
                        "\n" +
                        "import org.drools.compiler.Person;\n" +
                        "import org.drools.core.factmodel.traits.Traitable;\n" +
                        "\n" +
                        "declare Person @Traitable end \n" +
                        "" +
                        "declare trait Student\n" +
                        "  name : String\n" +
                        "end\n" +
                        "\n" +
                        "rule \"Init\"\n" +
                        "salience 10 \n" +
                        "when\n" +
                        "  $p : Person( this not isA Student )\n" +
                        "then\n" +
                        "  System.out.println( \"Don person\" ); \n" +
                        "  don( $p, Student.class );\n" +
                        "end\n" +
                        "\n" +
                        "rule \"Go\"\n" +
                        "when\n" +
                        "  $s : String( this == \"X\" )\n" +
                        "  $p : Person()\n" +
                        "then\n" +
                        "  System.out.println( \"Change name\" ); \n" +
                        "  delete( $s ); \n" +
                        "  modify( $p ) { setName( $s ); }\n" +
                        "end\n" +
                        "\n" +
                        "rule \"Mod\"\n" +
                        "when\n" +
                        "  Student( name == \"X\" )\n" +
                        "then\n" +
                        "  System.out.println( \"Update detected\" );\n" +
                        "  list.add( 0 );\n" +
                        "end";

        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );

        ks.insert( new Person( "john", 32 ) );
        ks.insert( "X" );

        ks.fireAllRules();

        assertTrue( list.contains( 0 ) );
        assertEquals( 1, list.size() );

        ks.dispose();
    }



    @Test
    public void testSoftPropertyClash() {
        String source = "package org.drools.text;\n" +
                        "\n" +
                        "global java.util.List list;\n" +
                        "\n" +
                        "import org.drools.core.factmodel.traits.Traitable;\n" +
                        "import org.drools.core.factmodel.traits.Alias;\n" +
                        "\n" +
                        "declare Person @Traitable @propertyReactive \n" +
                        "end \n" +
                        "" +
                        "declare trait Student\n" +
                        "   @propertyReactive \n" +
                        "   id : String = \"a\" \n" +
                        "   fld2 : int = 4 \n" +
                        "   fld3 : double = 4.0 \n" +
                        "   fld4 : String = \"hello\" \n" +
                        "   fldZ : String = \"hello\" @Alias( \"fld5\" )\n" +
                        "end\n" +
                        "declare trait Worker\n" +
                        "   @propertyReactive \n" +
                        "   id : int = 3 \n" +
                        "   fld2 : String = \"b\" \n " +
                        "   fld3 : int = 11 \n " +
                        "   fld4 : Class = Object.class \n " +
                        "   fldY : int = 42 @Alias( \"fld5\" )\n" +
                        "end\n" +
                        "" +
                        "rule \"Init\" when then \n" +
                        "   insert( new Person() ); \n" +
                        "end \n" +
                        "" +
                        "\n" +
                        "rule \"Don\"\n" +
                        "when\n" +
                        "   $p : Person() \n" +
                        "then\n" +
                        "  System.out.println( \"Don person\" ); \n"
                        +
                        "  Student $s = (Student) don( $p, Student.class );\n" +
                        "  modify ( $s ) { setId( \"xyz\" ); } " +
                        "  " +
                        "  Worker $w = don( $p, Worker.class );\n" +
                        "  modify ( $w ) { setId( 99 ); } " +
                        "end\n" +
                        "\n" +
                        "rule \"Stud\"\n" +
                        "when\n" +
                        "  $s : Student( $sid : id == \"xyz\", $f2 : fld2, $f3 : fld3, $f4 : fld4, $f5 : fldZ )\n" +
                        "then\n" +
                        "  System.out.println( \">>>>>>>>>> Student\" + $s ); \n" +
                        "  list.add( $sid ); \n" +
                        "  list.add( $f2 ); \n" +
                        "  list.add( $f3 ); \n" +
                        "  list.add( $f4 ); \n" +
                        "  list.add( $f5 ); \n" +
                        "end\n" +
                        "\n" +
                        "rule \"Mod\"\n" +
                        "when\n" +
                        "  $w : Worker( $wid : id == 99, $f2 : fld2, $f3 : fld3, $f4 : fld4, $f5 : fldY )\n" +
                        "then\n" +
                        "  System.out.println( \">>>>>>>>>> Worker\" + $w );\n" +
                        "  list.add( $wid ); \n" +
                        "  list.add( $f2 ); \n" +
                        "  list.add( $f3 ); \n" +
                        "  list.add( $f4 ); \n" +
                        "  list.add( $f5 ); \n" +
                        "end";

        StatefulKnowledgeSession ks = getSessionFromString( source );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );

        ks.fireAllRules();

        assertEquals( 5, list.size() );
        assertEquals( Arrays.asList( 99, "b", 11, Object.class, 42 ), list );

        ks.dispose();
    }


    @Test
    public void testMultipleModifications() {
        String drl = "package org.drools.traits.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "" +
                     "global java.util.List list;" +
                     "\n" +
                     "declare Person\n" +
                     "@Traitable\n" +
                     "@propertyReactive\n" +
                     "    ssn : String\n" +
                     "    pob : String\n" +
                     "    isStudent : boolean\n" +
                     "    hasAssistantship : boolean\n" +
                     "end\n" +
                     "\n" +
                     "declare trait Student\n" +
                     "@propertyReactive\n" +
                     "    studyingCountry : String\n" +
                     "    hasAssistantship : boolean\n" +
                     "end\n" +
                     "\n" +
                     "declare trait Worker\n" +
                     "@propertyReactive\n" +
                     "    pob : String\n" +
                     "    workingCountry : String\n" +
                     "end\n" +
                     "\n" +
                     "declare trait USCitizen\n" +
                     "@propertyReactive\n" +
                     "    pob : String = \"US\"\n" +
                     "end\n" +
                     "\n" +
                     "declare trait ITCitizen\n" +
                     "@propertyReactive\n" +
                     "    pob : String = \"IT\"\n" +
                     "end\n" +
                     "\n" +
                     "declare trait IRCitizen\n" +
                     "@propertyReactive\n" +
                     "    pob : String = \"IR\"\n" +
                     "end\n" +
                     "\n" +
                     "rule \"init\"\n" +
                     "when\n" +
                     "then\n" +
                     "    insert( new Person(\"1234\",\"IR\",true,true) );\n" +
                     "end\n" +
                     "\n" +
                     "rule \"check for being student\"\n" +
                     "when\n" +
                     "    $p : Person( $ssn : ssn, $pob : pob,  isStudent == true )\n" +
                     "then\n" +
                     "    Student st = (Student) don( $p , Student.class );\n" +
                     "    modify( st ){\n" +
                     "        setStudyingCountry( \"US\" );\n" +
                     "    }\n" +
                     "end\n" +
                     "\n" +
                     "rule \"check for IR\"\n" +
                     "when\n" +
                     "    $p : Person( pob == \"IR\" )\n" +
                     "then\n" +
                     "    don( $p , IRCitizen.class );\n" +
                     "end\n" +
                     "\n" +
                     "rule \"check for being US citizen\"\n" +
                     "when\n" +
                     "    $s : Student( studyingCountry == \"US\" )\n" +
                     "then\n" +
                     "    don( $s , USCitizen.class );\n" +
                     "end\n" +
                     "\n" +
                     "rule \"check for being worker\"\n" +
                     "when\n" +
                     "    $p : Student( hasAssistantship == true, $sc : studyingCountry  )\n" +
                     "then\n" +
                     "    Worker wr = (Worker) don( $p , Worker.class );\n" +
                     "    modify( wr ){\n" +
                     "        setWorkingCountry( $sc );\n" +
                     "    }\n" +
                     "\n" +
                     "end\n" +
                     "\n" +
                     "rule \"Join Full\"\n" +
                     "salience -1\n" +
                     "when\n" +
                     "    Student( )      // $sc := studyingCountry )\n" +
                     "    USCitizen( )\n" +
                     "    IRCitizen( )      // $pob := pob )\n" +
                     "    Worker( )       // pob == $pob , workingCountry == $sc )\n" +
                     "then\n" +
                     "    list.add( 1 ); " +
                     "end\n" +
                     "\n" +
                     "\n";

        StatefulKnowledgeSession ks = getSessionFromString( drl );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );

        HashMap map;
        ks.fireAllRules();

        assertTrue( list.contains( 1 ) );
        assertEquals( 1, list.size() );

        ks.dispose();

    }


    @Test
    public void testPropagation() {
        String drl = "package org.drools.test;\n" +
                     "import org.drools.core.factmodel.traits.*; \n" +
                     "\n" +
                     "global java.util.List list; \n" +
                     "" +
                     "declare X @Traitable end \n" +
                     "" +
                     "declare trait A @propertyReactive end\n" +
                     "declare trait B extends A @propertyReactive end\n" +
                     "declare trait C extends B @propertyReactive end \n" +
                     "declare trait D extends C @propertyReactive end\n" +
                     "declare trait E extends B,C @propertyReactive end\n" +
                     "declare trait F extends E @propertyReactive end\n" +
                     "declare trait G extends B @propertyReactive end\n" +
                     "declare trait H extends G @propertyReactive end\n" +
                     "declare trait I extends E,H @propertyReactive end\n" +
                     "declare trait J extends I @propertyReactive end\n" +
                     "" +
                     "rule Init when then X x = new X(); insert( x ); don( x, F.class); end \n"+
                     "rule Go when String( this == \"go\" ) $x : X() then don( $x, H.class); end \n" +
                     "rule Go2 when String( this == \"go2\" ) $x : X() then don( $x, D.class); end \n" +
                     "";

        for ( int j = 'A'; j <= 'J'; j ++ ) {
            String x = "" + (char) j;
            drl += "rule \"Log " + x + "\" when " + x + "() then System.out.println( \"@@ " + x + " detected \" ); list.add( \"" + x + "\" ); end \n";

            drl += "rule \"Log II" + x + "\" salience -1 when " + x + "( ";
            drl += "this isA H";
            drl += " ) then System.out.println( \"@@ as H >> " + x + " detected \" ); list.add( \"H" + x + "\" ); end \n";
        }

        StatefulKnowledgeSession ks = getSessionFromString( drl );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );

        ks.fireAllRules();

        assertTrue( list.contains( "A" ) );
        assertTrue( list.contains( "B" ) );
        assertTrue( list.contains( "C" ) );
        assertTrue( list.contains( "E" ) );
        assertTrue( list.contains( "F" ) );
        assertEquals( 5, list.size() );

        list.clear();

        System.out.println( "---------------------------------------" );

        ks.insert( "go" );
        ks.fireAllRules();

        assertTrue( list.contains( "H" ) );
        assertTrue( list.contains( "G" ) );
        assertTrue( list.contains( "HA" ) );
        assertTrue( list.contains( "HB" ) );
        assertTrue( list.contains( "HC" ) );
        assertTrue( list.contains( "HE" ) );
        assertTrue( list.contains( "HF" ) );
        assertTrue( list.contains( "HG" ) );
        assertTrue( list.contains( "HH" ) );
        assertEquals( 9, list.size() );
        list.clear();

        System.out.println( "---------------------------------------" );

        ks.insert( "go2" );
        ks.fireAllRules();

        assertTrue( list.contains( "D" ) );
        assertTrue( list.contains( "HA" ) );
        assertTrue( list.contains( "HB" ) );
        assertTrue( list.contains( "HC" ) );
        assertTrue( list.contains( "HE" ) );
        assertTrue( list.contains( "HF" ) );
        assertTrue( list.contains( "HG" ) );
        assertTrue( list.contains( "HH" ) );
        assertTrue( list.contains( "HH" ) );
        assertTrue( list.contains( "HD" ) );
        assertEquals( 9, list.size() );

        ks.dispose();

    }



    @Test
    public void testParentBlockers() {
        String drl = "package org.drools.test;\n" +
                     "import org.drools.core.factmodel.traits.*; \n" +
                     "\n" +
                     "global java.util.List list; \n" +
                     "" +
                     "declare X @Traitable end \n" +
                     "" +
                     "declare trait A @propertyReactive end\n" +
                     "declare trait B @propertyReactive end\n" +
                     "declare trait C extends A, B @propertyReactive end \n" +
                     "" +
                     "rule Init when then X x = new X(); insert( x ); don( x, A.class); don( x, B.class); end \n"+
                     "rule Go when String( this == \"go\" ) $x : X() then don( $x, C.class); end \n" +
                     "rule Go2 when String( this == \"go2\" ) $x : C() then System.out.println( 1000 ); end \n" +
                     "";


        StatefulKnowledgeSession ks = getSessionFromString( drl );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );

        ks.fireAllRules();

        ks.insert( "go" );
        ks.fireAllRules();

        ks.insert( "go2" );
        ks.fireAllRules();

        System.out.println( "---------------------------------------" );

        ks.dispose();

    }




    @Test
    public void testTraitLogicalTMS() {
        String drl = "package org.drools.test;\n" +
                     "import org.drools.core.factmodel.traits.*; \n" +
                     "\n" +
                     "global java.util.List list; \n" +
                     "" +
                     "declare X @Traitable end \n" +
                     "" +
                     "declare trait A @propertyReactive end\n" +
                     "declare trait B @propertyReactive end\n" +
                     "" +
                     "rule Init when then X x = new X(); insert( x ); end \n"+
                     "rule Go when String( this == \"go\" ) $x : X() then don( $x, A.class, true ); don( $x, B.class, true ); end \n" +
                     "rule Go2 when String( this == \"go2\" ) $x : X() then don( $x, A.class ); end \n" +
                     "rule Go3 when String( this == \"go3\" ) $x : A() not B() then list.add( 100 ); end \n" +
                     "";

        StatefulKnowledgeSession ks = getSessionFromString( drl );
        TraitFactory.setMode( mode, ks.getKieBase() );

        List list = new ArrayList();
        ks.setGlobal( "list", list );

        ks.fireAllRules();

        FactHandle handle = ks.insert( "go" );
        ks.fireAllRules();

        ks.insert( "go2" );
        ks.fireAllRules();

        ks.delete( handle );
        ks.fireAllRules();

        System.out.println( "---------------------------------------" );

        for ( Object o : ks.getObjects() ) {
            System.out.println( o );
        }

        ks.insert( "go3" );
        ks.fireAllRules();

        assertEquals( Arrays.asList( 100 ), list );

        ks.dispose();
    }


    @Test
    public void testTraitNoType() {
        String drl = "" +
                     "package org.drools.core.factmodel.traits.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.Thing;\n" +
                     "import org.drools.core.factmodel.traits.Traitable;\n" +
                     "import org.drools.core.factmodel.traits.Trait;\n" +
                     "import org.drools.core.factmodel.traits.Alias;\n" +
                     "import java.util.*;\n" +
                     "\n" +
                     "global java.util.List list;\n" +
                     "\n" +
                     "\n" +
                     "declare Parent\n" +
                     "@Traitable( logical = true )" +
                     "@propertyReactive\n" +
                     "end\n" +
                     "\n" +
                     "declare trait ChildTrait\n" +
                     "@propertyReactive\n" +
                     "    naam : String = \"kudak\"\n" +
                     "    id : int = 1020\n" +
                     "end\n" +
                     "\n" +
                     "rule \"don\"\n" +
                     "no-loop\n" +
                     "when\n" +
                     "then\n" +
                     "    Parent p = new Parent();" +
                     "    insert(p);\n" +
                     "    ChildTrait ct = don( p , ChildTrait.class );\n" +
                     "    list.add(\"correct1\");\n" +
                     "end\n" +
                     "\n" +
                     "rule \"check\"\n" +
                     "no-loop\n" +
                     "when\n" +
                     "    $c : ChildTrait($n : naam == \"kudak\", id == 1020 )\n" +
                     "    $p : Thing( core == $c.core, fields[\"naam\"] == $n )\n" +
                     "then\n" +
                     "    list.add(\"correct2\");\n" +
                     "end";

        StatefulKnowledgeSession ksession = loadKnowledgeBaseFromString(drl).newStatefulKnowledgeSession();
        TraitFactory.setMode( mode, ksession.getKieBase());

        List list = new ArrayList();
        ksession.setGlobal("list",list);
        ksession.fireAllRules();

        assertTrue(list.contains("correct1"));
        assertTrue(list.contains("correct2"));
    }




    @Test
    public void testTraitdeleteOrder() {
        String drl = "" +
                     "package org.drools.core.factmodel.traits.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.*;\n" +
                     "import java.util.*;\n" +
                     "\n" +
                     "declare trait A end \n" +
                     "declare trait B extends A end \n" +
                     "declare trait C end \n" +
                     "\n" +
                     "rule \"don\"\n" +
                     "when \n" +
                     "  $e : Entity() \n" +
                     "then\n" +
                     "  don( $e, A.class ); \n" +
                     "  don( $e, C.class ); \n" +
                     "  don( $e, B.class ); \n" +
                     "end\n" +
                     "";

        StatefulKnowledgeSession ksession = loadKnowledgeBaseFromString(drl).newStatefulKnowledgeSession();
        TraitFactory.setMode( mode, ksession.getKieBase() );

        FactHandle handle = ksession.insert( new Entity(  ) );
        ksession.fireAllRules();

        final ArrayList list = new ArrayList();

        ksession.addEventListener( new RuleRuntimeEventListener() {
            public void objectInserted( org.kie.api.event.rule.ObjectInsertedEvent objectInsertedEvent ) { }
            public void objectUpdated( org.kie.api.event.rule.ObjectUpdatedEvent objectUpdatedEvent ) { }
            public void objectDeleted( org.kie.api.event.rule.ObjectDeletedEvent objectRetractedEvent ) {
                Object o = objectRetractedEvent.getOldObject();
                if ( o instanceof TraitProxy ) {
                    String traitName = ( (TraitProxy) o ).getTraitName();
                    list.add( traitName.substring( traitName.lastIndexOf( "." ) + 1 ) );
                }
            }
        } );

        ksession.delete( handle );
        ksession.fireAllRules();

        System.out.println( list );
        assertEquals( Arrays.asList( "B", "C", "A" ), list );
    }


    @Test
    public void testTraitWithManySoftFields() {
        String drl = "" +
                     "package org.drools.core.factmodel.traits.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.*;\n" +
                     "import java.util.*;\n" +
                     "\n" +
                     "declare trait Tx \n";

        for ( int j = 0; j < 150; j ++ ) {
            drl += " fld" + j + " : String \n";
        }

        drl += "" +
               "end \n" +
               "\n" +
               "declare TBean @Traitable fld0 : String end \n" +
               "" +
               "rule \"don\"\n" +
               "when \n" +
               "then\n" +
               "  don( new TBean(), Tx.class ); \n" +
               "end\n" +
               "" +
               "";

        StatefulKnowledgeSession ksession = loadKnowledgeBaseFromString(drl).newStatefulKnowledgeSession();
        TraitFactory.setMode( mode, ksession.getKieBase() );

        ksession.fireAllRules();

        assertEquals( 2, ksession.getObjects().size() );

    }



    public static class CountingWorkingMemoryEventListener implements RuleRuntimeEventListener {

        private int inserts = 0;
        private int updates = 0;
        private int deletes = 0;

        public int getInserts() {
            return inserts;
        }

        public int getUpdates() {
            return updates;
        }

        public int getdeletes() {
            return deletes;
        }

        @Override
        public void objectInserted( org.kie.api.event.rule.ObjectInsertedEvent event ) {
            if ( ! ( event.getObject() instanceof String ) ) {
                inserts++;
            }
        }

        @Override
        public void objectUpdated( org.kie.api.event.rule.ObjectUpdatedEvent event ) {
            if ( ! ( event.getObject() instanceof String ) ) {
                updates++;
            }
        }

        public void objectDeleted( org.kie.api.event.rule.ObjectDeletedEvent objectdeleteedEvent ) {
            if ( ! ( objectdeleteedEvent.getOldObject() instanceof String ) ) {
                deletes++;
            }
        }

        public void reset() {
            inserts = 0;
            deletes = 0;
            updates = 0;
        }
    }


    @Test
    public void testDonManyTraitsAtOnce() {
        String drl = "" +
                     "package org.drools.core.factmodel.traits.test;\n" +
                     "\n" +
                     "import org.drools.core.factmodel.traits.*;\n" +
                     "import java.util.*;\n" +
                     "\n" +
                     "global List list; \n" +
                     "" +
                     "declare trait A end \n" +
                     "declare trait B end \n" +
                     "declare trait C end \n" +
                     "declare trait D end \n" +
                     "declare trait E end \n" +
                     "declare trait F end \n" +
                     "\n" +
                     "declare TBean @Traitable @propertyReactive fld0 : String end \n" +
                     "" +
                     "rule \"Don 1\"\n" +
                     "when \n" +
                     "then\n" +
                     "  TBean t = new TBean(); \n" +
                     "  don( t, A.class ); \n" +
                     "  don( t, B.class ); \n" +
                     "end\n" +
                     "" +
                     "rule \"Don 2\" " +
                     "when \n" +
                     "  $s : String( this == \"go\" ) \n" +
                     "  $t : TBean() \n" +
                     "then \n" +
                     "  list.add( 0 ); \n" +
                     "  System.out.println( \"Call DON MANY \" ); " +
                     "  don( $t, Arrays.asList( C.class, D.class, E.class, F.class ), true ); \n" +
                     "end \n" +
                     "" +
                     "rule Clear \n" +
                     "when \n" +
                     "  $s : String( this == \"undo\" ) \n" +
                     "  $t : TBean() \n" +
                     "then \n" +
                     "  delete( $s ); \n" +
                     "  delete( $t ); \n" +
                     "end \n" +
                     "" +
                     "rule C \n" +
                     "when\n" +
                     "  B( this isA C ) \n" +
                     "then \n" +
                     "  list.add( 1 ); \n" +
                     "  System.err.println( \"C is HERE !! \" ); " +
                     "end \n" +
                     "rule D \n" +
                     "when\n" +
                     "  D( this isA A, this isA C ) \n" +
                     "then \n" +
                     "  list.add( 2 ); \n" +
                     "  System.err.println( \"D is HERE TOO !! \" ); " +
                     "end \n"+
                     "rule E \n" +
                     "when\n" +
                     "  D( this isA A, this isA E ) \n" +
                     "then \n" +
                     "  list.add( 3 ); \n" +
                     "  System.err.println( \"AND E JOINS THE COMPANY !! \" ); " +
                     "end \n";

        StatefulKnowledgeSession ksession = loadKnowledgeBaseFromString(drl).newStatefulKnowledgeSession();
        TraitFactory.setMode( mode, ksession.getKieBase() );
        ArrayList list = new ArrayList();
        ksession.setGlobal( "list", list );

        CountingWorkingMemoryEventListener cwm = new CountingWorkingMemoryEventListener();
        ksession.addEventListener( cwm );

        ksession.fireAllRules();

        // insert Core Bean, A, B, Thing.
        // Update the bean on don A, update the bean and A on don B
        assertEquals( 0, cwm.getdeletes() );
        assertEquals( 3, cwm.getInserts() );
        assertEquals( 2, cwm.getUpdates() );
        cwm.reset();

        FactHandle handle = ksession.insert( "go" );
        ksession.fireAllRules();

        // don C, D, E, F at once : 4 inserts
        // Update the bean, A and B.
        assertEquals( 0, cwm.getdeletes() );
        assertEquals( 4, cwm.getInserts() );
        assertEquals( 3, cwm.getUpdates() );
        cwm.reset();

        ksession.delete( handle );
        ksession.fireAllRules();

        // logically asserted C, D, E, F are deleteed
        // as a logical deleteion, no update is made. This could be a bug....
        assertEquals( 4, cwm.getdeletes() );
        assertEquals( 0, cwm.getInserts() );
        assertEquals( 0, cwm.getUpdates() );
        cwm.reset();

        for ( Object o : ksession.getObjects() ) {
            System.out.println( o );
        }

        ksession.insert( "undo" );
        ksession.fireAllRules();

        // deleteing the core bean
        // A, B, Thing are deleteed too
        assertEquals( 3, cwm.getdeletes() );
        assertEquals( 0, cwm.getInserts() );
        assertEquals( 0, cwm.getUpdates() );
        cwm.reset();


        assertEquals( 4, list.size() );
        assertTrue( list.containsAll( Arrays.asList( 0, 1, 2, 3 ) ) );
    }




    @Traitable
    public static class Item {
        private String id;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }
    }

    public static class TraitRulesThread implements Runnable {
        int threadIndex;
        int numRepetitions;
        StatefulKnowledgeSession ksession;

        public TraitRulesThread(int threadIndex, int numRepetitions, final StatefulKnowledgeSession ksession) {
            this.threadIndex = threadIndex;
            this.numRepetitions = numRepetitions;
            this.ksession = ksession;
        }
        public void run() {
            for (int repetitionIndex = 0; repetitionIndex < numRepetitions; repetitionIndex++) {
                final Item i = new Item();
                i.setId(String.format("testId_%d%d", threadIndex, repetitionIndex));
                ksession.insert(i);
                ksession.fireAllRules();
            }
        }
    }

    @Test
    @Ignore("Triple Store is not thread safe and needs to be rewritten")
    public void testMultithreadingTraits() throws InterruptedException {
        final String s1 = "package test;\n" +
                          "import org.drools.core.factmodel.traits.TraitTest.Item;\n" +
                          "declare Item end\n" +
                          "declare trait ItemStyle\n" +
                          "  id: String\n" +
                          "  adjustable: boolean\n" +
                          "end\n" +
                          "rule \"Don ItemStyle\"\n" +
                          "  no-loop true\n" +
                          "  when\n" +
                          "    $p : Item ()\n" +
                          "    not ItemStyle ( id == $p.id )\n" +
                          "  then\n" +
                          "    don($p, ItemStyle.class);\n" +
                          "end\n" +
                          "rule \"Item Style - Adjustable\"" +
                          "  no-loop true" +
                          "  when" +
                          "    $style : ItemStyle ( !adjustable )" +
                          "    Item (" +
                          "      id == $style.id " +
                          "    )" +
                          "  then" +
                          "    modify($style) {" +
                          "      setAdjustable(true)" +
                          "    };" +
                          "end";
        final KnowledgeBase kbase = getKieBaseFromString(s1);
        TraitFactory.setMode( mode, kbase );

        // might need to tweak these numbers.  often works with 7-10,100,60, but often fails 15-20,100,60
        int MAX_THREADS = 20;
        int MAX_REPETITIONS = 100;
        int MAX_WAIT_SECONDS = 60;

        final ExecutorService executorService = Executors.newFixedThreadPool( MAX_THREADS );
        for (int threadIndex = 0; threadIndex < MAX_THREADS; threadIndex++) {
            executorService.execute(new TraitRulesThread(threadIndex, MAX_REPETITIONS, kbase.newStatefulKnowledgeSession()));
        }

        executorService.shutdown();
        executorService.awaitTermination(MAX_WAIT_SECONDS, TimeUnit.SECONDS);
        final List<Runnable> queuedTasks = executorService.shutdownNow();

        assertEquals(0, queuedTasks.size());
        assertEquals(true, executorService.isTerminated());
    }


    @Test
    public void testShedOneLastTrait() throws InterruptedException {
        final String s1 = "package test;\n" +
                          "import org.drools.core.factmodel.traits.*; \n" +
                          "global java.util.List list;\n" +
                          "" +
                          "declare Core @Traitable end\n" +
                          "" +
                          "declare trait Mask\n" +
                          "end\n" +
                          "" +
                          "rule \"Don ItemStyle\"\n" +
                          "  when\n" +
                          "  then\n" +
                          "    don( new Core(), Mask.class );\n" +
                          "end\n" +
                          "" +
                          "rule \"React\" \n" +
                          "  when \n" +
                          "     $s : String() \n" +
                          "    $m : Mask() \n" +
                          "then \n" +
                          "     delete( $s ); \n" +
                          "     shed( $m, Mask.class ); \n" +
                          "end\n" +
                          "" +
                          "rule Log \n" +
                          "when \n" +
                          " $t : Thing() \n" +
                          "then \n" +
                          " System.out.println( \"Thing detected \" + $t ); \n" +
                          " list.add( $t.getClass().getName() ); \n" +
                          "end \n" +
                          "";

        final KnowledgeBase kbase = getKieBaseFromString(s1);
        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession knowledgeSession = kbase.newStatefulKnowledgeSession();
        knowledgeSession.setGlobal( "list", list );

        knowledgeSession.fireAllRules();

        assertEquals( 1, list.size() );
        assertEquals( Arrays.asList( "test.Mask.test.Core_Proxy" ), list );

        knowledgeSession.insert( "shed" );
        knowledgeSession.fireAllRules();

        assertEquals( 2, list.size() );
        assertEquals( Arrays.asList( "test.Mask.test.Core_Proxy", "org.drools.core.factmodel.traits.Thing.test.Core_Proxy" ), list );
    }



    @Test
    public void testShedThingCompletelyThenDonAgain() throws InterruptedException {
        final String s1 = "package test;\n" +
                          "import org.drools.core.factmodel.traits.*; \n" +
                          "global java.util.List list;\n" +
                          "" +
                          "declare Core @Traitable end\n" +
                          "" +
                          "declare trait Mask end\n" +
                          "declare trait Mask2 end\n" +
                          "" +
                          "rule \"Don ItemStyle\"\n" +
                          "  when\n" +
                          "     $s : String( this == \"don1\" ) \n" +
                          "  then\n" +
                          "     delete( $s ); \n" +
                          "    don( new Core(), Mask.class );\n" +
                          "end\n" +
                          "" +
                          "rule \"Clear\" \n" +
                          "  when \n" +
                          "     $s : String( this == \"shed1\" ) \n" +
                          "    $m : Mask() \n" +
                          "then \n" +
                          "     delete( $s ); \n" +
                          "     shed( $m, Thing.class ); \n" +
                          "end\n" +
                          "" +
                          "rule \"Add\" \n" +
                          "  when \n" +
                          "     $s : String( this == \"don2\" ) \n" +
                          "    $c : Core() \n" +
                          "then \n" +
                          "     delete( $s ); \n" +
                          "     don( $c, Mask2.class ); \n" +
                          "end\n" +
                          "" +
                          "rule \"Clear Again\" \n" +
                          "  when \n" +
                          "     $s : String( this == \"shed2\" ) \n" +
                          "    $m : Mask2() \n" +
                          "then \n" +
                          "     delete( $s ); \n" +
                          "     shed( $m, Mask2.class ); \n" +
                          "end\n" +
                          "" +
                          "" +
                          "rule Log \n" +
                          "when \n" +
                          " $t : Thing() \n" +
                          "then \n" +
                          "  System.out.println( \"Thing detected \" + $t ); \n" +
                          "  list.add( $t.getClass().getName() ); \n" +
                          "end \n" +
                          "";

        final KnowledgeBase kbase = getKieBaseFromString(s1);
        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession knowledgeSession = kbase.newStatefulKnowledgeSession();
        knowledgeSession.setGlobal( "list", list );

        knowledgeSession.insert( "don1" );
        knowledgeSession.fireAllRules();

        assertEquals( 1, list.size() );
        assertEquals( Arrays.asList( "test.Mask.test.Core_Proxy" ), list );

        knowledgeSession.insert( "shed1" );
        knowledgeSession.fireAllRules();

        assertEquals( 1, list.size() );
        assertEquals( Arrays.asList( "test.Mask.test.Core_Proxy" ), list );

        knowledgeSession.insert( "don2" );
        knowledgeSession.fireAllRules();

        System.out.println( list );
        assertEquals( 2, list.size() );
        assertEquals( Arrays.asList( "test.Mask.test.Core_Proxy", "test.Mask2.test.Core_Proxy" ), list );

        knowledgeSession.insert( "shed2" );
        knowledgeSession.fireAllRules();

        assertEquals( 3, list.size() );
        assertEquals( Arrays.asList( "test.Mask.test.Core_Proxy", "test.Mask2.test.Core_Proxy", "org.drools.core.factmodel.traits.Thing.test.Core_Proxy" ), list );

    }


    @Test
    public void testTraitImplicitInsertionExceptionOnNonTraitable() throws InterruptedException {
        final String s1 = "package test;\n" +
                          "import org.drools.core.factmodel.traits.*; \n" +
                          "global java.util.List list;\n" +
                          "" +
                          "declare Core id : String  end\n" // should be @Traitable
                          "" +
                          "declare trait Mask  id : String end\n" +
                          "" +
                          "rule \"Don ItemStyle\"\n" +
                          "  when\n" +
                          "  then\n" +
                          "    don( new Core(), Mask.class );\n" +
                          "end\n" +
                          "" +
                          "";

        final KnowledgeBase kbase = getKieBaseFromString(s1);
        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession knowledgeSession = kbase.newStatefulKnowledgeSession();
        knowledgeSession.setGlobal( "list", list );

        try {
            knowledgeSession.fireAllRules();
            fail( "Core is not declared @Traitable, this test should have thrown an exception" );
        } catch ( Exception csq ) {
            assertTrue( csq.getCause() instanceof IllegalStateException );
        }

    }


    @Trait
    public static interface SomeTrait<K> extends Thing<K> {
        public String getFoo();
        public void setFoo( String foo );
    }

    @Test
    public void testTraitLegacyTraitableWithLegacyTrait() {
        final String s1 = "package org.drools.compiler.factmodel.traits;\n" +
                          "import " + TraitTest.class.getName() + ".SomeTrait; \n" +
                          "import org.drools.core.factmodel.traits.*; \n" +
                          "global java.util.List list;\n" +
                          "" +
                          "rule \"Don ItemStyle\"\n" +
                          "  when\n" +
                          "  then\n" +
                          "    don( new StudentImpl(), SomeTrait.class );\n" +
                          "end\n";

        final KnowledgeBase kbase = getKieBaseFromString(s1);
        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession knowledgeSession = kbase.newStatefulKnowledgeSession();
        knowledgeSession.setGlobal( "list", list );

        knowledgeSession.fireAllRules();

        assertEquals( 2, knowledgeSession.getObjects().size() );
    }

    @Test
    public void testIsALegacyTrait() {
        final String s1 = "package org.drools.compiler.factmodel.traits;\n" +
                          "import " + TraitTest.class.getName() + ".SomeTrait; \n" +
                          "import org.drools.core.factmodel.traits.*; \n" +
                          "global java.util.List list;\n" +
                          "" +
                          "declare trait IStudent end \n" +
                          "" +
                          "rule \"Don ItemStyle\"\n" +
                          "  when\n" +
                          "  then\n" +
                          "    insert( new StudentImpl() );\n" +
                          "    don( new Entity(), IStudent.class );\n" +
                          "end\n" +
                          "" +
                          "rule Check " +
                          " when " +
                          "  $s : StudentImpl() " +
                          "  $e : Entity( this isA $s ) " +
                          " then " +
                          "  list.add( 1 ); " +
                          " end ";

        final KnowledgeBase kbase = getKieBaseFromString(s1);
        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession knowledgeSession = kbase.newStatefulKnowledgeSession();
        knowledgeSession.setGlobal( "list", list );

        knowledgeSession.fireAllRules();

        assertEquals( Arrays.asList( 1 ), list );
    }


    @Test
    public void testClassLiteralsWithOr() {

        String drl = "package org.drools.test; " +
                     "import org.drools.core.factmodel.traits.*; " +
                     "global java.util.List list; " +

                     "declare Foo " +
                     "@Traitable " +
                     "end " +

                     "declare trait A end " +
                     "declare trait B end " +

                     "rule Init " +
                     "when " +
                     "then " +
                     "  Foo f = new Foo(); " +
                     "  insert( f ); " +
                     "end " +

                     "rule One " +
                     "when " +
                     "  $f : Foo( this not isA A ) " +
                     "then " +
                     "  don( $f, A.class ); " +
                     "end " +

                     "rule Two " +
                     "when " +
                     "  $f : Foo( this not isA B ) " +
                     "then " +
                     "  don( $f, B.class ); " +
                     "end " +

                     "rule Check " +
                     "when " +
                     "    $f : Foo( this isA B || this isA A ) " +
                     "then " +
                     "  list.add( 1 ); " +
                     "end " +

                     "";


        KnowledgeBase kbase = loadKnowledgeBaseFromString( drl );
        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.setGlobal( "list", list );

        ksession.fireAllRules();

        assertEquals( Arrays.asList( 1 ), list );

    }



    @Test
    public void testIsASwappedArg() {

        String drl = "package org.drools.test; " +
                     "import org.drools.core.factmodel.traits.*; " +
                     "import org.drools.compiler.factmodel.traits.*; " +
                     "global java.util.List list; " +

                     "declare Foo " +
                     "@Traitable " +
                     "  object : Object " +
                     "end " +

                     "declare Bar " +
                     "@Traitable " +
                     "end " +

                     "declare trait IPerson end " +
                     "declare trait IStudent end " +

                     "rule Init " +
                     "when " +
                     "then " +
                     "  Foo f = new Foo( new StudentImpl() ); " +
                     "  don( f, IPerson.class ); " +
                     "end " +

                     "rule Match1 " +
                     "when " +
                     "  $f : Foo( $x : object ) " +
                     "  $p : StudentImpl( this isA $f ) from $x " +
                     "then " +
                     "  list.add( 1 ); " +
                     "end " +

                     "rule Match2 " +
                     "when " +
                     "  $f : Foo( $x : object ) " +
                     "  $p : StudentImpl( $f isA this ) from $x " +
                     "then " +
                     "  list.add( 2 ); " +
                     "end " +

                     "";


        KnowledgeBase kbase = loadKnowledgeBaseFromString( drl );
        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        ksession.setGlobal( "list", list );

        ksession.fireAllRules();

        assertEquals( 2, list.size() );
        assertTrue( list.contains( 1 ) );
        assertTrue( list.contains( 2 ) );

    }


    @Test
    public void testHierarchyEncodeOnPackageMerge() {

        String drl0 = "package org.drools.test; " +
                      "declare trait X end ";

        String drl1 = "package org.drools.test; " +
                     "import org.drools.core.factmodel.traits.*; " +
                     "global java.util.List list; " +

                     "declare trait A end " +
                     "declare trait B extends A end " +
                     "declare trait C extends B end " +

                     "";

        KnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
        TraitFactory.setMode( mode, knowledgeBase );

        KnowledgeBuilder kb = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kb.add( new ByteArrayResource( drl0.getBytes() ), ResourceType.DRL );
        assertFalse( kb.hasErrors() );

        knowledgeBase.addKnowledgePackages( kb.getKnowledgePackages() );

        KnowledgeBuilder kb2 = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kb2.add( new ByteArrayResource( drl1.getBytes() ), ResourceType.DRL );
        System.out.print( kb2.getErrors() );
        assertFalse( kb2.hasErrors() );

        knowledgeBase.addKnowledgePackages( kb2.getKnowledgePackages() );

        HierarchyEncoder<String> hier = ( (KnowledgeBaseImpl) knowledgeBase ).getConfiguration().getComponentFactory().getTraitRegistry().getHierarchy();
        BitSet b = (BitSet) hier.getCode( "org.drools.test.B" ).clone();
        BitSet c = (BitSet) hier.getCode( "org.drools.test.C" ).clone();

        c.and( b );
        assertEquals( b, c );

    }




    @Test
    public void testDonThenReinsert() throws InterruptedException {
        final String s1 = "package test;\n" +
                          "import org.drools.core.factmodel.traits.*; \n" +
                          "import org.drools.compiler.factmodel.traits.TraitTest.TBean;\n" +
                          "global java.util.List list;\n" +
                          "" +
                          "declare TBean " +
                          " @Traitable " +
                          " @propertyReactive " +
                          "end " +
                          "" +
                          "declare trait Mask " +
                          " @propertyReactive " +
                          "end " +
                          "" +
                          "rule 'Don ItemStyle' " +
                          "  when\n" +
                          "     $e : TBean( ) " +
                          "  then " +
                          "     System.out.println( 'Don' ); " +
                          "    don( $e, Mask.class );\n" +
                          "end\n" +
                          "" +
                          "rule \"React\" \n" +
                          "  when \n" +
                          "    $m : Mask() \n" +
                          "then \n" +
                          "     System.out.println( $m ); \n" +
                          "end\n" +
                          "" +
                          "rule Zero when not Object() then System.out.println( 'Clean' ); end ";

        KieBaseConfiguration kbx = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();

        final RuleBaseConfiguration conf = new RuleBaseConfiguration();
        conf.setAssertBehaviour( RuleBaseConfiguration.AssertBehaviour.IDENTITY );

        final KnowledgeBase kbase = getKieBaseFromString(s1, conf);

        TraitFactory.setMode( mode, kbase );
        ArrayList list = new ArrayList();

        StatefulKnowledgeSession knowledgeSession = kbase.newStatefulKnowledgeSession();
        knowledgeSession.setGlobal( "list", list );
        TBean e = new TBean( "aaa" );

        int n = knowledgeSession.fireAllRules();
        assertEquals( 1, n );

        knowledgeSession.insert( e );
        n = knowledgeSession.fireAllRules();
        assertEquals( 2, n );

        knowledgeSession.insert( e );
        n = knowledgeSession.fireAllRules();
        assertEquals( 0, n );

        knowledgeSession.delete( knowledgeSession.getFactHandle( e ) );
        n = knowledgeSession.fireAllRules();
        assertEquals( 1, n );

        assertEquals( 0, knowledgeSession.getObjects().size() );

    }

}
TOP

Related Classes of org.drools.compiler.factmodel.traits.TraitTest

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