NAME

Workflow::Factory - Generates new workflow and supporting objects

VERSION

This documentation describes version 1.62 of this package

SYNOPSIS

# Import the singleton for easy access
use Workflow::Factory qw( FACTORY );

# Add XML configurations to the factory
FACTORY->add_config_from_file( workflow  => 'workflow.xml',
                               action    => [ 'myactions.xml', 'otheractions.xml' ],
                               validator => [ 'validator.xml', 'myvalidators.xml' ],
                               condition => 'condition.xml',
                               persister => 'persister.xml' );

# Create a new workflow of type 'MyWorkflow'
my $wf = FACTORY->create_workflow( 'MyWorkflow' );

# Fetch an existing workflow with ID '25'
my $wf = FACTORY->fetch_workflow( 'MyWorkflow', 25 );

DESCRIPTION

Public

The Workflow Factory is your primary interface to the workflow system. You give it the configuration files and/or data structures for the Workflow, Workflow::Action, Workflow::Condition, Workflow::Persister, and Workflow::Validator objects and then you ask it for new and existing Workflow objects.

Internal

Developers using the workflow system should be familiar with how the factory processes configurations and how it makes the various components of the system are instantiated and stored in the factory.

METHODS

Public Methods

instance()

The factory is a singleton, this is how you get access to the instance. You can also just import the 'FACTORY' constant as in the "SYNOPSIS".

create_workflow( $workflow_type, $context, $wf_class )

Create a new workflow of type $workflow_type. This will create a new record in whatever persistence mechanism you have associated with $workflow_type and set the workflow to its initial state.

The $context argument is optional, you can pass an exisiting instance of Workflow::Context to be reused. Otherwise a new instance is created.

The $wf_class argument is optional. Pass it the name of a class to be used for the workflow to be created. By default, all workflows are of the Workflow class.

Any observers you've associated with this workflow type will be attached to the returned workflow object.

This fires a 'create' event from the just-created workflow object. See WORKFLOWS ARE OBSERVABLE in Workflow for more.

Returns: newly created workflow object.

fetch_workflow( $workflow_type, $workflow_id, $context, $wf_class )

Retrieve a workflow object of type $workflow_type and ID $workflow_id. (The $workflow_type is necessary so we can fetch the workflow using the correct persister.) If a workflow with ID $workflow_id is not found undef is returned.

The $context argument is optional, you can pass an exisiting instance of Workflow::Context to be reused. Otherwise a new instance is created.

The $wf_class argument is optional. Pass it the name of a class to be used for the workflow to be created. By default, all workflows are of the Workflow class.

Any observers you've associated with this workflow type will be attached to the returned workflow object.

This fires a 'fetch' event from the retrieved workflow object. See WORKFLOWS ARE OBSERVABLE in Workflow for more.

Throws exception if no workflow type $workflow_type available.

Returns: Workflow object

add_config_from_file( %config_declarations )

Pass in filenames for the various components you wish to initialize using the keys 'action', 'condition', 'persister', 'validator' and 'workflow'. The value for each can be a single filename or an arrayref of filenames.

The system is familiar with the 'perl' and 'xml' configuration formats -- see the 'doc/configuration.txt' for what we expect as the format and will autodetect the types based on the file extension of each file. Just give your file the right extension and it will be read in properly.

You may also use your own custom configuration file format -- see SUBCLASSING in Workflow::Config for what you need to do.

You can also read it in yourself and add the resulting hash reference directly to the factory using add_config(). However, you need to ensure the configurations are added in the proper order -- when you add an 'action' configuration and reference 'validator' objects, those objects should already be read in. A good order is: 'validator', 'condition', 'action', 'workflow'. Then just pass the resulting hash references to add_config() using the right type and the behavior should be exactly the same.

Returns: nothing; if we run into a problem parsing one of the files or creating the objects it requires we throw a Workflow::Exception.

add_config( %config_hashrefs )

Similar to add_config_from_file() -- the keys may be 'action', 'condition', 'persister', 'validator' and/or 'workflow'. But the values are the actual configuration hashrefs instead of the files holding the configurations.

You normally will only need to call this if you are programmatically creating configurations (e.g., hot-deploying a validator class specified by a user) or using a custom configuration format and for some reason do not want to use the built-in mechanism in Workflow::Config to read it for you.

Returns: nothing; if we encounter an error trying to create the objects referenced in a configuration we throw a Workflow::Exception.

get_persister_for_workflow_type

get_persisters

#TODO

get_validators

#TODO

Internal Methods

#TODO

save_workflow( $workflow )

Stores the state and current datetime of the $workflow object. This is normally called only from the Workflow execute_action() method.

