File Coverage

lib/Workflow/Persister/File.pm
Criterion Covered Total %
statement 113 120 94.1
branch 11 22 50.0
condition 2 6 33.3
subroutine 22 22 100.0
pod 8 8 100.0
total 156 178 87.6


line stmt bran cond sub pod time code
1              
2             use warnings;
3 2     2   711 use strict;
  2         4  
  2         66  
4 2     2   11 use base qw( Workflow::Persister );
  2         4  
  2         65  
5 2     2   11 use Data::Dumper qw( Dumper );
  2         4  
  2         316  
6 2     2   14 use File::Spec::Functions qw( catdir catfile );
  2         4  
  2         95  
7 2     2   10 use Log::Log4perl qw( get_logger );
  2         2  
  2         129  
8 2     2   13 use Workflow::Exception qw( configuration_error persist_error );
  2         5  
  2         76  
9 2     2   144 use Workflow::Persister::RandomId;
  2         9  
  2         86  
10 2     2   277 use File::Slurp qw(slurp);
  2         10  
  2         13  
11 2     2   1068 use English qw( -no_match_vars );
  2         20838  
  2         112  
12 2     2   13  
  2         2  
  2         16  
13             $Workflow::Persister::File::VERSION = '1.60';
14              
15             my @FIELDS = qw( path );
16             __PACKAGE__->mk_accessors(@FIELDS);
17              
18             my ( $self, $params ) = @_;
19             $self->SUPER::init($params);
20 2     2 1 13 unless ( $self->use_uuid eq 'yes' || $self->use_random eq 'yes' ) {
21 2         17 $self->use_random('yes');
22 2 50 33     1533 }
23 2         57 $self->assign_generators($params);
24             unless ( $params->{path} ) {
25 2         28 configuration_error "The file persister must have the 'path' ",
26 2 50       144 "specified in the configuration";
27 0         0 }
28             unless ( -d $params->{path} ) {
29             configuration_error "The file persister must have a valid directory ",
30 2 50       35 "specified in the 'path' key of the configuration ",
31 0         0 "(given: '$params->{path}')";
32             }
33             $self->log->info(
34             "Using path for workflows and histories '$params->{path}'");
35             $self->path( $params->{path} );
36 2         29 }
37 2         632  
38             my ( $self, $wf ) = @_;
39             my $generator = $self->workflow_id_generator;
40             my $wf_id = $generator->pre_fetch_id();
41 2     2 1 4 $wf->id($wf_id);
42 2         10 $self->log->debug("Generated workflow ID '$wf_id'");
43 2         28 $self->_serialize_workflow($wf);
44 2         19 my $full_history_path = $self->_get_history_path($wf);
45 2         8 ## no critic (ProhibitMagicNumbers)
46 2         622 mkdir( $full_history_path, 0777 )
47 2         567 || persist_error "Cannot create history dir '$full_history_path': $!";
48              
49 2 50       182 return $wf_id;
50             }
51              
52 2         13 my ( $self, $wf_id ) = @_;
53             my $full_path = $self->_get_workflow_path($wf_id);
54             $self->log->debug("Checking to see if workflow exists in '$full_path'");
55             unless ( -f $full_path ) {
56 4     4 1 1546 $self->log->error("No file at path '$full_path'");
57 4         10 persist_error "No workflow with ID '$wf_id' is available";
58 4         74 }
59 4 50       1196 $self->log->debug("File exists, reconstituting workflow");
60 0         0 my $wf_info = eval { $self->constitute_object($full_path) };
61 0         0 if ($EVAL_ERROR) {
62             persist_error "Cannot reconstitute data from file for ",
63 4         18 "workflow '$wf_id': $EVAL_ERROR";
64 4         1205 }
  4         13  
