Hello John,
On 26 Nov., 06:11, "John Mettraux" <[EMAIL PROTECTED]> wrote:
>
> On Wed, Nov 26, 2008 at 1:53 AM, Torsten Schoenebaum
> <[EMAIL PROTECTED]> wrote:
>
> > If I'm not mistaken, I could set a field or variable in the workitem
> > to an array or hash this way. This could be a workaround, but not a
> > very nice one. I tried that one:
>
> > <process-definition name="ActiveResourceTest" revision="0.1">
> > <participant ref="reminder" site="http://localhost:7000"
> > resource_name="story" method="put" action="send_reminder"
> > resource_id="${field:story_id}" >
> > <a>
> > <array>
> > <string>First string</string>
> > <string>Second string</string>
> > </array>
> > </a>
> > </participant>
> > </process-definition>
>
> > This creates a child expression which I can get using
> > get_flow_expression(workitem).children -- but how to go further? I
> > assume the ValueMixin does the trick in the set expression, but how
> > could I use or adopt it?
>
> You could provide your own implementation of the ParticipantExpression
> to the engine. As implemented for now, it's rather static
> (http://github.com/jmettraux/ruote/tree/r0.9.19/lib%2Fopenwfe%2Fexpres...)
> the ParticipantExpression class is mapped to the 'participant' names
> (I guess it's time for me to make a more flexible expression map).
>
> Meanwhile you could Provide a TorstenParticipantExpression that
> extends ParticipantExpression and mixes in ValueMixin. You'd have to
> make sure to swap the apply() method in the participant to a reply().
> The ValueMixin provides an apply() method that then calls the reply()
> method. It's complicated, that's true.
And it would be overkill, somehow. I dropped the idea of passing the
arguments to the ActiveResource method to call in the process
definition. I'll simply use a kind of block template for that.
> Note that if you use a Ruby process definition you can more easily
> have array/hashes as expression attribute values, that could save you
> time.
Won't be necessary now, thanks to Ruby's block magic :-)
> I know it may be a pain in the ass, but I've always been trying to
> somehow keep data out of processes themselves.
Which seems to be a very good idea to me. I would have "abused" that
feature to build a template like that:
<participant ref="reminder" arguments="['send_reminder',
['special_prefix':${f:story_prefix}]]" />
This way the data stays in the workitems. Using a block to
ActiveResourceParticipant.new does the same trick, but not in the
process definition.
Please have a look at my second try, still test-less:
#
# Ruote participant which does a REST call. It's using ActiveResource
to do the
# actual magic. You can call every class and instance method
# ActiveResource::Base and it's mixins provide. You can also process
the
# response of the REST request and save some of it's data into the
workitem
# for example.
#
# Before using this participant you *really* should make you familiar
with
# ActiveResource and it's usage.
#
# ==Parameters
# default_site:: The URI (as string) of the site where your REST
interface sits. See <tt>site</tt> parameter in ActiveResource::Base.
# default_resource_name:: The name of the resource you like to access.
See <tt>element_name</tt> parameter in ActiveResource::Base.
# default_method:: The ActiveResource method to call. In most cases
should be "get", "put", "post" or "delete".
# default_action:: The first parameter which should be used as
argument to the ActiveResource method which will be called. This value
is ignored if a block is given (see below)
# default_resource_id:: The ID of the resource on which the action
should be called on default. If negative, nil or false, the action
will be called on the complete set of resources instead of on a single
resource determined by its ID.
# response_handling:: A proc object / block which gets called after
the request is done. It get's called with to arguments: The response
of the ActiveResource method called and the workitem.
#
# The new method also takes a block. It may be used to set the
arguments of the
# ActiveResource method to call. The block must return an array of
arguments.
# The array will be splitted and each entry will be used as argument
to the
# ActiveResource method called. See
OpenWFE::LocalParticipant#call_block for
# the arguments the block itself takes.
#
# The URLs which will be generated and called will look like this if
an id is given:
# <tt>#{default_site}/#{default_element_name.pluralize}/#
{default_element_id}/#{default_action}.xml</tt>
# If no id is given:
# <tt>#{default_site}/#{default_element_name.pluralize}/#
{default_action}.xml
#
# All parameters except response_handling and the block set default
values --
# you can always override them in the process definition.
#
# ==Using it
# The participant should be registered in the engine in a way like
this:
#
# engine.register_participant(
# 'reminder',
# ActiveResourceParticipant.new(
# 'http://localhost:7000',
# 'story',
# 'put', # we will use
ActiveResource::CustomMethods::InstanceMethods#put
# 'send_reminder', # put is happy with just one parameter: The
action to be called. So we won't have to use a block to set the
arguments of the ActiveResource method to call.
# nil, # no default id, we will use the resource_id attribute in
the process definition later
# nil # no response handling
# )
# )
#
# Let's try a more complex example:
#
# engine.register_participant(
# 'complex_ar',
# ActiveResourceParticipant.new(
# 'http://localhost:7000',
# 'story',
# 'find', # yes, even ActiveResource::Base#find method may be
used...
# nil, # don't use action parameter as we will use a block
instead
# nil, # don't use id
# proc do |response, workitem| # define response handling block
# workitem.set_attribute('title', response.attributes
['title']) # The type of the response object depends on the method you
use!
# end
# ) do |workitem| # define arguments to use with the find method
# # each argument is an entry in an array the block has to
return
# [
# workitem.attributes['story_id'], # the first argument
# {:prefix => 'foo'} # the second one is an hash
# ]
# end
# )
#
# You can now use the participant in your workflow definitions. An
example using
# XML:
#
# <concurrence count="1">
# <participant ref="qa" />
# <cron every="1m">
# <participant ref="reminder" site="http://localhost:7000"
resource_name="story" method="put" action="send_reminder"
resource_id="${field:story_id}" />
# </cron>
# </concurrence>
#
# Here, the RestCallParticipant is used to send a reminder.
#
# See the descriptions of the default parameters for an explanation of
the
# attributes <tt>site</tt>, <tt>method</tt>, <tt>resource_name</tt>,
# <tt>action</tt> and <tt>resource_id</tt>.
#
class ActiveResourceParticipant
include OpenWFE::LocalParticipant
def initialize(default_site, default_resource_name, default_method,
default_action, default_resource_id, response_handling, &block)
@default_site = default_site
@default_resource_name = default_resource_name
@default_method = default_method
@default_action = default_action
@default_resource_id = default_resource_id
@response_handling = response_handling
@block_arguments = block
end
#
# This method is called each time the participant receives a
workitem. It
# calls the requested ActiveResource method, calls the response
handling code
# if present and then immediatly replies to the engine.
#
def consume(workitem)
site = workitem.params['site'] || @default_site
resource_name = workitem.params['resource_name'] ||
@default_resource_name
method = workitem.params['method'] || @default_method
action = workitem.params['action'] || @default_action
resource_id = workitem.params['resource_id'] ||
@default_resource_id
method = method.to_sym
# use block to determine the method's arguments if given
if(@block_arguments)
args = call_block @block_arguments, workitem
elsif(action)
args = [action] # use action parameter if no block is given
else
args = [] # no arguments
end
# create new subclass of ActiveResource::Base
active_resource_class = Class.new(ActiveResource::Base)
active_resource_class.site = site # set site parameter
active_resource_class.element_name = resource_name # set element
name
# Do we work on a single or on a set of resources? If resource_id
is nil or
# negative, it's a set of resources.
if(!resource_id || (resource_id.to_i < 0))
# as we work on a set of resources, we can immediatly send the
request
response = active_resource_class.send(method, *args)
else
# create new object from the freshly created subclass
active_resource_object = active_resource_class.new(:id =>
resource_id) # set id to given element id. This way we don't have to
load the element first by using find -- but we won't know, if the
element exists
# do the action...
response = active_resource_object.send(method, *args)
end
# we got our response, but what to do with it?
@response_handling.call response, workitem if(@response_handling)
# reply to the engine
reply_to_engine(workitem)
end
end
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruote (OpenWFEru) users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/openwferu-users?hl=en
-~----------~----~----~----~------~----~------~--~---