1 package OpenSRF::Utils::Config::Section;
5 use vars qw/@ISA $AUTOLOAD/;
6 push @ISA, qw/OpenSRF::Utils/;
8 use OpenSRF::Utils (':common');
9 use Net::Domain qw/hostfqdn/;
11 our $VERSION = "1.000";
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,
194 =head2 OpenSRF::Utils::Config->load( config_file => '/some/config/file.cnf' )
196 Returns a OpenSRF::Utils::Config object representing the config file
197 that was loaded. The most recently loaded config file (hopefully the
198 only one per app) is stored at $OpenSRF::Utils::ConfigCache. Use
199 OpenSRF::Utils::Config::current() to get at it.
205 $pkg = ref($pkg) || $pkg;
209 (my $new_pkg = $args{config_file}) =~ s/\W+/_/g;
210 $new_pkg .= "::$pkg";
211 $new_section_pkg .= "${new_pkg}::Section";
217 sub section_pkg { return '$new_section_pkg'; }
219 package $new_section_pkg;
220 use base "${pkg}::Section";
225 return $new_pkg->_load( %args );
230 $pkg = ref($pkg) || $pkg;
235 if ((exists $$self{config_file} and OpenSRF::Utils::Config->current) and (OpenSRF::Utils::Config->current->FILE eq $$self{config_file}) and (!$self->{force})) {
236 delete $$self{force};
237 return OpenSRF::Utils::Config->current();
240 $self->_sub_builder('__id');
241 $self->FILE($$self{config_file});
242 delete $$self{config_file};
243 return undef unless ($self->FILE);
245 $self->load_config();
247 $self->mangle_dirs();
248 $self->mangle_logs();
250 $OpenSRF::Utils::ConfigCache = $self unless $self->nocache;
251 delete $$self{nocache};
252 delete $$self{force};
260 my @parts = (grep { UNIVERSAL::isa($_,'OpenSRF::Utils::Config::Section') } values %$self);
262 my $must_match = scalar(keys %filters);
264 foreach my $part (@parts) {
266 for my $fkey (keys %filters) {
267 $part_count++ if ($part->$key eq $filters{$key});
269 push @ok_parts, $part if ($part_count == $must_match);
277 return $OpenSRF::Utils::ConfigCache;
281 return shift()->__id(@_);
286 my $host = $ENV{'OSRF_HOSTNAME'} || hostfqdn();
288 $$self{env} = $self->section_pkg->new;
289 $$self{env}{hostname} = $host;
294 return unless ($self->logs && $self->dirs && $self->dirs->log_dir);
295 for my $i ( keys %{$self->logs} ) {
296 next if ($self->logs->$i =~ /^\//);
297 $self->logs->$i($self->dirs->log_dir."/".$self->logs->$i);
303 return unless ($self->dirs && $self->dirs->base_dir);
304 for my $i ( keys %{$self->dirs} ) {
305 if ( $i ne 'base_dir' ) {
306 next if ($self->dirs->$i =~ /^\//);
307 my $dir_tmp = $self->dirs->base_dir."/".$self->dirs->$i;
308 $dir_tmp =~ s#//#/#go;
309 $dir_tmp =~ s#/$##go;
310 $self->dirs->$i($dir_tmp);
317 my $parser = XML::LibXML->new();
319 # Hash of config values
322 # Return an XML::LibXML::Document object
323 my $config = $parser->parse_file($self->FILE);
326 OpenSRF::Utils::Logger->error("Could not open ".$self->FILE.": $!\n");
327 die "Could not open ".$self->FILE.": $!\n";
330 # Return an XML::LibXML::NodeList object matching all child elements
331 # of <config><opensrf>...
332 my $osrf_cfg = $config->findnodes('/config/opensrf/child::*');
334 # Iterate through the nodes to pull out key=>value pairs of config settings
335 foreach my $node ($osrf_cfg->get_nodelist()) {
338 # This will be overwritten if it's a scalar setting
339 $bootstrap{$node->nodeName()} = [];
341 foreach my $child_node ($node->childNodes) {
342 # from libxml/tree.h: nodeType 1 = ELEMENT_NODE
343 next if $child_node->nodeType() != 1;
345 # If the child node is an element, this element may
346 # have multiple values; therefore, push it into an array
347 my $content = OpenSRF::Utils::Config::extract_child($child_node);
348 push(@{$bootstrap{$node->nodeName()}}, $content) if $content;
352 $bootstrap{$node->nodeName()} = OpenSRF::Utils::Config::extract_text($node->textContent);
356 my $section = $self->section_pkg->new(\%bootstrap);
357 my $sub_name = $section->SECTION;
358 $self->_sub_builder($sub_name);
359 $self->$sub_name($section);
364 use OpenSRF::Utils::SettingsParser;
365 return OpenSRF::Utils::SettingsParser::XML2perl($node);
370 $self =~ s/^\s*([.*?])\s*$//m;
374 #------------------------------------------------------------------------------------------------------------------------------------
382 Elements containing heterogeneous child elements are treated as though they have the same element name;
385 <router>localhost</router>
386 <furniture>chair</furniture>
389 ... will simply generate a key=>value pair of C<< routers => ['localhost', 'chair'] >>.
393 No known bugs, but report any to open-ils-dev@list.georgialibraries.org or mrylander@gmail.com.
395 =head1 COPYRIGHT AND LICENSING
397 Copyright (C) 2000-2007, Mike Rylander
398 Copyright (C) 2007, Laurentian University, Dan Scott <dscott@laurentian.ca>
400 The OpenSRF::Utils::Config module is free software. You may distribute under the terms
401 of the GNU General Public License version 2 or greater.