diff -r 000000000000 -r 2e8eeb919028 configurationengine/source/plugins/common/ConeRulePlugin/ruleplugin/ruleml.py --- /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 =('{%', '%}'))