7 Replies Latest reply on Dec 1, 2006 5:55 AM by jimknopf

    Action ; Token.signal( ... ) ; Exception: locked tokens

    jimknopf

      Hi again,
      I am calling an action and in this action i am fire a Rule from JRules. Based on the result of this rule i want to use a transition ( token.signal( "xxx" ) ).
      But when i do this, i get an Exception. Is it not possible to use use token.signal in an action? And then, how should i realise actions in which i want to move to a next token? Is it only Possible with DecicionHandlers?

      The Exception:


      org.jbpm.JbpmException: can't continue execution on locked tokens. signalling the same token that executes an action is not allowed
      at org.jbpm.graph.exe.Token.signal(Token.java:164)
      at org.jbpm.graph.exe.Token.signal(Token.java:137)


       </decision>
       <decision name="SGA">
       <event type="node-enter">
       <action name="checkSGA" class="actions.DefaultRuleAction">
       <ruleFile>etr2.drl</ruleFile>
       <transitionName>t_sga a</transitionName>
       <transitionName_False>t_sga c</transitionName_False>
       </action>
       </event>
       <transition name="t_sga a" to="SGA A"></transition>
       <transition name="t_sga b" to="SGA B"></transition>
       <transition name="t_sga c" to="SGA C"></transition>
       </decision>
       <state name="SGA A">
      


      Action:
      public class DefaultRuleAction extends RuleAction {
       private static final long serialVersionUID = 8459834862286126414L;
      
       //Name der Variablen die in der Action beruecksichtigt werden.
       public List objectNames = null;
       public String transitionName = null;
       public String transitionName_False = null;
      
       public void execute( ExecutionContext executionContext) throws Exception {
       // TODO Auto-generated method stub
       System.err.println("My Timer-Rule-Action!");
      
       if (this.ruleFile == null) {
       System.err.println("Es wurde kein Rule-File angegeben.");
       // TODO String aus einer Property laden.
       return;
       }
      
       // load up the RuleBase
       WorkingMemory workingMemory = null;
       try {
       RuleBase ruleBase = readRule(this.ruleFile);
      
       workingMemory = this.generateWorkingMemory( ruleBase );
      
       this.assertObjectsIn( workingMemory, executionContext );
       workingMemory.fireAllRules();
      
       if( RuleAction.getResultFrom( workingMemory ) == true ){
       if(this.transitionName != null){
       executionContext.getToken().signal( transitionName );
       }
       }else{
       if(this.transitionName_False != null){
       executionContext.getToken().signal( transitionName_False );
       }
       }
      
       } catch (FileNotFoundException fnfe) {
       System.err.println("Es wurde ein falsches Rule-File angegeben.");
       fnfe.printStackTrace();
      // TODO String aus einer Property laden.
       } catch (MissingRuleResultException mrre){
       System.err.println("Es wurde kein RuleResult-Object im WorkingMemory der Regel gefunden.");
       mrre.printStackTrace();
      // TODO String aus einer Property laden.
       } catch (Exception e){
       System.err.println("Rule-Base konnte nicht angelegt werden.");
       e.printStackTrace();
      // TODO String aus einer Property laden.
       } finally{
       if(workingMemory != null)
       workingMemory.dispose();
       }
      
       //ArcaViaController.getInstance().cancelTimer( executionContext.getTimer() );
      
       }
      
      


      public abstract class RuleAction implements ActionHandler{
       /* Name der Variablen des Workflows welche in das WorkingMemory
       der Regel eingepflegt werden sollen.*/
       protected List objectNames = null;
      
       protected String ruleFile = null;
       private RuleResult ruleResult = new RuleResult();
      
       /**
       * Please note that this is the "low level" rule assembly API.
       * @throws Exception
       */
       protected static RuleBase readRule(String ruleFileLocation) throws Exception{
      // ruleFileLocation = "src" +
      // System.getProperty("file.separator") +
      // "rules" +
      // System.getProperty("file.separator") +
      // ruleFileLocation;
      
       System.err.println( ruleFileLocation );
      
       //read in the source
       Reader source = null;
       try{
       source = new InputStreamReader( RuleAction.class.getResourceAsStream( "/"+ruleFileLocation ) );
      // source = new InputStreamReader( new FileInputStream( new File(ruleFileLocation) ) );
      
       }catch( Exception e ){
       throw new FileNotFoundException();
       }
      
       //optionally read in the DSL (if you are using it).
       //Reader dsl = new InputStreamReader( DroolsTest.class.getResourceAsStream( "/mylang.dsl" ) );
      
       //Use package builder to build up a rule package.
       //An alternative lower level class called "DrlParser" can also be used...
      
       DrlParser parser = new DrlParser();
       PackageDescr packageDescr = parser.parse( source);
      
       /*
       * Wenn der default PackageBuilder eine Exception erzeugt (was er tat),
       * soll man ihn dann durch diese Code-Zeilen ersetzen laut der JBoss wiki Seite
       */
       PackageBuilderConfiguration pkgBuilderCfg = new PackageBuilderConfiguration();
       pkgBuilderCfg.setCompiler(PackageBuilderConfiguration.JANINO);
       PackageBuilder builder = new PackageBuilder(pkgBuilderCfg);
      
      
       //default PackageBuilder
       //PackageBuilder builder = new PackageBuilder();
      
       //this wil parse and compile in one step
       //NOTE: There are 2 methods here, the one argument one is for normal DRL.
       //builder.addPackageFromDrl( source );
       builder.addPackage(packageDescr);
      
       //Use the following instead of above if you are using a DSL:
       //builder.addPackageFromDrl( source, dsl );
      
       //get the compiled package (which is serializable)
       Package pkg = builder.getPackage();
      
       //add the package to a rulebase (deploy the rule package).
       RuleBase ruleBase = RuleBaseFactory.newRuleBase();
       ruleBase.addPackage( pkg );
       return ruleBase;
       }
      
       /**
       * Lädt aus dem uebergebenen WorkingMemory ein RuleResult-Object und
       * liefert den Result-Wert von diesem Object zurueck.
       * Dieser Result-Wert kann in einer Regel dazu verwendet werden,
       * ein Ergebniss zurueck zu liefern (zur Zeit nur true oder false).
       *
       * @param wm WorkingMemory aus welchem das RuleResult-Object geprueft werden soll.
       * @return Den Result-Wert des RuleResult-Objectes in dem uebergeben WorkingMemory.
       * @throws MissingRuleResultException Es gibt kein RuleResult-Object im uebergebenen WorkingMemory.
       */
       protected static boolean getResultFrom( WorkingMemory wm ) throws MissingRuleResultException{
      // if( wm == null )
      // throw new NullPointerException();
      
       List ruleResults = wm.getObjects( RuleResult.class );
      
       if( ruleResults.size() < 1 )
       throw new MissingRuleResultException();
      
       RuleResult rs = (RuleResult)ruleResults.get(0);
       return rs.getResult();
      
       }
      
       /**
       * Lädt das RuleResult Object in den WorkingMemory
       * so das man Ihn später in der Rule verwenden kann und
       * das in Ihm stehende Ergebniss der Regel mit der Methode
       * <code>getResultFrom(WorkingMemory wm)</code> auslesen kann.
       *
       * @param wm WorkingMemory welches mit einem RuleResult Object vorbereitet werden soll.
       */
       protected void prepareWorkingMemory( WorkingMemory wm ){
      // if( wm == null )
      // throw new NullPointerException();
       wm.assertObject( this.ruleResult );
       }
      
       /**
       * Erzeugt einen neuen WorkingMemory in der uebergebenen RuleBase und
       * ruft fuer diesen dann <code>prepareWorkingMemory( WorkingMemory wm )</code>
       * auf um den WorkingMemory mit dem RuleResult-Object zu beladen.
       *
       * @param ruleBase RuleBase in welchem das neue WorkingMemory erzeugt werden soll.
       * @return Das Erzeugte WorkingMemory.
       */
       protected WorkingMemory generateWorkingMemory( RuleBase ruleBase){
       WorkingMemory wm = ruleBase.newWorkingMemory();
       this.prepareWorkingMemory( wm );
      
       return wm;
       }
      
       /**
       * Lädt die Variablen des Workflows welche der Action bei Ihrem Aufruf
       * durch den Workflow uebergeben wurden in den WorkingMemory der Regel.
       *
       * @param wm WorkingMemory welcher mit den Objecten beladen werden soll.
       * @param executionContext Context mittels welcher die Variablen enthaelt.
       */
       protected void assertObjectsIn( WorkingMemory wm, ExecutionContext executionContext ){
      
       if (objectNames != null) {
       // Ausgewählte Variablen einladen
       ContextInstance ci = executionContext.getContextInstance();
       Iterator it = objectNames.iterator();
       while (it.hasNext()) {
       String objectName = (String) it.next();
       wm.assertObject(ci.getVariable(objectName));
       }
       }/*
       * Zu gefährlich in der Handhabung daher deaktiviert else{ //
       * Alle Variablen einladen wenn keine uebergeben wurden
       * ContextInstance ci = executionContext.getContextInstance();
       * Iterator it = ci.getVariables().entrySet().iterator();
       * while(it.hasNext()){ workingMemory.assertObject( it.next() ); } }
       */
      
       }
      
      }
      


        • 1. Re: Action ; Token.signal( ... ) ; Exception: locked tokens
          kukeltje

           

          "JimKnopf" wrote:
          Hi again,
          I am calling an action and in this action i am fire a Rule from JRules. Based on the result of this rule i want to use a transition ( token.signal( "xxx" ) ).
          But when i do this, i get an Exception. Is it not possible to use use token.signal in an action? And then, how should i realise actions in which i want to move to a next token? Is it only Possible with DecicionHandlers?

          The Exception:

          org.jbpm.JbpmException: can't continue execution on locked tokens. signalling the same token that executes an action is not allowed
          at org.jbpm.graph.exe.Token.signal(Token.java:164)
          at org.jbpm.graph.exe.Token.signal(Token.java:137)



          Correct, or by inplementing a custom node

          • 2. Re: Action ; Token.signal( ... ) ; Exception: locked tokens
            jimknopf

            Correct.

            But i allready solved the Problem ... simple just using leaveNode( ... ) instead of getToken.signal( ... ).

            A decisionHandler is not possible, because sometimes i need to have more then one Decision in one node so. (For Example Check some Rulebases if one of these Rulebase matched then use Transition "A" else the default Transition). So i need to use actions insted of DessionHandlers.


            • 3. Re: Action ; Token.signal( ... ) ; Exception: locked tokens
              jimknopf

              And ... thank u for ur response :)

              • 4. Re: Action ; Token.signal( ... ) ; Exception: locked tokens
                kukeltje

                a java classs (similar to an actionhandler) van be the decisionhandler.... what you describe is exactely what a decisionnode is for.

                • 5. Re: Action ; Token.signal( ... ) ; Exception: locked tokens
                  jimknopf

                  I know, but the Problem i have is that this ruleresults only give true or false and later it should be possible to create a new workflow with out the capacity to create a new decision- or action-class (my english isn't good so i am sorry if it is not well explaint). That is the reason, why need the ability to activate more then one decision but that in a single node. Like this:


                   <decision name="SGA">
                   <event type="node-enter">
                   <action name="checkTakeT_sgaA" class="actions.DefaultRuleAction">
                   <ruleFile>etr1.drl</ruleFile>
                   <transitionName>t_sgaA</transitionName>
                   </action>
                   <action name="checkTakeT_sgaBOrT_sgaC" class="actions.DefaultRuleAction">
                   <ruleFile>etr1.drl</ruleFile>
                   <transitionName>t_sgaB</transitionName>
                   <transitionName_False>t_sgaC</transitionName_False>
                   </action>
                   </event>
                   <transition name="t_sgaC" to="SGAC"></transition>
                   <transition name="t_sgaB" to="SGAB"></transition>
                   <transition name="t_sgaA" to="SGAA"></transition>
                   </decision>
                  


                  If i use a decision-Handler i must use two desicions to realise the same because it is only possible to call one (what is ok and logical) decision-Handler in a decision (or did i think in a wrong way?).

                  • 6. Re: Action ; Token.signal( ... ) ; Exception: locked tokens
                    kukeltje

                     

                    "to activate more than one decision?"


                    What do you mean by this, do you mean more than one transition? Then use a fork. Besides that, I'd use a handler on a decision, not the 'node enter' event to make the decision what to do. That is more common.

                    • 7. Re: Action ; Token.signal( ... ) ; Exception: locked tokens
                      jimknopf

                      I know u are right (normaly ;) )
                      But i need to check more then one dedicions in a node. Normaly the code for the disicion is in the desicionhandler and the handler returns the name of the transition.
                      But i must code the desicionhandler and actionhandler before i know the Workflow or the rules. The actions are predetermined. But what to do with the Desicionhandler? I know the rules are simple and only give True or False. So if i give the desicionhandler the rulename and the name of the transitions it is able to take transition "a" if the ruleresult is true else it takes transition "b". That works fine but at the moment i have more then 2 Transitions for example 3 i have a Problem, because i am not able to code a desicionhandler to handle n transitions(and easy use of it in the jbpm-file) if i only have true/false rules. If i could give the desicionhandler a vector containing Objects(Rulename, transition a, transition b) it where no problem, but i think that is not possible and normaly not realy usefull.

                      Thats the reason i am using actionhandler instat of desicionhandler.