# Copyright (c) 2004-2005 DoCoMo Euro-Labs GmbH (Munich, Germany). # Copyright (c) 2001-2005 LOGILAB S.A. (Paris, FRANCE). # # http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Core elements for narval memory's : - error - start-plan - listen-on - quit The engine rely on those elements so this module should not be disabled ! :version: $Revision:$ :author: Logilab :copyright: 2001-2005 LOGILAB S.A. (Paris, FRANCE) 2004-2005 DoCoMo Euro-Labs GmbH (Munich, Germany) :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com """ __revision__ = "$Id: lib.py,v 1.78 2002/10/14 14:24:11 syt Exp $" __docformat__ = "restructuredtext en" from narval.public import AL_NS, NO_NS from narval.element import NSAttribute, ALElement from narval.xml_handlers import BaseXMLHandler, data_handler from narval.serialutils import yn_value, yn_rev_value from narval.interfaces.core import IError, IStartPlan, IListenOn class ErrorElement(ALElement): """element representing an error during a plan execution :ivar type: optional error family :ivar msg: error message """ __implements__ = (IError,) __xml_element__ = (AL_NS, 'error') __child_handler__ = data_handler('msg') type = NSAttribute(NO_NS, None, str, str) msg = '' from_msg = None def children_as_xml(self, encoding='UTF-8'): """return the XML representation of the children node of this element :type encoding: str :param encoding: the encoding to use in the returned string :rtype: str :return: XML string representing the element """ if self.msg: msg = self.msg if isinstance(msg, unicode): msg = msg.encode(encoding) return '' % msg return '' class StartPlanElement(ALElement): """start plan element: ask for plan instanciation from a recipe :ivar recipe: identifier (.) of the recipe to start :ivar context: optional context, i.e. a match expressions used to select original plan inputs from memory """ __implements__ = (IStartPlan,) __xml_element__ = (AL_NS, 'start-plan') class StartPlanXMLHandler(BaseXMLHandler): """XML handler for start-plan elements""" def start_element(self, name, attrs): """SAX callback: start a new xml node :type name: tuple :param name: the tag name as a tuple (uri, name) :type attrs: dict :param attrs: the node's attribute values, indexed by attribute's name as a tuple (uri, name) """ prefix, local = name if local == 'time': assert not self.elmt.delay time_def = (attrs.get((NO_NS, 'seconds'), '*'), attrs.get((NO_NS, 'minutes'), '*'), attrs.get((NO_NS, 'hours'), '*'), attrs.get((NO_NS, 'monthdays'), '*'), attrs.get((NO_NS, 'months'), '*'), attrs.get((NO_NS, 'weekdays'), '*')) self.elmt.time = time_def elif local == 'delay': assert not self.elmt.time delay = 0 for attr, fact in ( ('seconds', 1), ('minutes', 60), ('hours', 60*60), ('days', 60*60*24)): delay += int(attrs.get((NO_NS, attr), 0)) * fact self.elmt.delay = delay self.elmt.delay_period = yn_value(attrs.get((NO_NS, 'period'), 'no')) else: raise AssertionError('unknown start plan child %s' % local) __child_handler__ = StartPlanXMLHandler recipe = NSAttribute(NO_NS, None, str, str) cancelled = NSAttribute(NO_NS, False, yn_value, yn_rev_value) cancelled_by = NSAttribute(NO_NS, False, int, str) cancelling = NSAttribute(NO_NS, False, int, str) context_expression = NSAttribute(NO_NS, None, str, str) time = None delay = None delay_period = False # FIXME: serialize/deserialize attributes below ? context = None parent_plan, parent_step = None, None def children_as_xml(self, encoding): if self.time: return ('' % self.time) if self.delay: return ('' % ( self.delay, yn_rev_value(self.delay_period))) return '' def context_elements(self, memory): """return elements that should be used as context for the started plan """ if self.context_expression: context = memory.match_elements(self.context_expression) else: context = self.context return context or [] def cancel(self, by=None): """cancel this start plan of the one which have replaced it :type by: `StartPlanElement` or None :param by: the start plan element replacing this one if any :rtype: `StartPlanElement` :return: the actually canccelled start plan element """ if self.cancelled_by: return self.cancelled_by.cancel(by) assert not self.cancelled log(LOG_NOTICE, 'cancelling start plan %s (%s)' % (self.recipe, self.eid)) self.cancelled = True self.cancelled_by = by by.cancelling = self.eid return self class ListenOnElement(ALElement): """listen-on element: ask to open a control communication channel :ivar type: the protocol identifier string :ivar port: the server port :ivar host: the server host """ __implements__ = (IListenOn,) __xml_element__ = (AL_NS, 'listen-on') type = NSAttribute(NO_NS, None, str, str) host = NSAttribute(NO_NS, 'localhost', str, str) port = NSAttribute(NO_NS, None, int, str) class QuitElement(ALElement): """quit element: ask for narval shutdown""" __xml_element__ = (AL_NS, 'quit') class GroupAliasElement(ALElement): """group-alias element: map an actual cookbook or module to an alias name :ivar name: the alias name :ivar actual: the actual cookbook/module name """ __xml_element__ = (AL_NS, 'group-alias') name = NSAttribute(NO_NS, None, str, str) actual = NSAttribute(NO_NS, None, str, str)