configurationengine/source/plugins/common/ConeRulePlugin/ruleplugin/ruleml.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 '''
       
    17 A plugin implementation for rule generation.
       
    18 '''
       
    19 
       
    20 
       
    21 import os
       
    22 import sys
       
    23 import logging
       
    24 import shutil
       
    25 
       
    26 import __init__
       
    27 import re
       
    28 
       
    29 from ruleplugin import relations
       
    30 from cone.public import exceptions,plugin,utils,api,rules
       
    31 
       
    32 class RuleImpl(plugin.ImplBase):
       
    33     """
       
    34     MakeImpl plugin finds feature references that are configured in a .ruleml file
       
    35     and generate a rule from them
       
    36     """
       
    37     IMPL_TYPE_ID = 'ruleml'
       
    38     DEFAULT_INVOCATION_PHASE = 'pre'
       
    39     
       
    40     def __init__(self, ref, configuration, relation_container):
       
    41         """
       
    42         Overloading the default constructor
       
    43         """
       
    44         plugin.ImplBase.__init__(self,ref,configuration)
       
    45         self.logger = logging.getLogger('cone.ruleml(%s)' % self.ref)
       
    46         self.relation_container = relation_container
       
    47 
       
    48     def list_output_files(self):
       
    49         """
       
    50         Return a list of output files as an array. 
       
    51         """
       
    52         return []
       
    53     
       
    54     def generate(self, context=None):
       
    55         self.logger.info("Generating rules from %s" % self.ref)
       
    56         relation_container = self.get_relation_container()
       
    57         relation_container.context = context
       
    58         return relation_container.execute()
       
    59     
       
    60     def has_tag(self, tags, policy=None):
       
    61         # RuleML should always be executed, regardless of the tags
       
    62         return True
       
    63     
       
    64     def get_relation_container(self):
       
    65         return self.relation_container
       
    66 
       
    67 class RulemlRelationContainer(plugin.RelationContainer):
       
    68     """
       
    69     Relation container for RuleML rules.
       
    70     
       
    71     Basically this is a wrapper for rules.RelationContainer that adapts
       
    72     it to the interface of plugin.RelationContainer.
       
    73     """
       
    74     def __init__(self, configuration, source, rule_list, eval_globals):
       
    75         plugin.RelationContainer.__init__(self, configuration, source=source)
       
    76         self.logger = logging.getLogger('cone.ruleml_relation_container(%s)' % self.source)
       
    77         self.configuration = configuration
       
    78         self.relation_container = rules.RelationContainerImpl()
       
    79         self.eval_globals = eval_globals
       
    80         self.context = None
       
    81         for rule in rule_list:
       
    82             self.relation_container.add_relation(rule)
       
    83     
       
    84     def execute(self):
       
    85         results = []
       
    86         
       
    87         # Create the autoconfig if not done already
       
    88         plugin.get_autoconfig(self.configuration)
       
    89         
       
    90         # Register relations etc. to the rule engine.
       
    91         # Due to unit test issues the relations are not registered
       
    92         # in the relations module, but only for the duration of
       
    93         # rule parsing and execution
       
    94         relations.register()
       
    95         try:
       
    96             # Using the configuration to pass the eval globals dict to the
       
    97             # eval expression. The configuration only contains the globals
       
    98             # dict for the duration of the rule execution, so hopefully this
       
    99             # shouldn't mess anything up
       
   100             self._set_builtin_eval_globals()
       
   101             self.configuration._eval_expression_globals_dict = self.eval_globals
       
   102             for i, rel in enumerate(self.relation_container):
       
   103                 index = i + 1
       
   104                 
       
   105                 # Execute
       
   106                 self._execute_relation_and_log_error(rel, self.source, index)
       
   107                 
       
   108                 # Collect execution result if supported
       
   109                 if hasattr(rel, 'get_execution_result'):
       
   110                     result = rel.get_execution_result()
       
   111                     if isinstance(result, plugin.RelationExecutionResult):
       
   112                         result.source = self.source
       
   113                         result.index = index
       
   114                         results.append(result)
       
   115             
       
   116             del self.configuration._eval_expression_globals_dict
       
   117             
       
   118             if self.relation_container.has_errors():
       
   119                 for error in self.relation_container.get_errors():
       
   120                     self.logger.error(error)
       
   121             
       
   122             if self.context:
       
   123                 self.context.results += results
       
   124             return results
       
   125         finally:
       
   126             relations.unregister()
       
   127     
       
   128     def get_relation_count(self):
       
   129         return len(self.relation_container)
       
   130     
       
   131     def _set_builtin_eval_globals(self):
       
   132         """
       
   133         Add built-in attributes into the eval globals dictionary.
       
   134         """
       
   135         class RuleBuiltinsModule(object):
       
   136             pass
       
   137                 
       
   138         builtins = RuleBuiltinsModule()
       
   139         builtins.configuration = self.configuration
       
   140         
       
   141         self.eval_globals['ruleml'] = builtins
       
   142 
       
   143 class RuleImplReaderBase(plugin.ReaderBase):
       
   144     NAMESPACE = None # Used as a base class, so should have no namespace
       
   145     FILE_EXTENSIONS = ['ruleml']
       
   146     
       
   147     def __init__(self, resource_ref, configuration):
       
   148         self.resource_ref = resource_ref
       
   149         self.configuration = configuration
       
   150         self.logger = logging.getLogger('cone.ruleml(%s)' % self.resource_ref)
       
   151     
       
   152     @classmethod
       
   153     def read_impl(cls, resource_ref, configuration, etree):
       
   154         reader = cls(resource_ref, configuration)
       
   155         
       
   156         # Register relations etc. to the rule engine.
       
   157         # Due to unit test issues the relations are not registered
       
   158         # in the relations module, but only for the duration of
       
   159         # rule parsing and execution
       
   160         relations.register()
       
   161         try:
       
   162             rules = reader.parse_rules(etree)
       
   163             eval_globals = reader.parse_eval_globals(etree)
       
   164             
       
   165             relation_container = RulemlRelationContainer(
       
   166                 configuration   = configuration,
       
   167                 source          = resource_ref,
       
   168                 rule_list       = rules,
       
   169                 eval_globals    = eval_globals)
       
   170             
       
   171             impl = RuleImpl(resource_ref, configuration, relation_container)
       
   172         finally:
       
   173             relations.unregister()
       
   174         
       
   175         return impl
       
   176         
       
   177 class RuleImplReader1(RuleImplReaderBase):
       
   178     NAMESPACE = 'http://www.s60.com/xml/ruleml/1'
       
   179     
       
   180     def __init__(self, resource_ref, configuration):
       
   181         RuleImplReaderBase.__init__(self, resource_ref, configuration)
       
   182     
       
   183     def parse_rules(self, etree):
       
   184         rules = []
       
   185         for elem in etree.getiterator("{%s}rule" % self.NAMESPACE):
       
   186             rules.extend(relations.RelationFactory.get_relations(self.configuration, elem.text))
       
   187         return rules
       
   188     
       
   189     def parse_eval_globals(self, etree):
       
   190         return {}
       
   191 
       
   192 class RuleImplReader2(RuleImplReaderBase):
       
   193     NAMESPACE = 'http://www.s60.com/xml/ruleml/2'
       
   194     
       
   195     def __init__(self, resource_ref, configuration):
       
   196         RuleImplReaderBase.__init__(self, resource_ref, configuration)
       
   197     
       
   198     def parse_rules(self, etree):
       
   199         rules = []
       
   200         for elem in etree.getiterator("{%s}rule" % self.NAMESPACE):
       
   201             rules.extend(relations.RelationFactory.get_relations(self.configuration, self._replace_eval_blocks(elem.text)))
       
   202         return rules
       
   203     
       
   204     def parse_eval_globals(self, etree):
       
   205         eval_globals = {}
       
   206         for elem in etree.getiterator("{%s}eval_globals" % self.NAMESPACE):
       
   207             text = ""
       
   208             if elem.get('file') != None:
       
   209                 self._read_eval_globals_from_file(elem.get('file'), eval_globals)
       
   210             else:
       
   211                 try: 
       
   212                     # Strip surrounding whitespace, otherwise there might be Python
       
   213                     # indentation errors
       
   214                     text = elem.text.strip()
       
   215                     exec(text, eval_globals)
       
   216                 except Exception, e:
       
   217                     self.logger.warning('Failed to evaluate eval_globals block, exception: %s' % (e))
       
   218         return eval_globals
       
   219     
       
   220     def _read_eval_globals_from_file(self, relative_path, eval_globals):
       
   221         # Get the actual path (relative to the current implementation file)
       
   222         base_path = os.path.dirname(self.resource_ref)
       
   223         pyfile_path = os.path.normpath(os.path.join(base_path, relative_path)).replace('\\', '/')
       
   224         # Read the data and execute
       
   225         try:
       
   226             resource = None
       
   227             resource = self.configuration.get_resource(pyfile_path)
       
   228             text = resource.read()
       
   229             exec(text.replace('\r', ''), eval_globals)
       
   230         except Exception, e:
       
   231             self.logger.warning('Cannot import eval file: %s. Exception: %s' % (pyfile_path, e))
       
   232         finally:
       
   233             if resource is not None: resource.close()
       
   234         
       
   235     
       
   236     @classmethod
       
   237     def _replace_eval_blocks(cls, code):
       
   238         return utils.expand_delimited_tokens(
       
   239             string          = code,
       
   240             expander_func   = lambda ref, index: '__eval__ %r' % ref,
       
   241             delimiters      =('{%', '%}'))