1 # Copyright (C) 2002 Stanislav Sinyagin
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17 # $Id: XMLCompiler.pm,v 1.1 2010-12-27 00:03:45 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
21 package Torrus::ConfigTree::XMLCompiler;
23 use Torrus::ConfigTree::Writer;
24 our @ISA=qw(Torrus::ConfigTree::Writer);
26 use Torrus::ConfigTree;
27 use Torrus::ConfigTree::Validator;
28 use Torrus::SiteConfig;
30 use Torrus::TimeStamp;
39 my $class = ref($proto) || $proto;
41 $options{'-Rebuild'} = 1;
43 my $self = $class->SUPER::new( %options );
44 if( not defined( $self ) )
51 if( $options{'-NoDSRebuild'} )
53 $self->{'-NoDSRebuild'} = 1;
56 $self->{'files_processed'} = {};
67 &Torrus::DB::checkInterrupted();
69 $filename = Torrus::SiteConfig::findXMLFile($filename);
70 if( not defined( $filename ) )
75 # Make sure we process each file only once
76 if( $self->{'files_processed'}{$filename} )
82 $self->{'files_processed'}{$filename} = 1;
85 Verbose('Compiling ' . $filename);
88 my $parser = new XML::LibXML;
90 eval { $doc = $parser->parse_file( $filename ); };
93 Error("Failed to parse $filename: $@");
97 my $root = $doc->documentElement();
99 # Initialize the '/' element
104 # First of all process all pre-required files
105 foreach $node ( $root->getElementsByTagName('include') )
107 my $incfile = $node->getAttribute('filename');
110 Error("No filename given in include statement in $filename");
115 $ok = $self->compile( $incfile ) ? $ok:0;
119 foreach $node ( $root->getElementsByTagName('param-properties') )
121 $ok = $self->compile_paramprops( $node ) ? $ok:0;
124 if( not $self->{'-NoDSRebuild'} )
126 foreach $node ( $root->getElementsByTagName('definitions') )
128 $ok = $self->compile_definitions( $node ) ? $ok:0;
131 foreach $node ( $root->getElementsByTagName('datasources') )
133 $ok = $self->compile_ds( $node ) ? $ok:0;
137 foreach $node ( $root->getElementsByTagName('monitors') )
139 $ok = $self->compile_monitors( $node ) ? $ok:0;
142 foreach $node ( $root->getElementsByTagName('token-sets') )
144 $ok = $self->compile_tokensets( $node ) ? $ok:0;
147 foreach $node ( $root->getElementsByTagName('views') )
149 $ok = $self->compile_views( $node ) ? $ok:0;
156 sub compile_definitions
162 foreach my $def ( $node->getChildrenByTagName('def') )
164 &Torrus::DB::checkInterrupted();
166 my $name = $def->getAttribute('name');
167 my $value = $def->getAttribute('value');
170 Error("Definition without a name"); $ok = 0;
174 Error("Definition without value: $name"); $ok = 0;
176 elsif( defined $self->getDefinition($name) )
178 Error("Duplicate definition: $name"); $ok = 0;
182 $self->addDefinition($name, $value);
189 sub compile_paramprops
195 foreach my $def ( $node->getChildrenByTagName('prop') )
197 &Torrus::DB::checkInterrupted();
199 my $param = $def->getAttribute('param');
200 my $prop = $def->getAttribute('prop');
201 my $value = $def->getAttribute('value');
202 if( not $param or not $prop or not defined($value) )
204 Error("Property definition error"); $ok = 0;
208 $self->setParamProperty($param, $prop, $value);
216 # Process <param name="name" value="value"/> and put them into DB.
217 # Usage: $self->compile_params($node, $name);
226 &Torrus::DB::checkInterrupted();
229 foreach my $p_node ( $node->getChildrenByTagName('param') )
231 my $param = $p_node->getAttribute('name');
232 my $value = $p_node->getAttribute('value');
233 if( not defined($value) )
235 $value = $p_node->textContent();
239 Error("Parameter without name in $name"); $ok = 0;
243 # Remove spaces in the head and tail.
244 $value =~ s/^\s+//om;
245 $value =~ s/\s+$//om;
249 $self->setNodeParam($name, $param, $value);
253 $self->setParam($name, $param, $value);
267 # First, process templates. We expect them to be direct children of
270 foreach my $template ( $ds_node->getChildrenByTagName('template') )
272 my $name = $template->getAttribute('name');
275 Error("Template without a name"); $ok = 0;
277 elsif( defined $self->{'Templates'}->{$name} )
279 Error("Duplicate template names: $name"); $ok = 0;
283 $self->{'Templates'}->{$name} = $template;
287 # Recursively traverse the tree
288 $ok = $self->compile_subtrees( $ds_node, $self->token('/') ) ? $ok:0;
296 sub validate_nodename
301 return ( $name =~ /^[0-9A-Za-z_\-\.\:]+$/o and
316 foreach my $templateapp ( $node->getChildrenByTagName('apply-template') )
318 my $name = $templateapp->getAttribute('name');
321 my $path = $self->path($token);
322 Error("Template application without a name at $path"); $ok = 0;
326 my $template = $self->{'Templates'}->{$name};
327 if( not defined $template )
329 my $path = $self->path($token);
330 Error("Cannot find template named $name at $path"); $ok = 0;
334 $ok = $self->compile_subtrees
335 ($template, $token, $iamLeaf) ? $ok:0;
340 $ok = $self->compile_params($node, $token, 1);
342 # Handle aliases -- we are still in compile_subtrees()
344 foreach my $alias ( $node->getChildrenByTagName('alias') )
346 my $apath = $alias->textContent();
347 $apath =~ s/\s+//mgo;
348 $ok = $self->setAlias($token, $apath) ? $ok:0;
351 foreach my $setvar ( $node->getChildrenByTagName('setvar') )
353 my $name = $setvar->getAttribute('name');
354 my $value = $setvar->getAttribute('value');
355 if( not defined( $name ) or not defined( $value ) )
357 my $path = $self->path($token);
358 Error("Setvar statement without name or value in $path"); $ok = 0;
362 $self->setVar( $token, $name, $value );
366 # Compile-time variables
368 foreach my $iftrue ( $node->getChildrenByTagName('iftrue') )
370 my $var = $iftrue->getAttribute('var');
371 if( not defined( $var ) )
373 my $path = $self->path($token);
374 Error("Iftrue statement without variable name in $path"); $ok = 0;
376 elsif( $self->isTrueVar( $token, $var ) )
378 $ok = $self->compile_subtrees( $iftrue, $token, $iamLeaf ) ? $ok:0;
382 foreach my $iffalse ( $node->getChildrenByTagName('iffalse') )
384 my $var = $iffalse->getAttribute('var');
385 if( not defined( $var ) )
387 my $path = $self->path($token);
388 Error("Iffalse statement without variable name in $path"); $ok = 0;
390 elsif( not $self->isTrueVar( $token, $var ) )
392 $ok = $self->compile_subtrees
393 ( $iffalse, $token, $iamLeaf ) ? $ok:0;
398 # Compile child nodes -- the last part of compile_subtrees()
402 foreach my $subtree ( $node->getChildrenByTagName('subtree') )
404 my $name = $subtree->getAttribute('name');
405 if( not defined( $name ) or length( $name ) == 0 )
407 my $path = $self->path($token);
408 Error("Subtree without a name at $path"); $ok = 0;
412 if( $self->validate_nodename( $name ) )
414 my $stoken = $self->addChild($token, $name.'/');
415 $ok = $self->compile_subtrees( $subtree, $stoken ) ? $ok:0;
419 my $path = $self->path($token);
420 Error("Invalid subtree name: $name at $path"); $ok = 0;
425 foreach my $leaf ( $node->getChildrenByTagName('leaf') )
427 my $name = $leaf->getAttribute('name');
428 if( not defined( $name ) or length( $name ) == 0 )
430 my $path = $self->path($token);
431 Error("Leaf without a name at $path"); $ok = 0;
435 if( $self->validate_nodename( $name ) )
437 my $ltoken = $self->addChild($token, $name);
438 $ok = $self->compile_subtrees( $leaf, $ltoken, 1 ) ? $ok:0;
442 my $path = $self->path($token);
443 Error("Invalid leaf name: $name at $path"); $ok = 0;
455 my $mon_node = shift;
458 foreach my $monitor ( $mon_node->getChildrenByTagName('monitor') )
460 my $mname = $monitor->getAttribute('name');
463 Error("Monitor without a name"); $ok = 0;
467 $ok = $self->addMonitor( $mname );
468 $ok = $self->compile_params($monitor, $mname) ? $ok:0;
472 foreach my $action ( $mon_node->getChildrenByTagName('action') )
474 my $aname = $action->getAttribute('name');
477 Error("Action without a name"); $ok = 0;
481 $self->addAction( $aname );
482 $ok = $self->compile_params($action, $aname);
489 sub compile_tokensets
492 my $tsets_node = shift;
495 $ok = $self->compile_params($tsets_node, 'SS') ? $ok:0;
497 foreach my $tokenset ( $tsets_node->getChildrenByTagName('token-set') )
499 my $sname = $tokenset->getAttribute('name');
502 Error("Token-set without a name"); $ok = 0;
506 $sname = 'S'. $sname;
507 $ok = $self->addTset( $sname );
508 $ok = $self->compile_params($tokenset, $sname) ? $ok:0;
519 my $parentname = shift;
522 foreach my $view ( $vw_node->getChildrenByTagName('view') )
524 my $vname = $view->getAttribute('name');
527 Error("View without a name"); $ok = 0;
531 $self->addView( $vname, $parentname );
532 $ok = $self->compile_params( $view, $vname ) ? $ok:0;
533 # Process child views
534 $ok = $self->compile_views( $view, $vname ) ? $ok:0;
546 # indent-tabs-mode: nil
547 # perl-indent-level: 4