| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package OpenInteract::Startup; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | # $Id: Startup.pm,v 1.37 2003/03/13 03:26:34 lachoy Exp $ | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 1 |  |  | 1 |  | 877 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 46 |  | 
| 6 | 1 |  |  | 1 |  | 5 | use Cwd            qw( cwd ); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 83 |  | 
| 7 | 1 |  |  | 1 |  | 1093 | use Data::Dumper   qw( Dumper ); | 
|  | 1 |  |  |  |  | 7078 |  | 
|  | 1 |  |  |  |  | 87 |  | 
| 8 | 1 |  |  | 1 |  | 11 | use File::Basename qw( dirname ); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 73 |  | 
| 9 | 1 |  |  | 1 |  | 6 | use File::Path     qw(); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 18 |  | 
| 10 | 1 |  |  | 1 |  | 1304 | use Getopt::Long   qw( GetOptions ); | 
|  | 1 |  |  |  |  | 13756 |  | 
|  | 1 |  |  |  |  | 9 |  | 
| 11 | 1 |  |  | 1 |  | 762 | use OpenInteract::Config; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 44 |  | 
| 12 | 1 |  |  | 1 |  | 515 | use OpenInteract::Config::GlobalOverride; | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 35 |  | 
| 13 | 1 |  |  | 1 |  | 8 | use OpenInteract::Error; | 
|  | 1 |  |  |  |  | 21 |  | 
|  | 1 |  |  |  |  | 21 |  | 
| 14 | 1 |  |  | 1 |  | 884 | use OpenInteract::Package; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | use OpenInteract::PackageRepository; | 
| 16 |  |  |  |  |  |  | use SPOPS::ClassFactory; | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | $OpenInteract::Startup::VERSION = sprintf("%d.%02d", q$Revision: 1.37 $ =~ /(\d+)\.(\d+)/); | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | use constant DEBUG => 0; | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | my $TEMP_LIB_DIR = 'tmplib'; | 
| 23 |  |  |  |  |  |  | my $REPOS_CLASS  = 'OpenInteract::PackageRepository'; | 
| 24 |  |  |  |  |  |  | my $PKG_CLASS    = 'OpenInteract::Package'; | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | sub main_initialize { | 
| 27 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | # Ensure we can find the base configuration, and use it or read it in | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | return undef unless ( $p->{base_config} or $p->{base_config_file} ); | 
| 32 |  |  |  |  |  |  | my $bc = $p->{base_config} || | 
| 33 |  |  |  |  |  |  | $class->read_base_config({ filename => $p->{base_config_file} }); | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | # Create our main config object | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | my $C = $class->create_config({ base_config  => $bc }); | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | # Initialize the package repository class -- it's a SPOPS class, | 
| 40 |  |  |  |  |  |  | # but a really simple one | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | $REPOS_CLASS->class_initialize( $C ); | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | # Read in our fundamental modules -- these should be in our @INC | 
| 45 |  |  |  |  |  |  | # already, since the 'request_class' is in | 
| 46 |  |  |  |  |  |  | # 'OpenInteract/OpenInteract' and the 'stash_class' is in | 
| 47 |  |  |  |  |  |  | # 'MyApp/MyApp' | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | $class->require_module({ class => [ $bc->{request_class}, $bc->{stash_class} ] }); | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | # Either use a package list provided or read in all the packages from | 
| 52 |  |  |  |  |  |  | # the website package database | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | my $packages = []; | 
| 55 |  |  |  |  |  |  | my $repository = $REPOS_CLASS->fetch( undef, { directory => $bc->{website_dir} } ); | 
| 56 |  |  |  |  |  |  | if ( my $package_list = $p->{package_list} ) { | 
| 57 |  |  |  |  |  |  | foreach my $pkg_name ( @{ $p->{package_list} } ) { | 
| 58 |  |  |  |  |  |  | my $pkg_info = $repository->fetch_pacakge_by_name({ name => $pkg_name }); | 
| 59 |  |  |  |  |  |  | push @{ $packages }, $pkg_info  if ( $pkg_info ); | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  | else { | 
| 63 |  |  |  |  |  |  | $packages = $repository->fetch_all_packages(); | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | # We keep track of the package names currently installed and use them | 
| 67 |  |  |  |  |  |  | # elsewhere in the system | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | $C->{package_list} = [ map { $_->{name} } @{ $packages } ]; | 
| 70 |  |  |  |  |  |  | foreach my $pkg_info ( @{ $packages } ) { | 
| 71 |  |  |  |  |  |  | $class->process_package( $pkg_info, $C ); | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | $class->_process_global_overrides( $C ); | 
| 75 |  |  |  |  |  |  | $class->_require_extra_classes( $C ); | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | # Store the configuration for later use | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | my $stash_class = $bc->{stash_class}; | 
| 80 |  |  |  |  |  |  | $stash_class->set_stash( 'config', $C ); | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | # Create an instance of $R since later steps might need it -- | 
| 83 |  |  |  |  |  |  | # particularly SPOPS initialization which may want a connection to | 
| 84 |  |  |  |  |  |  | # the datasource during setup. (Crossing fingers this doesn't mess | 
| 85 |  |  |  |  |  |  | # something up, particularly w/ parent/child sharing issues...) | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | my $request_class = $bc->{request_class}; | 
| 88 |  |  |  |  |  |  | my $R = $request_class->instance; | 
| 89 |  |  |  |  |  |  | $R->{stash_class} = $stash_class; | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | # The config object should now have all actions and SPOPS definitions | 
| 92 |  |  |  |  |  |  | # read in, so run any necessary configuration options | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | my $init_class = $class->finalize_configuration({ config => $C }); | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | # Tell OpenInteract::Request to setup aliases if they haven't already | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | if ( $p->{alias_init} ) { | 
| 99 |  |  |  |  |  |  | $request_class->setup_aliases; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | # Initialize all the SPOPS object classes | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | if ( $p->{spops_init} ) { | 
| 105 |  |  |  |  |  |  | $class->initialize_spops({ config => $C, class => $init_class }); | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | # Read in all the classes for all configured conductors | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | my @conductor_classes = (); | 
| 111 |  |  |  |  |  |  | foreach my $conductor ( keys %{ $C->{conductor} } ) { | 
| 112 |  |  |  |  |  |  | push @conductor_classes, $C->{conductor}{ $conductor }{class}; | 
| 113 |  |  |  |  |  |  | } | 
| 114 |  |  |  |  |  |  | $class->require_module({ class => \@conductor_classes }); | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | # Read in the modules referred to in the 'system_alias' key from | 
| 117 |  |  |  |  |  |  | # the configuration -- EXCEPT for anything beginning with the | 
| 118 |  |  |  |  |  |  | # website name since that's an SPOPS object and has already been | 
| 119 |  |  |  |  |  |  | # created | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | my @system_alias_classes = grep ! /^$bc->{website_name}/, values %{ $C->{system_alias} }; | 
| 122 |  |  |  |  |  |  | $class->require_module({ class => \@system_alias_classes }); | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | DEBUG && _w( 2, "Contents of INC: @INC" ); | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | # All done! Return the configuration object so the user can | 
| 127 |  |  |  |  |  |  | # do whatever else is necessary | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | return ( $init_class, $C ); | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | sub setup_static_environment_options { | 
| 134 |  |  |  |  |  |  | my ( $class, $usage, $options, $params ) = @_; | 
| 135 |  |  |  |  |  |  | $options ||= {}; | 
| 136 |  |  |  |  |  |  | my ( $OPT_website_dir ); | 
| 137 |  |  |  |  |  |  | $options->{'website_dir=s'} = \$OPT_website_dir; | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | # Get the options | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | GetOptions( %{ $options } ); | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | if ( ! $OPT_website_dir and $ENV{OIWEBSITE} ) { | 
| 144 |  |  |  |  |  |  | warn "Using ($ENV{OIWEBSITE}) for 'website_dir'.\n"; | 
| 145 |  |  |  |  |  |  | $OPT_website_dir = $ENV{OIWEBSITE}; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | unless ( -d $OPT_website_dir ) { | 
| 149 |  |  |  |  |  |  | die "$usage\n Parameter 'website_dir' must refer to an OpenInteract website directory!\n"; | 
| 150 |  |  |  |  |  |  | } | 
| 151 |  |  |  |  |  |  | return $class->setup_static_environment( $OPT_website_dir, undef, $params ); | 
| 152 |  |  |  |  |  |  | } | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | # Use this if you want to setup the OpenInteract environment outside | 
| 156 |  |  |  |  |  |  | # of the web application server -- just pass in the website directory! | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | sub setup_static_environment { | 
| 159 |  |  |  |  |  |  | my ( $class, $website_dir, $su_passwd, $params ) = @_; | 
| 160 |  |  |  |  |  |  | die "Directory ($website_dir) is not a valid directory!\n" unless ( -d $website_dir ); | 
| 161 |  |  |  |  |  |  | $params ||= {}; | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | my $bc = $class->read_base_config({ dir => $website_dir }); | 
| 164 |  |  |  |  |  |  | unless ( $bc and ref $bc eq 'HASH' ) { | 
| 165 |  |  |  |  |  |  | die "No base configuration file found in website directory ($website_dir)" ; | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | $class->create_temp_lib( $bc, $params->{temp_lib} ); | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | unshift @INC, $website_dir; | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | my ( $init, $C ) = $class->main_initialize({ base_config => $bc, | 
| 173 |  |  |  |  |  |  | alias_init  => 1, | 
| 174 |  |  |  |  |  |  | spops_init  => 1 }); | 
| 175 |  |  |  |  |  |  | my $REQUEST_CLASS = $C->{server_info}{request_class}; | 
| 176 |  |  |  |  |  |  | my $R = $REQUEST_CLASS->instance; | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | $R->{stash_class} = $C->{server_info}{stash_class}; | 
| 179 |  |  |  |  |  |  | $R->stash( 'config', $C ); | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | # If we were given the superuser password, retrieve the user and | 
| 182 |  |  |  |  |  |  | # check the password | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | if ( $su_passwd ) { | 
| 185 |  |  |  |  |  |  | my $user = $R->user->fetch( 1, { skip_security => 1 }); | 
| 186 |  |  |  |  |  |  | die "Cannot create superuser!" unless ( $user ); | 
| 187 |  |  |  |  |  |  | unless ( $user->check_password( $su_passwd ) ) { | 
| 188 |  |  |  |  |  |  | die "Password for superuser does not match!\n"; | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  | $R->{auth}{user} = $user; | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | return $R; | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | # Slimmed down initialization procedure -- just do everything | 
| 199 |  |  |  |  |  |  | # necessary to read the config and set various values there | 
| 200 |  |  |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | sub create_config { | 
| 202 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 203 |  |  |  |  |  |  | my $bc = $p->{base_config} || | 
| 204 |  |  |  |  |  |  | $class->read_base_config({ filename    => $p->{base_config_file}, | 
| 205 |  |  |  |  |  |  | website_dir => $p->{website_dir} }); | 
| 206 |  |  |  |  |  |  | return undef unless ( $bc ); | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | # Create the configuration file and set the base directory as configured; | 
| 209 |  |  |  |  |  |  | # also set other important classes from the config | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | my $config_file  = join( '/', $bc->{website_dir}, | 
| 212 |  |  |  |  |  |  | $bc->{config_dir}, $bc->{config_file} ); | 
| 213 |  |  |  |  |  |  | my $C = eval { OpenInteract::Config->instance( $bc->{config_type}, $config_file ) }; | 
| 214 |  |  |  |  |  |  | if ( $@ ) { | 
| 215 |  |  |  |  |  |  | die "Cannot read configuration file! Error: $@\n"; | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | # This information will be set for the life of the config object, | 
| 219 |  |  |  |  |  |  | # which should be as long as the apache child is alive if we're using | 
| 220 |  |  |  |  |  |  | # mod_perl, and will be set in the returned config object in any case | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | $C->{dir}{base}                  = $bc->{website_dir}; | 
| 223 |  |  |  |  |  |  | $C->{dir}{interact}              = $bc->{base_dir}; | 
| 224 |  |  |  |  |  |  | $C->{server_info}{request_class} = $bc->{request_class}; | 
| 225 |  |  |  |  |  |  | $C->{server_info}{stash_class}   = $bc->{stash_class}; | 
| 226 |  |  |  |  |  |  | $C->{server_info}{website_name}  = $bc->{website_name}; | 
| 227 |  |  |  |  |  |  | return $C; | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | # Method to copy all .pm files from all packages in a website to a | 
| 232 |  |  |  |  |  |  | # separate directory -- if it currently exists we clear it out first. | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | sub create_temp_lib { | 
| 235 |  |  |  |  |  |  | my ( $class, $base_config, $opt ) = @_; | 
| 236 |  |  |  |  |  |  | $opt ||= ''; | 
| 237 |  |  |  |  |  |  | my $site_dir = $base_config->{website_dir}; | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | my $lib_dir  = $base_config->{templib_dir} | 
| 240 |  |  |  |  |  |  | || "$site_dir/$TEMP_LIB_DIR"; | 
| 241 |  |  |  |  |  |  | unshift @INC, $lib_dir; | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | if ( -d $lib_dir and $opt eq 'lazy' ) { | 
| 244 |  |  |  |  |  |  | DEBUG && _w( 1, "Temp lib dir [$lib_dir] already exists and we're lazy;", | 
| 245 |  |  |  |  |  |  | "not copying modules to temp lib dir" ); | 
| 246 |  |  |  |  |  |  | return []; | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | File::Path::rmtree( $lib_dir ) if ( -d $lib_dir ); | 
| 250 |  |  |  |  |  |  | mkdir( $lib_dir, 0777 ); | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | my $site_repos = $REPOS_CLASS->fetch( undef, | 
| 253 |  |  |  |  |  |  | { directory => $base_config->{website_dir} } ); | 
| 254 |  |  |  |  |  |  | my $packages = $site_repos->fetch_all_packages(); | 
| 255 |  |  |  |  |  |  | my ( @all_files ); | 
| 256 |  |  |  |  |  |  | foreach my $package ( @{ $packages } ) { | 
| 257 |  |  |  |  |  |  | DEBUG && _w( 2, "Trying to copy files for package $package->{name}" ); | 
| 258 |  |  |  |  |  |  | my $files_copied = $PKG_CLASS->copy_modules( $package, $lib_dir ); | 
| 259 |  |  |  |  |  |  | push @all_files, @{ $files_copied }; | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  | DEBUG && _w( 3, "Copied ", scalar @all_files, " module files to [$lib_dir]" ); | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | # Now change permissions so all the files and directories are | 
| 264 |  |  |  |  |  |  | # world-everything, letting the process's umask kick in | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | chmod( 0666, @all_files ); | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | my %tmp_dirs = map { $_ => 1 } map { dirname( $_ ) } @all_files; | 
| 269 |  |  |  |  |  |  | chmod( 0777, keys %tmp_dirs ); | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | return \@all_files; | 
| 272 |  |  |  |  |  |  | } | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | sub read_package_list { | 
| 276 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 277 |  |  |  |  |  |  | return [] unless ( $p->{filename} or $p->{config} ); | 
| 278 |  |  |  |  |  |  | my $filename = $p->{filename} || | 
| 279 |  |  |  |  |  |  | join( '/', $p->{config}->get_dir( 'config' ), $p->{config}{package_list} ); | 
| 280 |  |  |  |  |  |  | open( PKG, $filename ) || die "Cannot open package list ($filename): $!"; | 
| 281 |  |  |  |  |  |  | my @packages = (); | 
| 282 |  |  |  |  |  |  | while (  ) { | 
| 283 |  |  |  |  |  |  | chomp; | 
| 284 |  |  |  |  |  |  | next if /^\s*\#/; | 
| 285 |  |  |  |  |  |  | next if /^\s*$/; | 
| 286 |  |  |  |  |  |  | s/^\s*//; | 
| 287 |  |  |  |  |  |  | s/\s*$//; | 
| 288 |  |  |  |  |  |  | push @packages, $_; | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  | close( PKG ); | 
| 291 |  |  |  |  |  |  | return \@packages; | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | # simple key-value config file | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | sub read_base_config { | 
| 299 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 300 |  |  |  |  |  |  | unless ( $p->{filename} ) { | 
| 301 |  |  |  |  |  |  | my $dir = $p->{dir} || $p->{website_dir}; | 
| 302 |  |  |  |  |  |  | if ( $dir ) { | 
| 303 |  |  |  |  |  |  | $p->{filename} = $class->create_base_config_filename( $dir ); | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  | return undef   unless ( -f $p->{filename} ); | 
| 307 |  |  |  |  |  |  | open( CONF, $p->{filename} ) || die "$!\n"; | 
| 308 |  |  |  |  |  |  | my $vars = {}; | 
| 309 |  |  |  |  |  |  | while (  ) { | 
| 310 |  |  |  |  |  |  | chomp; | 
| 311 |  |  |  |  |  |  | DEBUG && _w( 1, "Config line read: $_" ); | 
| 312 |  |  |  |  |  |  | next if ( /^\s*\#/ ); | 
| 313 |  |  |  |  |  |  | next if ( /^\s*$/ ); | 
| 314 |  |  |  |  |  |  | s/^\s*//; | 
| 315 |  |  |  |  |  |  | s/\s*$//; | 
| 316 |  |  |  |  |  |  | my ( $var, $value ) = split /\s+/, $_, 2; | 
| 317 |  |  |  |  |  |  | $vars->{ $var } = $value; | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  | return $vars; | 
| 320 |  |  |  |  |  |  | } | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | sub create_base_config_filename { | 
| 323 |  |  |  |  |  |  | my ( $class, $dir ) = @_; | 
| 324 |  |  |  |  |  |  | return join( '/', $dir, 'conf', 'base.conf' ); | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | # Params: | 
| 328 |  |  |  |  |  |  | #  filename - file with modules to read, one per line (skip blanks, commented lines) | 
| 329 |  |  |  |  |  |  | #  class    - arrayref of classes to require | 
| 330 |  |  |  |  |  |  | # (pick one) | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | sub require_module { | 
| 333 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 334 |  |  |  |  |  |  | my @success = (); | 
| 335 |  |  |  |  |  |  | if ( $p->{filename} ) { | 
| 336 |  |  |  |  |  |  | DEBUG && _w( 1, "Trying to open file $p->{filename}" ); | 
| 337 |  |  |  |  |  |  | return [] unless ( -f $p->{filename} ); | 
| 338 |  |  |  |  |  |  | open( MOD, $p->{filename} ) || die "Cannot open $p->{filename}: $!"; | 
| 339 |  |  |  |  |  |  | while (  ) { | 
| 340 |  |  |  |  |  |  | next if ( /^\s*$/ ); | 
| 341 |  |  |  |  |  |  | next if ( /^\s*\#/ ); | 
| 342 |  |  |  |  |  |  | chomp; | 
| 343 |  |  |  |  |  |  | DEBUG && _w( 1, "Trying to require $_" ); | 
| 344 |  |  |  |  |  |  | eval "require $_"; | 
| 345 |  |  |  |  |  |  | if ( $@ ) { _w( 0, sprintf( " --require error: %-40s: %s", $_, $@ ) )  } | 
| 346 |  |  |  |  |  |  | else      { push @success, $_ } | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  | close( MOD ); | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  | elsif ( $p->{class} ) { | 
| 351 |  |  |  |  |  |  | $p->{class} = [ $p->{class} ] unless ( ref $p->{class} eq 'ARRAY' ); | 
| 352 |  |  |  |  |  |  | foreach ( @{ $p->{class} } ) { | 
| 353 |  |  |  |  |  |  | DEBUG && _w( 1, "Trying to require class ($_)" ); | 
| 354 |  |  |  |  |  |  | eval "require $_"; | 
| 355 |  |  |  |  |  |  | if ( $@ ) { _w( 0, sprintf( " --require error: %-40s (from %s): %s", $_, $p->{pkg_link}{$_}, $@ ) ) } | 
| 356 |  |  |  |  |  |  | else      { push @success, $_ } | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  | } | 
| 359 |  |  |  |  |  |  | return \@success; | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | # Params: | 
| 365 |  |  |  |  |  |  | #  config = config object | 
| 366 |  |  |  |  |  |  | #  package = name of package | 
| 367 |  |  |  |  |  |  | #  package_dir = arrayref of base package directories (optional, read from config if not passed) | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  | sub process_package { | 
| 370 |  |  |  |  |  |  | my ( $class, $pkg_info, $CONF ) = @_; | 
| 371 |  |  |  |  |  |  | return undef unless ( $pkg_info ); | 
| 372 |  |  |  |  |  |  | return undef unless ( $CONF ); | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | my $pkg_name = join( '-', $pkg_info->{name}, $pkg_info->{version} ); | 
| 375 |  |  |  |  |  |  | DEBUG && _w( 1, "Trying to process package ($pkg_name)" ); | 
| 376 |  |  |  |  |  |  |  | 
| 377 |  |  |  |  |  |  | my $site_pkg_dir = join( '/', $pkg_info->{website_dir}, $pkg_info->{package_dir} ); | 
| 378 |  |  |  |  |  |  | my $base_pkg_dir = join( '/', $pkg_info->{base_dir}, $pkg_info->{package_dir} ); | 
| 379 |  |  |  |  |  |  | DEBUG && _w( 1, "Pkg dirs: ($base_pkg_dir, $site_pkg_dir) for $pkg_name" ); | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | # Plow through the directories and find the module listings (to | 
| 382 |  |  |  |  |  |  | # include), action config (to parse and set) and the SPOPS config (to | 
| 383 |  |  |  |  |  |  | # parse and set). Base package first so its info can be overridden. | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | foreach my $package_dir ( $base_pkg_dir, $site_pkg_dir ) { | 
| 386 |  |  |  |  |  |  | my $conf_pkg_dir = "$package_dir/conf"; | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | # If the package does not have a 'list_module.dat', that's ok and the | 
| 389 |  |  |  |  |  |  | # 'require_module' class method will simply return an empty list. | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | $class->require_module({ filename => "$conf_pkg_dir/list_module.dat" }); | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | # Read in the 'action' information and set in the config object | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | $class->read_action_definition({ filename => "$conf_pkg_dir/action.perl", | 
| 396 |  |  |  |  |  |  | config   => $CONF, | 
| 397 |  |  |  |  |  |  | package  => $pkg_info }); | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  | # Read in the SPOPS information and set in the config object; note | 
| 400 |  |  |  |  |  |  | # that we cannot *process* the SPOPS config yet because we must be | 
| 401 |  |  |  |  |  |  | # able to relate SPOPS objects, which cannot be done until all the | 
| 402 |  |  |  |  |  |  | # definitions are read in. (Yes, we could use 'map' here and above, | 
| 403 |  |  |  |  |  |  | # but it's confusing to people first reading the code) | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | $class->read_spops_definition({ filename => "$conf_pkg_dir/spops.perl", | 
| 406 |  |  |  |  |  |  | config   => $CONF, | 
| 407 |  |  |  |  |  |  | package  => $pkg_info }); | 
| 408 |  |  |  |  |  |  | } | 
| 409 |  |  |  |  |  |  | } | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | # Read in the action config info and set the information in the CONFIG | 
| 414 |  |  |  |  |  |  | # object. note that we overwrite whatever information is in the CONFIG | 
| 415 |  |  |  |  |  |  | # object -- this is a feature, not a bug, since it allows the base | 
| 416 |  |  |  |  |  |  | # installation to define lots of information and the website to only | 
| 417 |  |  |  |  |  |  | # override what it needs. | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | # Also save the key under which this was retrieved under 'key' | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  | sub read_action_definition { | 
| 422 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 423 |  |  |  |  |  |  | DEBUG && _w( 1, "Reading action definitions from ($p->{filename})" ); | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | # $CONF is easier to read and more consistent | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | my $CONF = $p->{config}; | 
| 428 |  |  |  |  |  |  | my $action_info = eval { $class->read_perl_file({ filename => $p->{filename} }) }; | 
| 429 |  |  |  |  |  |  | return undef  unless ( $action_info ); | 
| 430 |  |  |  |  |  |  | my @class_list = (); | 
| 431 |  |  |  |  |  |  | foreach my $action_key ( keys %{ $action_info } ) { | 
| 432 |  |  |  |  |  |  | $CONF->{action}{ $action_key }{key} = $action_key; | 
| 433 |  |  |  |  |  |  | foreach my $action_conf ( keys %{ $action_info->{ $action_key } } ) { | 
| 434 |  |  |  |  |  |  | $CONF->{action}{ $action_key }{ $action_conf } = | 
| 435 |  |  |  |  |  |  | $action_info->{ $action_key }{ $action_conf }; | 
| 436 |  |  |  |  |  |  | } | 
| 437 |  |  |  |  |  |  | if ( ref $p->{package} ) { | 
| 438 |  |  |  |  |  |  | $CONF->{action}{ $action_key }{package_name}    = $p->{package}{name}; | 
| 439 |  |  |  |  |  |  | $CONF->{action}{ $action_key }{package_version} = $p->{package}{version}; | 
| 440 |  |  |  |  |  |  | } | 
| 441 |  |  |  |  |  |  | } | 
| 442 |  |  |  |  |  |  | } | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | # See comments in read_action_definition | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | sub read_spops_definition { | 
| 449 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 450 |  |  |  |  |  |  | DEBUG && _w( 1, "Reading SPOPS definitions from ($p->{filename})" ); | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | # $CONF is easier to read and more consistent | 
| 453 |  |  |  |  |  |  | my $CONF = $p->{config}; | 
| 454 |  |  |  |  |  |  | my $spops_info = eval { $class->read_perl_file({ filename => $p->{filename} }) }; | 
| 455 |  |  |  |  |  |  | return undef unless ( $spops_info ); | 
| 456 |  |  |  |  |  |  | my @class_list = (); | 
| 457 |  |  |  |  |  |  | foreach my $spops_key ( keys %{ $spops_info } ) { | 
| 458 |  |  |  |  |  |  | $CONF->{SPOPS}{ $spops_key }{key} = $spops_key; | 
| 459 |  |  |  |  |  |  | foreach my $spops_conf ( keys %{ $spops_info->{ $spops_key } } ) { | 
| 460 |  |  |  |  |  |  | $CONF->{SPOPS}{ $spops_key }{ $spops_conf } = | 
| 461 |  |  |  |  |  |  | $spops_info->{ $spops_key }{ $spops_conf }; | 
| 462 |  |  |  |  |  |  | } | 
| 463 |  |  |  |  |  |  | if ( ref $p->{package} ) { | 
| 464 |  |  |  |  |  |  | $CONF->{SPOPS}{ $spops_key }{package_name}    = $p->{package}{name}; | 
| 465 |  |  |  |  |  |  | $CONF->{SPOPS}{ $spops_key }{package_version} = $p->{package}{version}; | 
| 466 |  |  |  |  |  |  | } | 
| 467 |  |  |  |  |  |  | } | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | # Read in a perl structure (probably generated by Data::Dumper) from a | 
| 472 |  |  |  |  |  |  | # file and return the actual structure. We should probably use | 
| 473 |  |  |  |  |  |  | # SPOPS::HashFile for this for consistency... | 
| 474 |  |  |  |  |  |  |  | 
| 475 |  |  |  |  |  |  | sub read_perl_file { | 
| 476 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 477 |  |  |  |  |  |  | return undef unless ( -f $p->{filename} ); | 
| 478 |  |  |  |  |  |  | eval { open( INFO, $p->{filename} ) || die $! }; | 
| 479 |  |  |  |  |  |  | if ( $@ ) { | 
| 480 |  |  |  |  |  |  | warn "Cannot open config file for evaluation ($p->{filename}): $@ "; | 
| 481 |  |  |  |  |  |  | return undef; | 
| 482 |  |  |  |  |  |  | } | 
| 483 |  |  |  |  |  |  | local $/ = undef; | 
| 484 |  |  |  |  |  |  | no strict; | 
| 485 |  |  |  |  |  |  | my $info = ; | 
| 486 |  |  |  |  |  |  | close( INFO ); | 
| 487 |  |  |  |  |  |  | my $data = eval $info; | 
| 488 |  |  |  |  |  |  | if ( $@ ) { | 
| 489 |  |  |  |  |  |  | die "Cannot read data structure! from $p->{filename}\nError: $@"; | 
| 490 |  |  |  |  |  |  | } | 
| 491 |  |  |  |  |  |  | return $data; | 
| 492 |  |  |  |  |  |  | } | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | # Everything has been read in, now just finalize aliases and so on | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | sub finalize_configuration { | 
| 498 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 499 |  |  |  |  |  |  | my $CONF = $p->{config}; | 
| 500 |  |  |  |  |  |  | my $REQUEST_CLASS      = $CONF->{server_info}{request_class}; | 
| 501 |  |  |  |  |  |  | my $STASH_CLASS        = $CONF->{server_info}{stash_class}; | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | # Create all the packages and subroutines on the fly as necessary | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | DEBUG && _w( 1, "Trying to configure SPOPS classes with SPOPS::ClassFactory" ); | 
| 506 |  |  |  |  |  |  | my $init_class = SPOPS::ClassFactory->create( $CONF->{SPOPS} ); | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  | # Setup the default responses, template classes, etc. for all the | 
| 509 |  |  |  |  |  |  | # actions read in. | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | $CONF->flatten_action_config; | 
| 512 |  |  |  |  |  |  | DEBUG && _w( 2, "Config: \n", Dumper( $CONF ) ); | 
| 513 |  |  |  |  |  |  | DEBUG && _w( 1, "Configuration read into Request ok." ); | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | # We also want to go through each alias in the 'SPOPS' config key | 
| 516 |  |  |  |  |  |  | # and setup aliases to the proper class within our Request class; so | 
| 517 |  |  |  |  |  |  | # $request_alias is just a reference to where we'll actually be storing | 
| 518 |  |  |  |  |  |  | # this stuff | 
| 519 |  |  |  |  |  |  |  | 
| 520 |  |  |  |  |  |  | my $request_alias = $REQUEST_CLASS->ALIAS; | 
| 521 |  |  |  |  |  |  | DEBUG && _w( 1, "Setting up SPOPS aliases" ); | 
| 522 |  |  |  |  |  |  | foreach my $init_alias ( keys %{ $CONF->{SPOPS} } ) { | 
| 523 |  |  |  |  |  |  | next if ( $init_alias =~ /^_/ ); | 
| 524 |  |  |  |  |  |  | my $info        = $CONF->{SPOPS}{ $init_alias }; | 
| 525 |  |  |  |  |  |  | my $class_alias = $info->{class}; | 
| 526 |  |  |  |  |  |  | my @alias_list  = ( $init_alias ); | 
| 527 |  |  |  |  |  |  | push @alias_list, @{ $info->{alias} } if ( $info->{alias} ); | 
| 528 |  |  |  |  |  |  | foreach my $alias ( @alias_list ) { | 
| 529 |  |  |  |  |  |  | DEBUG && _w( 1, "Tag $alias in $STASH_CLASS to be $class_alias" ); | 
| 530 |  |  |  |  |  |  | $request_alias->{ $alias }{ $STASH_CLASS } = $class_alias; | 
| 531 |  |  |  |  |  |  | } | 
| 532 |  |  |  |  |  |  | } | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | DEBUG && _w( 1, "Setting up System aliases" ); | 
| 535 |  |  |  |  |  |  | foreach my $alias ( keys %{ $CONF->{system_alias} } ) { | 
| 536 |  |  |  |  |  |  | $request_alias->{ $alias }{ $STASH_CLASS } = $CONF->{system_alias}{ $alias }; | 
| 537 |  |  |  |  |  |  | } | 
| 538 |  |  |  |  |  |  | DEBUG && _w( 1, "Setup object and system aliases ok" ); | 
| 539 |  |  |  |  |  |  | return $init_class; | 
| 540 |  |  |  |  |  |  | } | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  |  | 
| 543 |  |  |  |  |  |  | # Plow through a list of classes and call the class_initialize | 
| 544 |  |  |  |  |  |  | # method on each; ok to call OpenInteract::Startup->initialize_spops( ... ) | 
| 545 |  |  |  |  |  |  | # from the mod_perl child init handler | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | sub initialize_spops { | 
| 548 |  |  |  |  |  |  | my ( $class, $p ) = @_; | 
| 549 |  |  |  |  |  |  | return undef unless ( ref $p->{class} ); | 
| 550 |  |  |  |  |  |  | return undef unless ( ref $p->{config} ); | 
| 551 |  |  |  |  |  |  | my @success = (); | 
| 552 |  |  |  |  |  |  |  | 
| 553 |  |  |  |  |  |  | # Just cycle through and initialize each | 
| 554 |  |  |  |  |  |  |  | 
| 555 |  |  |  |  |  |  | foreach my $spops_class ( @{ $p->{class} } ) { | 
| 556 |  |  |  |  |  |  | eval { $spops_class->class_initialize( $p->{config} ); }; | 
| 557 |  |  |  |  |  |  | push @success, $spops_class unless ( $@ ); | 
| 558 |  |  |  |  |  |  | DEBUG && _w( 1, sprintf( "%-40s: %-30s","init: $spops_class", ( $@ ) ? $@ : 'ok' ) ); | 
| 559 |  |  |  |  |  |  | } | 
| 560 |  |  |  |  |  |  | return \@success; | 
| 561 |  |  |  |  |  |  | } | 
| 562 |  |  |  |  |  |  |  | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | # Do any global overrides for both SPOPS and the action table entries. | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | sub _process_global_overrides { | 
| 567 |  |  |  |  |  |  | my ( $class, $config ) = @_; | 
| 568 |  |  |  |  |  |  | my $override_spops_file = join( '/', $config->{dir}{base}, | 
| 569 |  |  |  |  |  |  | $config->{override}{spops_file} ); | 
| 570 |  |  |  |  |  |  | my $override_action_file = join( '/', $config->{dir}{base}, | 
| 571 |  |  |  |  |  |  | $config->{override}{action_file} ); | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | if ( -f $override_spops_file ) { | 
| 574 |  |  |  |  |  |  | my $override_spops = OpenInteract::Config::GlobalOverride->new( | 
| 575 |  |  |  |  |  |  | { filename => $override_spops_file } ); | 
| 576 |  |  |  |  |  |  | $override_spops->apply_rules( $config->{SPOPS} ); | 
| 577 |  |  |  |  |  |  | } | 
| 578 |  |  |  |  |  |  | if ( -f $override_action_file ) { | 
| 579 |  |  |  |  |  |  | my $override_action = OpenInteract::Config::GlobalOverride->new( | 
| 580 |  |  |  |  |  |  | { filename => $override_action_file } ); | 
| 581 |  |  |  |  |  |  | $override_action->apply_rules( $config->{action} ); | 
| 582 |  |  |  |  |  |  | } | 
| 583 |  |  |  |  |  |  | } | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | sub _require_extra_classes { | 
| 587 |  |  |  |  |  |  | my ( $class, $config ) = @_; | 
| 588 |  |  |  |  |  |  | my ( %require_class ); | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | my $action_require = $class->_find_extra_action_classes( $config ); | 
| 591 |  |  |  |  |  |  | my $spops_require  = $class->_find_extra_spops_classes( $config ); | 
| 592 |  |  |  |  |  |  |  | 
| 593 |  |  |  |  |  |  | # Read in all the classes specified by the packages | 
| 594 |  |  |  |  |  |  |  | 
| 595 |  |  |  |  |  |  | my $successful_action = $class->require_module({ | 
| 596 |  |  |  |  |  |  | class    => [ keys %{ $action_require } ], | 
| 597 |  |  |  |  |  |  | pkg_link => $action_require }); | 
| 598 |  |  |  |  |  |  | if ( scalar @{ $successful_action } != scalar keys %{ $action_require } ) { | 
| 599 |  |  |  |  |  |  | my %all_tried = map { $_ => 1 } keys %{ $action_require }; | 
| 600 |  |  |  |  |  |  | delete $all_tried{ $_ } for ( @{ $successful_action } ); | 
| 601 |  |  |  |  |  |  | _w( 0, "Some action classes were not required: ", | 
| 602 |  |  |  |  |  |  | join( ', ', keys %all_tried ) ); | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | my $successful_spops = $class->require_module({ | 
| 606 |  |  |  |  |  |  | class    => [ keys %{ $spops_require } ], | 
| 607 |  |  |  |  |  |  | pkg_link => $spops_require }); | 
| 608 |  |  |  |  |  |  | if ( scalar @{ $successful_spops } != scalar keys %{ $spops_require } ) { | 
| 609 |  |  |  |  |  |  | my %all_tried = map { $_ => 1 } keys %{ $spops_require }; | 
| 610 |  |  |  |  |  |  | delete $all_tried{ $_ } for ( @{ $successful_spops } ); | 
| 611 |  |  |  |  |  |  | _w( 0, "Some SPOPS classes were not required: ", | 
| 612 |  |  |  |  |  |  | join( ', ', keys %all_tried ) ); | 
| 613 |  |  |  |  |  |  | } | 
| 614 |  |  |  |  |  |  | } | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | sub _find_extra_action_classes { | 
| 618 |  |  |  |  |  |  | my ( $class, $config ) = @_; | 
| 619 |  |  |  |  |  |  | my %map = (); | 
| 620 |  |  |  |  |  |  | my $action = $config->{action}; | 
| 621 |  |  |  |  |  |  | foreach my $key ( keys %{ $action } ) { | 
| 622 |  |  |  |  |  |  | next unless ( $key and $action->{ $key }); | 
| 623 |  |  |  |  |  |  | my $package = $action->{ $key }{package_name}; | 
| 624 |  |  |  |  |  |  | if ( $action->{ $key }{class} ) { | 
| 625 |  |  |  |  |  |  | $map{ $action->{ $key }{class} } = $package | 
| 626 |  |  |  |  |  |  | } | 
| 627 |  |  |  |  |  |  | if ( $action->{ $key }{filter} ) { | 
| 628 |  |  |  |  |  |  | if ( ref $action->{ $key }{filter} eq 'ARRAY' ) { | 
| 629 |  |  |  |  |  |  | $map{ $_ } = $package for ( @{ $action->{ $key }{filter} } ); | 
| 630 |  |  |  |  |  |  | } | 
| 631 |  |  |  |  |  |  | else { | 
| 632 |  |  |  |  |  |  | $map{ $action->{ $key }{filter} } = $package | 
| 633 |  |  |  |  |  |  | } | 
| 634 |  |  |  |  |  |  | } | 
| 635 |  |  |  |  |  |  | if ( $action->{ $key }{error} ) { | 
| 636 |  |  |  |  |  |  | if ( ref $action->{ $key }{error} eq 'ARRAY' ) { | 
| 637 |  |  |  |  |  |  | $map{ $_ } = $package for ( @{ $action->{ $key }{error} } ); | 
| 638 |  |  |  |  |  |  | } | 
| 639 |  |  |  |  |  |  | else { | 
| 640 |  |  |  |  |  |  | $map{ $action->{ $key }{error} } = $package; | 
| 641 |  |  |  |  |  |  | } | 
| 642 |  |  |  |  |  |  | } | 
| 643 |  |  |  |  |  |  | } | 
| 644 |  |  |  |  |  |  | return \%map; | 
| 645 |  |  |  |  |  |  | } | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | sub _find_extra_spops_classes { | 
| 649 |  |  |  |  |  |  | my ( $class, $config ) = @_; | 
| 650 |  |  |  |  |  |  | my %map = (); | 
| 651 |  |  |  |  |  |  | my $spops = $config->{SPOPS}; | 
| 652 |  |  |  |  |  |  | foreach my $key ( keys %{ $spops } ) { | 
| 653 |  |  |  |  |  |  | next unless ( $key and $spops->{ $key }); | 
| 654 |  |  |  |  |  |  | my $package = $spops->{ $key }{package_name}; | 
| 655 |  |  |  |  |  |  | if ( ref $spops->{ $key }{isa} eq 'ARRAY' ) { | 
| 656 |  |  |  |  |  |  | map { $map{ $_ } = $package } @{ $spops->{ $key }{isa} }; | 
| 657 |  |  |  |  |  |  | } | 
| 658 |  |  |  |  |  |  | } | 
| 659 |  |  |  |  |  |  | return \%map; | 
| 660 |  |  |  |  |  |  | } | 
| 661 |  |  |  |  |  |  |  | 
| 662 |  |  |  |  |  |  |  | 
| 663 |  |  |  |  |  |  |  | 
| 664 |  |  |  |  |  |  | sub _w { | 
| 665 |  |  |  |  |  |  | return unless ( DEBUG >= shift ); | 
| 666 |  |  |  |  |  |  | my ( $pkg, $file, $line ) = caller; | 
| 667 |  |  |  |  |  |  | my @ci = caller(1); | 
| 668 |  |  |  |  |  |  | warn "$ci[3] ($line) >> ", join( ' ', @_ ), "\n"; | 
| 669 |  |  |  |  |  |  | } | 
| 670 |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  | 1; | 
| 672 |  |  |  |  |  |  |  | 
| 673 |  |  |  |  |  |  | __END__ |