This method respects transactions if the selected persister supports it. Currently, the DBI-based persisters will commit the workflow transaction if everything executes successfully and roll back if something fails. Note that you need to manage any Workflow::Persister::DBI::ExtraData transactions yourself.

Returns: $workflow

get_workflow_history( $workflow )

Retrieves all Workflow::History objects related to $workflow.

NOTE: Normal users get the history objects from the Workflow object itself. Under the covers it calls this.

Returns: list of Workflow::History objects

get_action( $workflow, $action_name ) [ deprecated ]

Retrieves the action $action_name from workflow $workflow. Note that this does not do any checking as to whether the action is proper given the state of $workflow or anything like that. It is mostly an internal method for Workflow (which does do checking as to the propriety of the action) to instantiate new actions.

Throws exception if no action with name $action_name available.

get_action_config( $workflow, $action_name )

Retrieves the configuration for action $action_name as specified in the actions configuration file, with the keys listed in the 'action' section of Workflow::Config

Throws exception if no action with name $action_name available.

Returns: A hash with the configuration as its keys.

get_persister( $persister_name )

Retrieves the persister with name $persister_name.

Throws exception if no persister with name $persister_name available.

get_condition( $condition_name )

Retrieves the condition with name $condition_name.

Throws exception if no condition with name $condition_name available.

get_validator( $validator_name )

Retrieves the validator with name $validator_name.

Throws exception if no validator with name $validator_name available.

Internal Configuration Methods

_add_workflow_config( @config_hashrefs )

Adds all configurations in @config_hashrefs to the factory. Also cycles through the workflow states and creates a Workflow::State object for each. These states are passed to the workflow when it is instantiated.

We also require any necessary observer classes and throw an exception if we cannot. If successful the observers are kept around and attached to a workflow in create_workflow() and fetch_workflow().

Returns: nothing

_load_observers( $workflow_config_hashref )

Loads and adds observers based on workflow type

Returns number indicating amount of observers added, meaning zero can indicate success based on expected outcome.

_add_action_config( @config_hashrefs )

Adds all configurations in @config_hashrefs to the factory, doing a 'require' on the class referenced in the 'class' attribute of each action.

Throws an exception if there is no 'class' associated with an action or if we cannot 'require' that class.

Returns: nothing

_add_persister_config( @config_hashrefs )

Adds all configurations in @config_hashrefs to the factory, doing a 'require' on the class referenced in the 'class' attribute of each persister.

Throws an exception if there is no 'class' associated with a persister, if we cannot 'require' that class, or if we cannot instantiate an object of that class.

Returns: nothing

_add_condition_config( @config_hashrefs )

Adds all configurations in @config_hashrefs to the factory, doing a 'require' on the class referenced in the 'class' attribute of each condition.

Throws an exception if there is no 'class' associated with a condition, if we cannot 'require' that class, or if we cannot instantiate an object of that class.

Returns: nothing

_add_validator_config( @config_hashrefs )

Adds all configurations in @config_hashrefs to the factory, doing a 'require' on the class referenced in the 'class' attribute of each validator.

Throws an exception if there is no 'class' associated with a validator, if we cannot 'require' that class, or if we cannot instantiate an object of that class.

Returns: nothing

_commit_transaction

Calls the commit method in the workflow's persister.

Returns: nothing

_rollback_transaction

Calls the rollback method in the workflow's persister.

associate_observers_with_workflow

Add defined observers with workflow.

The workflow has to be provided as the single parameter accepted by this method.

The observers added will have to be of the type relevant to the workflow type.

new

The new method is a dummy constructor, since we are using a factory it makes no sense to call new - and calling new will result in a Workflow::Exception

"instance" should be called or the imported 'FACTORY' should be utilized.

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 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;
    }
  );
}

SUBCLASSING

Implementation and Usage

You can subclass the factory to implement your own methods and still use the useful facade of the FACTORY constant. For instance, the implementation is typical Perl subclassing:

package My::Cool::Factory;

use strict;
use base qw( Workflow::Factory );

sub some_cool_method {
    my ( $self ) = @_;
    ...
}

To use your factory you can just do the typical import:

#!/usr/bin/perl

use strict;
use My::Cool::Factory qw( FACTORY );

Or you can call instance() directly:

#!/usr/bin/perl

use strict;
use My::Cool::Factory;

my $factory = My::Cool::Factory->instance();

GLOBAL RUN-TIME OPTIONS

Setting package variable $VALIDATE_ACTION_CONFIG to a true value (it is undef by default) turns on optional validation of extra attributes of Workflow::Action configs. See Workflow::Action for details.

SEE ALSO

COPYRIGHT

Copyright (c) 2003-2023 Chris Winters. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

Please see the LICENSE

AUTHORS

Please see Workflow