| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Web::App::Config; | 
| 2 |  |  |  |  |  |  | # $Id: Config.pm,v 1.31 2009/06/07 20:57:49 apla Exp $ | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 1 |  |  | 1 |  | 9 | use Class::Easy; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 11 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 1 |  |  | 1 |  | 1427 | use Storable qw(retrieve nstore); | 
|  | 1 |  |  |  |  | 4384 |  | 
|  | 1 |  |  |  |  | 119 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 1 |  |  | 1 |  | 555 | use XML::LibXML; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | use Web::App::Config::Screen; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | =pod | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | =head1 NAME | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | Web::App::Config - parsing Web::App configuration | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | Web::App | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | =cut | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | sub path_to_val { | 
| 27 |  |  |  |  |  |  | my ($data, $path)  = @_; | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | my @path  = split '/', $path; | 
| 30 |  |  |  |  |  |  | foreach (@path) { | 
| 31 |  |  |  |  |  |  | $data = $data->[$_], next | 
| 32 |  |  |  |  |  |  | if ref $data eq 'ARRAY'; | 
| 33 |  |  |  |  |  |  | $data = $data->{$_}; | 
| 34 |  |  |  |  |  |  | } | 
| 35 |  |  |  |  |  |  | return $data; | 
| 36 |  |  |  |  |  |  | } | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | sub assign_path { | 
| 39 |  |  |  |  |  |  | my ($data, $path, $value)  = @_; | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | my @path = split '/', $path; | 
| 42 |  |  |  |  |  |  | my $last = pop @path; | 
| 43 |  |  |  |  |  |  | foreach (@path) { | 
| 44 |  |  |  |  |  |  | unless (exists $data->{$_}) { | 
| 45 |  |  |  |  |  |  | # debug "$path => $_"; | 
| 46 |  |  |  |  |  |  | $data->{$_} = {}; | 
| 47 |  |  |  |  |  |  | } | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | $data = $data->{$_}; | 
| 50 |  |  |  |  |  |  | } | 
| 51 |  |  |  |  |  |  | $data->{$last} = $value; | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 56 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 57 |  |  |  |  |  |  | sub last_modified_since { | 
| 58 |  |  |  |  |  |  | my $self = shift; | 
| 59 |  |  |  |  |  |  | my $last_modified = shift; | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | my $config_file = $self->file; | 
| 62 |  |  |  |  |  |  | my $config_dir  = ($config_file =~ /^(.*\/)[^\/]+$/)[0]; | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | my $config_files = [$config_file, map {"$config_dir$_"} @{$self->int->{'files'}}]; | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | debug "compare timestamps of the config file '$config_file' and module Web::App::Config"; | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | my $configuration_package_file = $INC {'Web/App/Config.pm'}; | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | my $package_change = (stat ($configuration_package_file))[9]; | 
| 71 |  |  |  |  |  |  | my $config_change  = 0; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | foreach $config_file (@$config_files) { | 
| 74 |  |  |  |  |  |  | my $mtime = (stat ($config_file))[9]; | 
| 75 |  |  |  |  |  |  | $config_change = $mtime | 
| 76 |  |  |  |  |  |  | if $mtime > $config_change; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | my $outdated = 0; | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | # workaround for configuration init | 
| 82 |  |  |  |  |  |  | if (not defined $last_modified or $last_modified == 0) { | 
| 83 |  |  |  |  |  |  | debug "initial configuration"; | 
| 84 |  |  |  |  |  |  | $last_modified = $config_change; | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | if ($config_change > $last_modified) { | 
| 88 |  |  |  |  |  |  | debug "config changed since last modified"; | 
| 89 |  |  |  |  |  |  | # debug "config (" . scalar localtime ($config_change) . ") changed since last modified (".scalar localtime ($last_modified).")"; | 
| 90 |  |  |  |  |  |  | $last_modified = $config_change; | 
| 91 |  |  |  |  |  |  | $outdated = $last_modified; | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | if ($package_change > $last_modified) { | 
| 95 |  |  |  |  |  |  | debug "module are newer than configuration"; | 
| 96 |  |  |  |  |  |  | # debug "module (" . scalar localtime ($package_change) . ") are newer than configuration (".scalar localtime ($last_modified).")"; | 
| 97 |  |  |  |  |  |  | $last_modified = $package_change; | 
| 98 |  |  |  |  |  |  | $outdated = $last_modified; | 
| 99 |  |  |  |  |  |  | } | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | return $outdated; | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 105 |  |  |  |  |  |  | has 'app',  is => 'ro'; | 
| 106 |  |  |  |  |  |  | has 'file', is => 'ro'; | 
| 107 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 108 |  |  |  |  |  |  | sub int { | 
| 109 |  |  |  |  |  |  | return shift->{'internals'}; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 112 |  |  |  |  |  |  | sub screens { | 
| 113 |  |  |  |  |  |  | return shift->{'internals'}->{'screens'}; | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 116 |  |  |  |  |  |  | sub modules { | 
| 117 |  |  |  |  |  |  | return shift->{'internals'}->{'modules'}; | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 120 |  |  |  |  |  |  | sub presenters { | 
| 121 |  |  |  |  |  |  | return shift->{'internals'}->{'presenters'}; | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 124 |  |  |  |  |  |  | sub get { | 
| 125 |  |  |  |  |  |  | my $class = shift; | 
| 126 |  |  |  |  |  |  | my $app   = shift; | 
| 127 |  |  |  |  |  |  | my $config_file  = shift; | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | # first we need to check existing config in web::app | 
| 130 |  |  |  |  |  |  | # then we check | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | my $bin_config_file = $config_file . '.binary'; | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | my $self = { | 
| 135 |  |  |  |  |  |  | 'file'  => $config_file, | 
| 136 |  |  |  |  |  |  | 'app'   => $app, | 
| 137 |  |  |  |  |  |  | 'mtime' => 0, | 
| 138 |  |  |  |  |  |  | 'internals' => { | 
| 139 |  |  |  |  |  |  | 'screens' => {}, | 
| 140 |  |  |  |  |  |  | 'modules' => {}, | 
| 141 |  |  |  |  |  |  | 'presenters' => {}, | 
| 142 |  |  |  |  |  |  | 'files' => {}, | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  | }; | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | my $mtime_config_binary = 0; | 
| 147 |  |  |  |  |  |  | my $loaded = 0; | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | if (-f $bin_config_file) { | 
| 150 |  |  |  |  |  |  | $self->{'mtime'} = $mtime_config_binary = (stat ($bin_config_file))[9]; | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | debug "loading configuration binary"; | 
| 153 |  |  |  |  |  |  | eval { | 
| 154 |  |  |  |  |  |  | $self->{'internals'} = retrieve ($bin_config_file); | 
| 155 |  |  |  |  |  |  | $loaded = 1; | 
| 156 |  |  |  |  |  |  | }; | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | }; | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | unless (-f $config_file) { | 
| 161 |  |  |  |  |  |  | critical "Can't read config from file $config_file"; | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | bless $self, $class; | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | if (not $loaded or $self->last_modified_since ($mtime_config_binary)) { | 
| 167 |  |  |  |  |  |  | debug 'parsing configuration'; | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | $self->parse_file ($app); | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | nstore ($self->{'internals'}, $bin_config_file) | 
| 172 |  |  |  |  |  |  | or debug ("cannot write binary config to '$bin_config_file'"); | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | # reload mtime after store or retrieve | 
| 177 |  |  |  |  |  |  | $self->{'mtime'} = (stat ($bin_config_file))[9]; | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | return $self; | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 182 |  |  |  |  |  |  | sub init_modules { | 
| 183 |  |  |  |  |  |  | my $self = shift; | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | my $app  = $self->app; | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | my $dump_separators = ',;:\/ '; | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | foreach my $module (keys %{$self->modules}) { | 
| 190 |  |  |  |  |  |  | next unless $module; | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | my $t = timer ("$module require"); | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | debug "$@" | 
| 195 |  |  |  |  |  |  | unless try_to_use ($module); | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | my $params = $self->modules->{$module}; | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | my $dump = 'all'; | 
| 200 |  |  |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | if (ref $params eq 'HASH') { | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | if ($module->can ('init') and $params->{type} ne 'use') { | 
| 204 |  |  |  |  |  |  | $t->lap ("$module init"); | 
| 205 |  |  |  |  |  |  | $module->init ($params); | 
| 206 |  |  |  |  |  |  | } else { | 
| 207 |  |  |  |  |  |  | # debug "module $module doesn't have 'init' method"; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | $t->end; | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | } | 
| 215 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 216 |  |  |  |  |  |  | sub screen { | 
| 217 |  |  |  |  |  |  | my $self = shift; | 
| 218 |  |  |  |  |  |  | my $screen_name = shift; | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | return $self->screens->{$screen_name}; | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 223 |  |  |  |  |  |  | sub parse_file { | 
| 224 |  |  |  |  |  |  | my $self = shift; | 
| 225 |  |  |  |  |  |  | my $app  = shift; | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | my $screen_config_path = $self->{'file'}; | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | debug 'loading screens configuration'; | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | my $parser = new XML::LibXML; | 
| 232 |  |  |  |  |  |  | my $xp = $parser->parse_file ($screen_config_path); | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | my @files = $xp->findnodes ('/config/xi:include'); | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | $self->int->{'files'} = [map {$_->getAttribute ('href')} @files]; | 
| 237 |  |  |  |  |  |  | $parser->processXIncludes ($xp); | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | my @plugin_list = $xp->findnodes ('/config/*[local-name() = "extension" or local-name() = "presenter" or local-name() = "use" or local-name() = "request" or local-name() = "session"]'); | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | my $modules = $self->int->{'modules'} = {}; | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | foreach my $plugin (@plugin_list) { | 
| 244 |  |  |  |  |  |  | my @arguments = $plugin->findnodes ('@*'); | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | my $module_params = {'type' => ''}; | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | foreach (@arguments) { | 
| 249 |  |  |  |  |  |  | #$module = $module->string_value; | 
| 250 |  |  |  |  |  |  | #debug "found '" . $plugin->nodeName . "'in module: '$module'"; | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | $module_params->{$_->localname} = $_->nodeValue; | 
| 253 |  |  |  |  |  |  | } | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | my $defined_type = $module_params->{'type'}; | 
| 256 |  |  |  |  |  |  | my $computed_type = $plugin->nodeName; | 
| 257 |  |  |  |  |  |  | $computed_type .= ':' . $defined_type | 
| 258 |  |  |  |  |  |  | if defined $defined_type and $defined_type ne ''; | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | $module_params->{'type'} = $computed_type; | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | my $module_name = delete $module_params->{'pack'}; | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | # after parsing, store module config | 
| 265 |  |  |  |  |  |  | $modules->{$module_name} = $module_params; | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | debug "found $module_name in ", $plugin->localname; | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | my $screens_node = $xp->findnodes ('/config/screens')->get_node(1); | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | my $screens = $self->int->{'screens'} = {}; | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | $screens->{'#base-uri'} = $screens_node->findvalue ('base-url/text()'); | 
| 275 |  |  |  |  |  |  | $screens->{'#separators'} = $screens_node->findvalue ('request-queue/@separators'); | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | $screens->{'#user-name-separator'} = | 
| 278 |  |  |  |  |  |  | $screens_node->findvalue ('request-queue/user-name/@separator-symbol'); | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | $screens->{'#user-name-position'} = | 
| 281 |  |  |  |  |  |  | $screens_node->findvalue ('request-queue/user-name/@name-position'); | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | my @screen_nodes_list = $screens_node->findnodes ('screen'); | 
| 284 |  |  |  |  |  |  | # find all paragraphs | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | #my $presenters_dir = $self->{'home'} . '/share/presentation/' . | 
| 287 |  |  |  |  |  |  | #					 $self->{'template-set'} . '/'; | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | #debug 'presenters in \'' . $presenters_dir . '\''; | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | foreach my $screen (@screen_nodes_list) { | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | my $id = $screen->getAttribute ('id'); | 
| 294 |  |  |  |  |  |  | next | 
| 295 |  |  |  |  |  |  | unless defined $id; | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | my $screen_object = Web::App::Config::Screen->create ($id); | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | $screen_object->{auth} = $screen->getAttribute ('auth'); | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | if ($id ne '') { | 
| 302 |  |  |  |  |  |  | assign_path ($screens, "$id/?", $screen_object); | 
| 303 |  |  |  |  |  |  | $screens->{$id}->{'?'} = $screen_object | 
| 304 |  |  |  |  |  |  | unless defined $screens->{$id}; | 
| 305 |  |  |  |  |  |  | } else { | 
| 306 |  |  |  |  |  |  | assign_path ($screens, "?", $screen_object); | 
| 307 |  |  |  |  |  |  | } | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | my $presenter_attrs = (); | 
| 310 |  |  |  |  |  |  | foreach my $presenter_attr (($screen->findnodes ('presentation'))[0]->attributes) { | 
| 311 |  |  |  |  |  |  | $presenter_attrs->{$presenter_attr->localName} = | 
| 312 |  |  |  |  |  |  | $presenter_attr->value; | 
| 313 |  |  |  |  |  |  | } | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | die "Can't locate presenter type in screen '$id', ", $screen->toString (1) | 
| 316 |  |  |  |  |  |  | unless $presenter_attrs->{type}; | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | my $regexp = $screen->findvalue ('@regexp'); | 
| 319 |  |  |  |  |  |  | $screen_object->{regexp} = $regexp | 
| 320 |  |  |  |  |  |  | if $regexp; | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | $screen_object->presentation ($presenter_attrs); | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | my $req_max_size = $screen->findvalue ('@request-max-size'); | 
| 325 |  |  |  |  |  |  | $screen_object->request->{'max-size'} = $req_max_size | 
| 326 |  |  |  |  |  |  | if defined $req_max_size and $req_max_size =~ /\d+/; | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | foreach my $context ('call', 'init/call', 'process/call') { | 
| 329 |  |  |  |  |  |  | my @call_nodes = $screen->findnodes ($context); | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | my $type = ($context =~ /^(?:(init|process)\/)?call$/)[0]; | 
| 332 |  |  |  |  |  |  | my $call = 'add_call'; | 
| 333 |  |  |  |  |  |  | $call = "add_${type}_call" | 
| 334 |  |  |  |  |  |  | if defined $type; | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | foreach my $call_node (@call_nodes) { | 
| 337 |  |  |  |  |  |  | my @param_attrs = $call_node->findnodes ('@*'); | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | my $params = {}; | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | foreach (@param_attrs) { | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | my $param_name  = $_->localname; | 
| 344 |  |  |  |  |  |  | my $param_value = $_->nodeValue; | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | $params->{$param_name} = $param_value; | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | if (exists $params->{'sub'}) { | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | my $sub = $params->{'sub'}; | 
| 352 |  |  |  |  |  |  | $screen_object->$call ($params); | 
| 353 |  |  |  |  |  |  | # debug "added $call to $sub"; | 
| 354 |  |  |  |  |  |  | my $module = ($sub =~ /(.*)(?:->|::)/)[0]; | 
| 355 |  |  |  |  |  |  |  | 
| 356 |  |  |  |  |  |  | if ($module =~ /^\$([^:]+)/ and $app->can ($1)) { | 
| 357 |  |  |  |  |  |  | # debug 'this is a call for web app internals'; | 
| 358 |  |  |  |  |  |  | } else { | 
| 359 |  |  |  |  |  |  | $modules->{$module} = {type => 'use'}; | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | # try_to_use ($module); | 
| 363 |  |  |  |  |  |  | } | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  | } | 
| 366 |  |  |  |  |  |  |  | 
| 367 |  |  |  |  |  |  | $screen_object->{'params'} = []; | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  | my @param_nodes = $screen->findnodes ('param'); | 
| 370 |  |  |  |  |  |  |  | 
| 371 |  |  |  |  |  |  | foreach my $param (@param_nodes) { | 
| 372 |  |  |  |  |  |  | my $field_params = { | 
| 373 |  |  |  |  |  |  | 'name'     => undef, | 
| 374 |  |  |  |  |  |  | 'required' => undef, | 
| 375 |  |  |  |  |  |  | 'type'     => undef, # regexp:... or email, as example. available types in request.pm | 
| 376 |  |  |  |  |  |  | 'multi'    => undef, # multivalued parameter | 
| 377 |  |  |  |  |  |  | 'filter'   => undef, # trim-space, as example. available types in request.pm | 
| 378 |  |  |  |  |  |  | 'default'  => undef, # default values for this object | 
| 379 |  |  |  |  |  |  | }; | 
| 380 |  |  |  |  |  |  | push @{$screen_object->{'params'}}, $field_params; | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | foreach my $var (keys %$field_params) { | 
| 383 |  |  |  |  |  |  | $field_params->{$var} = $param->getAttribute ($var) | 
| 384 |  |  |  |  |  |  | if $param->hasAttribute ($var); | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | if ($field_params->{name}) { | 
| 388 |  |  |  |  |  |  | $screen_object->{'params_hash'}->{$field_params->{name}} = $field_params; | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | $field_params->{'default'} = [$field_params->{'default'}] | 
| 392 |  |  |  |  |  |  | if defined $field_params->{'default'}; | 
| 393 |  |  |  |  |  |  | $field_params->{'default'} = [] | 
| 394 |  |  |  |  |  |  | if $param->findvalue ('count(default)') > 0; | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | foreach my $defaults ($param->findnodes ('default')) { | 
| 397 |  |  |  |  |  |  | push @{$field_params->{'default'}}, $defaults->textContent; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  | } | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | # use Data::Dumper; | 
| 403 |  |  |  |  |  |  | # debug Dumper $self; | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | return; | 
| 406 |  |  |  |  |  |  | } | 
| 407 |  |  |  |  |  |  | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | =pod | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | sub path_from_request | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | this procedure return screen object and path info. | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | example: | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | request is: http://some.com/web-app/admin/article/12345 | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | configuration is: | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | ... | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | ... | 
| 425 |  |  |  |  |  |  | /web-app | 
| 426 |  |  |  |  |  |  | ... | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  |  | 
| 434 |  |  |  |  |  |  | ... | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  |  | 
| 439 |  |  |  |  |  |  | sub return screen object for screen with | 
| 440 |  |  |  |  |  |  | id = 'admin/article' and path info = '12345' | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | =cut | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | sub screen_from_request { | 
| 445 |  |  |  |  |  |  | my $self = shift; | 
| 446 |  |  |  |  |  |  | my $path = shift; | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | my $screens = $self->screens; | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | my $separators = $screens->{'#separators'}; | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | $separators =~ s/([\/\[\]\(\)])/\\$1/g; | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | my $screen = $screens; | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | my $matches = []; | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | while (1) { | 
| 459 |  |  |  |  |  |  | my ($path_element, $tail) = split /[$separators]/, $path, 2; | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | #debug "path element: $path_element, tail: $tail"; | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | return ($screen->{'?'}, $path, $matches) | 
| 464 |  |  |  |  |  |  | unless defined $path_element; | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | if (defined $screen->{$path_element} and $screen->{$path_element}->{'?'}) { | 
| 467 |  |  |  |  |  |  | $screen = $screen->{$path_element}; | 
| 468 |  |  |  |  |  |  | $path = $tail; | 
| 469 |  |  |  |  |  |  | } else { | 
| 470 |  |  |  |  |  |  | # try to find screen by regexp | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | my $matched = 0; | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | my @children_screen = grep {!/[\/\#\?]/} keys %$screen; | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  | # use Data::Dumper; | 
| 477 |  |  |  |  |  |  | # debug Dumper \@children_screen; | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | foreach my $match (@children_screen) { | 
| 480 |  |  |  |  |  |  | my $is_regexp = $screen->{$match}->{'?'}->{regexp}; | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | next unless $is_regexp; | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | if ($path_element =~ /$match/i and $screen->{$match}->{'?'}) { | 
| 485 |  |  |  |  |  |  | $screen = $screen->{$match}; | 
| 486 |  |  |  |  |  |  | $path = $tail; | 
| 487 |  |  |  |  |  |  | push @$matches, $1 | 
| 488 |  |  |  |  |  |  | if defined $1; | 
| 489 |  |  |  |  |  |  | $matched = 1; | 
| 490 |  |  |  |  |  |  | } | 
| 491 |  |  |  |  |  |  | } | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | return ($screen->{'?'}, $path, $matches) | 
| 494 |  |  |  |  |  |  | unless $matched; | 
| 495 |  |  |  |  |  |  | } | 
| 496 |  |  |  |  |  |  | } | 
| 497 |  |  |  |  |  |  | } | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | 1; |