Skip Menu |
 

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Workflow CPAN distribution.

Report information
The Basics
Id: 18265
Status: resolved
Priority: 0/
Queue: Workflow

People
Owner: jonasbn [...] cpan.org
Requestors: andrewo [...] oriel.com.au
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: (no value)
Fixed in:
  • 1.33_2
  • 1.33

Attachments


Subject: [PATCH] enable dynamic loading of config files
Download (untitled) / with headers
text/plain 638b
I was unable to subclass Workflow::Factory to allow me to dynamically load configs at runtime so here's a patch to the core that allows just that. I've added a new section to the docs and added an _initialize_workflow_config function which calls a user-specified callback located in the factory accessor "get_workflow_config_func". Example usage in the pod. I haven't added full details to the function list nor have I added an external "initialize_workflow_config" wrapper as I'm not sure if this is useful or wanted. And no, there is no test for this yet :) Comments, flames and requests for changes welcome. Thanks for the module!
Subject: dynamically_loaded_configs.0.17.diff
diff -rBbu Workflow-0.17.orig/lib/Workflow/Factory.pm Workflow-0.17/lib/Workflow/Factory.pm --- Workflow-0.17.orig/lib/Workflow/Factory.pm 2006-03-16 13:03:23.000000000 +1100 +++ Workflow-0.17/lib/Workflow/Factory.pm 2006-03-21 18:56:49.000000000 +1100 @@ -7,6 +7,7 @@ use DateTime; use Log::Log4perl qw( get_logger ); use Workflow::Exception qw( configuration_error workflow_error ); +use Oriel::WF::Config (); $Workflow::Factory::VERSION = sprintf("%d.%02d", q$Revision: 1.16 $ =~ /(\d+)\.(\d+)/); @@ -51,7 +52,7 @@ my $INITIAL_STATE = 'INITIAL'; -my @FIELDS = qw(); +my @FIELDS = qw(get_workflow_config_func); __PACKAGE__->mk_accessors( @FIELDS ); sub new { @@ -80,6 +81,30 @@ my %CONFIG = ( 'Workflow::Config' => 1 ); +#################################### +#### Oriel functions start here #### +#################################### + +sub _dump_instances { + my $class = shift; + $class = ref($class) || $class; + require Data::Dumper; + warn Data::Dumper::Dumper( $class, \%INSTANCES ); +} +sub _initialize_workflow_config { + my $self = shift; + my $wf_type = shift; + $log ||= get_logger(); + if ( ref($self->get_workflow_config_func) eq 'CODE' ) { + my $args = &{ $self->get_workflow_config_func }( $wf_type ); + $self->add_config_from_file( %$args ) if $args && %$args; + } +} + +################################## +#### Oriel functions end here #### +################################## + sub add_config_from_file { my ( $self, %params ) = @_; return unless ( scalar keys %params ); @@ -321,6 +346,7 @@ sub _get_workflow_config { my ( $self, $wf_type ) = @_; + $self->_initialize_workflow_config( $wf_type ) unless $self->{_workflow_config}{ $wf_type }; return $self->{_workflow_config}{ $wf_type }; } @@ -803,6 +829,39 @@ Returns: nothing +=head1 DYNAMIC CONFIG LOADING + +If you have either a large set of config files or a set of large +config files then you may not want to incur the overhead of loading +each and every one on startup if you cannot predict which set you will +use in that instance of your application. + +To combat this you can specify a callback that the factory will use to +retrieve batched hashes of config_declarations. Whenever an unknown +workflow name is encountered the factory will first try to load your +config declarations then continue. + +The callback takes one argument which is the workflow type. It should +return a reference to a hash of arguments in a form suitable for +C<add_config_from_file>. + +For example: + + use Workflow::Factory qw(FACTORY); + use My::Config::System; + + sub my_application_init { + my $self = shift; + + FACTORY->get_workflow_config_func( + sub { + my $wf_type = shift; + my %ret = My::Config::System->get_files_for_wf( $wf_type ) || (); + return \%ret; + } + ); + } + =head1 SUBCLASSING =head2 Implementation and Usage
From: jonasbn [...] cpan.org
Download (untitled) / with headers
text/plain 806b
On Tue Mar 21 03:11:58 2006, guest wrote: Show quoted text
> I was unable to subclass Workflow::Factory to allow me to dynamically > load configs at runtime so here's a patch to the core that allows just that. > > I've added a new section to the docs and added an > _initialize_workflow_config function which calls a user-specified > callback located in the factory accessor "get_workflow_config_func". > Example usage in the pod. > > I haven't added full details to the function list nor have I added an > external "initialize_workflow_config" wrapper as I'm not sure if this is > useful or wanted. And no, there is no test for this yet :) > > Comments, flames and requests for changes welcome. > > Thanks for the module!
Hello, I am very keen on the feature, but do you have some tests to accompagny this? jonasbn
Download (untitled) / with headers
text/plain 156b
See attached for an updated patch against 1.32. This new patch includes documentation and tests but does not modify the Changes file. Hope this is helpful!
diff -rNu Workflow-1.32.orig/MANIFEST Workflow-1.32/MANIFEST --- Workflow-1.32.orig/MANIFEST 2009-01-27 02:07:31.000000000 +1100 +++ Workflow-1.32/MANIFEST 2009-01-28 18:50:30.000000000 +1100 @@ -92,6 +92,7 @@ t/context.t t/exception.t t/factory.t +t/factory_callback_config.t t/factory_subclass.t t/FactorySubclass.pm t/history.t @@ -112,6 +113,7 @@ t/TestApp/Action/TicketCreate.pm t/TestApp/Action/TicketCreateType.pm t/TestApp/Action/TicketUpdate.pm +t/TestApp/Condition/AlwaysTrue.pm t/TestApp/Condition/HasUser.pm t/TestApp/Condition/HasUserType.pm t/TestApp/Ticket.pm @@ -129,14 +131,17 @@ t/workflow.xml t/workflow_action.perl t/workflow_action.xml +t/workflow_action_callback.xml t/workflow_action_type.perl t/workflow_action_type.xml t/workflow_autorun.xml t/workflow_cached_condition.xml t/workflow_cached_condition_action.xml t/workflow_cached_condition_condition.xml +t/workflow_callback.xml t/workflow_condition.perl t/workflow_condition.xml +t/workflow_condition_callback.xml t/workflow_condition_type.perl t/workflow_condition_type.xml t/workflow_errorprone.perl diff -rNu Workflow-1.32.orig/lib/Workflow/Factory.pm Workflow-1.32/lib/Workflow/Factory.pm --- Workflow-1.32.orig/lib/Workflow/Factory.pm 2009-01-27 02:07:31.000000000 +1100 +++ Workflow-1.32/lib/Workflow/Factory.pm 2009-01-28 17:18:42.000000000 +1100 @@ -56,7 +56,7 @@ my $INITIAL_STATE = 'INITIAL'; -my @FIELDS = qw(); +my @FIELDS = qw(config_callback); __PACKAGE__->mk_accessors(@FIELDS); sub new { @@ -405,8 +405,19 @@ $wf->add_observer($_) for ( @{$observers} ); } +sub _initialize_workflow_config { + my $self = shift; + my $wf_type = shift; + $log ||= get_logger(); + if ( ref($self->config_callback) eq 'CODE' ) { + my $args = &{ $self->config_callback }( $wf_type ); + $self->add_config_from_file( %$args ) if $args && %$args; + } +} + sub _get_workflow_config { my ( $self, $wf_type ) = @_; + $self->_initialize_workflow_config( $wf_type ) unless $self->{_workflow_config}{ $wf_type }; return $self->{_workflow_config}{$wf_type}; } @@ -1001,6 +1012,44 @@ L</instance> should be called or the imported 'FACTORY' should be utilized. +=head1 DYNAMIC CONFIG LOADING + +If you have either a large set of config files or a set of very large +config files then you may not want to incur the overhead of loading +each and every one on startup if you cannot predict which set you will +use in that instance of your application. + +This approach doesn't make much sense in a persistent environment such +as mod_perl but it may lower startup costs if you have regularly +scheduled scripts that may not need to touch all possible types of +workflow. + +To do this you can specify a callback that the factory will use to +retrieve batched hashes of config declarations. Whenever an unknown +workflow name is encountered the factory will first try to load your +config declarations then continue. + +The callback takes one argument which is the workflow type. It should +return a reference to a hash of arguments in a form suitable for +C<add_config_from_file>. + +For example: + + use Workflow::Factory qw(FACTORY); + use My::Config::System; + + sub init { + my $self = shift; + + FACTORY->config_callback( + sub { + my $wf_type = shift; + my %ret = My::Config::System->get_files_for_wf( $wf_type ) || (); + return \%ret; + } + ); + } + =head1 SUBCLASSING =head2 Implementation and Usage diff -rNu Workflow-1.32.orig/t/TestApp/Condition/AlwaysTrue.pm Workflow-1.32/t/TestApp/Condition/AlwaysTrue.pm --- Workflow-1.32.orig/t/TestApp/Condition/AlwaysTrue.pm 1970-01-01 10:00:00.000000000 +1000 +++ Workflow-1.32/t/TestApp/Condition/AlwaysTrue.pm 2009-01-28 17:41:33.000000000 +1100 @@ -0,0 +1,19 @@ +package TestApp::Condition::AlwaysTrue; + +# $Id$ + +use strict; +use base qw( Workflow::Condition ); +use Log::Log4perl qw( get_logger ); +use Workflow::Exception qw( condition_error ); + +$TestApp::Condition::AlwaysTrue::VERSION = '0.01'; + +sub evaluate { + my ( $self, $wf ) = @_; + my $log = get_logger(); + $log->debug( "Trying to execute condition ", ref( $self ) ); + $log->debug( 'Condition met ok' ); +} + +1; diff -rNu Workflow-1.32.orig/t/factory_callback_config.t Workflow-1.32/t/factory_callback_config.t --- Workflow-1.32.orig/t/factory_callback_config.t 1970-01-01 10:00:00.000000000 +1000 +++ Workflow-1.32/t/factory_callback_config.t 2009-01-29 09:39:39.000000000 +1100 @@ -0,0 +1,39 @@ +# -*-perl-*- + +# $Id$ + +use strict; +use lib 't'; +use TestUtil; +use Test::More tests => 7; +use Test::Exception; + +require_ok( 'Workflow::Factory' ); + +my $factory = Workflow::Factory->instance(); +my $wf; + +lives_ok { TestUtil->init_mock_persister } + 'Loading test persister succeeds'; + +dies_ok { $wf = $factory->create_workflow( 'CallbackTest' ) } + 'Attempt to create new workflow without loading its config first dies'; + +can_ok( $factory, 'config_callback' ); + +lives_ok { $factory->config_callback( sub { + my $type = shift; + if ($type eq 'CallbackTest') { + return { workflow => 'workflow_callback.xml', + action => 'workflow_action_callback.xml', + condition => 'workflow_condition_callback.xml' }; + } + return {}; + } ) } + 'Setting callback function succeeds'; + +dies_ok { $wf = $factory->create_workflow( 'CallbackTestBogus' ) } + 'Attempt to create unknown workflow still dies'; + +lives_ok { $wf = $factory->create_workflow( 'CallbackTest' ) } + 'Attempt to create known workflow via callback succeeds'; diff -rNu Workflow-1.32.orig/t/workflow_action_callback.xml Workflow-1.32/t/workflow_action_callback.xml --- Workflow-1.32.orig/t/workflow_action_callback.xml 1970-01-01 10:00:00.000000000 +1000 +++ Workflow-1.32/t/workflow_action_callback.xml 2009-01-28 18:18:45.000000000 +1100 @@ -0,0 +1,8 @@ +<actions> + <type>CallbackTest</type> + <description>Actions for the CallbackTest workflow only</description> + + <action name="CALLBACK_CLOSE" class="Workflow::Action::Null"> + <description>Dummy close a callback test workflow</description> + </action> +</actions> \ No newline at end of file diff -rNu Workflow-1.32.orig/t/workflow_callback.xml Workflow-1.32/t/workflow_callback.xml --- Workflow-1.32.orig/t/workflow_callback.xml 1970-01-01 10:00:00.000000000 +1000 +++ Workflow-1.32/t/workflow_callback.xml 2009-01-29 09:40:17.000000000 +1100 @@ -0,0 +1,17 @@ +<workflow> + <type>CallbackTest</type> + <description>This is a sample workflow used to test loading config on demand</description> + <persister>TestPersister</persister> + <state name="INITIAL"> + <description>This is the state the workflow enters when + instantiated. It's like a 'state zero' but since we're + using names rather than IDs we cannot assume</description> + <action name="CALLBACK_CLOSE" resulting_state="Callback_Closed"> + <condition name="CallbackAlwaysTrue"/> + </action> + </state> + + <state name="Callback_Closed"> + <description>Placeholder closed state</description> + </state> +</workflow> diff -rNu Workflow-1.32.orig/t/workflow_condition_callback.xml Workflow-1.32/t/workflow_condition_callback.xml --- Workflow-1.32.orig/t/workflow_condition_callback.xml 1970-01-01 10:00:00.000000000 +1000 +++ Workflow-1.32/t/workflow_condition_callback.xml 2009-01-28 17:38:24.000000000 +1100 @@ -0,0 +1,4 @@ +<conditions> + <type>CallbackTest</type> + <condition name="CallbackAlwaysTrue" class="TestApp::Condition::AlwaysTrue"/> +</conditions>
This patch is currently under evaluation, please see release 1.33_2 jonasbn


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.