You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by Abigail Gertner <ge...@mitre.org> on 2010/08/11 01:11:58 UTC

[scxml] datamodel, custom actions and digester

Hi --

I have a couple of questions about using commons SCXML.

I am trying to use the datamodel within a state as a kind of template,
so when I enter the state, I will set some values within the datamodel
and then execute some code with the resulting data.

I was trying to use an <assign> statement within the state's <onentry>
tag and then use the onEntry() method of a Listener to do the additional
processing of the data, but I found that the listener did not get the
values that had been set by the assign statement as part of the
datamodel associated with its target node. It only gets the original
datamodel when I call target.getDatamodel() - not the version with the
updated values. Is this correct?

So, I think I need to use a custom action to do this. I think I have
figured out how to implement the custom action. My problem now is that
(for unrelated reasons) I am using a dispatcher obtained from
SCXMLParser.newInstance() to parse the scxml document and I don't know
how to include the custom action when I am doing it this way. In the
documentation for custom actions, it says that "the digester rules can
be added by directly by obtaining a Digester instance with the "default"
SCXML rules using the newInstance() methods and further directly adding
the necessary rules using the digester API." Can someone give me a bit
more information or an example on how to accomplish this?

Alternatively, if there is a way to do what I am trying to do (assign
some values to the data and then pass that data to a listener) without a
custom action I would like to know that too.

Thanks for your help

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: [scxml] datamodel, custom actions and digester

Posted by Rahul Akolkar <ra...@gmail.com>.
On Wed, Aug 11, 2010 at 3:51 PM, Abigail Gertner <ge...@mitre.org> wrote:
>
>
> On 8/11/2010 3:36 PM, Rahul Akolkar wrote:
>> On Wed, Aug 11, 2010 at 2:19 PM, Abigail Gertner <ge...@mitre.org> wrote:
>>
>>>
>>> On 8/11/2010 12:29 AM, Rahul Akolkar wrote:
>>>
>>>> <snip/>
>>>> The way to obtain the live values of the datamodel is to use the
>>>> expression evaluator, see interfaces mentioned here:
>>>>
>>>>   http://commons.apache.org/scxml/guide/contexts-evaluators.html
>>>>
>>>>
>>>>
>>> Is it possible to call a method using the expression evaluator with an
>>> argument that is a node in the XML tree, rather than just a string value?
>>>
>>>
>> <snip/>
>>
>> Executable content is open ended in SCXML, as largely speaking most
>> things are possible with custom actions. I'm afraid I've lost the
>> bigger picture of your scenario in the pin-pointed question above.
>>
>> To obtain a node using the expression evaluator, use
>> Evaluator#evalLocation(...) which returns a Node.
>>
>
> What I mean is, if I want to do something like:
>
> <onentry>
>  <cs:var name="result" expr="foo.bar(...)"/>
> </onentry>
>
> Where the argument to foo.bar() is a Node from the datamodel, but with
> the current context values included, how can I get that from the
> expression evaluator. I tried using the Data('var','path') expression
> but it doesn't seem to work for nodes.
>
<snip/>

Here are some ways to tackle this:

 * Break the above into smaller operations: (1) obtain a node, (2)
invoke the method. For example:

    <onentry>
      <my:node name="arg" expr="..."/>
      <cs:var name="result" expr="foo.bar(arg)"/>
    </onentry>

  where <my:node> uses Evaluator#evalLocation(...) and creates a "var"
matching the name argument.

 * Use XPath as the expression language as its better equipped to deal
with XML nodes. The above would then become:

   <onentry>
     <cs:var name="result" expr="foo:bar($dataid/xpath/to/node)"/>
   </onentry>

   However, the XPath evaluator isn't available in the latest release
however, but rather in a branch:

   http://svn.apache.org/repos/asf/commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/env/xpath/

 * A bit of background - The Data() function is mostly limited to
values of leaf nodes (strings, integers) and is designed to satisfy
the rvalue of most assignment expressions. There is a corresponding
LData() -- I presume you're using JEXL -- that is meant to satisfy the
lvalue (and will return nodes) but these are implementation details so
resorting to using LData isn't recommended.