65 4 50       11 return $wf_info;
66 0         0 }
67              
68             my ( $self, $wf ) = @_;
69 4         10 $self->_serialize_workflow($wf);
70             }
71              
72             my ( $self, $wf, @history ) = @_;
73 2     2 1 5 my $generator = $self->history_id_generator;
74 2         4 my $history_dir = $self->_get_history_path($wf);
75             $self->log->info("Will use directory '$history_dir' for history");
76             foreach my $history (@history) {
77             if ( $history->is_saved ) {
78 4     4 1 9 $self->log->debug("History object saved, skipping...");
79 4         10 next;
80 4         38 }
81 4         88 $self->log->debug("History object unsaved, continuing...");
82 4         1250 my $history_id = $generator->pre_fetch_id();
83 3 50       16 $history->id($history_id);
84 0         0 my $history_file = catfile( $history_dir, $history_id );
85 0         0 $self->serialize_object( $history_file, $history );
86             $self->log->info("Created history object '$history_id' ok");
87 3         10 $history->set_saved();
88 3         1187 }
89 3         13 }
90 3         37  
91 3         10 my ( $self, $wf ) = @_;
92 3         960 my $history_dir = $self->_get_history_path($wf);
93 3         894 $self->log->debug("Trying to read history files from dir '$history_dir'");
94             opendir( HISTORY, $history_dir )
95             || persist_error "Cannot read history from '$history_dir': $!";
96             my @history_files = grep { -f $_ }
97             map { catfile( $history_dir, $_ ) } readdir HISTORY;
98 2     2 1 4 closedir HISTORY;
99 2         5 my @histories = ();
100 2         39  
101 2 50       619 foreach my $history_file (@history_files) {
102             $self->log->debug("Reading history from file '$history_file'");
103 7         77 my $history = $self->constitute_object($history_file);
104 2         49 $history->set_saved();
  7         29  
105 2         23 push @histories, $history;
106 2         6 }
107             return @histories;
108 2         4 }
109 3         11  
110 3         878 my ( $self, $wf ) = @_;
111 3         11 local $Data::Dumper::Indent = 1;
112 3         6 my $full_path = $self->_get_workflow_path( $wf->id );
113             $self->log->debug("Trying to write workflow to '$full_path'");
114 2         7 my %wf_info = (
115             id => $wf->id,
116             state => $wf->state,
117             last_update => $wf->last_update,
118 4     4   10 type => $wf->type,
119 4         6 context => $wf->context,
120 4         12  
121 4         80 );
122 4         1167 $self->serialize_object( $full_path, \%wf_info );
123             $self->log->debug("Wrote workflow ok");
124             }
125              
126             my ( $self, $path, $object ) = @_;
127             $self->log->info( "Trying to save object of type '",
128             ref($object), "' ", "to path '$path'" );
129             open( THINGY, '>', $path )
130 4         13 || persist_error "Cannot write to '$path': $!";
131 4         1289 print THINGY Dumper($object)
132             || persist_error "Error writing to '$path': $!";
133             close(THINGY) || persist_error "Cannot close '$path': $!";
134             $self->log->debug("Wrote object to file ok");
135 9     9 1 102 }
136 9         21  
137             my ( $self, $object_path ) = @_;
138 9 50       3195  
139             my $content = slurp($object_path);
140 9   33     44  
141             no strict;
142 9 50       7834 my $object = eval $content;
143 9         45 croak $EVAL_ERROR if ($EVAL_ERROR);
144             return $object;
145              
146             }
147 9     9 1 712  
148             my ( $self, $wf_id ) = @_;
149 9         26 $self->log->info( "Creating workflow file from '",
150             $self->path, "' ", "and ID '$wf_id'" );
151 2     2   2655 return catfile( $self->path, $wf_id . '_workflow' );
  2         6  
  2         328  
152 9         6678 }
153 9 50       45  
154 9         23 my ( $self, $wf ) = @_;
155             return catdir( $self->path, $wf->id . '_history' );
156             }
157              
158             1;
159 8     8   45  
160 8         17  
161             =pod
162 8         2605  
163             =head1 NAME
164              
165             Workflow::Persister::File - Persist workflow and history to the filesystem
166 8     8   13  
167 8         17 =head1 VERSION
168              
169             This documentation describes version 1.60 of this package
170              
171             =head1 SYNOPSIS
172              
173             <persister name="MainPersister"
174             class="Workflow::Persister::File"
175             path="/home/workflow/storage"/>
176              
177             =head1 DESCRIPTION
178              
179             Main persistence class for storing the workflow and workflow history
180             records to a filesystem for later retrieval. Data are stored in
181             serialized Perl data structure files.
182              
183             =head2 METHODS
184              
185             =head3 constitute_object
186              
187             This method deserializes an object.
188              
189             Takes a single parameter of an filesystem path pointing to an object
190              
191             Returns the re-instantiated object or dies.
192              
193             =head3 create_history
194              
195             Serializes history records associated with a workflow object
196              
197             Takes two parameters: a workflow object and an array of workflow history objects
198              
199             Returns: provided array of workflow history objects upon success
200              
201             =head3 create_workflow
202              
203             Serializes a workflow into the persistance entity configured by our workflow.
204              
205             Takes a single parameter: a workflow object
206              
207             Returns a single value, a id for unique identification of out serialized
208             workflow for possible deserialization.
209              
210             =head3 fetch_history
211              
212             Deserializes history records associated with a workflow object
213              
214             Takes a single parameter: a workflow object
215              
216             Returns an array of workflow history objects upon success
217              
218             =head3 fetch_workflow
219              
220             Deserializes a workflow from the persistance entity configured by our workflow.
221              
222             Takes a single parameter: the unique id assigned to our workflow upon
223             serialization (see L</create_workflow>).
224              
225             Returns a hashref consisting of two keys:
226              
227             =over
228              
229             =item * state, the workflows current state
230              
231             =item * last_update, date indicating last update
232              
233             =back
234              
235             =head3 init ( \%params )
236              
237             Method to initialize the persister object. Sets up the configured generators
238              
239             Throws a L<Workflow::Exception> if a valid filesystem path is not provided with
240             the parameters.
241              
242             =head3 serialize_object
243              
244             Method that writes a given object to a given path.
245              
246             Takes two parameters: path (a filesystem path) and an object
247              
248             Throws L<Workflow::Exception> if unable to serialize the given object to the
249             given path.
250              
251             Returns: Nothing
252              
253             =head3 update_workflow
254              
255             Updates a serialized workflow in the persistance entity configured by our
256             workflow.
257              
258             Takes a single parameter: a workflow object
259              
260             Returns: Nothing
261              
262             =head1 TODO
263              
264             =over
265              
266             =item * refactor L</constitute_object>, no checks are made on filesystem prior
267             to deserialization attempt.
268              
269             =back
270              
271             =head1 SEE ALSO
272              
273             =over
274              
275             =item * L<Workflow::Persister>
276              
277             =back
278              
279             =head1 COPYRIGHT
280              
281             Copyright (c) 2003-2022 Chris Winters. All rights reserved.
282              
283             This library is free software; you can redistribute it and/or modify
284             it under the same terms as Perl itself.
285              
286             Please see the F<LICENSE>
287              
288             =head1 AUTHORS
289              
290             Please see L<Workflow>
291              
292             =cut