Merge "Document MuranoPL Metadata"
This commit is contained in:
commit
91051a0ef7
|
@ -17,4 +17,6 @@ YAQL languages. The sections below describe these languages.
|
||||||
.. include:: murano_pl/core_lib.rst
|
.. include:: murano_pl/core_lib.rst
|
||||||
.. include:: murano_pl/reflection.rst
|
.. include:: murano_pl/reflection.rst
|
||||||
.. include:: murano_pl/statics.rst
|
.. include:: murano_pl/statics.rst
|
||||||
|
.. include:: murano_pl/metadata.rst
|
||||||
.. include:: murano_pl/actions.rst
|
.. include:: murano_pl/actions.rst
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
.. _metadata:
|
||||||
|
|
||||||
|
MuranoPL Metadata
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
MuranoPL metadata is a way to attach additional information to various MuranoPL
|
||||||
|
entities such as classes, packages, properties, methods, and method arguments.
|
||||||
|
That information can be used by both applications (to implement dynamic
|
||||||
|
programming techniques) or by the external callers (API consumers like UI or
|
||||||
|
even by the Murano Engine itself to impose some runtime behavior based on
|
||||||
|
well known meta values). Thus, metadata is a flexible alternative to adding new
|
||||||
|
keyword for every new feature.
|
||||||
|
|
||||||
|
Work with metadata includes the following cases:
|
||||||
|
|
||||||
|
* Defining your own meta-classes
|
||||||
|
* Attaching metadata to various parts of MuranoPL code
|
||||||
|
* Obtaining metadata and its usage
|
||||||
|
|
||||||
|
Define meta-classes
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Define meta-class with the description of arbitrary metadata. Meta-class and
|
||||||
|
regular class have two differences. The ``Usage`` attribute of meta-class
|
||||||
|
equals to ``Meta``, while the ``Usage`` attribute of regular class equals to
|
||||||
|
``Class``. The default value of the ``Usage`` attribute is ``Class``.
|
||||||
|
Meta-class also has additional attributes (``Cardinality``, ``Applies`` and
|
||||||
|
``Inherited``) to control how and where instances of that meta-class can
|
||||||
|
be attached.
|
||||||
|
|
||||||
|
Cardinality
|
||||||
|
+++++++++++
|
||||||
|
|
||||||
|
The ``Cardinality`` attribute can be set to either ``One`` or ``Many`` and
|
||||||
|
indicates the possibility to attach two or more instances of meta-class to a
|
||||||
|
single language entity. The default value is ``One``.
|
||||||
|
|
||||||
|
Applies
|
||||||
|
+++++++
|
||||||
|
|
||||||
|
The ``Applies`` attribute can be set to one of ``Package``, ``Type``,
|
||||||
|
``Method``, ``Property``, ``Argument`` or ``All`` and controls the possible
|
||||||
|
language entities which instances of meta-class can be attached to. It is
|
||||||
|
possible to specify several values using YAML list notation. The default value
|
||||||
|
is ``All``.
|
||||||
|
|
||||||
|
Inherited
|
||||||
|
+++++++++
|
||||||
|
|
||||||
|
The ``Inherited`` attribute can be set to ``true`` or ``false`` and specifies
|
||||||
|
if there is metadata retained for child classes, overridden methods and
|
||||||
|
properties. The default value is ``false``.
|
||||||
|
|
||||||
|
Using of ``Inherited: true`` has the following consequences.
|
||||||
|
|
||||||
|
If some class inherits from two classes with the same metadata attached and
|
||||||
|
this metadata has ``Cardinality: One``, it will lead to emerging of two
|
||||||
|
metadata objects with ``Cardinality: One`` within a single entity and will
|
||||||
|
throw an exception. However, if the child class has this metadata attached
|
||||||
|
explicitly, it will override the inherited metas and there is no conflict.
|
||||||
|
|
||||||
|
If the child class has the same meta as its parent (attached explicitly),
|
||||||
|
then in case of ``Cardinatity: One`` the meta of the child overrides the
|
||||||
|
meta of the parent as it is mentioned above. And in case of
|
||||||
|
``Cardinatity: Many`` meta of the parent is added to the list of the child's
|
||||||
|
metas.
|
||||||
|
|
||||||
|
Example
|
||||||
|
+++++++
|
||||||
|
|
||||||
|
The following example shows a simple meta-class implementation:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
Name: MetaClassOne
|
||||||
|
Usage: Meta
|
||||||
|
Cardinality: One
|
||||||
|
Applies: All
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
description:
|
||||||
|
Contract: $.string()
|
||||||
|
Default: null
|
||||||
|
|
||||||
|
count:
|
||||||
|
Contract: $.int().check($ >= 0)
|
||||||
|
Default: 0
|
||||||
|
|
||||||
|
``MetaClassOne`` is defined as a meta-class by setting the ``Usage``
|
||||||
|
attribute to ``Meta``. The ``Cardinality`` and ``Applies`` attributes determine
|
||||||
|
that only one instance of ``MetaClassOne`` can be attached to object of any
|
||||||
|
type. The ``Inherited`` attribute is omitted so there is no metadata
|
||||||
|
retained for child classes, overridden methods and properties. In the
|
||||||
|
example above, ``Cardinality`` and ``Applies`` can be omitted as well, as
|
||||||
|
their values are set to default but in this case the author wants to be
|
||||||
|
explicit.
|
||||||
|
|
||||||
|
The following example shows meta-class with different values of attributes:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
Name: MetaClassMany
|
||||||
|
Usage: Meta
|
||||||
|
Cardinality: Many
|
||||||
|
Applies: [Property, Method]
|
||||||
|
Inherited: true
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
description:
|
||||||
|
Contract: $.string()
|
||||||
|
Default: null
|
||||||
|
|
||||||
|
count:
|
||||||
|
Contract: $.int().check($ >= 0)
|
||||||
|
Default: 0
|
||||||
|
|
||||||
|
An instance (or several instances) of ``MetaClassMany`` can be attached to
|
||||||
|
either property or method. Overridden methods and properties inherit
|
||||||
|
metadata from its parents.
|
||||||
|
|
||||||
|
Attach metadata to a MuranoPL entity
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
To attach metadata to MuranoPL class, package, property, method or method
|
||||||
|
argument, add the ``Meta`` keyword to its description. Under the
|
||||||
|
description, specify a list of meta-class instances which you want to attach
|
||||||
|
to the entity. To attach only one meta-class instance, use a single scalar
|
||||||
|
instead of a list.
|
||||||
|
|
||||||
|
Consider the example of attaching previously defined metadata to different
|
||||||
|
entities in a class definition:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.bar
|
||||||
|
std: io.murano
|
||||||
|
res: io.murano.resources
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
|
||||||
|
Name: Bar
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
MetaClassOne:
|
||||||
|
description: "Just an empty application class with some metadata"
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
name:
|
||||||
|
Contract: $.string().notNull()
|
||||||
|
Meta:
|
||||||
|
- MetaClassOne:
|
||||||
|
description: "Name of the app"
|
||||||
|
count: 1
|
||||||
|
- MetaClassMany:
|
||||||
|
count: 2
|
||||||
|
- MetaClassMany:
|
||||||
|
count: 3
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $._environment: $.find(std:Environment).require()
|
||||||
|
Meta:
|
||||||
|
MetaClassOne:
|
||||||
|
description: "Method for initializing app"
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- If: not $.getAttr(deployed, false)
|
||||||
|
Then:
|
||||||
|
- $._environment.reporter.report($this, 'Deploy started')
|
||||||
|
- $._environment.reporter.report($this, 'Deploy finished')
|
||||||
|
- $.setAttr(deployed, true)
|
||||||
|
|
||||||
|
The ``Bar`` class has an instance of meta-class ``MetaClassOne`` attached. For
|
||||||
|
this, the ``Meta`` keyword is added to the ``Bar`` class description and
|
||||||
|
the instance of the ``MetaClassOne`` class is specified under it. This
|
||||||
|
instance's properties are ``description`` and ``count``.
|
||||||
|
|
||||||
|
There are three meta-objects attached to the ``name`` property of the ``Bar``
|
||||||
|
class. One of it is a ``MetaclassOne`` object and the other two are
|
||||||
|
``MetaClassMany`` objects. There can be more than one instance of
|
||||||
|
``MetaClassMany`` attached to a single entity since the ``Cardinality``
|
||||||
|
attribute of ``MetaClassMany`` is set to ``Many``.
|
||||||
|
|
||||||
|
The ``initialize`` method of ``Bar`` also has its metadata.
|
||||||
|
|
||||||
|
To attach metadata to the package, add the ``Meta`` keyword to
|
||||||
|
``manifest.yaml`` file.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.bar.Bar
|
||||||
|
Name: Bar
|
||||||
|
Description: |
|
||||||
|
Empty Description
|
||||||
|
Author: author
|
||||||
|
Tags: [bar]
|
||||||
|
Classes:
|
||||||
|
io.murano.bar.Bar: Bar.yaml
|
||||||
|
io.murano.bar.MetaClassOne: MetaClassOne.yaml
|
||||||
|
io.murano.bar.MetaClassMany: MetaClassMany.yaml
|
||||||
|
Supplier:
|
||||||
|
Name: Name
|
||||||
|
Description: Description
|
||||||
|
Summary: Summary
|
||||||
|
Meta:
|
||||||
|
io.murano.bar.MetaClassOne:
|
||||||
|
description: "Just an empty application with some metadata"
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
Obtain metadata in runtime
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Metadata can be accessed from MuranoPL using reflection capabilities and
|
||||||
|
from Python code using existing YAQL mechanism.
|
||||||
|
|
||||||
|
The following example shows how applications can access attached metadata:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.bar
|
||||||
|
std: io.murano
|
||||||
|
res: io.murano.resources
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
Name: Bar
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
MetaClassOne:
|
||||||
|
description: "Just an empty application class with some metadata"
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
sampleAction:
|
||||||
|
Usage: Action
|
||||||
|
Body:
|
||||||
|
- $._environment.reporter.report($this, typeinfo($).meta.
|
||||||
|
where($ is MetaClassOne).single().description)
|
||||||
|
|
||||||
|
The ``sampleAction`` method is added to the ``Bar`` class definition. This
|
||||||
|
makes use of metadata attached to the ``Bar`` class.
|
||||||
|
|
||||||
|
The information about the ``Bar`` class is received by calling the
|
||||||
|
``typeinfo`` function. Then metadata is accessed through the ``meta``
|
||||||
|
property which returns the collection of all meta attached to the property.
|
||||||
|
Then it is checked that the meta is a ``MetaClassOne`` object to ensure that
|
||||||
|
it has ``description``. While executing the action, the phrase "Just an
|
||||||
|
empty application class with some metadata" is reported to a log. Some
|
||||||
|
advanced usages of MuranoPL reflection capabilities can be found in the
|
||||||
|
corresponding section of this reference.
|
||||||
|
|
||||||
|
By using metadata, an application can get information of any type attached
|
||||||
|
to any object and use this information to change its own behavior. The most
|
||||||
|
valuable use-cases of metadata can be:
|
||||||
|
|
||||||
|
* Providing information about capabilities of application and its parts
|
||||||
|
* Setting application requirements
|
||||||
|
|
||||||
|
Capabilities can include version of software, information for use in UI or
|
||||||
|
CLI, permissions, and any other. Metadata can also be used in requirements as
|
||||||
|
a part of the contract.
|
||||||
|
|
||||||
|
The following example demonstrates the possible use cases for the
|
||||||
|
meta-classes:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
Name: BlogApp
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
m:SomeFeatureSupport:
|
||||||
|
support: true
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
volumeName:
|
||||||
|
Contract: $.string().notNull()
|
||||||
|
Meta:
|
||||||
|
m:Deprecated:
|
||||||
|
text: "volumeName property is deprecated"
|
||||||
|
server:
|
||||||
|
Contract: $.class(srv:CoolServer).notNull().check(typeinfo($).meta.
|
||||||
|
where($ is m:SomeFeatureSupport and $.support = true).any())
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
importantAction:
|
||||||
|
Usage: Action
|
||||||
|
Meta:
|
||||||
|
m:CallerMustBeAdmin
|
||||||
|
|
||||||
|
Note, that the classes in the example do not exist as of Murano Mitaka, and
|
||||||
|
therefore the example is not a real working code.
|
||||||
|
|
||||||
|
The ``SomeFeatureSupport`` meta-class with ``support: true`` says that the
|
||||||
|
``BlogApp`` application supports some feature. The ``Deprecated`` meta-class
|
||||||
|
attached to the ``volumeName`` property informs that this
|
||||||
|
property has a better alternative and it will not be used in the future
|
||||||
|
versions anymore. The ``CallerMustBeAdmin`` meta-class attached to the
|
||||||
|
``importantAction`` method sets permission to execute this method to the
|
||||||
|
admin users only.
|
||||||
|
|
||||||
|
In the contract of the ``server`` property it is specified that the server
|
||||||
|
application must be of the ``srv:CoolServer`` class and must have the
|
||||||
|
attached meta-object of the ``m:SomeFeatureSupport`` meta-class with the
|
||||||
|
``support`` property set to ``true``.
|
Loading…
Reference in New Issue