import torrus 1.0.9
[freeside.git] / torrus / perllib / Torrus / ConfigBuilder.pm
diff --git a/torrus/perllib/Torrus/ConfigBuilder.pm b/torrus/perllib/Torrus/ConfigBuilder.pm
new file mode 100644 (file)
index 0000000..7762c00
--- /dev/null
@@ -0,0 +1,529 @@
+#  Copyright (C) 2002  Stanislav Sinyagin
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: ConfigBuilder.pm,v 1.1 2010-12-27 00:03:40 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# XML configuration builder
+
+package Torrus::ConfigBuilder;
+
+use strict;
+use XML::LibXML;
+use IO::File;
+
+use Torrus::Log;
+
+sub new
+{
+    my $self = {};
+    my $class = shift;
+    bless $self, $class;
+
+    my $doc = XML::LibXML->createDocument( "1.0", "UTF-8" );
+    my $root = $doc->createElement('configuration');
+    $doc->setDocumentElement( $root );
+    $self->{'doc'} = $doc;
+    $self->{'docroot'} = $root;
+
+    $root->appendChild($doc->createComment('DO NOT EDIT THIS FILE'));
+
+    my $dsnode = $doc->createElement('datasources');
+    $self->{'docroot'}->appendChild( $dsnode );
+    $self->{'datasources'} = $dsnode;
+
+    $self->{'required_templates'} = {};
+
+    $self->{'statistics'} = {};
+
+    $self->{'registry_overlays'} = [];
+    
+    return $self;
+}
+
+
+sub setRegistryOverlays
+{
+    my $self = shift;
+    
+    $self->{'registry_overlays'} = [];
+    push( @{$self->{'registry_overlays'}}, @_ );
+}
+
+
+sub lookupRegistry
+{
+    my $self = shift;
+    my $template = shift;
+
+    my $ret = undef;
+
+    foreach my $regOverlay ( @{$self->{'registry_overlays'}} )
+    {
+        if( defined( $regOverlay->{$template} ) )
+        {
+            $ret = $regOverlay->{$template};
+        }
+    }
+    
+    if( not defined( $ret ) and
+        defined( $Torrus::ConfigBuilder::templateRegistry{$template} ) )
+    {
+        $ret = $Torrus::ConfigBuilder::templateRegistry{$template};
+    }
+    
+    if( not defined( $ret ) )
+    {
+        if( scalar( %Torrus::ConfigBuilder::templateRegistry ) > 0 )
+        {
+            Warn('Template ' . $template .
+                 ' is not listed in ConfigBuilder template registry');
+        }
+    }
+
+    return $ret;
+}
+    
+
+
+
+sub addCreatorInfo
+{
+    my $self = shift;
+    my $creatorInfo = shift;
+
+    my $creatorNode = $self->{'doc'}->createElement('creator-info');
+    $creatorNode->appendText( $creatorInfo );
+    $self->{'docroot'}->insertBefore( $creatorNode, $self->{'datasources'} );
+}
+
+
+sub addRequiredFiles
+{
+    my $self = shift;
+
+    foreach my $file ( $self->requiredFiles() )
+    {
+        $self->addFileInclusion( $file );
+    }
+}
+
+
+sub addFileInclusion
+{
+    my $self = shift;
+    my $file = shift;
+
+    my $node = $self->{'doc'}->createElement('include');
+    $node->setAttribute( 'filename', $file );
+    $self->{'docroot'}->insertBefore( $node, $self->{'datasources'} );
+}
+
+
+sub startDefinitions
+{
+    my $self = shift;
+
+    my $node = $self->{'doc'}->createElement('definitions');
+    $self->{'docroot'}->insertBefore( $node, $self->{'datasources'} );
+    return $node;
+}
+
+
+sub addDefinition
+{
+    my $self = shift;
+    my $definitionsNode = shift;;
+    my $name = shift;
+    my $value = shift;
+
+    my $node = $self->{'doc'}->createElement('def');
+    $node->setAttribute( 'name', $name );
+    $node->setAttribute( 'value', $value );
+    $definitionsNode->appendChild( $node );
+}
+
+
+sub startParamProps
+{
+    my $self = shift;
+
+    my $node = $self->{'doc'}->createElement('param-properties');
+    $self->{'docroot'}->insertBefore( $node, $self->{'datasources'} );
+    return $node;
+}
+
+
+sub addParamProp
+{
+    my $self = shift;
+    my $propsNode = shift;;
+    my $param = shift;
+    my $prop = shift;
+    my $value = shift;
+
+    my $node = $self->{'doc'}->createElement('prop');
+    $node->setAttribute( 'param', $param );
+    $node->setAttribute( 'prop', $prop );
+    $node->setAttribute( 'value', $value );
+    $propsNode->appendChild( $node );
+}
+
+
+
+sub addSubtree
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $subtreeName = shift;
+    my $params = shift;      # hash reference with param name-value pairs
+    my $templates = shift;   # array reference with template names
+
+    return $self->addChildElement( 0, $parentNode, $subtreeName,
+                                   $params, $templates );
+}
+
+
+sub addLeaf
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $leafName = shift;
+    my $params = shift;      # hash reference with param name-value pairs
+    my $templates = shift;   # array reference with template names
+
+    return $self->addChildElement( 1, $parentNode, $leafName,
+                                   $params, $templates );
+}
+
+
+sub addChildElement
+{
+    my $self = shift;
+    my $isLeaf = shift;
+    my $parentNode = shift;
+    my $childName = shift;
+    my $params = shift;
+    my $templates = shift;
+
+    my $doc = $self->{'doc'};
+
+    if( not ref( $parentNode ) )
+    {
+        $parentNode = $self->{'datasources'};
+    }
+
+    my $childNode = $doc->createElement( $isLeaf ? 'leaf' : 'subtree' );
+    $childNode->setAttribute( 'name', $childName );
+    $childNode = $parentNode->appendChild( $childNode );
+
+    if( ref( $templates ) )
+    {
+        foreach my $tmpl ( sort @{$templates} )
+        {
+            $self->addTemplateApplication( $childNode, $tmpl );
+        }
+    }
+
+    $self->addParams( $childNode, $params );
+
+    return $childNode;
+}
+
+
+sub getChildSubtree
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $childName = shift;
+
+    if( not ref( $parentNode ) )
+    {
+        $parentNode = $self->{'datasources'};
+    }
+    
+    my @subtrees =
+        $parentNode->findnodes( 'subtree[@name="' . $childName . '"]' );
+    if( not @subtrees )
+    {
+        Error('Cannot find subtree named ' . $childName);
+        return undef;
+    }
+    return $subtrees[0];
+}
+
+
+# Reconstruct the path to the given subtree or leaf
+sub getElementPath
+{
+    my $self = shift;
+    my $node = shift;
+
+    my $path = '';
+    if( $node->nodeName() eq 'subtree' )
+    {
+        $path = '/';
+    }
+
+    while( not $node->isSameNode( $self->{'datasources'} ) )
+    {
+        $path = '/' . $node->getAttribute( 'name' ) . $path;
+        $node = $node->parentNode();
+    }
+    
+    return $path;
+}
+
+
+sub getTopSubtree
+{
+    my $self = shift;
+    return $self->{'datasources'};
+}
+
+
+sub addTemplateApplication
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $template = shift;
+
+    if( not ref( $parentNode ) )
+    {
+        $parentNode = $self->{'datasources'};
+    }
+
+    my $found = 0;
+
+    my $reg = $self->lookupRegistry( $template );
+    if( defined( $reg ) )
+    {
+        $self->{'required_templates'}{$template} = 1;
+        my $name = $reg->{'name'};
+        if( defined( $name ) )
+        {
+            $template = $name;
+        }
+    }
+    
+    my $tmplNode = $self->{'doc'}->createElement( 'apply-template' );
+    $tmplNode->setAttribute( 'name', $template );
+    $parentNode->appendChild( $tmplNode );
+}
+
+
+sub addParams
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $params = shift;
+
+    if( ref( $params ) )
+    {
+        foreach my $paramName ( sort keys %{$params} )
+        {
+            $self->addParam( $parentNode, $paramName, $params->{$paramName} );
+        }
+    }
+}
+
+
+sub addParam
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $param = shift;
+    my $value = shift;
+
+    if( not ref( $parentNode ) )
+    {
+        $parentNode = $self->{'datasources'};
+    }
+
+    my $paramNode = $self->{'doc'}->createElement( 'param' );
+    $paramNode->setAttribute( 'name', $param );
+    $paramNode->setAttribute( 'value', $value );
+    $parentNode->appendChild( $paramNode );
+}
+
+
+sub addAlias
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $aliasPath = shift;
+
+    if( not ref( $parentNode ) ) # I hope nobody would need this
+    {
+        $parentNode = $self->{'datasources'};
+    }
+
+    my $aliasNode = $self->{'doc'}->createElement( 'alias' );
+    $aliasNode->appendText( $aliasPath );
+    $parentNode->appendChild( $aliasNode );
+}
+
+
+sub setVar
+{
+    my $self = shift;
+    my $parentNode = shift;
+    my $name = shift;
+    my $value = shift;
+
+    my $setvarNode = $self->{'doc'}->createElement( 'setvar' );
+    $setvarNode->setAttribute( 'name', $name );
+    $setvarNode->setAttribute( 'value', $value );
+    $parentNode->appendChild( $setvarNode );
+}
+    
+    
+
+sub startMonitors
+{
+    my $self = shift;
+
+    my $node = $self->{'doc'}->createElement('monitors');
+    $self->{'docroot'}->appendChild( $node );
+    return $node;
+}
+
+
+sub addMonitorAction
+{
+    my $self = shift;
+    my $monitorsNode = shift;;
+    my $name = shift;
+    my $params = shift;
+
+    my $node = $self->{'doc'}->createElement('action');
+    $node->setAttribute( 'name', $name );
+    $monitorsNode->appendChild( $node );
+
+    $self->addParams( $node, $params );
+}
+
+
+sub addMonitor
+{
+    my $self = shift;
+    my $monitorsNode = shift;;
+    my $name = shift;
+    my $params = shift;
+
+    my $node = $self->{'doc'}->createElement('monitor');
+    $node->setAttribute( 'name', $name );
+    $monitorsNode->appendChild( $node );
+
+    $self->addParams( $node, $params );
+}
+
+
+sub startTokensets
+{
+    my $self = shift;
+
+    my $node = $self->{'doc'}->createElement('token-sets');
+    $self->{'docroot'}->appendChild( $node );
+    return $node;
+}
+
+
+sub addTokenset
+{
+    my $self = shift;
+    my $tsetsNode = shift;;
+    my $name = shift;
+    my $params = shift;
+
+    my $node = $self->{'doc'}->createElement('token-set');
+    $node->setAttribute( 'name', $name );
+    $tsetsNode->appendChild( $node );
+
+    $self->addParams( $node, $params );
+}
+
+
+sub addStatistics
+{
+    my $self = shift;
+
+    foreach my $stats ( sort keys %{$self->{'statistics'}} )
+    {
+        my $node = $self->{'doc'}->createElement('configbuilder-statistics');
+        $node->setAttribute( 'category', $stats );
+        $node->setAttribute( 'value', $self->{'statistics'}{$stats} );
+        $self->{'docroot'}->appendChild( $node );
+    }
+}
+
+
+
+sub requiredFiles
+{
+    my $self = shift;
+
+    my %files;
+    foreach my $template ( keys %{$self->{'required_templates'}} )
+    {
+        my $file;
+        my $reg = $self->lookupRegistry( $template );
+        if( defined( $reg ) )
+        {
+            $file = $reg->{'source'};
+        }
+        
+        if( defined( $file ) )
+        {
+            $files{$file} = 1;
+        }
+        else
+        {
+            Error('Source file is not defined for template ' . $template .
+                  ' in ConfigBuilder template registry');
+        }
+    }
+    return( sort keys %files );
+}
+
+
+
+sub toFile
+{
+    my $self = shift;
+    my $filename = shift;
+
+    my $fh = new IO::File('> ' . $filename);
+    if( defined( $fh ) )
+    {
+        my $ok = $self->{'doc'}->toFH( $fh, 2 );
+        $fh->close();
+        return $ok;
+    }
+    else
+    {
+        return undef;
+    }
+}
+
+1;
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End: