3 # Written by Petr Grigoriev the OpenXPKI project 2007
4 # Copyright (c) 2007 by The OpenXPKI Project
17 use Locale
::Messages qw
(:locale_h
:libintl_h nl_putenv bind_textdomain_filter
);
18 use POSIX qw
(setlocale
);
19 use Image
::Size
'html_imgsize';
23 # command line options
28 # file name for the website document
29 my $html_name = 'workflow-graphs.html';
31 #default i18n language
32 my $language = "en_GB";
34 # default list of workflow definitions
35 # assumed to be in the corresponding SVN directory
36 my $wf_all = '../../trunk/deployment/etc/templates/default/workflow.xml';
38 # default directory for html pages and pictures
39 # assumed to be in the corresponding SVN directory (website leaf)
40 my $dot_dir = '../../www.openxpki.org/trunk/src/htdocs/docs/wf-pictures';
42 my $pic_format = 'png';
44 if( GetOptions
( 'help|?' => \
$help,
47 'directory=s' => \
$dot_dir,
48 'format=s' => \
$pic_format,
49 'lang=s' => \
$language,
53 pod2usage
(1) if $help;
54 pod2usage
(-exitstatus
=> 0, -verbose
=> 2) if $man;
56 print STDERR
"See manual: wf_grapfs.pl --man\n"; exit 0;
58 #print "LANGUAGE <".$language.">\n"; exit 1;
59 my $loc = "${language}.UTF-8";
60 setlocale
(LC_MESSAGES
, $loc);
61 setlocale
(LC_TIME
, $loc);
62 nl_putenv
("LC_MESSAGES=$loc");
63 nl_putenv
("LC_TIME=$loc");
64 textdomain
('openxpki');
65 bindtextdomain
('openxpki' => '/usr/local/share/locale');
66 bind_textdomain_codeset
("openxpki", "UTF-8");
67 #my $msg=gettext ("I18N_OPENXPKI_SERVER_AUTHENTICATION_PASSWORD_LOGIN_FAILED");
68 #print STDERR $msg."\n";
71 #print STDERR $dot_dir."\n"; exit 1;
73 #subdirectory for html references
74 my $ref_dir = $dot_dir;
75 $ref_dir =~ s/^.*\///;
77 # call for a graphviz picture creator
78 my $genpic = "dot -T" . $pic_format . " -o ";
80 # get directory with workflow definitions
81 # it assumed to be the same as the directory with definition list
82 # if wf_all is /x/y/z then def_dir is /x/y/
84 my $def_dir = $wf_all;
85 $def_dir =~ s/[^\/]*$//;
87 #print STDERR $def_dir."\n";exit 1;
89 # get a list of workflow definitions
90 my $config = XMLin
($wf_all);
92 my $wf_config = $config->{'workflows'}->{'xi:include'};
94 open(WEBFILE
, ">", $dot_dir ."/../". $html_name ) or
95 die "Opening file $html_name in $dot_dir: $!";
96 print WEBFILE
"<%attr>\n";
97 print WEBFILE
"title => 'OpenXPKI workflows graphical representation'\n";
98 print WEBFILE
"</%attr>\n\n";
99 print WEBFILE
"<h1>OpenXPKI workflows' graphical representation</h1>\n";
100 print WEBFILE
"<p>\n";
101 print WEBFILE
"Here are links to graphs describing main OpenXPKI workflows\n";
102 print WEBFILE
"</p>\n\n"
105 foreach my $wf_file_hash (@
{$wf_config}){
106 my $wf_def = $wf_file_hash->{'href'};
108 # dot file has the same name but suffix 'dot' instead of 'xml'
109 my $wf_dot = $wf_def;
110 $wf_dot =~ s/xml$/dot/;
112 # build a full path to workflow definition file
113 $wf_def = $def_dir . $wf_def;
115 # we get workflow title after parsing it's definition
117 my $data=wf_visualize
($wf_def,\
$wf_title);
118 # print STDERR "TITLE ". $wf_title."\n";
119 $wf_title = gettext
($wf_title);
120 print STDERR
"Processing <".$wf_title.">\n";
122 # now we build the full path to dot-file and create it
123 my $dot_file= $dot_dir . "/" . $wf_dot;
124 open(DOTFILE
, ">:encoding(UTF8)", $dot_file ) or
125 die "Opening file $wf_dot in $dot_dir: $!";
129 # create graphviz command line and compile a picture
131 $genpic . " " . $dot_file . "." . $pic_format . " < " . $dot_file;
132 my $picture_done=`$generator`;
134 # create html file with the picture and write a link to it
135 # to the main html file
137 open(WEBLINKFILE
, ">", $dot_file . ".html") or
138 die "Opening file $dot_file" . ".html in $dot_dir: $!";
139 print WEBLINKFILE
"<%attr>\n";
140 print WEBLINKFILE
"title => 'OpenXPKI workflows graphical representation'\n";
141 print WEBLINKFILE
"</%attr>\n\n";
142 print WEBLINKFILE
"<h1>OpenXPKI workflows' graphical representation</h1>\n";
143 print WEBLINKFILE
"<h2> Workflow ". $wf_title ."</h2>\n\n";
144 print WEBLINKFILE
"<p>\nAutorun states are yellow.\n";
145 print WEBLINKFILE
"You may need to pan or scroll to view a picture.\n</p>\n\n";
146 my $image_name = $dot_file . "." . $pic_format;
147 my $image_size = html_imgsize
($image_name);
148 print WEBLINKFILE
'<img ' . $image_size .
149 ' src="'. $wf_dot . '.' . $pic_format . '"' .
150 'alt="' . $wf_title . '" ' .
151 'title="' . $wf_title . '" ' .
154 print WEBFILE
'<a href="' . $ref_dir . '/' . $wf_dot . '.html">' .
155 $wf_title . '</a><br/>'."\n";
169 my $wf_title = shift;
170 my %wf_parsed = wfparse
($wf_xml);
171 my $wf = \
%wf_parsed;
173 #return type for picture caption in html file
174 ${$wf_title}=$wf->{'type'};
176 my $data = wf_make_graph
($wf);
184 # Configuration variables for special states colors
185 my $SUCCESS_STATE = 'SUCCESS';
186 my $SUCCESS_COLOR = 'darkgreen';
187 my $FAILURE_STATE = 'FAILURE';
188 my $FAILURE_COLOR = 'firebrick';
189 my $AUTORUN_COLOR = '"yellow"';
191 my $type=$wf->{'type'};
192 my $data=get_preamble
($type);
196 foreach my $state (keys %{$wf->{'states'}}){
198 if(defined $wf->{'states'}->{$state} ->{'autorun'}){
199 $nodes .= "[ fillcolor = ".$AUTORUN_COLOR."];\n";
203 if( defined $wf->{'states'}->{$state}->{'actions'}){
204 foreach my $action (keys %{$wf->{'states'}->
205 {$state}->{'actions'}}
207 my $edge_label=' [label="'.$action;
209 {'states'}->{$state}->
210 {'actions'}->{$action}->{'result'};
211 $edges .= $state ." -> ".$result;
212 if( defined $wf->{'states'}->
213 {$state}->{'actions'}->
214 {$action}->{'conditions'}){
215 $edge_label .='\\n if ';
216 foreach my $condition (keys %{$wf->
217 {'states'}->{$state}->
218 {'actions'}->{$action}->
220 $edge_label .= " $condition \\n ";
223 $edges .= $edge_label .'"];'."\n";
227 # finalize the graphic file
237 $config = XMLin
($wf_xml);
240 my $wf_type = $config->{'type'};
241 # print "TYPE $wf_type \n";
242 $wf->{'type'} = $wf_type;
243 $wf->{'states'} = {};
244 my $wf_states = $config->{'state'};
245 foreach my $state (keys %{$wf_states}){
246 # print " STATE $state";
247 $wf->{'states'}->{$state} = {};
248 my $autorun = $wf_states->{$state}->{'autorun'};
249 if(defined $autorun){
250 # print " AUTORUN $autorun \n";
251 $wf->{'states'}->{$state} ->{'autorun'}='yes';
255 my $state_actions = $wf_states->{$state}->{'action'};
256 if( ref($state_actions) ne 'HASH'){
257 # print " NO ACTIONS\n";
259 $wf->{'states'}->{$state}->{'actions'} = {};
260 if( defined $state_actions->{'name'}){
261 my $resulting_state =
262 $state_actions->{'resulting_state'};
264 $state_actions->{'name'};
266 $state_actions->{'condition'};
267 # print " ACTION $name \n";
268 # print " RESULTING STATE $resulting_state \n";
269 $wf->{'states'}->{$state}->{'actions'}->{$name} = {};
273 {$name}->{'result'} = $resulting_state;
274 if( defined $conditions ){
275 $wf->{'states'} -> {$state} ->
276 {'actions'} -> {$name} ->
278 if( defined $conditions->{'name'}){
279 my $condition = $conditions->{'name'};
280 # print " CONDITION $condition \n";
281 $wf->{'states'} -> {$state}->
282 {'actions'} -> {$name}->
283 {'conditions'} -> {$condition} = 'if';
285 foreach my $condition (keys %{$conditions}){
286 # print " CONDITION $condition \n";
287 $wf->{'states'} -> {$state}->
288 {'actions'} -> {$name}->
289 {'conditions'} -> {$condition} = 'if';
295 foreach my $action (keys %{$state_actions}){
296 # print " ACTION $action \n";
297 my $resulting_state =
298 $state_actions->{$action}->{'resulting_state'};
300 $state_actions->{$action}->{'condition'};
301 # print " RESULTING STATE $resulting_state \n";
302 $wf->{'states'}->{$state}->{'actions'}->{$action} = {};
306 {$action}->{'result'} = $resulting_state;
307 if( defined $conditions ){
308 $wf->{'states'} -> {$state} ->
309 {'actions'} -> {$action} ->
311 if( defined $conditions->{'name'}){
312 my $condition = $conditions->{'name'};
313 # print " CONDITION $condition \n";
314 $wf->{'states'} -> {$state}->
315 {'actions'} -> {$action}->
316 {'conditions'} -> {$condition} = 'if';
318 foreach my $condition (keys %{$conditions}){
319 # print " CONDITION $condition \n";
320 $wf->{'states'} -> {$state}->
321 {'actions'} -> {$action}->
322 {'conditions'} -> {$condition} = 'if';
335 $type = '"'.gettext
($type).'"';
337 my $RANKDIR = '"TB"'; #rank direction, LR or TB (left to right or top to bottom)
338 my $RATIO = 0.71; # useful for A4 paper
339 my $ROTATE = 0; # either 0 or 90
340 my $GRAPH_FONTNAME = '"Futura-CondensedMedium"';
341 my $GRAPH_FONTSIZE = 24;
342 my $LABEL_LOCATION = "b"; # t for top or b for bottom
344 my $NODE_SHAPE = '"rect"';
345 my $NODE_STYLE = '"filled"';
346 my $NODE_FONTNAME = $GRAPH_FONTNAME;
347 my $NODE_FONTSIZE = 16;
348 my $EDGE_FONTNAME = $GRAPH_FONTNAME;
349 my $EDGE_FONTSIZE = 16;
351 my $preamble ="digraph $type" . " {\n".
352 "graph [ rankdir=$RANKDIR,".
356 "fontname=$GRAPH_FONTNAME,".
357 "fontsize=$GRAPH_FONTSIZE,".
359 "labelloc=$LABEL_LOCATION,".
363 "node [shape=$NODE_SHAPE,".
364 "style=$NODE_STYLE,".
365 "fontname=$NODE_FONTNAME,".
366 "fontsize=$NODE_FONTSIZE".
368 "edge [fontname=$EDGE_FONTNAME,".
369 "fontsize=$EDGE_FONTSIZE".
381 wf_graphs.pl - workflow graph generator
385 wf_graphs.pl [options]
388 --help brief help message
389 --man full documentation
390 --html create html files for website
391 with links to pictures
392 --directory <dir> create pictures in directory 'dir'
393 --def <file> use 'file' as a list of workflow
395 --format <type> format of the graphics files to be created
396 (use only types supported by graphviz)
397 --lang <locale> locale to print picture captions
398 supports en_GB and de_DE
402 B<wf_graphs.pl> creates dot-files for graphviz program
403 to create pictures of all workflow types
404 specified in the files with workflow definitions.
405 B<workflow.xml> is used by default as a list of files
406 with workflow definitions which will be processed.
407 Workflow definition files are being parsed and then the corresponding
408 dot-files for graphviz are created. Autorun states are marked yellow.
409 Using I18N translations is supported for B<en_GB> (default) and B<de_DE>.
410 Definition files are supposed to have 'xml'
411 extension. Names for dot-files are built by substituting
412 extension 'dot' instead of 'xml'. After dot-files are created
413 graphviz B<dot> utility is called to create pictures in desirable format.
414 Optionally html-files with links to pictures are created in the same directory
415 and the main html-file with link list of workflow types in the parent directory.
417 The name of the main html-file is predefined: B<workflow-graphs.html>
419 The default list of workflow definitions is assumed to be
420 in the corresponding SVN directory:
422 ../../trunk/deployment/etc/templates/default/workflow.xml
424 Default directory for html pages and pictures is
425 assumed to be in the corresponding SVN directory (website leaf)
427 ../../www.openxpki.org/trunk/src/htdocs/docs/wf-pictures
435 Use it to read all the manual
439 Use it to get information on command line options only
443 Creates html file 'workflow-graphs.html' and child
444 html-pages with pictures.
446 =item B<--directory> dir
448 Makes it possible to create dot-files in another directory.
449 If B<--html> option is used html-files with pictures will also be
450 created in the given directory but the main html-file with links to
451 picture pages will be created in the parent directory.
455 Use 'file' as a list of workflow definitions which will
456 be processed to create their graphs. The file format must be
457 the same as in OpenXPKI workflow.xml:
459 <workflow_config id="default">
461 <configfile>workflow_def_1.xml</configfile>
462 <configfile>workflow_def_2.xml</configfile>
463 ...........................................
465 ..............................................
468 The path of the specified file will be used to search
469 workflow-definitions files.
471 =item B<--format> type
473 Generate graphics files in B<type> format.
474 As B<dot> is called only formats supported by B<graphviz>
477 =item B<--lang> locale
479 Uses B<locale> to select language for picture captions.
480 Supports en_GB and de_DE translations of OpenXPKI tags.
481 Assumes i18n is installed in /usr/local/share/locale.
485 =head1 Built-in-functions
489 =item B<wf_visualize>
491 Calls wfparse and wf_make_graph for passed filename with
492 workflow definitions. Returns the output of wf_make_graph.
493 Writes the workflow type to the variable which link is
494 passed to the function as the second parameter .
496 =item B<wf_make_graph>
498 Creates data to write in dot-file using passed hash with workflow
499 definitions. Autorun states are marked yellow.
501 =item B<get_preamble>
503 Creates a header of the dot-file and returns it.
504 The only argument is used as a label for the picture.
505 Picture options are concentrated in this function.
509 Parses the passed xml-file with workflow definitions and creates
510 a hash with those definitions. Returns the hash.
512 An example is self-explanatory:
514 { 'type' => 'WORKFLOW TYPE',
520 'result' => 'RESULTING_STATE_1',
522 'CONDITION_1' => 'if',
523 'CONDITION_2' => 'if',
527 'result' => 'RESULTING_STATE_2',
529 'CONDITION_3' => 'if',
530 'CONDITION_4' => 'if',
538 'result' => 'RESULTING_STATE_3',
540 'CONDITION_5' => 'if',
541 'CONDITION_6' => 'if',
545 'result' => 'RESULTING_STATE_4',
547 'CONDITION_7' => 'if',
548 'CONDITION_8' => 'if',
558 To get pictures of the current SVN-snapshot go to the directory
559 where wf_graphs is stored ( tools/automated_wf_visual ) and say:
561 ./wf_graphs.pl --directory .
563 Set of dot-files and png-pictures will be created in the current
566 To update pictures of the current SVN snapshot in the website
567 source directory (new set of files must be then registered with svn
568 B<add> and B<delete> commands):
570 ./wf_graphs.pl --html