[jboss-jira] [JBoss JIRA] (DROOLS-645) Accumulate returned fact causing NPE

Mario Fusco (JIRA) issues at jboss.org
Tue Nov 11 09:37:01 EST 2014


     [ https://issues.jboss.org/browse/DROOLS-645?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Mario Fusco resolved DROOLS-645.
--------------------------------
    Resolution: Cannot Reproduce Bug


I tried both accumulate syntax with the test case I am pasting below and they both work correctly. I cannot reproduce this issue, but if there's something that I am missing with my reproducer please let me know and eventually reopen this ticket.

Moreover there's another couple of things to notice:

1. Apparently the accumulate class you attached has a bug. Indeed it throws a CCE saying:

Caused by: java.lang.ClassCastException: org.drools.compiler.integrationtests.AccumulateTest$StatusMessage cannot be cast to java.util.List
	at org.drools.compiler.integrationtests.AccumulateTest$RetryOldestCallTimeAccumulateFunction.accumulate(AccumulateTest.java:2853)

As you can see in my test case I changed 

data.addAll((List<StatusMessage>) value);

with 

data.add((StatusMessage) value);

let me know if this is ok and corresponds to what you wanted to achieve.

2. Apparently you're using that custom accumulate only to retrieve the StatusMessage with the lowest callTime. If that's true there's a more efficient way to obtain the same result with a simple not as it follows:

$message: StatusMessage( /* add constraints here */ )
not StatusMessage( callTime.before($message.callTime) )

{code}
    @Test
    public void testSortingAccumulate() throws Exception {
        String drl =
                "package org.foo.bar\n" +
                "global java.util.List list\n" +
                "import " + StatusMessage.class.getCanonicalName() + "\n" +
                "import accumulate " + RetryOldestCallTimeAccumulateFunction.class.getCanonicalName() + " oldestRetry\n" +
                "rule X when\n" +
                //"    accumulate($sm: StatusMessage(campaignName==\"test\"), $message:oldestRetry( $sm )) \n" +
                "    $message: StatusMessage() from accumulate($sm: StatusMessage(campaignName==\"test\"), oldestRetry( $sm )) \n" +
                "then\n" +
                "    modify($message) { setCampaignName(\"notest\") };" +
                "end\n";

        KieSession ksession = new KieHelper().addContent(drl, ResourceType.DRL)
                                             .build()
                                             .newKieSession();

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

        ksession.insert(new StatusMessage("test", 3));
        ksession.insert(new StatusMessage("test", 2));
        ksession.insert(new StatusMessage("test", 4));
        ksession.fireAllRules();

        assertEquals(1, list.size());
        assertEquals(2, list.get(0).getCallTime());
    }

    public static class StatusMessage {
        private String campaignName;
        private final int callTime;

        public StatusMessage(String campaignName, int callTime) {
            this.campaignName = campaignName;
            this.callTime = callTime;
        }

        public int getCallTime() {
            return callTime;
        }

        public String getCampaignName() {
            return campaignName;
        }

        public void setCampaignName(String campaignName) {
            this.campaignName = campaignName;
        }
    }

    public static class RetryOldestCallTimeAccumulateFunction implements AccumulateFunction {

        private static final Comparator<StatusMessage> callTimeComparator = new Comparator<StatusMessage>() {
            @Override
            public int compare(StatusMessage s1, StatusMessage s2) {
                return s1.getCallTime() - s2.getCallTime();
            }
        };

        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        }

        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
        }

        /* (non-Javadoc)
         * @see org.kie.api.runtime.rule.AccumulateFunction#createContext()
         */
        @Override
        public Serializable createContext() {
            return new ArrayList<StatusMessage>();
        }


        /* (non-Javadoc)
         * @see org.kie.api.runtime.rule.AccumulateFunction#init(java.lang.Object)
         */
        @Override
        public void init(Serializable context) throws Exception {
            @SuppressWarnings("unchecked")
            List<StatusMessage> data = (List<StatusMessage>) context;
            data.clear();
        }


        /* (non-Javadoc)
         * @see org.kie.api.runtime.rule.AccumulateFunction#accumulate(java.lang.Object, java.lang.Object)
         */
        @SuppressWarnings("unchecked")
        @Override
        public void accumulate(Serializable context, Object value) {
            List<StatusMessage> data = (List<StatusMessage>) context;
            // data.addAll((List<StatusMessage>) value); <-- CCE
            data.add((StatusMessage) value);
        }


        /* (non-Javadoc)
         * @see org.kie.api.runtime.rule.AccumulateFunction#reverse(java.lang.Object, java.lang.Object)
         */
        @Override
        public void reverse(Serializable context, Object value) throws Exception {
        }


        /* (non-Javadoc)
         * @see org.kie.api.runtime.rule.AccumulateFunction#getResult(java.lang.Object)
         */
        @Override
        public Object getResult(Serializable context) throws Exception {
            @SuppressWarnings("unchecked")
            List<StatusMessage> data = (List<StatusMessage>) context;
            if (data.size() > 1) {
                Collections.sort(data, callTimeComparator);
            }
            return data.get(0);
        }


        /**
         * (non-Javadoc)
         *
         * @see org.kie.api.runtime.rule.AccumulateFunction#supportsReverse()
         */
        @Override
        public boolean supportsReverse() {
            return false;
        }


        /**
         * {@inheritDoc}
         */
        @Override
        public Class<?> getResultType() {
            return StatusMessage.class;
        }
    }
{code}

> Accumulate returned fact causing NPE
> ------------------------------------
>
>                 Key: DROOLS-645
>                 URL: https://issues.jboss.org/browse/DROOLS-645
>             Project: Drools
>          Issue Type: Bug
>    Affects Versions: 6.2.0.Beta2
>         Environment: Mac OSX (maverick)
>            Reporter: Roger Lefebvre
>            Assignee: Mario Fusco
>         Attachments: RetryOldestCallTimeAccumulateFunction.java, RetryOldestCallTimeAccumulateFunction.java
>
>
> The issue is discussed in https://groups.google.com/forum/?hl=en-GB#!topic/drools-usage/aZU5mXSgHMI.
> Here is the gist of it....
> I changed the accumulator to the following and it worked:
> accumulate($sm:StatusMessage(campaignName==$campaign.campaignName, status==ManagerCallState.CALLER_FAILURE, attempts<3, sent==true), $message:oldestRetry( $sm ))  
> The previous approach was this:
> $message:StatusMessage() from accumulate($sm:StatusMessage(campaignName==$campaign.campaignName, status==ManagerCallState.CALLER_FAILURE, attempts<3, sent==true), oldestRetry( $sm ))
> which I thought was the correct or acceptable syntax option. Is there something I have overlooked in the second one ("from"??). It does give me a StatusMessage object but it lacks the underlying properties to allow the subsequent modify to work.



--
This message was sent by Atlassian JIRA
(v6.3.8#6338)


More information about the jboss-jira mailing list