diff -r 000000000000 -r 2e8eeb919028 configurationengine/doc/plugins/dev-plugin/plugin-interface.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configurationengine/doc/plugins/dev-plugin/plugin-interface.rst Thu Mar 11 17:04:37 2010 +0200 @@ -0,0 +1,200 @@ +.. _plugin-howto-plugin-interface: + +Plug-in interface +================= + +A ConE plug-in has two points for interfacing with ConE: + +#. Reader classes that derive from ``cone.public.plugin.ReaderBase`` . These classes + define supported Implementation Markup Languages (i.e. supported XML namespaces) + and other attributes related to them like file extensions. As the name suggests, they are + also responsible for reading implementation instances from XML data. +#. Implementation classes that derive from ``cone.public.plugin.ImplBase``. These classes + supply the actual run-time functionality of the plug-ins. + +The following UML diagram shows the most important classes and their interdependencies: + +.. image:: plugin_classes.jpg + +ConE generation can be seen to consist of two phases, implementation parsing +and output generation: + +Parsing phase: + +- Implementation file list is filtered based on a user-given file name pattern + and supported file extensions +- All remaining files are parsed into ``ElementTree`` instances +- The ``ElementTree`` instance is scanned for supported ImplML namespaces and + implementation instances are created using the correct reader classes + (the ``read_impl()`` method) +- All implementations are collected into an ``ImplSet`` instance + +Generation phase: + +- Implementation instances are further filtered using tags and ConfML references + (the ``has_tag()`` and ``has_ref()`` methods) +- Implementations instances are divided into separate sets based on their invocation + phases +- Output is generated using each implementation set. For each implementation set: + + - The ``generation_context`` variable of each implementation instance is set + (this context contains generation-scope information implementations instances may use) + - The ``generate()`` method of each instance is called + - The ``post_generate()`` method of each instance is called + +From a plug-in's point of view, the sequence of method calls goes as follows: + +.. image:: plugin_lifecycle.jpg + +Explanations of the steps in the diagram: + +====== ======================================================================== +Step Explanation +====== ======================================================================== +1 ``read_impl()`` is called to create an implementation instance based on + XML data. +2 ``read_impl()`` creates the instance. +3-6 Filtering based on ConfML references and implementation tags is done. + The implementation instance returns True in all cases, so it is included + in the actual generation. +7-8 The instance is asked for its invocation phase (here it returns "normal") +9 The implementation instance's ``generation_context`` variable is set, so + then it can be used in the actual generation. +10-11 Output generation methods are called +====== ======================================================================== + +Plug-in interface class source +------------------------------ + +The following source listings show the most important parts of the ``ImplReader`` +and ``ImplBase`` classes from a plug-in's point of view: + +.. code-block:: python + + class ReaderBase(object): + """ + Base class for implementation readers. + + Each reader class supports one XML namespace, from which it reads an implementation + instance. + + The method for parsing an implementation (read_impl()) is given an ElementTree + XML element as the root from which to parse the implementation. The plug-in + machinery handles each XML file so that the correct reader class is used to read + the implementations from XML elements based on the namespaces. + """ + + # The XML namespace supported by the implementation reader. + # Should be something like "http://www.xyz.org/xml/1". + # Can also be None, in which case the reader will not be used + # (this can be useful for defining base classes for e.g. readers + # for different versions of an implementation). + NAMESPACE = None + + # Any extra XML namespaces that should be ignored by the + # implementation parsing machinery. This is useful for specifying + # namespaces that are not actual ImplML namespaces, but are used + # inside an implementation (e.g. XInclude) + IGNORED_NAMESPACES = [] + + # Supported implementation file extensions. + # Sub-classes can override this to add new supported file extensions + # if necessary. The file extensions simply control whether implementations + # are attempted to be read from a file or not. + # Note that the extensions are case-insensitive. + FILE_EXTENSIONS = ['implml'] + + @classmethod + def read_impl(cls, resource_ref, configuration, doc_root): + """ + Read an implementation instance from the given element tree. + + @param resource_ref: Reference to the resource in the configuration in + which the given document root resides. + @param configuration: The configuration used. + @param doc_root: The document root from which to parse the implementation. + @return: The read implementation instance, or None. + """ + raise exceptions.NotSupportedException() + +.. code-block:: python + + class GenerationContext(object): + """ + Context object that can be used for passing generation-scope + data to implementation instances. + """ + + def __init__(self, tags={}): + # The tags used in this generation context + # (i.e. the tags passed from command line) + self.tags = tags + + # A dictionary that implementation instances can use to + # pass any data between each other + self.impl_data_dict = {} + +.. code-block:: python + + class ImplBase(object): + """ + Base class for any confml implementation. + """ + + # Identifier for the implementation type, used e.g. in .cfg files. + # Should be a string like e.g. 'someml'. + IMPL_TYPE_ID = None + + # Defines the default invocation phase for the implementation. + # The default is used if the phase is not explicitly set in the + # ImplML file or manually overridden by calling set_invocation_phase() + DEFAULT_INVOCATION_PHASE = None + + def __init__(self,ref, configuration): + """ + Create a ImplBase object + @param ref : the ref to the Implml file resource. + @param configuration : the Configuration instance for the + configuration data. + """ + self._settings = None + self.ref = ref + self.index = None + self.configuration = configuration + self.output_root = self.settings.get('output_root','output') + self.output_subdir = self.settings.get('output_subdir','') + self.plugin_output = self.settings.get('plugin_output','') + + self.generation_context = None + self._tags = None + self._invocation_phase = None + self._tempvar_defs = [] + + def generate(self): + """ + Generate the given implementation. + @return: + """ + raise exceptions.NotSupportedException() + + def post_generate(self): + """ + Called when all normal generation has been done. + + @attention: This is a temporary method used for implementing cenrep_rfs.txt generation. + """ + pass + + def list_output_files(self): + """ + Return a list of output files as an array. + """ + raise exceptions.NotSupportedException() + + def get_refs(self): + """ + Return a list of all ConfML setting references that affect this + implementation. May also return None if references are not relevant + for the implementation. + """ + return None