>>>> Might be worthwhile revisiting the need for using
>>>> SCXMLParser#newInstance() rather than the static parse methods.
>>>>
>>>>
>>>>
>>>>
>>> The reason I am doing this is that I am using xinclude to include a
>>> separate xml file and I found that I needed to call setXIncludeAware()
>>> on the parser to make it do the include. Is there some way to do this
>>> using the static parse methods?
>>>
>>>
>> <snap/>
>>
>> Not in the latest release (v0.9) so thats one of the cases where you
>> may indeed not be able to use the static parse methods. Based on what
>> I've read so far, it seems your best bet may be to register the
>> digester rules for your custom actions by hand after you obtain the
>> new instance and let the custom action do the appropriate expression
>> evaluation and datamodel / context processing.
>>
> I'm trying to do it this way now and having trouble getting the custom
> action to fire. I am using
>
> dig.addObjectCreate("!*/onentry/sendMessage", SendMessage.class);
>
> Where my custom action is called SendMessage.
>
> Then in my scxml file I have
>
> <onentry>
>  <sendMessage/>
> </onentry>
>
> The SendMessage object is being created when the file is parsed, but the
> execute() method is not being called when the state is entered.
> Do I have to do something else to get it to call execute()?
>
<snap/>

Minimally, you'll have to add the SetNextRule (and maybe others, as
per your action needs), so this:

  dig.addSetNext("!*/onentry/sendMessage", "addAction");

Also, best to use a different XML namespace for custom actions. See
Digester#setRuleNamespaceURI(...) for this purpose.

-Rahul

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: [scxml] datamodel, custom actions and digester

Posted by Abigail Gertner <ge...@mitre.org>.

On 8/11/2010 3:36 PM, Rahul Akolkar wrote:
> On Wed, Aug 11, 2010 at 2:19 PM, Abigail Gertner <ge...@mitre.org> wrote:
>   
>>
>> On 8/11/2010 12:29 AM, Rahul Akolkar wrote:
>>     
>>> <snip/>
>>> The way to obtain the live values of the datamodel is to use the
>>> expression evaluator, see interfaces mentioned here:
>>>
>>>   http://commons.apache.org/scxml/guide/contexts-evaluators.html
>>>
>>>
>>>       
>> Is it possible to call a method using the expression evaluator with an
>> argument that is a node in the XML tree, rather than just a string value?
>>
>>     
> <snip/>
>
> Executable content is open ended in SCXML, as largely speaking most
> things are possible with custom actions. I'm afraid I've lost the
> bigger picture of your scenario in the pin-pointed question above.
>
> To obtain a node using the expression evaluator, use
> Evaluator#evalLocation(...) which returns a Node.
>   

What I mean is, if I want to do something like:

<onentry>
  <cs:var name="result" expr="foo.bar(...)"/>
</onentry>

Where the argument to foo.bar() is a Node from the datamodel, but with
the current context values included, how can I get that from the
expression evaluator. I tried using the Data('var','path') expression
but it doesn't seem to work for nodes.

>>> Might be worthwhile revisiting the need for using
>>> SCXMLParser#newInstance() rather than the static parse methods.
>>>
>>>
>>>
>>>       
>> The reason I am doing this is that I am using xinclude to include a
>> separate xml file and I found that I needed to call setXIncludeAware()
>> on the parser to make it do the include. Is there some way to do this
>> using the static parse methods?
>>
>>     
> <snap/>
>
> Not in the latest release (v0.9) so thats one of the cases where you
> may indeed not be able to use the static parse methods. Based on what
> I've read so far, it seems your best bet may be to register the
> digester rules for your custom actions by hand after you obtain the
> new instance and let the custom action do the appropriate expression
> evaluation and datamodel / context processing.
>   
I'm trying to do it this way now and having trouble getting the custom
action to fire. I am using

dig.addObjectCreate("!*/onentry/sendMessage", SendMessage.class);

Where my custom action is called SendMessage.

Then in my scxml file I have

<onentry>
  <sendMessage/>
</onentry>

The SendMessage object is being created when the file is parsed, but the
execute() method is not being called when the state is entered.
Do I have to do something else to get it to call execute()?

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: [scxml] datamodel, custom actions and digester

Posted by Rahul Akolkar <ra...@gmail.com>.
On Wed, Aug 11, 2010 at 2:19 PM, Abigail Gertner <ge...@mitre.org> wrote:
>
>
> On 8/11/2010 12:29 AM, Rahul Akolkar wrote:
>> <snip/>
>> The way to obtain the live values of the datamodel is to use the
>> expression evaluator, see interfaces mentioned here:
>>
>>   http://commons.apache.org/scxml/guide/contexts-evaluators.html
>>
>>
>
> Is it possible to call a method using the expression evaluator with an
> argument that is a node in the XML tree, rather than just a string value?
>
<snip/>

