[Design the new POJO MicroContainer] - MC meets Drools - new Reliance module
by alesj
The idea started from an endless debate regarding Drool vs. jBPM. :-)
Thinking about the JIRA issue of being able to create your own dependency
+ listening to MarkP here @ Farnborough, I hacked the next stuff over the weekends + some details now during the visit.
The basic idea is to define a set of rules for certain bean.
And than add dependency items based on those rules.
There is a RuleDependencyMapper - aop-lifecycle bean - that matches the beans and applies the
dependency item created from the DependencyItemFactory.
The rules are held in a Drools StatefulSession (WorkingMemory - WM), and I applied JBossAOP interceptors
for all CRUD methods (insert, update, retract) on the WM instance, so that WM.fireAllRules() method is
transperently invoked. Basically meaning any change to WM can lead to some rules dependencies being resolved.
Here I still need to find a way to transperently push forward contexts that have been resolved by this WM invocation.
I also added a few ways to aviod fireAllRules for any CRUD. You can set an @DisableFireAllRules on a method, and a ThreadLocal
flag will be set which will prevent FireAllRulesAdvice to fire.
Or you can set @FireAllRulesAfter, in which case all invocation of fireAllRules method will be ignored, and the interceptor will
issue the execution at the end of the method.
I've also added a couple of deployers that know how to handle Drools .drl, .dsl, .xsl, .csv files.
All this stuff is pushed into new MC module called reliance (since dependency already exists, I went to webster thesaurus for the name).
When I find some time - and it looks it won't be any time soon :-) - I have a similar idea for jBPM.
I'll wait with commiting this stuff after Scott releases MC beta4.
I still have to write some tests, but this will be done with jBPM idea - after the JBAS5 dust settles.
The concept test case is here:
| <deployment xmlns="urn:jboss:bean-deployer:2.0">
|
| <!-- aspects -->
|
| <bean name="AspectManager" class="org.jboss.aop.AspectManager">
| <constructor factoryClass="org.jboss.aop.AspectManager" factoryMethod="instance"/>
| </bean>
|
| <!-- intercepts any StatefulSession creation from our RuleBase bean -->
| <aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0"
| name="WrapStatefulSessionAdvice"
| class="org.jboss.reliance.drools.core.aspects.StatefulSessionCreationInterceptor"
| pointcut="execution(* org.jboss.reliance.drools.core.RuleBaseBean->newStatefulSession(..))"/>
|
| <!-- invokes fireAllRules after any CRUD method invocation on WorkingMemory instance -->
| <aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0"
| name="FireAllRulesCheckAdvice"
| class="org.jboss.reliance.drools.core.aspects.CRUDAwareAspect"
| pointcut="execution(* $instanceof{org.drools.StatefulSession}->$implements{org.drools.WorkingMemory}(..))" />
|
| <!-- disables fireAllRules if @DisableFireAllRules is present -->
| <aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0"
| name="DisableFireAllRulesAdvice"
| class="org.jboss.reliance.drools.core.aspects.DisableFireAllRulesInterceptor"
| pointcut="execution(* @org.jboss.reliance.drools.core.aspects.DisableFireAllRules->*(..)) OR execution(* *->@org.jboss.reliance.drools.core.aspects.DisableFireAllRulesAllRules(..))" />
|
| <!-- only invokes fireAllRules at the end of invocation -->
| <aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0"
| name="FireAllRulesAfterInvocationAdvice"
| class="org.jboss.reliance.drools.core.aspects.FireAllRulesAfterInvocationInterceptor"
| pointcut="execution(* @org.jboss.reliance.drools.core.aspects.FireAllRulesAfter->*(..)) OR execution(* *->@org.jboss.reliance.drools.core.aspects.FireAllRulesAfterlesAfter(..))">
| <constructor>
| <parameter><inject bean="WorkingMemory" property="statefulSession"/></parameter>
| </constructor>
| </aop:aspect>
|
| <!-- applies RuleBasedDependencyItem to all @RulesAware beans -->
| <aop:lifecycle-describe xmlns:aop="urn:jboss:aop-beans:1.0"
| name="RulesMapper"
| class="org.jboss.reliance.drools.dependency.RuleDependencyMapper"
| classes="@org.jboss.reliance.drools.dependency.RulesAware">
| <property name="factory"><inject bean="RuleBasedDependencyFactory"/></property>
| </aop:lifecycle-describe>
|
| <bean name="RuleBasedDependencyFactory" class="org.jboss.reliance.drools.dependency.RuleBasedDependencyItemFactory">
| <property name="whenRequired">Create</property>
| </bean>
|
| <!-- drools beans -->
|
| <bean name="WorkingMemory" class="org.jboss.reliance.drools.core.ManagedWorkingMemory">
| <constructor>
| <parameter><inject bean="RuleBase"/></parameter>
| <parameter><inject bean="jboss.kernel:service=KernelController"/></parameter>
| </constructor>
| <incallback method="addEventListener" signature="org.drools.event.AgendaEventListener"/>
| <incallback method="addEventListener" signature="org.drools.event.WorkingMemoryEventListener"/>
| <uncallback method="removeEventListener" signature="org.drools.event.AgendaEventListener"/>
| <uncallback method="removeEventListener" signature="org.drools.event.WorkingMemoryEventListener"/>
| </bean>
|
| <bean name="debugAgendaEventListener" class="org.drools.event.DebugAgendaEventListener"/>
| <bean name="debugWorkingMemoryEventListener" class="org.drools.event.DebugWorkingMemoryEventListener"/>
|
| <bean name="RuleBase" class="org.jboss.reliance.drools.core.RuleBaseBean">
| <demand>packageGenerator</demand>
| </bean>
|
| <bean name="packageGenerator" class="org.jboss.reliance.drools.core.PackageGenerator">
| <property name="fromDRL">
| <value>
| package SimplePermissions;
|
| import org.jboss.reliance.drools.core.security.PermissionCheck;
| import org.jboss.reliance.drools.core.security.RoleTracker;
| import org.jboss.reliance.drools.core.security.Role;
| import org.jboss.reliance.drools.core.rules.Flag;
|
| global org.jboss.dependency.spi.Controller controller;
|
| rule TesterCanBeCreated
| when
| c: PermissionCheck(name == "tester", action == "Create")
| Role(name == "admin")
| then
| c.grant();
| end;
|
| rule RoleTrackerAddition
| salience 10
| when
| Role(name == "admin")
| then
| insert( new Flag("admin_flag") );
| insertLogical( new RoleTracker("admin") );
| end;
|
| rule RoleTrackerRemovalTrigger
| when
| f : Flag(name == "admin_flag")
| not( RoleTracker(name == "admin") )
| then
| retract( f );
| RoleTracker.change(controller, "tester", "Configured");
| end;
| </value>
| </property>
| </bean>
|
| <bean name="configuration" class="org.jboss.reliance.identity.Configuration"/>
|
| <bean name="identity" class="org.jboss.reliance.drools.core.security.RoleBasedIdentity">
| <property name="securityContext"><inject bean="WorkingMemory" property="statefulSession"/></property>
| <property name="configuration"><inject bean="configuration"/></property>
| </bean>
|
| <!-- user beans -->
|
| <bean name="roles" class="org.jboss.test.reliance.drools.support.RolesAdapter">
| <constructor>
| <parameter><inject bean="identity"/></parameter>
| </constructor>
| <property name="username">alesj</property>
| <property name="password">qwert</property>
| <property name="roles">
| <set elementClass="java.lang.String">
| <value>guest</value>
| </set>
| </property>
| </bean>
|
| <bean name="tester" class="org.jboss.test.reliance.drools.support.Tester">
| <annotation>@org.jboss.reliance.drools.dependency.RulesAware</annotation>
| <demand state="PreInstall">roles</demand>
| </bean>
|
| </deployment>
|
and the matching JUnit code
| public void testRulesConcept() throws Throwable
| {
| // only in Configured state, since there is no admin role present
| KernelControllerContext testerContext = getControllerContext("tester", ControllerState.CONFIGURED);
| assertEquals(ControllerState.CONFIGURED, testerContext.getState());
|
| RolesAdapter rolesAdapter = (RolesAdapter)getBean("roles");
| rolesAdapter.addRole("admin");
|
| // should be Installed now, since admin role is present
| change(testerContext, ControllerState.INSTALLED);
| assertEquals(ControllerState.INSTALLED, testerContext.getState());
|
| rolesAdapter.removeRole("admin");
| // should be unwinded to Configured, since the admin role was removed
| assertEquals(ControllerState.CONFIGURED, testerContext.getState());
|
| KernelControllerContext identityContext = getControllerContext("identity");
| change(identityContext, ControllerState.NOT_INSTALLED);
|
| // should be uninstalled as well, since it relies on identity
| assertEquals(ControllerState.NOT_INSTALLED, testerContext.getState());
| }
|
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4080123#4080123
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4080123
17 years, 4 months
[Design of Clustering on JBoss (Clusters/JBoss)] - Re: Transaction Sticky LB policy for 4.2/trunk
by bstansberry@jboss.com
"galder.zamarreno(a)jboss.com" wrote :
| Ok, I'll implement this for all invokers and will look into the most efficient way to unit test them all.
Good. Take the "don't deploy in AS" thing as just an idea I threw out. That comes from a general feeling I have that unit testing in clustering is inadequate because it's too hard to 1) write complex deployment descriptors that cover all the cases, package them and then deploy them 2) properly check system state when you can only expose that state via JMX or as part of a web or ejb response.
anonymous wrote : 1.- Rather than implementing 4 brand new policies, it might be easier to add a new element to cluster-config XML called transaction-sticky with true/false values and modify the existing load balance policies to act upon the value of that element, what do you think? This hasn't been fully baked, it's just something that I had in mind.
Hmm. I don't want to reject that idea yet, but I'm concerned about pushing more config stuff into both EJB3 and EJB2. Plus, theoretically these policies can be used outside of EJB, so we'd have to find a way to expose the option wherever they are used.
Also, doing that requires a new field in the LBP impls, which changes their serialization. That will break clients using the old versions, so no good in 4.x and something to avoid in 5.
Also means changing the LBP interface to add a setTransactionSticky(boolean) method.
I know where you're coming from though. The proliferation of classes gets worse when we start talking about doing things properly for Remoting based proxies (e.g. EJB3) vs. the existing detached invoker-based ones. LoadBalancePolicy.chooseTarget (FamilyClusterInfo clusterFamily, Invocation routingDecision) is not meaningful in a Remoting based proxy, because the "org.jboss.invocation.Invocation" class is not used, "org.jboss.aop.joinpoint.Invocation" is. So, handling that doubles the number of classes. :(
anonymous wrote :
| 2.- Should transaction sticky (either implementations or solution mentioned in 1) be the default? IMO, 4.x should maintain existing (default) behavior while transaction sticky should be default in trunk. Thoughts?
+1
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4080120#4080120
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4080120
17 years, 4 months