From ec5193e5d371ab8542b5d27a5a6addfd4a636e16 Mon Sep 17 00:00:00 2001 From: JT Smith Date: Thu, 9 Feb 2006 18:45:14 +0000 Subject: [PATCH] more workflow stuff --- docs/upgrades/upgrade_6.8.5-6.9.0.pl | 23 ++- etc/WebGUI.conf.original | 12 +- lib/WebGUI/SQL.pm | 10 +- lib/WebGUI/Workflow.pm | 252 +++++++++++++++++++++++++++ lib/WebGUI/Workflow/Activity.pm | 7 +- lib/WebGUI/Workflow/Cron.pm | 252 +++++++++++++++++++++++++++ lib/WebGUI/Workflow/Spectre.pm | 126 ++++++++++++++ sbin/upgrade.pl | 4 +- 8 files changed, 676 insertions(+), 10 deletions(-) create mode 100644 lib/WebGUI/Workflow.pm create mode 100644 lib/WebGUI/Workflow/Cron.pm create mode 100644 lib/WebGUI/Workflow/Spectre.pm diff --git a/docs/upgrades/upgrade_6.8.5-6.9.0.pl b/docs/upgrades/upgrade_6.8.5-6.9.0.pl index 4b0882985..c45b7ab3f 100644 --- a/docs/upgrades/upgrade_6.8.5-6.9.0.pl +++ b/docs/upgrades/upgrade_6.8.5-6.9.0.pl @@ -34,15 +34,23 @@ finish($session); # this line required #------------------------------------------------- sub addWorkflow { print "\tAdding workflow.\n"; + $session->config->set("spectreIp","127.0.0.1"); + $session->config->set("spectrePort",32133); + $session->config->set("spectreSubnets",["127.0.0.1/32"]); + $session->config->set("spectreCryptoKey","123qwe"); $session->db->write("create table WorkflowSchedule ( taskId varchar(22) binary not null primary key, - enabled int not null default 1, + enabled int not null default 0, + runOnce int not null default 0, minuteofHour varchar(25) not null default '0', hourOfDay varchar(25) not null default '*', dayOfMonth varchar(25) not null default '*', monthOfYear varchar(25) not null default '*', dayOfWeek varchar(25) not null default '*', workflowId varchar(22) binary not null + className varchar(255), + methodName varchar(255), + parameters text, )"); $session->db->write("create table WorkflowInstance ( instanceId varchar(22) binary not null primary key, @@ -57,14 +65,15 @@ sub addWorkflow { $session->db->write("create table Workflow ( workflowId varchar(22) binary not null primary key, title varchar(255) not null default 'Untitled', - description text + description text, + enabled int not null default 0 )"); $session->db->write("create table WorkflowActivity ( activityId varchar(22) binary not null primary key, workflowId varchar(22) binary not null, title varchar(255) not null default 'Untitled', description text, - previousActivityId varchar(22) binary not null, + sequenceNumber int not null default 1, dateCreated bigint, className varchar(255) )"); @@ -279,6 +288,12 @@ SQL6 #------------------------------------------------- sub addSearchEngine { print "\tUpgrading search engine.\n" unless ($quiet); + $session->config->set("searchIndexerPlugins", { + "txt" => "/bin/cat", + "readme"=> "/bin/cat", + "html" => "/bin/cat", + "htm" => "/bin/cat" + }); $session->db->write("create table search ( assetId varchar(22) binary not null, revisionDate bigint not null default 0, @@ -324,6 +339,8 @@ sub addSearchEngine { #------------------------------------------------- sub templateParsers { print "\tAdding support for multiple template parsers.\n" unless ($quiet); + $session->conf->set("templateParsers",["WebGUI::Asset::Template::HTMLTemplate"]); + $session->conf->set("defaultTemplateParser","WebGUI::Asset::Template::HTMLTemplate"); $session->db->write("alter table template add column parser varchar(255) not null default 'WebGUI::Asset::Template::HTMLTemplate'"); } diff --git a/etc/WebGUI.conf.original b/etc/WebGUI.conf.original index 0df0d8c03..832c8561e 100644 --- a/etc/WebGUI.conf.original +++ b/etc/WebGUI.conf.original @@ -126,7 +126,7 @@ # Specify the default template parser. -"defaultTemplateParser" : ["WebGUI::Asset::Template::HTMLTemplate"], +"defaultTemplateParser" : "WebGUI::Asset::Template::HTMLTemplate", # Specify external helper apps that will enable WebGUI's search # engine to index content in various uploaded file formats. The @@ -328,6 +328,16 @@ "spectreSubnets" : [ "127.0.0.1/32" ], +# Define the IP Address that should be used by WebGUI to connect +# to Spectre. Depending upon your cluster configuration, this may +# or may not be the same as the information in spectreSubnets. + +"spectreIp" : "127.0.0.1", + +# Define the port number WebGUI should use to connect to Spectre + +"spectrePort" : 32133, + # Define the key that will be used to encrypt communcation # between Spectre and WebGUI. Note that this must match the # cryptoKey in the Spectre config file. diff --git a/lib/WebGUI/SQL.pm b/lib/WebGUI/SQL.pm index 52723b259..4a784d18e 100644 --- a/lib/WebGUI/SQL.pm +++ b/lib/WebGUI/SQL.pm @@ -400,7 +400,7 @@ sub prepare { #------------------------------------------------------------------- -=head2 quickArray ( sql ) +=head2 quickArray ( sql, params ) Executes a query and returns a single row of data as an array. @@ -408,13 +408,19 @@ Executes a query and returns a single row of data as an array. An SQL query. +=head3 params + +An array reference containing values for any placeholder params used in the SQL query. + =cut sub quickArray { my $self = shift; my $sql = shift; + my $params = shift; my ($sth, @data); - $sth = $self->read($sql); + $sth = $self->prepare($sql); + $sth->execute($params); @data = $sth->array; $sth->finish; return @data; diff --git a/lib/WebGUI/Workflow.pm b/lib/WebGUI/Workflow.pm new file mode 100644 index 000000000..8069c2373 --- /dev/null +++ b/lib/WebGUI/Workflow.pm @@ -0,0 +1,252 @@ +package WebGUI::Workflow; + + +=head1 LEGAL + + ------------------------------------------------------------------- + WebGUI is Copyright 2001-2006 Plain Black Corporation. + ------------------------------------------------------------------- + Please read the legal notices (docs/legal.txt) and the license + (docs/license.txt) that came with this distribution before using + this software. + ------------------------------------------------------------------- + http://www.plainblack.com info@plainblack.com + ------------------------------------------------------------------- + +=cut + +use strict; + + +=head1 NAME + +Package WebGUI::Workflow + +=head1 DESCRIPTION + +This package provides the API for manipulating workflows. + +=head1 SYNOPSIS + + use WebGUI::Workflow; + +=head1 METHODS + +These methods are available from this class: + +=cut + +#------------------------------------------------------------------- + +=head2 addActivity ( class ) + +Adds an activity to this workflow. + +=head3 class + +The classname of the activity to add. + +=cut + +sub addActivity { + my $self = shift; + my $class = shift; + $class->create($self->session, $self->getId); +} + + +#------------------------------------------------------------------- + +=head2 create ( session ) + +Creates a new instance of a workflow. + +=head3 session + +A reference to the current session. + +=cut + +sub create { + my $class = shift; + my $session = shift; + my $workflowId = $session->db->setRow("Workflow","workflowId",{workflowId=>"new",enabled=>0}); + return $class->new($session, $workflowId); +} + +#------------------------------------------------------------------- + +=head2 delete ( ) + +Removes this workflow and everything associated with it.. + +=cut + +sub delete { + my $self = shift; + # delete crons + foreach my $activity (@{$self->getActivities}) { + $activity->delete; + } + # delete instances + $self->session->db->deleteRow("Workflow","workflowId",$self->getId); + $self->undef; +} + +#------------------------------------------------------------------- + +=head2 deleteActivity ( activityId ) + +Removes an activity from this workflow. + +=head3 activityId + +The unique id of the activity to remove. + +=cut + +sub deleteActivity { + my $self = shift; + my $activityId = shift; + my ($class) = $self->session->db->quickArray("select className from WorkflowActivity where activityId=?",[$activityId]); + $class->new($self->session, $activityId)->delete; +} + +#------------------------------------------------------------------- + +=head2 DESTROY ( ) + +Deconstructor. + +=cut + +sub DESTROY { + my $self = shift; + undef $self; +} + + +#------------------------------------------------------------------- + +=head2 get ( name ) + +Returns the value for a given property. + +=cut + +sub get { + my $self = shift; + return $self->{_data}{shift}; +} + + +#------------------------------------------------------------------- + +=head2 getActivities ( ) + +Returns an array reference of the activity objects associated with this workflow. + +=cut + +sub getActivities { + my $self = shift; + my @activities = (); + my $rs = $self->session->db->prepare("select activityId, className from WorkflowActivity where workflowId=? order by sequenceNumber"); + $rs->execute([$self->getId]); + while (my ($activityId, $class) = $rs->array) { + push(@activities, $class->new($self->session, $activityId)); + } + return \@activities; +} + +#------------------------------------------------------------------- + +=head2 getId ( ) + +Returns the ID of this workflow. + +=cut + +sub getId { + my $self = shift; + return $self->{_id}; +} + +#------------------------------------------------------------------- + +=head2 new ( session, workflowId ) + +Constructor. + +=head3 session + +A reference to the current session. + +=head3 workflowId + +The unique id of this workflow. + +=cut + +sub new { + my $class = shift; + my $session = shift; + my $workflowId = shift; + my $data = $session->db->getRow("Workflow","workflowId", $workflowId); + return undef unless $data->{workflowId}; + bless {_session=>$session, _id=>$workflowId, _data=>$data}, $class; +} + +#------------------------------------------------------------------- + +=head2 session ( ) + +Returns a reference to the current session. + +=cut + +sub session { + my $self = shift; + return $self->{_session}; +} + +#------------------------------------------------------------------- + +=head2 set ( name , value ) + +Sets a variable for this workflow. + +=head3 name + +The name of the variable to set. The following are the available fields to set. + +=head4 title + +A title indicating what this workflow does. It should be short and descriptive as it will appear in dropdown forms. + +=head4 description + +A longer description of the workflow. + +=head4 enabled + +A boolean indicating whether this workflow may be executed right now. + +=head3 value + +The value of the variable. + +=cut + +sub set { + my $self = shift; + my $name = shift; + my $value = shift; + $self->{_data}{$name} = $value; + $self->session->db->setRow("Workflow","workflowId",$self->{_data}); +} + + +1; + + diff --git a/lib/WebGUI/Workflow/Activity.pm b/lib/WebGUI/Workflow/Activity.pm index d67f41278..5489b08b3 100644 --- a/lib/WebGUI/Workflow/Activity.pm +++ b/lib/WebGUI/Workflow/Activity.pm @@ -57,7 +57,9 @@ sub create { my $class = shift; my $session = shift; my $workflowId = shift; - my $activityId = $session->db->setRow("WorkflowActivity","activityId",{activityId=>"new", workflowId=>$workflowId}); + my ($sequenceNumber) = $session->db->quickArray("select count(*) from WorkflowActivity where workflowId=?", [$workflowId]); + $sequenceNumber++; + my $activityId = $session->db->setRow("WorkflowActivity","activityId",{sequenceNumber=>$sequenceNumber, activityId=>"new", className=>$class, workflowId=>$workflowId}); return $class->new($session, $activityId); } @@ -72,8 +74,9 @@ Removes this activity from its workflow. sub delete { my $self = shift; my $sth = $self->session->db->prepare("delete from WorkflowActivityData where activityId=?"); - $sth->execute($self->getId); + $sth->execute([$self->getId]); $self->session->db->deleteRow("WorkflowActivity","activityId",$self->getId); + undef $self; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Workflow/Cron.pm b/lib/WebGUI/Workflow/Cron.pm new file mode 100644 index 000000000..8d7c5cc5f --- /dev/null +++ b/lib/WebGUI/Workflow/Cron.pm @@ -0,0 +1,252 @@ +package WebGUI::Workflow::Cron; + + +=head1 LEGAL + + ------------------------------------------------------------------- + WebGUI is Copyright 2001-2006 Plain Black Corporation. + ------------------------------------------------------------------- + Please read the legal notices (docs/legal.txt) and the license + (docs/license.txt) that came with this distribution before using + this software. + ------------------------------------------------------------------- + http://www.plainblack.com info@plainblack.com + ------------------------------------------------------------------- + +=cut + +use strict; +use WebGUI::Workflow::Spectre; + + +=head1 NAME + +Package WebGUI::Workflow::Cron + +=head1 DESCRIPTION + +This package provides an API for controlling Spectre/Workflow scheduler activities. + +=head1 SYNOPSIS + + use WebGUI::Workflow::Cron + +=head1 METHODS + +These methods are available from this class: + +=cut + +#------------------------------------------------------------------- + +=head2 create ( session, properties ) + +Creates a new scheduler job. + +=head3 session + +A reference to the current session. + +=head3 properties + +The settable properties of the scheduler. See the set() method for details. + +=cut + +sub create { + my $class = shift; + my $session = shift; + my $properties = shift; + my $taskId = $session->db->setRow("WorkflowSchedule","taskId",{taskId=>"new"}); + my $self = $class->new($session, $taskId); + $self->set($properties); + return $self; +} + +#------------------------------------------------------------------- + +=head2 delete ( ) + +Removes this job from the schedule. + +=cut + +sub delete { + my $self = shift; + $self->session->db->deleteRow("WorkflowSchedule","taskId",$self->getId); + WebGUI::Workflow::Spectre->new($self->session)->notify("cron/deleteJob",$self->getId); + undef $self; +} + +#------------------------------------------------------------------- + +=head2 DESTROY ( ) + +Deconstructor. + +=cut + +sub DESTROY { + my $self = shift; + undef $self; +} + + +#------------------------------------------------------------------- + +=head2 get ( name ) + +Returns the value for a given property. + +=cut + +sub get { + my $self = shift; + return $self->{_data}{shift}; +} + +#------------------------------------------------------------------- + +=head2 getId ( ) + +Returns the ID of this instance. + +=cut + +sub getId { + my $self = shift; + return $self->{_id}; +} + +#------------------------------------------------------------------- + +=head2 new ( session, taskId ) + +Constructor. + +=head3 session + +A reference to the current session. + +=head3 taskId + +A unique id refering to a task. + +=cut + +sub new { + my $class = shift; + my $session = shift; + my $taskId = shift; + my $data = $session->db->getRow("WorkflowSchedule","taskId", $taskId); + return undef unless $data->{taskId}; + bless {_session=>$session, _id=>$taskId, _data=>$data}, $class; +} + +#------------------------------------------------------------------- + +=head2 session ( ) + +Returns a reference to the current session. + +=cut + +sub session { + my $self = shift; + return $self->{_session}; +} + +#------------------------------------------------------------------- + +=head2 set ( properties ) + +Sets one or more of the properties of this task. + +=head3 properties + +A hash reference containing properties to change. + +=head4 enabled + +A boolean indicating whether this task is enabled. + +=head4 runOnce + +A boolean indicating whether this task should run once and delete itself, or if it should continue to be executed each time it's schedule matches the current time. + +=head4 minuteOfHour + +A string in cron format representing which minutes (0-59) of the hour this workflow should run. Valid formats are as follows: + + * All + n A specific minute + n,n,n A series of specific minutes + */n Every n minutes + +=head4 hourOfDay + +A string representing hours (0-23). See minuteOfHour for formatting details. + +=head4 dayOfMonth + +A string representing days in a month (1-31). See minuteOfHour for formatting details. + +=head4 monthOfYear + +A string representing months in a year (1-12). See minuteOfHour for formatting details. + +=head4 dayOfWeek + +A string representing days in a week (0-6 with Sunday being 0). See minuteOfHour for formatting details. + +=head4 workflowId + +The unique ID of the workflow we should kick off when this cron matches. + +=head4 className + +The classname of an object that will be created to pass into the workflow. + +=head4 method + +The method name of the constructor for className. + +=head4 parameters + +The parameters to be passed into the constructor. Note that the system will always pass in the session as the first argument. + +=cut + +sub set { + my $self = shift; + my $properties = shift; + if ($properties->{enabled} == 1) { + $self->{enabled} = 1; + } elsif ($properties->{enabled} == 0) { + $self->{enabled} = 0; + } + if ($properties->{runOnce} == 1) { + $self->{runOnce} = 1; + } elsif ($properties->{runOnce} == 0) { + $self->{runOnce} = 0; + } + $self->{_data}{minuteOfHour} = $properties->{minuteOfHour} || $self->{_data}{minuteOfHour} || 0; + $self->{_data}{hourOfDay} = $properties->{hourOfDay} || $self->{_data}{hourOfDay} || "*"; + $self->{_data}{dayOfMonth} = $properties->{dayOfMonth} || $self->{_data}{dayOfMonth} || "*"; + $self->{_data}{monthOfYear} = $properties->{monthOfYear} || $self->{_data}{monthOfYear} || "*"; + $self->{_data}{dayOfWeek} = $properties->{dayOfWeek} || $self->{_data}{dayOfWeek} || "*"; + $self->{_data}{workflowId} = $properties->{workflowId} || $self->{_data}{workflowId}; + $self->{_data}{className} = (exists $properties->{className}) ? $properties->{className} : $self->{_data}{className}; + $self->{_data}{method} = (exists $properties->{method}) ? $properties->{method} : $self->{_data}{method}; + $self->{_data}{parameters} = (exists $properties->{parameters}) ? $properties->{parameters} : $self->{_data}{parameters}; + $self->{_data}{enabled} = 0 unless ($self->get("workflowId")); + my $spectre = WebGUI::Workflow::Spectre->new($self->session); + $spectre->notify("cron/deleteJob",$self->getId); + $spectre->notify("cron/addJob",$self->session->config->getFilename, $self->getId); + $self->session->db->setRow("WorkflowSchedule","taskId",$self->{_data}); +} + + +1; + + diff --git a/lib/WebGUI/Workflow/Spectre.pm b/lib/WebGUI/Workflow/Spectre.pm new file mode 100644 index 000000000..35e49633d --- /dev/null +++ b/lib/WebGUI/Workflow/Spectre.pm @@ -0,0 +1,126 @@ +package WebGUI::Workflow::Spectre; + + +=head1 LEGAL + + ------------------------------------------------------------------- + WebGUI is Copyright 2001-2006 Plain Black Corporation. + ------------------------------------------------------------------- + Please read the legal notices (docs/legal.txt) and the license + (docs/license.txt) that came with this distribution before using + this software. + ------------------------------------------------------------------- + http://www.plainblack.com info@plainblack.com + ------------------------------------------------------------------- + +=cut + +use strict; +use POE::Component::IKC::ClientLite; + + +=head1 NAME + +Package WebGUI::Workflow::Spectre + +=head1 DESCRIPTION + +This package is used to send messages between the workflow system and Spectre. + +=head1 SYNOPSIS + + use WebGUI::Workflow::Spectre; + +=head1 METHODS + +These methods are available from this class: + +=cut + +#------------------------------------------------------------------- + +=head2 DESTROY ( ) + +Deconstructor. + +=cut + +sub DESTROY { + my $self = shift; + undef $self; +} + +#------------------------------------------------------------------- + +=head2 notify ( module, params ) + +Sends a message to Spectre. + +=head3 session + +A reference to the current session. + +=head3 module + +The module/method pair you wish to communicate with in Spectre. + +=head3 params + +An array of the parameters to send. + +=cut + +sub notify { + my $self = shift; + my $module = shift; + my @params = @_; + my $remote = create_ikc_client( + port=>$self->session->config->get("spectrePort"), + ip=>$self->session->config->get("spectreIp"), + name=>rand(100000), + timeout=>10 + ); + if ($remote) { + my $result = $remote->post('admin/shutdown', @params); + unless (defined $result) { + $self->session->errorHandler->warn("Couldn't send command to Spectre because ".$POE::Component::IKC::ClientLite::error); + } + undef $remote; + } else { + $self->session->errorHandler->warn("Couldn't connect to Spectre because ".$POE::Component::IKC::ClientLite::error); + } +} + +#------------------------------------------------------------------- + +=head2 new ( session ) + +Constructor. + +=head3 session + +A reference to the current session. + +=cut + +sub new { + my $class = shift; + my $session = shift; + bless {_session=>$session}, $class; +} + +#------------------------------------------------------------------- + +=head2 session ( ) + +Returns a reference to the current session. + +=cut + +sub session { + my $self = shift; + return $self->{_session}; +} + +1; + diff --git a/sbin/upgrade.pl b/sbin/upgrade.pl index 85b6cbf07..320b6f5a4 100644 --- a/sbin/upgrade.pl +++ b/sbin/upgrade.pl @@ -317,13 +317,13 @@ STOP #----------------------------------------- # checkVersion($versionNumber) #----------------------------------------- -# Version number must be 6.2.0 or greater +# Version number must be 6.9.0 or greater # in order to be upgraded by this utility. #----------------------------------------- sub checkVersion { $_[0] =~ /(\d+)\.(\d+)\.(\d+)/; my $goal = 6; - my $feature = 2; + my $feature = 9; my $fix = 0; if ($1 > $goal) { return 1;