Executable content is open ended in SCXML, as largely speaking most
things are possible with custom actions. I'm afraid I've lost the
bigger picture of your scenario in the pin-pointed question above.

To obtain a node using the expression evaluator, use
Evaluator#evalLocation(...) which returns a Node.


>> Might be worthwhile revisiting the need for using
>> SCXMLParser#newInstance() rather than the static parse methods.
>>
>>
>>
> The reason I am doing this is that I am using xinclude to include a
> separate xml file and I found that I needed to call setXIncludeAware()
> on the parser to make it do the include. Is there some way to do this
> using the static parse methods?
>
<snap/>

Not in the latest release (v0.9) so thats one of the cases where you
may indeed not be able to use the static parse methods. Based on what
I've read so far, it seems your best bet may be to register the
digester rules for your custom actions by hand after you obtain the
new instance and let the custom action do the appropriate expression
evaluation and datamodel / context processing.

-Rahul


> Thanks again,
> -Abigail
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: [scxml] datamodel, custom actions and digester

Posted by Abigail Gertner <ge...@mitre.org>.

On 8/11/2010 12:29 AM, Rahul Akolkar wrote:
> <snip/>
> The way to obtain the live values of the datamodel is to use the
> expression evaluator, see interfaces mentioned here:
>
>   http://commons.apache.org/scxml/guide/contexts-evaluators.html
>
>   

Is it possible to call a method using the expression evaluator with an
argument that is a node in the XML tree, rather than just a string value?

> Might be worthwhile revisiting the need for using
> SCXMLParser#newInstance() rather than the static parse methods.
>
>
>   
The reason I am doing this is that I am using xinclude to include a
separate xml file and I found that I needed to call setXIncludeAware()
on the parser to make it do the include. Is there some way to do this
using the static parse methods?

Thanks again,
-Abigail


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: [scxml] datamodel, custom actions and digester

Posted by Rahul Akolkar <ra...@gmail.com>.
On Tue, Aug 10, 2010 at 7:11 PM, Abigail Gertner <ge...@mitre.org> wrote:
> Hi --
>
> I have a couple of questions about using commons SCXML.
>
> I am trying to use the datamodel within a state as a kind of template,
> so when I enter the state, I will set some values within the datamodel
> and then execute some code with the resulting data.
>
> I was trying to use an <assign> statement within the state's <onentry>
> tag and then use the onEntry() method of a Listener to do the additional
> processing of the data, but I found that the listener did not get the
> values that had been set by the assign statement as part of the
> datamodel associated with its target node. It only gets the original
> datamodel when I call target.getDatamodel() - not the version with the
> updated values. Is this correct?
>
<snip/>

The getDatamodel() call returns an oacs.model.Datamodel object
(anything belonging to the model package is not part of an executing
state machine, rather its part of the state machine description itself
i.e. the "model" on which the executor operates).

So yes, the above behavior you note is certainly as expected. Note
that the above is useful in some scenarios, such as "reset" type
scenarios where one may want to restore the datamodel to its original
values.

The way to obtain the live values of the datamodel is to use the
expression evaluator, see interfaces mentioned here:

  http://commons.apache.org/scxml/guide/contexts-evaluators.html


> So, I think I need to use a custom action to do this. I think I have
> figured out how to implement the custom action. My problem now is that
> (for unrelated reasons) I am using a dispatcher obtained from
> SCXMLParser.newInstance() to parse the scxml document and I don't know
> how to include the custom action when I am doing it this way. In the
> documentation for custom actions, it says that "the digester rules can
> be added by directly by obtaining a Digester instance with the "default"
> SCXML rules using the newInstance() methods and further directly adding
> the necessary rules using the digester API." Can someone give me a bit
> more information or an example on how to accomplish this?
>
<snap/>

You'll need to be familiar with Digester, which is what the above
method returns (an instance thereof):

  http://commons.apache.org/digester/

The idea is to register the custom action related digester rule(s)
that inject the backing action classes in the SCXML object model (for
example, the digester paths will likely be "!*/onentry/foo",
"!*/onexit/foo", "!*/transition/foo", "!*/if/foo" where "foo" is the
custom action).

Might be worthwhile revisiting the need for using
SCXMLParser#newInstance() rather than the static parse methods.


> Alternatively, if there is a way to do what I am trying to do (assign
> some values to the data and then pass that data to a listener) without a
> custom action I would like to know that too.
>
<snip/>

Some data, such as that available in the root context, may be accessed
directly if the listener has a handle to the root context.

-Rahul


> Thanks for your help
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org