1 package OpenSRF::Utils::Config::Section;
5 use vars qw/@ISA $AUTOLOAD $VERSION/;
6 push @ISA, qw/OpenSRF::Utils/;
8 use OpenSRF::Utils (':common');
9 use Net::Domain qw/hostfqdn/;
11 $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
16 #use overload '""' => \&OpenSRF::Utils::Config::dump_ini;
20 return $sec->__id(@_);
25 my $class = ref($self) || $self;
27 $self = bless {}, $class;
29 $self->_sub_builder('__id');
30 # Hard-code this to match old bootstrap.conf section name
31 $self->__id('bootstrap');
33 my $bootstrap = shift;
35 foreach my $key (sort keys %$bootstrap) {
36 $self->_sub_builder($key);
37 $self->$key($bootstrap->{$key});
43 package OpenSRF::Utils::Config;
45 use vars qw/@ISA $AUTOLOAD $VERSION $OpenSRF::Utils::ConfigCache/;
46 push @ISA, qw/OpenSRF::Utils/;
50 use OpenSRF::Utils (':common');
51 use OpenSRF::Utils::Logger;
52 use Net::Domain qw/hostfqdn/;
54 #use overload '""' => \&OpenSRF::Utils::Config::dump_ini;
58 my $config_file = shift;
60 return unless $config_file;
62 $class->load( config_file => $config_file);
70 if ($self->isa('OpenSRF::Utils::Config')) {
71 if (UNIVERSAL::isa(scalar(caller()), 'OpenSRF::Utils::Config' )) {
74 $string = "# Main File: " . $self->FILE . "\n\n" . $string;
77 for my $section ( ('__id', grep { $_ ne '__id' } sort keys %$self) ) {
78 next if ($section eq 'env' && $self->isa('OpenSRF::Utils::Config'));
79 if ($section eq '__id') {
80 $string .= '['.$self->SECTION."]\n" if ($self->isa('OpenSRF::Utils::Config::Section'));
81 } elsif (ref($self->$section)) {
82 if (ref($self->$section) =~ /ARRAY/o) {
83 $string .= "list:$section = ". join(', ', @{$self->$section}) . "\n";
84 } elsif (UNIVERSAL::isa($self->$section,'OpenSRF::Utils::Config::Section')) {
85 if ($self->isa('OpenSRF::Utils::Config::Section')) {
86 $string .= "subsection:$section = " . $self->$section->SECTION . "\n";
89 next if ($self->$section->{__sub} && !$included);
90 $string .= $self->$section . "\n";
92 } elsif (UNIVERSAL::isa($self->$section,'OpenSRF::Utils::Config')) {
93 $string .= $self->$section . "\n";
96 next if $section eq '__sub';
97 $string .= "$section = " . $self->$section . "\n";
101 $string =~ s/^/## /gm;
102 $string = "# Subfile: " . $self->FILE . "\n#" . '-'x79 . "\n".'#include "'.$self->FILE."\"\n". $string;
110 OpenSRF::Utils::Config
116 use OpenSRF::Utils::Config;
118 my $config_obj = OpenSRF::Utils::Config->load( config_file => '/config/file.cnf' );
120 my $attrs_href = $config_obj->bootstrap();
122 $config_obj->bootstrap->loglevel(0);
124 open FH, '>'.$config_obj->FILE() . '.new';
125 print FH $config_obj;
133 This module is mainly used by other OpenSRF modules to load an OpenSRF configuration file.
134 OpenSRF configuration files are XML files that contain a C<< <config> >> root element and an C<< <opensrf> >>
135 child element (in XPath notation, C</config/opensrf/>). Each child element is converted into a
136 hash key=>value pair. Elements that contain other XML elements are pushed into arrays and added
137 as an array reference to the hash. Scalar values have whitespace trimmed from the left and right
140 Child elements of C<< <config> >> other than C<< <opensrf> >> are currently ignored by this module.
144 Given an OpenSRF configuration file named F<opensrf_core.xml> with the following content:
146 <?xml version='1.0'?>
149 <router_name>router</router_name>
152 <router>localhost</router>
153 <router>otherhost</router>
156 <logfile>/openils/var/log/osrfsys.log</logfile>
160 ... calling C<< OpenSRF::Utils::Config->load(config_file => 'opensrf_core.xml') >> will create a hash
161 with the following structure:
164 router_name => 'router',
165 routers => ['localhost', 'otherhost'],
166 logfile => '/openils/var/log/osrfsys.log'
169 You can retrieve any of these values by name from the bootstrap section of C<$config_obj>; for example:
171 $config_obj->bootstrap->router_name
175 For compatibility with a previous version of OpenSRF configuration files, the F</config/opensrf/> section
176 has a hardcoded name of B<bootstrap>. However, future iterations of this module may extend the ability
177 of the module to parse the entire OpenSRF configuration file and provide sections named after the sibling
178 elements of C</config/opensrf>.
180 Hashrefs of sections can be returned by calling a method of the object of the same name as the section.
181 They can be set by passing a hashref back to the same method. Sections will B<NOT> be autovivicated, though.
190 $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
193 =head2 OpenSRF::Utils::Config->load( config_file => '/some/config/file.cnf' )
195 Returns a OpenSRF::Utils::Config object representing the config file that was loaded.
196 The most recently loaded config file (hopefully the only one per app)
197 is stored at $OpenSRF::Utils::ConfigCache. Use OpenSRF::Utils::Config::current() to get at it.
204 $pkg = ref($pkg) || $pkg;
208 (my $new_pkg = $args{config_file}) =~ s/\W+/_/g;
209 $new_pkg .= "::$pkg";
210 $new_section_pkg .= "${new_pkg}::Section";
216 sub section_pkg { return '$new_section_pkg'; }
218 package $new_section_pkg;
219 use base "${pkg}::Section";
224 return $new_pkg->_load( %args );
229 $pkg = ref($pkg) || $pkg;
234 if ((exists $$self{config_file} and OpenSRF::Utils::Config->current) and (OpenSRF::Utils::Config->current->FILE eq $$self{config_file}) and (!$self->{force})) {
235 delete $$self{force};
236 return OpenSRF::Utils::Config->current();
239 $self->_sub_builder('__id');
240 $self->FILE($$self{config_file});
241 delete $$self{config_file};
242 return undef unless ($self->FILE);
244 $self->load_config();
246 $self->mangle_dirs();
247 $self->mangle_logs();
249 $OpenSRF::Utils::ConfigCache = $self unless $self->nocache;
250 delete $$self{nocache};
251 delete $$self{force};
259 my @parts = (grep { UNIVERSAL::isa($_,'OpenSRF::Utils::Config::Section') } values %$self);
261 my $must_match = scalar(keys %filters);
263 foreach my $part (@parts) {
265 for my $fkey (keys %filters) {
266 $part_count++ if ($part->$key eq $filters{$key});
268 push @ok_parts, $part if ($part_count == $must_match);
276 return $OpenSRF::Utils::ConfigCache;
280 return shift()->__id(@_);
285 my $host = $ENV{'OSRF_HOSTNAME'} || hostfqdn();
287 $$self{env} = $self->section_pkg->new;
288 $$self{env}{hostname} = $host;
293 return unless ($self->logs && $self->dirs && $self->dirs->log_dir);
294 for my $i ( keys %{$self->logs} ) {
295 next if ($self->logs->$i =~ /^\//);
296 $self->logs->$i($self->dirs->log_dir."/".$self->logs->$i);
302 return unless ($self->dirs && $self->dirs->base_dir);
303 for my $i ( keys %{$self->dirs} ) {
304 if ( $i ne 'base_dir' ) {
305 next if ($self->dirs->$i =~ /^\//);
306 my $dir_tmp = $self->dirs->base_dir."/".$self->dirs->$i;
307 $dir_tmp =~ s#//#/#go;
308 $dir_tmp =~ s#/$##go;
309 $self->dirs->$i($dir_tmp);
316 my $parser = XML::LibXML->new();
318 # Hash of config values
321 # Return an XML::LibXML::Document object
322 my $config = $parser->parse_file($self->FILE);
325 OpenSRF::Utils::Logger->error("Could not open ".$self->FILE.": $!\n");
326 die "Could not open ".$self->FILE.": $!\n";
329 # Return an XML::LibXML::NodeList object matching all child elements
330 # of <config><opensrf>...
331 my $osrf_cfg = $config->findnodes('/config/opensrf/child::*');
333 # Iterate through the nodes to pull out key=>value pairs of config settings
334 foreach my $node ($osrf_cfg->get_nodelist()) {
337 # This will be overwritten if it's a scalar setting
338 $bootstrap{$node->nodeName()} = [];
340 foreach my $child_node ($node->childNodes) {
341 # from libxml/tree.h: nodeType 1 = ELEMENT_NODE
342 next if $child_node->nodeType() != 1;
344 # If the child node is an element, this element may
345 # have multiple values; therefore, push it into an array
346 push @{$bootstrap{$node->nodeName()}}, OpenSRF::Utils::Config::extract_text($child_node->textContent);
350 $bootstrap{$node->nodeName()} = OpenSRF::Utils::Config::extract_text($node->textContent);
354 my $section = $self->section_pkg->new(\%bootstrap);
355 my $sub_name = $section->SECTION;
356 $self->_sub_builder($sub_name);
357 $self->$sub_name($section);
363 $self =~ s/^\s*([.*?])\s*$//m;
367 #------------------------------------------------------------------------------------------------------------------------------------
375 Elements containing heterogeneous child elements are treated as though they have the same element name;
378 <router>localhost</router>
379 <furniture>chair</furniture>
382 ... will simply generate a key=>value pair of C<< routers => ['localhost', 'chair'] >>.
386 No known bugs, but report any to open-ils-dev@list.georgialibraries.org or mrylander@gmail.com.
388 =head1 COPYRIGHT AND LICENSING
390 Copyright (C) 2000-2007, Mike Rylander
391 Copyright (C) 2007, Laurentian University, Dan Scott <dscott@laurentian.ca>
393 The OpenSRF::Utils::Config module is free software. You may distribute under the terms
394 of the GNU General Public License version 2 or greater.