/*
 * Copyright 2018 Red Hat, Inc. and/or its affiliates.
 *
 * 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.kie.camel.embedded.camel.component;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.naming.Context;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JaxbDataFormat;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.custommonkey.xmlunit.XMLUnit;
import org.drools.core.common.InternalFactHandle;
import org.drools.core.impl.StatefulKnowledgeSessionImpl;
import org.drools.core.util.StringUtils;
import org.jbpm.process.core.context.variable.VariableScope;
import org.jbpm.process.instance.context.variable.VariableScopeInstance;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.CommandExecutor;
import org.kie.api.runtime.ExecutionResults;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.StatelessKieSession;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.process.WorkItemManager;
import org.kie.api.runtime.process.WorkflowProcessInstance;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.camel.embedded.camel.testdomain.ChangeCollector;
import org.kie.camel.embedded.camel.testdomain.Cheese;
import org.kie.camel.embedded.camel.testdomain.Person;
import org.kie.camel.embedded.component.KiePolicy;
import org.kie.internal.io.ResourceFactory;
import org.mvel2.templates.SimpleTemplateRegistry;
import org.mvel2.templates.TemplateCompiler;
import org.mvel2.templates.TemplateRegistry;
import org.mvel2.templates.TemplateRuntime;
import org.mvel2.templates.res.Node;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

@RunWith(JUnit4.class)
public abstract class BatchTest extends CamelTestSupport {
    protected CommandExecutor exec;
    protected String dataformat;
    protected String copyToDataFormat;

    public BatchTest() {
    }

    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() throws Exception {
                JaxbDataFormat jaxbDf = new JaxbDataFormat();
                jaxbDf.setContextPath("org.kie.camel.testdomain");

                from("direct:exec").policy(new KiePolicy()).unmarshal(dataformat).to("kie-local://ksession1").marshal(dataformat);
                from("direct:execWithLookup").policy(new KiePolicy()).unmarshal(dataformat).to("kie-local://dynamic").marshal(dataformat);
                from("direct:unmarshal").policy(new KiePolicy()).unmarshal(dataformat);
                from("direct:marshal").policy(new KiePolicy()).marshal(dataformat);
                from("direct:to-xstream").policy(new KiePolicy()).unmarshal(dataformat).marshal("xstream");
                from("direct:to-jaxb").policy(new KiePolicy()).unmarshal(dataformat).marshal(jaxbDf);
            }
        };
    }

    public String prettyPrintXml(String xmlSource) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new InputSource(new StringReader(xmlSource)));

            TransformerFactory tfactory = TransformerFactory.newInstance();
            tfactory.setAttribute("indent-number", 4);
            Transformer serializer;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            serializer = tfactory.newTransformer();
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(baos, "UTF-8")));
            return new String(baos.toByteArray());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected Context createJndiContext() throws Exception {
        Context context = super.createJndiContext();
        context.bind("ksession1", this.exec);
        return context;
    }

    public void setUp() throws Exception {
        // Delays the setup until the CommandExecutor won't be available
    }

    public void setExec(CommandExecutor exec) {
        this.exec = exec;
        try {
            super.setUp();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected final TemplateRegistry tempReg = new SimpleTemplateRegistry();

    protected PrintWriter writer;

    @Before
    public void before() throws Exception {
        tempReg.addNamedTemplate("tempReg", TemplateCompiler.compileTemplate(getClass().getResourceAsStream(dataformat + ".mvt"), (Map<String, Class<? extends Node>>)null));
        TemplateRuntime.execute(tempReg.getNamedTemplate("tempReg"), null, tempReg);

        XMLUnit.setIgnoreComments(true);
        XMLUnit.setIgnoreWhitespace(true);
        XMLUnit.setIgnoreAttributeOrder(true);
        XMLUnit.setNormalizeWhitespace(true);
        XMLUnit.setNormalize(true);

        if (!StringUtils.isEmpty(copyToDataFormat)) {
            writer = new PrintWriter(new BufferedWriter(new FileWriter(copyToDataFormat + ".mvt", true)));
        }
    }

    @After
    public void after() throws Exception {
        if (!StringUtils.isEmpty(copyToDataFormat)) {
            writer.close();
        }
    }

    public String getContent(String name, String... vars) {
        Map<String, String> map = new HashMap<String, String>();
        int counter = 1;
        for (String var : vars) {
            map.put("var" + counter++, var);
        }

        if (!StringUtils.isEmpty(copyToDataFormat)) {
            writer.println();
            writer.println("@declare{\"" + name + "\"}");
        }
        String s = (String) TemplateRuntime.execute(tempReg.getNamedTemplate(name), map);
        if (!StringUtils.isEmpty(copyToDataFormat)) {
            writer.print(prettyPrintXml(template.requestBody("direct:to-" + copyToDataFormat, s, String.class)));
            writer.println("@end{}");
        }

        return roundTripFromXml(s.trim());
    }

    public String execContent(String name) {
        return execContent(name, String.class);
    }

    public <T> T execContent(String name, Class<T> cls) {
        return execContent(name, cls, new String[0]);
    }

    public <T> T execContent(String name, Class<T> cls, String... vars) {
        String s = execContent(name, vars);
        if (cls.isAssignableFrom(String.class)) {
            return (T)s;
        } else {
            return unmarshalOutXml(s, cls);
        }
    }

    public String execContent(String name, String... vars) {
        String inXml = getContent(name, vars);
        return execInXml(inXml);
    }

    public String execInXml(String inXml) {
        String outXml = template.requestBody("direct:exec", inXml, String.class);
        return roundTripFromXml(outXml);
    }

    public <T> T unmarshalOutXml(String outXml, Class<T> cls) {
        Object object = template.requestBody("direct:unmarshal", outXml, Object.class);
        return (T)roundTripFromObject(object);
    }

    public abstract void assertXMLEqual(String expectedXml, String resultXml);

    public String roundTripFromXml(String inXml) {
        Object object = template.requestBody("direct:unmarshal", inXml);
        inXml = template.requestBody("direct:marshal", object, String.class);
        object = template.requestBody("direct:unmarshal", inXml);
        return template.requestBody("direct:marshal", object, String.class);
    }

    public Object roundTripFromObject(Object object) {
        String inXml = template.requestBody("direct:marshal", object, String.class);
        object = template.requestBody("direct:unmarshal", inXml);
        inXml = template.requestBody("direct:marshal", object, String.class);
        return template.requestBody("direct:unmarshal", inXml);
    }

    private StatelessKieSession getStatelessKieSession(Resource resource) throws Exception {
        return getStatelessKieSessionFromResource(resource.setSourcePath("src/main/resources/rule.drl").setResourceType(ResourceType.DRL));
    }

    private StatelessKieSession getStatelessKieSessionFromResource(Resource resource) throws Exception {
        KieServices ks = KieServices.Factory.get();
        KieFileSystem kfs = ks.newKieFileSystem();

        kfs.write(resource);

        KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();

        List<Message> errors = kieBuilder.getResults().getMessages(Message.Level.ERROR);
        if (!errors.isEmpty()) {
            fail("" + errors);
        }

        return ks.newKieContainer(ks.getRepository().getDefaultReleaseId()).newStatelessKieSession();
    }

    private KieSession getKieSession(Resource resource) throws Exception {
        return getKieSessionFromResource(resource.setSourcePath("src/main/resources/rule.drl").setResourceType(ResourceType.DRL));
    }

    private KieSession getKieSessionFromResource(Resource resource) throws Exception {
        KieServices ks = KieServices.Factory.get();
        KieFileSystem kfs = ks.newKieFileSystem();

        kfs.write(resource);

        KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();

        List<Message> errors = kieBuilder.getResults().getMessages(Message.Level.ERROR);
        if (!errors.isEmpty()) {
            fail("" + errors);
        }

        return ks.newKieContainer(ks.getRepository().getDefaultReleaseId()).newKieSession();
    }

    @Test
    public void testListenForChanges() throws Exception {
        String str = "";
        str += "package org.kie.camel.testdomain \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Person \n";
        str += "import org.kie.camel.embedded.camel.testdomain.ChangeCollector \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese(price==25) \n";
        str += " \n";
        str += "  then \n";
        str += "end\n";

        str += "rule rule2 \n";
        str += "  when \n";
        str += "    p : Person(name=='mic') \n";
        str += "    c : Cheese(price != 42) \n";
        str += " \n";
        str += "  then \n";
        str += "    c.setPrice( 42 ); \n";
        str += "    update(c); \n";
        str += "end\n";

        str += "rule rule3 \n";
        str += "  when \n";
        str += "    p : Person(name=='mark') \n";
        str += "    c : Cheese(price == 42) \n";
        str += " \n";
        str += "  then \n";
        str += "    retract(c); \n";
        str += "end\n";

        str += "rule ruleBootStrap \n";
        str += "salience 10000\n";
        str += "  when \n";
        str += "    $c : ChangeCollector() \n";
        str += " \n";
        str += "  then \n";
        str += "    kcontext.getKnowledgeRuntime().addEventListener($c); \n";
        str += "end\n";

        str += "rule ruleCleanup \n";
        str += "salience -10000\n";
        str += "  when \n";
        str += "    $c : ChangeCollector() \n";
        str += " \n";
        str += "  then \n";
        str += "    kcontext.getKnowledgeRuntime().removeEventListener($c); \n";
        str += "    retract($c); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testListenForChanges.in.1");

        outXml = execContent("testListenForChanges.in.2");
        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        assertXMLEqual(getContent("testListenForChanges.expected.1", ((FactHandle)result.getFactHandle("changes")).toExternalForm(),
                                  ((FactHandle)result.getFactHandle("person")).toExternalForm()), outXml);

        ChangeCollector collector = (ChangeCollector)result.getValue("changes");
        Cheese c = (Cheese)collector.getChanges().get(0);
        assertEquals(42, c.getPrice());

        result = execContent("testListenForChanges.in.3", ExecutionResults.class);

        collector = (ChangeCollector)result.getValue("changes");
        assertEquals("stilton", collector.getRetracted().get(0));

    }

    @Test
    public void testInsertWithDefaults() throws Exception {

        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testInsertWithDefaults.in.1");

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        Cheese stilton = (Cheese)result.getValue("outStilton");
        assertEquals(30, stilton.getPrice());

        FactHandle factHandle = (FactHandle)result.getFactHandle("outStilton");
        stilton = (Cheese)ksession.getObject(factHandle);
        assertEquals(30, stilton.getPrice());

        String expectedXml = getContent("testInsertWithDefaults.expected.1", ((FactHandle)result.getFactHandle("outStilton")).toExternalForm());

        assertXMLEqual(expectedXml, outXml);
    }

    @Test
    public void testInsertWithReturnObjectFalse() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testInsertWithReturnObjectFalse.in.1");
        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        String expectedXml = getContent("testInsertWithReturnObjectFalse.expected.1", ((FactHandle)result.getFactHandle("outStilton")).toExternalForm());

        assertXMLEqual(expectedXml, outXml);
    }

    @Test
    public void testFactHandleReturn() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "global java.util.List list1 \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    System.err.println(42); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        FactHandle fh = ksession.insert(new Person("mic", 42));
        List<FactHandle> list = new ArrayList<FactHandle>();
        list.add(fh);

        ksession.setGlobal("list1", list);

        String outXml = execContent("testFactHandleReturn.in.1");

        assertXMLEqual(getContent("testFactHandleReturn.expected.1", fh.toExternalForm()), outXml);

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        List outList = (List)result.getValue("out-list");
        assertEquals(1, outList.size());
        assertEquals(fh.toExternalForm(), ((FactHandle)outList.get(0)).toExternalForm());
        assertNotSame(fh, outList.get(0));
    }

    @Test
    public void testGetObject() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        ExecutionResults result = execContent("testGetObject.in.1", ExecutionResults.class);

        Cheese stilton = (Cheese)result.getValue("outStilton");
        assertEquals(30, stilton.getPrice());

        String outXml = execContent("testGetObject.in.2", ((FactHandle)result.getFactHandle("outStilton")).toExternalForm());
        result = unmarshalOutXml(outXml, ExecutionResults.class);

        stilton = (Cheese)result.getValue("outStilton");
        assertEquals(30, stilton.getPrice());
    }

    @Test
    public void testRetractObject() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        ExecutionResults result = execContent("testRetractObject.in.1", ExecutionResults.class);

        Cheese stilton = (Cheese)result.getValue("outStilton");
        assertEquals(30, stilton.getPrice());

        String outXml = execContent("testRetractObject.in.2", ((FactHandle)result.getFactHandle("outStilton")).toExternalForm());

        outXml = execContent("testRetractObject.in.3", ((FactHandle)result.getFactHandle("outStilton")).toExternalForm());
        result = unmarshalOutXml(outXml, ExecutionResults.class);

        assertNull(result.getValue("outStilton"));
    }

    @Test
    public void testModifyObject() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testModifyObject.in.1");
        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        String stiltonfh = ((FactHandle)result.getFactHandle("outStilton")).toExternalForm();

        Cheese stilton = (Cheese)result.getValue("outStilton");
        assertEquals(30, stilton.getPrice());

        String expectedXml = getContent("testModifyObject.expected.1", stiltonfh);

        assertXMLEqual(expectedXml, outXml);

        execContent("testModifyObject.in.2", ExecutionResults.class, stiltonfh);

        result = execContent("testModifyObject.in.3", ExecutionResults.class, stiltonfh);

        stilton = (Cheese)result.getValue("outStilton");
        assertEquals(42, stilton.getOldPrice());
        assertEquals(55, stilton.getPrice());

        // now test for code injection:
        execContent("testModifyObject.in.4", ExecutionResults.class, stiltonfh);

        // should be the same as before
        result = execContent("testModifyObject.in.5", ExecutionResults.class, stiltonfh);

        // The value gets turned into a literal to avoid injection
        stilton = (Cheese)result.getValue("outStilton");
        assertEquals("throwException()", stilton.getType());

    }

    @Test
    public void testInsertElements() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "global java.util.List list1 \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "     list1.add( $c );";
        str += "end\n";
        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testInsertElements.in.1");

        assertXMLEqual(getContent("testInsertElements.expected.1"), outXml);

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        List list = (List)result.getValue("list1");
        Cheese stilton25 = new Cheese("stilton", 30);
        Cheese stilton30 = new Cheese("stilton", 35);

        Set expectedList = new HashSet();
        expectedList.add(stilton25);
        expectedList.add(stilton30);

        assertEquals(expectedList, new HashSet(list));
    }

    @Test
    public void testInsertElementsWithReturnObjects() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "global java.util.List list1 \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "    list1.add( $c );";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testInsertElementsWithReturnObjects.in.1");

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        List list1 = (List)result.getValue("list1");
        assertEquals(2, list1.size());
        assertTrue(list1.contains(new Cheese("stilton", 35)));
        assertTrue(list1.contains(new Cheese("stilton", 30)));

        List myFacts = (List)result.getValue("myfacts");
        assertEquals(2, list1.size());
        assertTrue(myFacts.contains(new Cheese("stilton", 35)));
        assertTrue(myFacts.contains(new Cheese("stilton", 30)));

        List<FactHandle> factHandles = (List<FactHandle>)result.getFactHandle("myfacts");
        List list = new ArrayList();
        list.add(ksession.getObject(((InternalFactHandle)factHandles.get(0))));
        list.add(ksession.getObject(((InternalFactHandle)factHandles.get(1))));
        assertTrue(list.contains(new Cheese("stilton", 35)));
        assertTrue(list.contains(new Cheese("stilton", 30)));

        assertXMLEqual(getContent("testInsertElementsWithReturnObjects.expected.1", factHandles.get(0).toExternalForm(), factHandles.get(1).toExternalForm()), outXml);
    }

    @Test
    public void testSetGlobal() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "global java.util.List list1 \n";
        str += "global java.util.List list2 \n";
        str += "global java.util.List list3 \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( 30 ); \n";
        str += "    list1.add( $c ); \n";
        str += "    list2.add( $c ); \n";
        str += "    list3.add( $c ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testSetGlobal.in.1");

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        assertXMLEqual(getContent("testSetGlobal.expected.1", ((FactHandle)result.getFactHandle("outStilton")).toExternalForm()), outXml);

        Cheese stilton = new Cheese("stilton", 30);

        assertNull(result.getValue("list1"));

        List list2 = (List)result.getValue("list2");
        assertEquals(1, list2.size());
        assertEquals(stilton, list2.get(0));

        List list3 = (List)result.getValue("outList3");
        assertEquals(1, list3.size());
        assertEquals(stilton, list3.get(0));
    }

    @Test
    public void testGetGlobal() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "global java.util.List list1 \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    list1.add( $c ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testGetGlobal.in.1");

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        assertXMLEqual(getContent("testGetGlobal.expected.1", ((FactHandle)result.getFactHandle("outStilton")).toExternalForm()), outXml);

        List resultsList = (List)result.getValue("out-list");
        assertEquals(1, resultsList.size());
        assertEquals(new Cheese("stilton", 25), resultsList.get(0));

    }

    @Test
    public void testGetObjects() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        String inXml = "";
        inXml = "{\"batch-execution\":{\"commands\":[";
        inXml += "  {\"insert-elements\":{\"objects\":[";
        inXml += "   {   \"org.kie.camel.embedded.camel.testdomain.Cheese\":{\"type\":\"stilton\",\"price\":25,\"oldPrice\":0}}, ";
        inXml += "   {   \"org.kie.camel.embedded.camel.testdomain.Cheese\":{\"type\":\"stilton\",\"price\":30,\"oldPrice\":0}} ";
        inXml += "   ]}}";
        inXml += ",  {\"get-objects\":{\"out-identifier\":\"list1\"}}";
        inXml += "]}}";

        StatelessKieSession ksession = getStatelessKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testGetObjects.in.1");

        // Can't compare content a hashmap of objects keeps changing order
        // assertXMLEqual( getContent( "testGetObjects.expected.1" ),
        // outXml );

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        List list = (List)result.getValue("list1");
        Cheese stilton25 = new Cheese("stilton", 30);
        Cheese stilton30 = new Cheese("stilton", 35);

        Set expectedList = new HashSet();
        expectedList.add(stilton25);
        expectedList.add(stilton30);

        assertEquals(expectedList, new HashSet(list));
    }

    @Test
    public void testQuery() throws Exception {
        String str = "";
        str += "package org.kie.test  \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "query cheeses \n";
        str += "    stilton : Cheese(type == 'stilton') \n";
        str += "    cheddar : Cheese(type == 'cheddar', price == stilton.price) \n";
        str += "end\n";
        str += "query cheesesWithParams(String a, String b) \n";
        str += "    stilton : Cheese(type == a) \n";
        str += "    cheddar : Cheese(type == b, price == stilton.price) \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testQuery.in.1");

        // Order is not determinstic, so can't test.
        // assertXMLEqual( getContent( "testQuery.expected.1" ),
        // outXml );
        getContent("testQuery.expected.1"); // just to force a tostring for comparison

        ExecutionResults batchResult = unmarshalOutXml(outXml, ExecutionResults.class);

        Cheese stilton1 = new Cheese("stilton", 1);
        Cheese cheddar1 = new Cheese("cheddar", 1);
        Cheese stilton2 = new Cheese("stilton", 2);
        Cheese cheddar2 = new Cheese("cheddar", 2);

        Set set = new HashSet();
        List list = new ArrayList();
        list.add(stilton1);
        list.add(cheddar1);
        set.add(list);

        list = new ArrayList();
        list.add(stilton2);
        list.add(cheddar2);
        set.add(list);

        org.kie.api.runtime.rule.QueryResults results = (org.kie.api.runtime.rule.QueryResults)batchResult.getValue("cheeses");
        assertEquals(2, results.size());
        assertEquals(2, results.getIdentifiers().length);
        Set newSet = new HashSet();
        for (org.kie.api.runtime.rule.QueryResultsRow result : results) {
            list = new ArrayList();
            list.add(result.get("stilton"));
            list.add(result.get("cheddar"));
            newSet.add(list);
        }
        assertEquals(set, newSet);
    }

    @Test
    public void testManualFireAllRules() throws Exception {
        String str = "";
        str += "package org.kie \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "global java.util.List list1 \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "    list1.add( $c );";
        str += "end\n";

        StatelessKieSession ksession = getStatelessKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testManualFireAllRules.in.1");

        ExecutionResults result = unmarshalOutXml(outXml, ExecutionResults.class);

        assertXMLEqual(getContent("testManualFireAllRules.expected.1", ((FactHandle)result.getFactHandle("outBrie")).toExternalForm()), outXml);

        // brie should not have been added to the list
        List list = (List)result.getValue("list1");
        Cheese stilton25 = new Cheese("stilton", 30);
        Cheese stilton30 = new Cheese("stilton", 35);

        Set expectedList = new HashSet();
        expectedList.add(stilton25);
        expectedList.add(stilton30);

        assertEquals(expectedList, new HashSet(list));

        // brie should not have changed
        Cheese brie10 = new Cheese("brie", 10);
        brie10.setOldPrice(5);
        assertEquals(brie10, result.getValue("outBrie"));
    }

    @Test
    public void testProcess() throws Exception {
        String str = "";
        str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        str += "<process xmlns=\"http://drools.org/drools-5.0/process\"\n";
        str += "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
        str += "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n";
        str += "         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.actions\" package-name=\"org.drools\" version=\"1\" >\n";
        str += "\n";
        str += "  <header>\n";
        str += "    <imports>\n";
        str += "      <import name=\"org.kie.camel.embedded.camel.testdomain.TestVariable\" />\n";
        str += "    </imports>\n";
        str += "    <globals>\n";
        str += "      <global identifier=\"list1\" type=\"java.util.List\" />\n";
        str += "    </globals>\n";
        str += "    <variables>\n";
        str += "      <variable name=\"person\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.ObjectDataType\" className=\"TestVariable\" />\n";
        str += "      </variable>\n";
        str += "    </variables>\n";
        str += "  </header>\n";
        str += "\n";
        str += "  <nodes>\n";
        str += "    <start id=\"1\" name=\"Start\" />\n";
        str += "    <actionNode id=\"2\" name=\"MyActionNode\" >\n";
        str += "      <action type=\"expression\" dialect=\"mvel\" >System.out.println(\"Triggered\");\n";
        str += "list1.add(person.name);\n";
        str += "</action>\n";
        str += "    </actionNode>\n";
        str += "    <end id=\"3\" name=\"End\" />\n";
        str += "  </nodes>\n";
        str += "\n";
        str += "  <connections>\n";
        str += "    <connection from=\"1\" to=\"2\" />\n";
        str += "    <connection from=\"2\" to=\"3\" />\n";
        str += "  </connections>\n" + "\n";
        str += "</process>";

        StatelessKieSession ksession = getStatelessKieSessionFromResource(ResourceFactory.newByteArrayResource(str.getBytes()).setSourcePath("src/main/resources/rule.rf")
            .setResourceType(ResourceType.DRF));
        List<String> list = new ArrayList<String>();
        ksession.setGlobal("list1", list);
        setExec(ksession);

        String outXml = execContent("testProcess.in.1");

        assertXMLEqual(getContent("testProcess.expected.1"), outXml);

        ExecutionResults results = unmarshalOutXml(outXml, ExecutionResults.class);

        list = (List)results.getValue("out-list");

        assertEquals(1, list.size());
        assertEquals("John Doe", list.get(0));
    }

    @Test
    public void testProcessInstanceSignalEvent() throws Exception {
        String str = "";
        str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        str += "<process xmlns=\"http://drools.org/drools-5.0/process\"\n";
        str += "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
        str += "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n";
        str += "         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.core.event\" package-name=\"org.drools\" version=\"1\" >\n";
        str += "\n";
        str += "  <header>\n";
        str += "    <variables>\n";
        str += "      <variable name=\"MyVar\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        <value>SomeText</value>\n";
        str += "      </variable>\n";
        str += "    </variables>\n";
        str += "  </header>\n";
        str += "\n";
        str += "  <nodes>\n";
        str += "    <start id=\"1\" name=\"Start\" />\n";
        str += "    <eventNode id=\"2\" name=\"Event\" variableName=\"MyVar\" >\n";
        str += "      <eventFilters>\n";
        str += "        <eventFilter type=\"eventType\" eventType=\"MyEvent\" />\n";
        str += "      </eventFilters>\n";
        str += "    </eventNode>\n";
        str += "    <join id=\"3\" name=\"Join\" type=\"1\" />\n";
        str += "    <end id=\"4\" name=\"End\" />\n";
        str += "  </nodes>\n";
        str += "\n";
        str += "  <connections>\n";
        str += "    <connection from=\"1\" to=\"3\" />\n";
        str += "    <connection from=\"2\" to=\"3\" />\n";
        str += "    <connection from=\"3\" to=\"4\" />\n";
        str += "  </connections>\n";
        str += "\n";
        str += "</process>";

        KieSession ksession = getKieSessionFromResource(ResourceFactory.newByteArrayResource(str.getBytes()).setSourcePath("src/main/resources/rule.rf")
            .setResourceType(ResourceType.DRF));
        setExec(ksession);

        ProcessInstance processInstance = ksession.startProcess("org.drools.core.event");
        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());

        execContent("testProcessInstanceSignalEvent.in.1");

        assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());
        assertEquals("MyValue",
                     ((VariableScopeInstance)((org.jbpm.process.instance.ProcessInstance)processInstance).getContextInstance(VariableScope.VARIABLE_SCOPE)).getVariable("MyVar"));
    }

    @Test
    public void testProcessRuntimeSignalEvent() throws Exception {
        String str = "";
        str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        str += "<process xmlns=\"http://drools.org/drools-5.0/process\"\n";
        str += "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
        str += "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n";
        str += "         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.core.event\" package-name=\"org.drools\" version=\"1\" >\n";
        str += "\n";
        str += "  <header>\n";
        str += "    <variables>\n";
        str += "      <variable name=\"MyVar\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        <value>SomeText</value>\n";
        str += "      </variable>\n";
        str += "    </variables>\n";
        str += "  </header>\n";
        str += "\n";
        str += "  <nodes>\n";
        str += "    <start id=\"1\" name=\"Start\" />\n";
        str += "    <eventNode id=\"2\" name=\"Event\" scope=\"external\" variableName=\"MyVar\" >\n";
        str += "      <eventFilters>\n";
        str += "        <eventFilter type=\"eventType\" eventType=\"MyEvent\" />\n";
        str += "      </eventFilters>\n";
        str += "    </eventNode>\n";
        str += "    <join id=\"3\" name=\"Join\" type=\"1\" />\n";
        str += "    <end id=\"4\" name=\"End\" />\n";
        str += "  </nodes>\n";
        str += "\n";
        str += "  <connections>\n";
        str += "    <connection from=\"1\" to=\"3\" />\n";
        str += "    <connection from=\"2\" to=\"3\" />\n";
        str += "    <connection from=\"3\" to=\"4\" />\n";
        str += "  </connections>\n";
        str += "\n";
        str += "</process>";

        KieSession ksession = getKieSessionFromResource(ResourceFactory.newByteArrayResource(str.getBytes()).setSourcePath("src/main/resources/rule.rf")
            .setResourceType(ResourceType.DRF));
        setExec(ksession);

        ProcessInstance processInstance = ksession.startProcess("org.drools.core.event");
        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());

        execContent("testProcessRuntimeSignalEvent.in.1");

        assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());
        assertEquals("MyValue",
                     ((VariableScopeInstance)((org.jbpm.process.instance.ProcessInstance)processInstance).getContextInstance(VariableScope.VARIABLE_SCOPE)).getVariable("MyVar"));
    }

    @Test
    public void testCompleteWorkItem() throws Exception {
        String str = "";
        str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        str += "<process xmlns=\"http://drools.org/drools-5.0/process\"\n";
        str += "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
        str += "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n";
        str += "         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.actions\" package-name=\"org.drools\" version=\"1\" >\n";
        str += "\n";
        str += "  <header>\n";
        str += "    <variables>\n";
        str += "      <variable name=\"UserName\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        <value>John Doe</value>\n";
        str += "      </variable>\n";
        str += "      <variable name=\"Person\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.ObjectDataType\" className=\"org.kie.camel.embedded.camel.testdomain.Person\" />\n";
        str += "      </variable>\n";
        str += "      <variable name=\"MyObject\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" className=\"java.lang.String\" />\n";
        str += "      </variable>\n";
        str += "      <variable name=\"Number\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.IntegerDataType\" />\n";
        str += "      </variable>\n";
        str += "    </variables>\n";
        str += "  </header>\n";
        str += "\n";
        str += "  <nodes>\n";
        str += "    <start id=\"1\" name=\"Start\" />\n";
        str += "    <workItem id=\"2\" name=\"HumanTask\" >\n";
        str += "      <work name=\"Human Task\" >\n";
        str += "        <parameter name=\"ActorId\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "          <value>#{UserName}</value>\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Content\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "          <value>#{Person.name}</value>\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"TaskName\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "          <value>Do something</value>\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Priority\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Comment\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Attachment\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.ObjectDataType\" className=\"java.lang.Object\" />\n";
        str += "        </parameter>\n";
        str += "      </work>\n";
        str += "      <mapping type=\"in\" from=\"MyObject\" to=\"Attachment\" />";
        str += "      <mapping type=\"in\" from=\"Person.name\" to=\"Comment\" />";
        str += "      <mapping type=\"out\" from=\"Result\" to=\"MyObject\" />";
        str += "      <mapping type=\"out\" from=\"Result.length()\" to=\"Number\" />";
        str += "    </workItem>\n";
        str += "    <end id=\"3\" name=\"End\" />\n";
        str += "  </nodes>\n";
        str += "\n";
        str += "  <connections>\n";
        str += "    <connection from=\"1\" to=\"2\" />\n";
        str += "    <connection from=\"2\" to=\"3\" />\n";
        str += "  </connections>\n";
        str += "\n";
        str += "</process>";

        KieSession ksession = getKieSessionFromResource(ResourceFactory.newByteArrayResource(str.getBytes()).setSourcePath("src/main/resources/rule.rf")
            .setResourceType(ResourceType.DRF));
        setExec(ksession);

        TestWorkItemHandler handler = new TestWorkItemHandler();
        ksession.getWorkItemManager().registerWorkItemHandler("Human Task", handler);
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("UserName", "John Doe");
        Person person = new Person();
        person.setName("John Doe");
        parameters.put("Person", person);
        WorkflowProcessInstance processInstance = (WorkflowProcessInstance)ksession.startProcess("org.drools.actions", parameters);
        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
        WorkItem workItem = handler.getWorkItem();
        assertNotNull(workItem);
        assertEquals("John Doe", workItem.getParameter("ActorId"));
        assertEquals("John Doe", workItem.getParameter("Content"));
        assertEquals("John Doe", workItem.getParameter("Comment"));

        assertEquals(WorkItem.PENDING, workItem.getState());

        execContent("testCompleteWorkItem.in.1", Long.toString(workItem.getId()));

        assertEquals(WorkItem.COMPLETED, workItem.getState());

        assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());

        parameters = new HashMap<String, Object>();
        parameters.put("UserName", "Jane Doe");
        parameters.put("MyObject", "SomeString");
        person = new Person();
        person.setName("Jane Doe");
        parameters.put("Person", person);
        processInstance = (WorkflowProcessInstance)ksession.startProcess("org.drools.actions", parameters);
        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
        workItem = handler.getWorkItem();
        assertNotNull(workItem);
        assertEquals("Jane Doe", workItem.getParameter("ActorId"));
        assertEquals("SomeString", workItem.getParameter("Attachment"));
        assertEquals("Jane Doe", workItem.getParameter("Content"));
        assertEquals("Jane Doe", workItem.getParameter("Comment"));

        assertEquals(WorkItem.PENDING, workItem.getState());

        execContent("testCompleteWorkItem.in.2", Long.toString(workItem.getId()));

        assertEquals(WorkItem.COMPLETED, workItem.getState());

        assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());
        assertEquals("SomeOtherString", processInstance.getVariable("MyObject"));
        assertEquals(15, processInstance.getVariable("Number"));
    }

    @Test
    public void testAbortWorkItem() throws Exception {
        String str = "";
        str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        str += "<process xmlns=\"http://drools.org/drools-5.0/process\"\n";
        str += "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
        str += "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n";
        str += "         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.actions\" package-name=\"org.drools\" version=\"1\" >\n";
        str += "\n";
        str += "  <header>\n";
        str += "    <variables>\n";
        str += "      <variable name=\"UserName\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        <value>John Doe</value>\n";
        str += "      </variable>\n";
        str += "      <variable name=\"Person\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.ObjectDataType\" className=\"org.kie.camel.embedded.camel.testdomain.Person\" />\n";
        str += "      </variable>\n";
        str += "      <variable name=\"MyObject\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" className=\"java.lang.String\" />\n";
        str += "      </variable>\n";
        str += "      <variable name=\"Number\" >\n";
        str += "        <type name=\"org.drools.core.process.core.datatype.impl.type.IntegerDataType\" />\n";
        str += "      </variable>\n";
        str += "    </variables>\n";
        str += "  </header>\n";
        str += "\n";
        str += "  <nodes>\n";
        str += "    <start id=\"1\" name=\"Start\" />\n";
        str += "    <workItem id=\"2\" name=\"HumanTask\" >\n";
        str += "      <work name=\"Human Task\" >\n";
        str += "        <parameter name=\"ActorId\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "          <value>#{UserName}</value>\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Content\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "          <value>#{Person.name}</value>\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"TaskName\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "          <value>Do something</value>\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Priority\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Comment\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.StringDataType\" />\n";
        str += "        </parameter>\n";
        str += "        <parameter name=\"Attachment\" >\n";
        str += "          <type name=\"org.drools.core.process.core.datatype.impl.type.ObjectDataType\" className=\"java.lang.Object\" />\n";
        str += "        </parameter>\n";
        str += "      </work>\n";
        str += "      <mapping type=\"in\" from=\"MyObject\" to=\"Attachment\" />";
        str += "      <mapping type=\"in\" from=\"Person.name\" to=\"Comment\" />";
        str += "      <mapping type=\"out\" from=\"Result\" to=\"MyObject\" />";
        str += "      <mapping type=\"out\" from=\"Result.length()\" to=\"Number\" />";
        str += "    </workItem>\n";
        str += "    <end id=\"3\" name=\"End\" />\n";
        str += "  </nodes>\n";
        str += "\n";
        str += "  <connections>\n";
        str += "    <connection from=\"1\" to=\"2\" />\n";
        str += "    <connection from=\"2\" to=\"3\" />\n";
        str += "  </connections>\n";
        str += "\n";
        str += "</process>";

        KieSession ksession = getKieSessionFromResource(ResourceFactory.newByteArrayResource(str.getBytes()).setSourcePath("src/main/resources/rule.rf")
            .setResourceType(ResourceType.DRF));
        setExec(ksession);

        TestWorkItemHandler handler = new TestWorkItemHandler();
        ksession.getWorkItemManager().registerWorkItemHandler("Human Task", handler);
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("UserName", "John Doe");
        Person person = new Person();
        person.setName("John Doe");
        parameters.put("Person", person);
        WorkflowProcessInstance processInstance = (WorkflowProcessInstance)ksession.startProcess("org.drools.actions", parameters);
        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
        WorkItem workItem = handler.getWorkItem();
        assertNotNull(workItem);

        assertEquals(WorkItem.PENDING, workItem.getState());

        execContent("testAbortWorkItem.in.1", Long.toString(workItem.getId()));

        assertEquals(WorkItem.ABORTED, workItem.getState());
    }

    @Test
    public void testInsertObjectWithDeclaredFact() throws Exception {
        String str = "";
        str += "package org.foo \n";
        str += "declare Whee \n\ttype: String\n\tprice: Integer\n\toldPrice: Integer\nend\n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Whee() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        ExecutionResults results = null;
        String outXml = null;
        ClassLoader orig = null;
        ClassLoader cl = ((StatefulKnowledgeSessionImpl)ksession).getKnowledgeBase().getRootClassLoader();
        try {
            orig = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(cl);
            outXml = execContent("testInsertObjectWithDeclaredFact.in.1");
            results = unmarshalOutXml(outXml, ExecutionResults.class);
        } finally {
            Thread.currentThread().setContextClassLoader(orig);
        }
        FactHandle factHandle = (FactHandle)results.getFactHandle("outStilton");
        Object object = results.getValue("outStilton");

        assertEquals("org.foo.Whee", object.getClass().getName());
        assertXMLEqual(getContent("testInsertObjectWithDeclaredFact.expected.1", factHandle.toExternalForm()), outXml);

    }

    @Test
    public void testInsertObjectWithDeclaredFactAndQuery() throws Exception {
        String str = "";
        str += "package org.foo \n";
        str += "declare Whee \n\ttype: String\n\tprice: Integer\n\toldPrice: Integer\nend\n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Whee(price < 30) \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n update($c);\n";
        str += "end\n";
        str += "query results\n";
        str += "    w: Whee(price > 0)";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);
        ClassLoader cl = ((StatefulKnowledgeSessionImpl)ksession).getKnowledgeBase().getRootClassLoader();
        ClassLoader orig = null;
        try {
            orig = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(cl);

            String outXml = execContent("testInsertObjectWithDeclaredFactAndQuery.in.1");

            ExecutionResults results = unmarshalOutXml(outXml, ExecutionResults.class);
            FactHandle fh = (FactHandle)results.getFactHandle("outStilton");

            outXml = execContent("testInsertObjectWithDeclaredFactAndQuery.in.2");

            assertXMLEqual(getContent("testInsertObjectWithDeclaredFactAndQuery.expected.1", fh.toExternalForm()), outXml);
        } finally {
            Thread.currentThread().setContextClassLoader(orig);
        }
    }

    @Test
    public void testExecutionNodeLookup() throws Exception {
        String str = "";
        str += "package org.drools \n";
        str += "import org.kie.camel.embedded.camel.testdomain.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";

        KieSession ksession = getKieSession(ResourceFactory.newByteArrayResource(str.getBytes()));
        setExec(ksession);

        String outXml = execContent("testExecutionNodeLookup.in.1");
        ExecutionResults results = unmarshalOutXml(outXml, ExecutionResults.class);

        Cheese stilton = (Cheese)results.getValue("outStilton");
        assertEquals(30, stilton.getPrice());

        FactHandle factHandle = (FactHandle)results.getFactHandle("outStilton");
        stilton = (Cheese)ksession.getObject(factHandle);
        assertEquals(30, stilton.getPrice());

        assertXMLEqual(getContent("testExecutionNodeLookup.expected.1", factHandle.toExternalForm()), outXml);
    }

    public static class TestWorkItemHandler implements WorkItemHandler {
        private WorkItem workItem;

        public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
            this.workItem = workItem;
        }

        public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
        }

        public WorkItem getWorkItem() {
            return workItem;
        }
    }

}
