j-easy / easy-rules

The simple, stupid rules engine for Java
https://github.com/j-easy/easy-rules/wiki
MIT License
4.9k stars 1.06k forks source link

Inject a dynamic object inside a rule when using spring configuration #59

Closed khushal1024 closed 7 years ago

khushal1024 commented 7 years ago

Is there any way to inject an object inside a rule when using spring configuration.

An example of what I am trying to achieve ::

@SpringRule
public class rule1 {

    private object myObj;
    private static int priority=1;

    @Autowired
    private customService cService;

    @Condition
    public boolean check() {
        }

        @Action
    public void act(){
        System.out.println("Ran rule 1");
    }
}

@SpringRule
public class rule2 {

    private object myObj;
    private static int priority=1;

    @Autowired
    private customService cService;

    @Condition
    public boolean check() {
        }

        @Action
    public void act(){
        System.out.println("Ran rule 2");
    }
}

Now I am building a rules engine using

RulesEngine rulesEngine = (RulesEngine) context.getBean("myRuleEngine");
 rulesEngine.fireRules();

All the rules will have same value of myObj. How can I set the value of myObj in this case for each rule ?

Thanks in advance.

fmbenhassine commented 7 years ago

Hi,

Looks similar to #51

Are your rules managed by Spring ?

Kind regards Mahmoud

khushal1024 commented 7 years ago

Yes, the rules are managed by spring. The autowiring thing works in case of services. I have an object(as in a DTO) which is used in running the rules. When I was building the rules engine by registering rules in the java code it was working fine. My question is how can I set the value of the object when I am building using spring configuration.

`

<!-- configure rule listener -->
<bean id="ruleListener" class="DummyRuleListener"/>

<!-- configure rules engine -->
<bean id="rulesEngine" class="org.easyrules.spring.RulesEngineFactoryBean">
    <property name="skipOnFirstAppliedRule" value="true"/>
    <property name="skipOnFirstFailedRule" value="true"/>
    <property name="rulePriorityThreshold" value="10"/>
    <property name="silentMode" value="false"/>
    <property name="rules">
        <list>
            <ref bean="rule"/>
        </list>
    </property>
    <property name="ruleListeners">
        <list>
            <ref bean="ruleListener"/>
        </list>
    </property>
</bean>

`

How can I set the object value for rule1 class ?

maomaomarry commented 7 years ago

I have faced the same issue..!!

fmbenhassine commented 7 years ago

Will look into this asap

Sorry for the late reply

tledwar commented 7 years ago

I have switched from XML to Java Config, but this is how I am doing it (assuming I understood your question):

First I added a Constructor to the rule per the documentation at the site for EasyRules.

public rule1(Object theObject) {
        this. myObj = theObject;
    }

Second is the use of passing parameters to the bean. With Java, I do this: rulesEngine.registerRule(context.getBean(rule1.class, objectToPass);

Looking at your code example, this would happen between RulesEngine rulesEngine = (RulesEngine) context.getBean("myRuleEngine"); and rulesEngine.fireRules();

fmbenhassine commented 7 years ago

@khushal1024

To pass a different instance of myObject to each rule, you can autowire a prototype scoped bean of this type in your rule class and spring will inject a different instance each time. do you agree?

In xml this would be:

    <bean id="object" class="java.lang.String" scope="prototype"/>

    <!-- configure rules  -->
    <bean id="rule1" class="Rule1" scope="prototype">
        <property name="myObj" ref="object"/>
    </bean>
    <bean id="rule2" class="Rule2" scope="prototype">
        <property name="myObj" ref="object"/>
    </bean>

    <!-- configure rules engine -->
    <bean id="rulesEngine" class="org.easyrules.spring.RulesEngineFactoryBean">
        <property name="rules">
            <list>
                <ref bean="rule1"/>
                <ref bean="rule2"/>
            </list>
        </property>
    </bean>
public static void main(String[] args) throws Exception {
    ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
    RulesEngine rulesEngine = (RulesEngine) context.getBean("rulesEngine");

    rulesEngine.fireRules();
}

Both rules should have different instances of myObj since it is prototype scoped. You can achieve the same with java config.

@maomaomarry

I have faced the same issue..!!

Is it ok with my example?

@tledwar Thanks for your replay! Indeed we can do it like you suggest.

@khushal1024 @maomaomarry

Could you please tell me if it is ok for you after using a prototype scoped bean injected as in the shown example?

Many thanks upfront

khushal1024 commented 7 years ago

Thanks Mahmoud. Works for me.

Regards Khushal

On Fri, Feb 3, 2017 at 3:30 AM, Mahmoud Ben Hassine < notifications@github.com> wrote:

@khushal1024 https://github.com/khushal1024

To pass a different instance of myObject to each rule, you can autowire a prototype scope bean of this type in your rule class and spring will inject a different instance each time. do you agree?

In xml this would be:

<bean id="object" class="java.lang.String" scope="prototype"/>

<!-- configure rules  -->
<bean id="rule1" class="Rule1" scope="prototype">
    <property name="myObj" ref="object"/>
</bean>
<bean id="rule2" class="Rule2" scope="prototype">
    <property name="myObj" ref="object"/>
</bean>

<!-- configure rules engine -->
<bean id="rulesEngine" class="org.easyrules.spring.RulesEngineFactoryBean">
    <property name="rules">
        <list>
            <ref bean="rule1"/>
            <ref bean="rule2"/>
        </list>
    </property>
</bean>

public static void main(String[] args) throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); RulesEngine rulesEngine = (RulesEngine) context.getBean("rulesEngine");

rulesEngine.fireRules();

}

Both rules should have different instances of myObj since it is scope prototyped. You can achieve the same with java config.

@maomaomarry https://github.com/maomaomarry

I have faced the same issue..!!

Is it ok with my example?

@tledwar https://github.com/tledwar Thank your replay! Indeed we can do it like you suggest.

@khushal1024 https://github.com/khushal1024 @maomaomarry https://github.com/maomaomarry

Could you please tell me if it is ok for you after using a prototype scoped bean injected as in the shown example?

Many thanks upfront

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/EasyRules/easyrules/issues/59#issuecomment-277097910, or mute the thread https://github.com/notifications/unsubscribe-auth/AGckR1CHNcnhBeGXKaW4PUOedlMuSminks5rYlHqgaJpZM4K06sb .

fmbenhassine commented 7 years ago

Great! Glad it helped.

@maomaomarry Could you please tell me if it is ok for you after using a prototype scoped bean injected as in the shown example? If it is the case, we can close the issue.

fmbenhassine commented 7 years ago

@maomaomarry Any update on this?

fmbenhassine commented 7 years ago

I'm closing this issue with release v2.4.

@maomaomarry if you still have problems with a prototype scoped bean injected as shown in the example, don't hesitate to reopen this issue