configurationengine/source/plugins/common/ConeRulePlugin/ruleplugin/ruleml.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/plugins/common/ConeRulePlugin/ruleplugin/ruleml.py	Thu Mar 11 17:04:37 2010 +0200
@@ -0,0 +1,241 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description: 
+#
+'''
+A plugin implementation for rule generation.
+'''
+
+
+import os
+import sys
+import logging
+import shutil
+
+import __init__
+import re
+
+from ruleplugin import relations
+from cone.public import exceptions,plugin,utils,api,rules
+
+class RuleImpl(plugin.ImplBase):
+    """
+    MakeImpl plugin finds feature references that are configured in a .ruleml file
+    and generate a rule from them
+    """
+    IMPL_TYPE_ID = 'ruleml'
+    DEFAULT_INVOCATION_PHASE = 'pre'
+    
+    def __init__(self, ref, configuration, relation_container):
+        """
+        Overloading the default constructor
+        """
+        plugin.ImplBase.__init__(self,ref,configuration)
+        self.logger = logging.getLogger('cone.ruleml(%s)' % self.ref)
+        self.relation_container = relation_container
+
+    def list_output_files(self):
+        """
+        Return a list of output files as an array. 
+        """
+        return []
+    
+    def generate(self, context=None):
+        self.logger.info("Generating rules from %s" % self.ref)
+        relation_container = self.get_relation_container()
+        relation_container.context = context
+        return relation_container.execute()
+    
+    def has_tag(self, tags, policy=None):
+        # RuleML should always be executed, regardless of the tags
+        return True
+    
+    def get_relation_container(self):
+        return self.relation_container
+
+class RulemlRelationContainer(plugin.RelationContainer):
+    """
+    Relation container for RuleML rules.
+    
+    Basically this is a wrapper for rules.RelationContainer that adapts
+    it to the interface of plugin.RelationContainer.
+    """
+    def __init__(self, configuration, source, rule_list, eval_globals):
+        plugin.RelationContainer.__init__(self, configuration, source=source)
+        self.logger = logging.getLogger('cone.ruleml_relation_container(%s)' % self.source)
+        self.configuration = configuration
+        self.relation_container = rules.RelationContainerImpl()
+        self.eval_globals = eval_globals
+        self.context = None
+        for rule in rule_list:
+            self.relation_container.add_relation(rule)
+    
+    def execute(self):
+        results = []
+        
+        # Create the autoconfig if not done already
+        plugin.get_autoconfig(self.configuration)
+        
+        # Register relations etc. to the rule engine.
+        # Due to unit test issues the relations are not registered
+        # in the relations module, but only for the duration of
+        # rule parsing and execution
+        relations.register()
+        try:
+            # Using the configuration to pass the eval globals dict to the
+            # eval expression. The configuration only contains the globals
+            # dict for the duration of the rule execution, so hopefully this
+            # shouldn't mess anything up
+            self._set_builtin_eval_globals()
+            self.configuration._eval_expression_globals_dict = self.eval_globals
+            for i, rel in enumerate(self.relation_container):
+                index = i + 1
+                
+                # Execute
+                self._execute_relation_and_log_error(rel, self.source, index)
+                
+                # Collect execution result if supported
+                if hasattr(rel, 'get_execution_result'):
+                    result = rel.get_execution_result()
+                    if isinstance(result, plugin.RelationExecutionResult):
+                        result.source = self.source
+                        result.index = index
+                        results.append(result)
+            
+            del self.configuration._eval_expression_globals_dict
+            
+            if self.relation_container.has_errors():
+                for error in self.relation_container.get_errors():
+                    self.logger.error(error)
+            
+            if self.context:
+                self.context.results += results
+            return results
+        finally:
+            relations.unregister()
+    
+    def get_relation_count(self):
+        return len(self.relation_container)
+    
+    def _set_builtin_eval_globals(self):
+        """
+        Add built-in attributes into the eval globals dictionary.
+        """
+        class RuleBuiltinsModule(object):
+            pass
+                
+        builtins = RuleBuiltinsModule()
+        builtins.configuration = self.configuration
+        
+        self.eval_globals['ruleml'] = builtins
+
+class RuleImplReaderBase(plugin.ReaderBase):
+    NAMESPACE = None # Used as a base class, so should have no namespace
+    FILE_EXTENSIONS = ['ruleml']
+    
+    def __init__(self, resource_ref, configuration):
+        self.resource_ref = resource_ref
+        self.configuration = configuration
+        self.logger = logging.getLogger('cone.ruleml(%s)' % self.resource_ref)
+    
+    @classmethod
+    def read_impl(cls, resource_ref, configuration, etree):
+        reader = cls(resource_ref, configuration)
+        
+        # Register relations etc. to the rule engine.
+        # Due to unit test issues the relations are not registered
+        # in the relations module, but only for the duration of
+        # rule parsing and execution
+        relations.register()
+        try:
+            rules = reader.parse_rules(etree)
+            eval_globals = reader.parse_eval_globals(etree)
+            
+            relation_container = RulemlRelationContainer(
+                configuration   = configuration,
+                source          = resource_ref,
+                rule_list       = rules,
+                eval_globals    = eval_globals)
+            
+            impl = RuleImpl(resource_ref, configuration, relation_container)
+        finally:
+            relations.unregister()
+        
+        return impl
+        
+class RuleImplReader1(RuleImplReaderBase):
+    NAMESPACE = 'http://www.s60.com/xml/ruleml/1'
+    
+    def __init__(self, resource_ref, configuration):
+        RuleImplReaderBase.__init__(self, resource_ref, configuration)
+    
+    def parse_rules(self, etree):
+        rules = []
+        for elem in etree.getiterator("{%s}rule" % self.NAMESPACE):
+            rules.extend(relations.RelationFactory.get_relations(self.configuration, elem.text))
+        return rules
+    
+    def parse_eval_globals(self, etree):
+        return {}
+
+class RuleImplReader2(RuleImplReaderBase):
+    NAMESPACE = 'http://www.s60.com/xml/ruleml/2'
+    
+    def __init__(self, resource_ref, configuration):
+        RuleImplReaderBase.__init__(self, resource_ref, configuration)
+    
+    def parse_rules(self, etree):
+        rules = []
+        for elem in etree.getiterator("{%s}rule" % self.NAMESPACE):
+            rules.extend(relations.RelationFactory.get_relations(self.configuration, self._replace_eval_blocks(elem.text)))
+        return rules
+    
+    def parse_eval_globals(self, etree):
+        eval_globals = {}
+        for elem in etree.getiterator("{%s}eval_globals" % self.NAMESPACE):
+            text = ""
+            if elem.get('file') != None:
+                self._read_eval_globals_from_file(elem.get('file'), eval_globals)
+            else:
+                try: 
+                    # Strip surrounding whitespace, otherwise there might be Python
+                    # indentation errors
+                    text = elem.text.strip()
+                    exec(text, eval_globals)
+                except Exception, e:
+                    self.logger.warning('Failed to evaluate eval_globals block, exception: %s' % (e))
+        return eval_globals
+    
+    def _read_eval_globals_from_file(self, relative_path, eval_globals):
+        # Get the actual path (relative to the current implementation file)
+        base_path = os.path.dirname(self.resource_ref)
+        pyfile_path = os.path.normpath(os.path.join(base_path, relative_path)).replace('\\', '/')
+        # Read the data and execute
+        try:
+            resource = None
+            resource = self.configuration.get_resource(pyfile_path)
+            text = resource.read()
+            exec(text.replace('\r', ''), eval_globals)
+        except Exception, e:
+            self.logger.warning('Cannot import eval file: %s. Exception: %s' % (pyfile_path, e))
+        finally:
+            if resource is not None: resource.close()
+        
+    
+    @classmethod
+    def _replace_eval_blocks(cls, code):
+        return utils.expand_delimited_tokens(
+            string          = code,
+            expander_func   = lambda ref, index: '__eval__ %r' % ref,
+            delimiters      =('{%', '%}'))