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
115 use OpenSRF::Utils::Config;
117 my $config_obj = OpenSRF::Utils::Config->load( config_file => '/config/file.cnf' );
119 my $attrs_href = $config_obj->bootstrap();
121 $config_obj->bootstrap->loglevel(0);
123 open FH, '>'.$config_obj->FILE() . '.new';
124 print FH $config_obj;
129 This module is mainly used by other OpenSRF modules to load an OpenSRF
130 configuration file. OpenSRF configuration files are XML files that
131 contain a C<< <config> >> root element and an C<< <opensrf> >> child
132 element (in XPath notation, C</config/opensrf/>). Each child element
133 is converted into a hash key=>value pair. Elements that contain other
134 XML elements are pushed into arrays and added as an array reference to
135 the hash. Scalar values have whitespace trimmed from the left and
138 Child elements of C<< <config> >> other than C<< <opensrf> >> are
139 currently ignored by this module.
143 Given an OpenSRF configuration file named F<opensrf_core.xml> with the
146 <?xml version='1.0'?>
149 <router_name>router</router_name>
152 <router>localhost</router>
153 <router>otherhost</router>
156 <logfile>/var/log/osrfsys.log</logfile>
160 ... calling C<< OpenSRF::Utils::Config->load(config_file =>
161 'opensrf_core.xml') >> will create a hash with the following
165 router_name => 'router',
166 routers => ['localhost', 'otherhost'],
167 logfile => '/var/log/osrfsys.log'
170 You can retrieve any of these values by name from the bootstrap
171 section of C<$config_obj>; for example:
173 $config_obj->bootstrap->router_name
177 For compatibility with a previous version of OpenSRF configuration
178 files, the F</config/opensrf/> section has a hardcoded name of
179 B<bootstrap>. However, future iterations of this module may extend the
180 ability of the module to parse the entire OpenSRF configuration file
181 and provide sections named after the sibling elements of
184 Hashrefs of sections can be returned by calling a method of the object
185 of the same name as the section. They can be set by passing a hashref
186 back to the same method. Sections will B<NOT> be autovivicated,
196 $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
199 =head2 OpenSRF::Utils::Config->load( config_file => '/some/config/file.cnf' )
201 Returns a OpenSRF::Utils::Config object representing the config file
202 that was loaded. The most recently loaded config file (hopefully the
203 only one per app) is stored at $OpenSRF::Utils::ConfigCache. Use
204 OpenSRF::Utils::Config::current() to get at it.
210 $pkg = ref($pkg) || $pkg;
214 (my $new_pkg = $args{config_file}) =~ s/\W+/_/g;
215 $new_pkg .= "::$pkg";
216 $new_section_pkg .= "${new_pkg}::Section";
222 sub section_pkg { return '$new_section_pkg'; }
224 package $new_section_pkg;
225 use base "${pkg}::Section";
230 return $new_pkg->_load( %args );
235 $pkg = ref($pkg) || $pkg;
240 if ((exists $$self{config_file} and OpenSRF::Utils::Config->current) and (OpenSRF::Utils::Config->current->FILE eq $$self{config_file}) and (!$self->{force})) {
241 delete $$self{force};
242 return OpenSRF::Utils::Config->current();
245 $self->_sub_builder('__id');
246 $self->FILE($$self{config_file});
247 delete $$self{config_file};
248 return undef unless ($self->FILE);
250 $self->load_config();
252 $self->mangle_dirs();
253 $self->mangle_logs();
255 $OpenSRF::Utils::ConfigCache = $self unless $self->nocache;
256 delete $$self{nocache};
257 delete $$self{force};
265 my @parts = (grep { UNIVERSAL::isa($_,'OpenSRF::Utils::Config::Section') } values %$self);
267 my $must_match = scalar(keys %filters);
269 foreach my $part (@parts) {
271 for my $fkey (keys %filters) {
272 $part_count++ if ($part->$key eq $filters{$key});
274 push @ok_parts, $part if ($part_count == $must_match);
282 return $OpenSRF::Utils::ConfigCache;
286 return shift()->__id(@_);
291 my $host = $ENV{'OSRF_HOSTNAME'} || hostfqdn();
293 $$self{env} = $self->section_pkg->new;
294 $$self{env}{hostname} = $host;
299 return unless ($self->logs && $self->dirs && $self->dirs->log_dir);
300 for my $i ( keys %{$self->logs} ) {
301 next if ($self->logs->$i =~ /^\//);
302 $self->logs->$i($self->dirs->log_dir."/".$self->logs->$i);
308 return unless ($self->dirs && $self->dirs->base_dir);
309 for my $i ( keys %{$self->dirs} ) {
310 if ( $i ne 'base_dir' ) {
311 next if ($self->dirs->$i =~ /^\//);
312 my $dir_tmp = $self->dirs->base_dir."/".$self->dirs->$i;
313 $dir_tmp =~ s#//#/#go;
314 $dir_tmp =~ s#/$##go;
315 $self->dirs->$i($dir_tmp);
322 my $parser = XML::LibXML->new();
324 # Hash of config values
327 # Return an XML::LibXML::Document object
328 my $config = $parser->parse_file($self->FILE);
331 OpenSRF::Utils::Logger->error("Could not open ".$self->FILE.": $!\n");
332 die "Could not open ".$self->FILE.": $!\n";
335 # Return an XML::LibXML::NodeList object matching all child elements
336 # of <config><opensrf>...
337 my $osrf_cfg = $config->findnodes('/config/opensrf/child::*');
339 # Iterate through the nodes to pull out key=>value pairs of config settings
340 foreach my $node ($osrf_cfg->get_nodelist()) {
343 # This will be overwritten if it's a scalar setting
344 $bootstrap{$node->nodeName()} = [];
346 foreach my $child_node ($node->childNodes) {
347 # from libxml/tree.h: nodeType 1 = ELEMENT_NODE
348 next if $child_node->nodeType() != 1;
350 # If the child node is an element, this element may
351 # have multiple values; therefore, push it into an array
352 my $content = OpenSRF::Utils::Config::extract_child($child_node);
353 push(@{$bootstrap{$node->nodeName()}}, $content) if $content;
357 $bootstrap{$node->nodeName()} = OpenSRF::Utils::Config::extract_text($node->textContent);
361 my $section = $self->section_pkg->new(\%bootstrap);
362 my $sub_name = $section->SECTION;
363 $self->_sub_builder($sub_name);
364 $self->$sub_name($section);
369 use OpenSRF::Utils::SettingsParser;
370 return OpenSRF::Utils::SettingsParser::XML2perl($node);
375 $self =~ s/^\s*([.*?])\s*$//m;
379 #------------------------------------------------------------------------------------------------------------------------------------
387 Elements containing heterogeneous child elements are treated as though they have the same element name;
390 <router>localhost</router>
391 <furniture>chair</furniture>
394 ... will simply generate a key=>value pair of C<< routers => ['localhost', 'chair'] >>.
398 No known bugs, but report any to open-ils-dev@list.georgialibraries.org or mrylander@gmail.com.
400 =head1 COPYRIGHT AND LICENSING
402 Copyright (C) 2000-2007, Mike Rylander
403 Copyright (C) 2007, Laurentian University, Dan Scott <dscott@laurentian.ca>
405 The OpenSRF::Utils::Config module is free software. You may distribute under the terms
406 of the GNU General Public License version 2 or greater.