You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by em...@apache.org on 2017/03/03 02:15:43 UTC

[2/3] incubator-ariatosca git commit: Add types to modeling, plus many fixes to models

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 081829e..b4c15bb 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -13,11 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# pylint: disable=too-many-lines
+# pylint: disable=too-many-lines, no-self-argument, no-member, abstract-method
 
 from __future__ import absolute_import  # so we can import standard 'types'
 
-
 from copy import deepcopy
 from types import FunctionType
 from datetime import datetime
@@ -30,32 +29,16 @@ from sqlalchemy import (
 )
 from sqlalchemy.ext.declarative import declared_attr
 
-from ..storage import exceptions
 from ..parser import validation
-from ..parser.modeling import utils as parser_utils
 from ..utils import collections, formatting, console
-from .service import _InstanceModelMixin
+from .bases import TemplateModelMixin
 from . import (
     utils,
     types as modeling_types
 )
 
-# pylint: disable=no-self-argument, no-member, abstract-method
-
-
-
-class _TemplateModelMixin(_InstanceModelMixin):
-    """
-    Mixin for :class:`ServiceTemplate` models.
-
-    All model models can be instantiated into :class:`ServiceInstance` models.
-    """
-
-    def instantiate(self, context, container):
-        raise NotImplementedError
 
-
-class ServiceTemplateBase(_TemplateModelMixin):
+class ServiceTemplateBase(TemplateModelMixin):
     """
     A service template is a normalized blueprint from which :class:`ServiceInstance` instances can
     be created.
@@ -64,6 +47,7 @@ class ServiceTemplateBase(_TemplateModelMixin):
     also be created programmatically.
 
     :ivar description: Human-readable description
+    :vartype description: string
     :ivar meta_data: Dict of :class:`Metadata`
     :ivar node_templates: List of :class:`NodeTemplate`
     :ivar group_templates: List of :class:`GroupTemplate`
@@ -74,16 +58,14 @@ class ServiceTemplateBase(_TemplateModelMixin):
     :ivar operation_templates: Dict of :class:`OperationTemplate`
     """
 
-    __tablename__ = 'service_template' # redundancy for PyLint: SqlAlchemy injects this
-
-    __private_fields__ = ['substitution_template_fk']
+    __tablename__ = 'service_template'
 
     description = Column(Text)
 
     @declared_attr
     def meta_data(cls):
         # Warning! We cannot use the attr name "metadata" because it's used by SqlAlchemy!
-        return cls.many_to_many_relationship('metadata', key_column_name='name')
+        return cls.many_to_many_relationship('metadata', dict_key='name')
 
     @declared_attr
     def node_templates(cls):
@@ -104,18 +86,18 @@ class ServiceTemplateBase(_TemplateModelMixin):
     @declared_attr
     def inputs(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='inputs',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     @declared_attr
     def outputs(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='outputs',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     @declared_attr
     def operation_templates(cls):
-        return cls.one_to_many_relationship('operation_template', key_column_name='name')
+        return cls.one_to_many_relationship('operation_template', dict_key='name')
 
-    # region orchestrator required columns
+    # region orchestration
 
     created_at = Column(DateTime, nullable=False, index=True)
     updated_at = Column(DateTime)
@@ -123,12 +105,14 @@ class ServiceTemplateBase(_TemplateModelMixin):
 
     @declared_attr
     def plugins(cls):
-        return cls.one_to_many_relationship('plugin', key_column_name='name')
+        return cls.one_to_many_relationship('plugin', dict_key='name')
 
     # endregion
 
     # region foreign keys
 
+    __private_fields__ = ['substitution_template_fk']
+
     # ServiceTemplate one-to-one to SubstitutionTemplate
     @declared_attr
     def substitution_template_fk(cls):
@@ -143,6 +127,13 @@ class ServiceTemplateBase(_TemplateModelMixin):
                     return node_template
         return None
 
+    def get_group_template(self, group_template_name):
+        if self.group_templates:
+            for group_template in self.group_templates:
+                if group_template.name == group_template_name:
+                    return group_template
+        return None
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -232,13 +223,12 @@ class ServiceTemplateBase(_TemplateModelMixin):
         utils.dump_dict_values(context, self.operation_templates, 'Operation templates')
 
 
-class NodeTemplateBase(_TemplateModelMixin):
+class NodeTemplateBase(TemplateModelMixin):
     """
     A template for creating zero or more :class:`Node` instances.
 
     :ivar name: Name (will be used as a prefix for node IDs)
     :ivar description: Description
-    :ivar type_name: Must be represented in the :class:`ModelingContext`
     :ivar default_instances: Default number nodes that will appear in the deployment plan
     :ivar min_instances: Minimum number nodes that will appear in the deployment plan
     :ivar max_instances: Maximum number nodes that will appear in the deployment plan
@@ -250,12 +240,13 @@ class NodeTemplateBase(_TemplateModelMixin):
     :ivar target_node_template_constraints: List of :class:`FunctionType`
     """
 
-    __tablename__ = 'node_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'node_template'
 
-    __private_fields__ = ['service_template_fk']
+    @declared_attr
+    def type(cls):
+        return cls.many_to_one_relationship('type')
 
     description = Column(Text)
-    type_name = Column(Text)
     default_instances = Column(Integer, default=1)
     min_instances = Column(Integer, default=0)
     max_instances = Column(Integer, default=None)
@@ -264,34 +255,43 @@ class NodeTemplateBase(_TemplateModelMixin):
     @declared_attr
     def properties(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='properties',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls.one_to_many_relationship('interface_template', key_column_name='name')
+        return cls.one_to_many_relationship('interface_template', dict_key='name')
 
     @declared_attr
     def artifact_templates(cls):
-        return cls.one_to_many_relationship('artifact_template', key_column_name='name')
+        return cls.one_to_many_relationship('artifact_template', dict_key='name')
 
     @declared_attr
     def capability_templates(cls):
-        return cls.one_to_many_relationship('capability_template', key_column_name='name')
+        return cls.one_to_many_relationship('capability_template', dict_key='name')
 
     @declared_attr
     def requirement_templates(cls):
-        return cls.one_to_many_relationship('requirement_template')
+        return cls.one_to_many_relationship('requirement_template',
+                                            foreign_key='node_template_fk')
 
-    # region orchestrator required columns
+    # region orchestration
 
     @declared_attr
     def plugins(cls):
-        return cls.many_to_many_relationship('plugin', key_column_name='name')
+        return cls.many_to_many_relationship('plugin', dict_key='name')
 
     # endregion
 
     # region foreign_keys
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk']
+
+    # NodeTemplate many-to-one to Type
+    @declared_attr
+    def type_fk(cls):
+        return cls.foreign_key('type')
+
     # ServiceTemplate one-to-many to NodeTemplate
     @declared_attr
     def service_template_fk(cls):
@@ -311,7 +311,7 @@ class NodeTemplateBase(_TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name),
             ('description', self.description),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('default_instances', self.default_instances),
             ('min_instances', self.min_instances),
             ('max_instances', self.max_instances),
@@ -325,7 +325,7 @@ class NodeTemplateBase(_TemplateModelMixin):
         from . import models
         name = context.modeling.generate_node_id(self.name)
         node = models.Node(name=name,
-                           type_name=self.type_name,
+                           type=self.type,
                            state='',
                            node_template=self)
         utils.instantiate_dict(context, node, node.properties, self.properties)
@@ -335,12 +335,6 @@ class NodeTemplateBase(_TemplateModelMixin):
         return node
 
     def validate(self, context):
-        if context.modeling.node_types.get_descendant(self.type_name) is None:
-            context.validation.report('node template "{0}" has an unknown type: {1}'.format(
-                self.name,
-                formatting.safe_repr(self.type_name)),
-                                      level=validation.Issue.BETWEEN_TYPES)
-
         utils.validate_dict_values(context, self.properties)
         utils.validate_dict_values(context, self.interface_templates)
         utils.validate_dict_values(context, self.artifact_templates)
@@ -359,7 +353,7 @@ class NodeTemplateBase(_TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            console.puts('Type: {0}'.format(context.style.type(self.type_name)))
+            console.puts('Type: {0}'.format(context.style.type(self.type.name)))
             console.puts('Instances: {0:d} ({1:d}{2})'.format(
                 self.default_instances,
                 self.min_instances,
@@ -373,7 +367,7 @@ class NodeTemplateBase(_TemplateModelMixin):
             utils.dump_list_values(context, self.requirement_templates, 'Requirement templates')
 
 
-class GroupTemplateBase(_TemplateModelMixin):
+class GroupTemplateBase(TemplateModelMixin):
     """
     A template for creating zero or more :class:`Group` instances.
 
@@ -382,34 +376,41 @@ class GroupTemplateBase(_TemplateModelMixin):
 
     :ivar name: Name (will be used as a prefix for group IDs)
     :ivar description: Description
-    :ivar type_name: Must be represented in the :class:`ModelingContext`
     :ivar properties: Dict of :class:`Parameter`
     :ivar interface_templates: Dict of :class:`InterfaceTemplate`
-    :ivar member_node_template_names: Must be represented in the :class:`ServiceTemplate`
-    :ivar member_group_template_names: Must be represented in the :class:`ServiceTemplate`
     """
 
-    __tablename__ = 'group_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'group_template'
 
-    __private_fields__ = ['service_template_fk']
+    @declared_attr
+    def type(cls):
+        return cls.many_to_one_relationship('type')
 
     description = Column(Text)
-    type_name = Column(Text)
 
     @declared_attr
     def properties(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='properties',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls.one_to_many_relationship('interface_template', key_column_name='name')
+        return cls.one_to_many_relationship('interface_template', dict_key='name')
 
-    member_node_template_names = Column(modeling_types.StrictList(basestring))
-    member_group_template_names = Column(modeling_types.StrictList(basestring))
+    @declared_attr
+    def node_templates(cls):
+        return cls.many_to_many_relationship('node_template')
 
     # region foreign keys
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk']
+
+    # GroupTemplate many-to-one to Type
+    @declared_attr
+    def type_fk(cls):
+        return cls.foreign_key('type')
+
     # ServiceTemplate one-to-many to GroupTemplate
     @declared_attr
     def service_template_fk(cls):
@@ -422,37 +423,23 @@ class GroupTemplateBase(_TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name),
             ('description', self.description),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('properties', formatting.as_raw_dict(self.properties)),
-            ('interface_templates', formatting.as_raw_list(self.interface_templates)),
-            ('member_node_template_names', self.member_node_template_names),
-            ('member_group_template_names', self.member_group_template_names1)))
+            ('interface_templates', formatting.as_raw_list(self.interface_templates))))
 
     def instantiate(self, context, *args, **kwargs):
         from . import models
         group = models.Group(name=self.name,
-                             type_name=self.type_name,
+                             type=self.type,
                              group_template=self)
         utils.instantiate_dict(context, self, group.properties, self.properties)
         utils.instantiate_dict(context, self, group.interfaces, self.interface_templates)
-        if self.member_node_template_names:
-            group.member_node_ids = []
-            for member_node_template_name in self.member_node_template_names:
-                group.member_node_ids += \
-                    context.modeling.instance.get_node_ids(member_node_template_name)
-        if self.member_group_template_names:
-            group.member_group_ids = []
-            for member_group_template_name in self.member_group_template_names:
-                group.member_group_ids += \
-                    context.modeling.instance.get_group_ids(member_group_template_name)
+        if self.node_templates:
+            for node_template in self.node_templates:
+                group.nodes += node_template.nodes.all()
         return group
 
     def validate(self, context):
-        if context.modeling.group_types.get_descendant(self.type_name) is None:
-            context.validation.report('group template "{0}" has an unknown type: {1}'.format(
-                self.name, formatting.safe_repr(self.type_name)),
-                                      level=validation.Issue.BETWEEN_TYPES)
-
         utils.validate_dict_values(context, self.properties)
         utils.validate_dict_values(context, self.interface_templates)
 
@@ -465,44 +452,55 @@ class GroupTemplateBase(_TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            if self.type_name:
-                console.puts('Type: {0}'.format(context.style.type(self.type_name)))
+            console.puts('Type: {0}'.format(context.style.type(self.type.name)))
             utils.dump_parameters(context, self.properties)
             utils.dump_interfaces(context, self.interface_templates)
-            if self.member_node_template_names:
+            if self.node_templates:
                 console.puts('Member node templates: {0}'.format(', '.join(
-                    (str(context.style.node(v)) for v in self.member_node_template_names))))
+                    (str(context.style.node(v.name)) for v in self.node_templates))))
 
 
-class PolicyTemplateBase(_TemplateModelMixin):
+class PolicyTemplateBase(TemplateModelMixin):
     """
     Policies can be applied to zero or more :class:`NodeTemplate` or :class:`GroupTemplate`
     instances.
 
     :ivar name: Name
     :ivar description: Description
-    :ivar type_name: Must be represented in the :class:`ModelingContext`
     :ivar properties: Dict of :class:`Parameter`
-    :ivar target_node_template_names: Must be represented in the :class:`ServiceTemplate`
-    :ivar target_group_template_names: Must be represented in the :class:`ServiceTemplate`
     """
-    __tablename__ = 'policy_template' # redundancy for PyLint: SqlAlchemy injects this
 
-    __private_fields__ = ['service_template_fk']
+    __tablename__ = 'policy_template'
+
+    @declared_attr
+    def type(cls):
+        return cls.many_to_one_relationship('type')
 
     description = Column(Text)
-    type_name = Column(Text)
 
     @declared_attr
     def properties(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='properties',
-                                             key_column_name='name')
+                                             dict_key='name')
 
-    target_node_template_names = Column(modeling_types.StrictList(basestring))
-    target_group_template_names = Column(modeling_types.StrictList(basestring))
+    @declared_attr
+    def node_templates(cls):
+        return cls.many_to_many_relationship('node_template')
+
+    @declared_attr
+    def group_templates(cls):
+        return cls.many_to_many_relationship('group_template')
 
     # region foreign keys
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk']
+
+    # PolicyTemplate many-to-one to Type
+    @declared_attr
+    def type_fk(cls):
+        return cls.foreign_key('type')
+
     # ServiceTemplate one-to-many to PolicyTemplate
     @declared_attr
     def service_template_fk(cls):
@@ -515,35 +513,24 @@ class PolicyTemplateBase(_TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name),
             ('description', self.description),
-            ('type_name', self.type_name),
-            ('properties', formatting.as_raw_dict(self.properties)),
-            ('target_node_template_names', self.target_node_template_names),
-            ('target_group_template_names', self.target_group_template_names)))
+            ('type_name', self.type.name),
+            ('properties', formatting.as_raw_dict(self.properties))))
 
     def instantiate(self, context, *args, **kwargs):
         from . import models
         policy = models.Policy(name=self.name,
-                               type_name=self.type_name,
+                               type=self.type,
                                policy_template=self)
         utils.instantiate_dict(context, self, policy.properties, self.properties)
-        if self.target_node_template_names:
-            policy.target_node_ids = []
-            for node_template_name in self.target_node_template_names:
-                policy.target_node_ids += \
-                    context.modeling.instance.get_node_ids(node_template_name)
-        if self.target_group_template_names:
-            policy.target_group_ids = []
-            for group_template_name in self.target_group_template_names:
-                policy.target_group_ids += \
-                    context.modeling.instance.get_group_ids(group_template_name)
+        if self.node_templates:
+            for node_template in self.node_templates:
+                policy.nodes += node_template.nodes.all()
+        if self.group_templates:
+            for group_template in self.group_templates:
+                policy.groups += group_template.groups.all()
         return policy
 
     def validate(self, context):
-        if context.modeling.policy_types.get_descendant(self.type_name) is None:
-            context.validation.report('policy template "{0}" has an unknown type: {1}'.format(
-                self.name, formatting.safe_repr(self.type_name)),
-                                      level=validation.Issue.BETWEEN_TYPES)
-
         utils.validate_dict_values(context, self.properties)
 
     def coerce_values(self, context, container, report_issues):
@@ -554,51 +541,58 @@ class PolicyTemplateBase(_TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            console.puts('Type: {0}'.format(context.style.type(self.type_name)))
+            console.puts('Type: {0}'.format(context.style.type(self.type.name)))
             utils.dump_parameters(context, self.properties)
-            if self.target_node_template_names:
+            if self.node_templates:
                 console.puts('Target node templates: {0}'.format(', '.join(
-                    (str(context.style.node(v)) for v in self.target_node_template_names))))
-            if self.target_group_template_names:
+                    (str(context.style.node(v.name)) for v in self.node_templates))))
+            if self.group_templates:
                 console.puts('Target group templates: {0}'.format(', '.join(
-                    (str(context.style.node(v)) for v in self.target_group_template_names))))
+                    (str(context.style.node(v.name)) for v in self.group_templates))))
 
 
-class SubstitutionTemplateBase(_TemplateModelMixin):
+class SubstitutionTemplateBase(TemplateModelMixin):
     """
     Used to substitute a single node for the entire deployment.
 
-    :ivar node_type_name: Must be represented in the :class:`ModelingContext`
     :ivar mappings: Dict of :class:` SubstitutionTemplateMapping`
     """
 
-    __tablename__ = 'substitution_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'substitution_template'
 
-    node_type_name = Column(Text)
+    @declared_attr
+    def node_type(cls):
+        return cls.many_to_one_relationship('type')
 
     @declared_attr
     def mappings(cls):
-        return cls.one_to_many_relationship('substitution_template_mapping', key_column_name='name')
+        return cls.one_to_many_relationship('substitution_template_mapping', dict_key='name')
+
+    # region foreign keys
+
+    __private_fields__ = ['node_type_fk']
+
+    # SubstitutionTemplate many-to-one to Type
+    @declared_attr
+    def node_type_fk(cls):
+        return cls.foreign_key('type')
+
+    # endregion
 
     @property
     def as_raw(self):
         return collections.OrderedDict((
-            ('node_type_name', self.node_type_name),
+            ('node_type_name', self.node_type.name),
             ('mappings', formatting.as_raw_dict(self.mappings))))
 
     def instantiate(self, context, container):
         from . import models
-        substitution = models.Substitution(node_type_name=self.node_type_name,
+        substitution = models.Substitution(node_type=self.node_type,
                                            substitution_template=self)
         utils.instantiate_dict(context, container, substitution.mappings, self.mappings)
         return substitution
 
     def validate(self, context):
-        if context.modeling.node_types.get_descendant(self.node_type_name) is None:
-            context.validation.report('substitution template has an unknown type: {0}'.format(
-                formatting.safe_repr(self.node_type_name)),
-                                      level=validation.Issue.BETWEEN_TYPES)
-
         utils.validate_dict_values(context, self.mappings)
 
     def coerce_values(self, context, container, report_issues):
@@ -607,23 +601,18 @@ class SubstitutionTemplateBase(_TemplateModelMixin):
     def dump(self, context):
         console.puts('Substitution template:')
         with context.style.indent:
-            console.puts('Node type: {0}'.format(context.style.type(self.node_type_name)))
+            console.puts('Node type: {0}'.format(context.style.type(self.node_type.name)))
             utils.dump_dict_values(context, self.mappings, 'Mappings')
 
 
-class SubstitutionTemplateMappingBase(_TemplateModelMixin):
+class SubstitutionTemplateMappingBase(TemplateModelMixin):
     """
     Used by :class:`SubstitutionTemplate` to map a capability or a requirement to a node.
 
     :ivar name: Exposed capability or requirement name
     """
 
-    __tablename__ = 'substitution_template_mapping' # redundancy for PyLint: SqlAlchemy injects this
-
-    __private_fields__ = ['substitution_template_fk',
-                          'node_template_fk',
-                          'capability_template_fk',
-                          'requirement_template_fk']
+    __tablename__ = 'substitution_template_mapping'
 
     @declared_attr
     def node_template(cls):
@@ -639,6 +628,11 @@ class SubstitutionTemplateMappingBase(_TemplateModelMixin):
 
     # region foreign keys
 
+    __private_fields__ = ['substitution_template_fk',
+                          'node_template_fk',
+                          'capability_template_fk',
+                          'requirement_template_fk']
+
     # SubstitutionTemplate one-to-many to SubstitutionTemplateMapping
     @declared_attr
     def substitution_template_fk(cls):
@@ -705,33 +699,37 @@ class SubstitutionTemplateMappingBase(_TemplateModelMixin):
                                else self.requirement_template.name)))
 
 
-class RequirementTemplateBase(_TemplateModelMixin):
+class RequirementTemplateBase(TemplateModelMixin):
     """
     A requirement for a :class:`NodeTemplate`. During instantiation will be matched with a
-    capability of another
-    node.
+    capability of another node.
 
     Requirements may optionally contain a :class:`RelationshipTemplate` that will be created between
     the nodes.
 
     :ivar name: Name
-    :ivar target_node_type_name: Must be represented in the :class:`ModelingContext`
-    :ivar target_node_template_name: Must be represented in the :class:`ServiceTemplate`
     :ivar target_node_template_constraints: List of :class:`FunctionType`
-    :ivar target_capability_type_name: Type of capability in target node
     :ivar target_capability_name: Name of capability in target node
     :ivar relationship_template: :class:`RelationshipTemplate`
     """
 
-    __tablename__ = 'requirement_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'requirement_template'
 
-    __private_fields__ = ['node_template_fk',
-                          'relationship_template_fk']
+    @declared_attr
+    def target_node_type(cls):
+        return cls.many_to_one_relationship('type', key='target_node_type_fk', backreference='')
+
+    @declared_attr
+    def target_node_template(cls):
+        return cls.one_to_one_relationship('node_template', key='target_node_template_fk',
+                                           backreference='')
+
+    @declared_attr
+    def target_capability_type(cls):
+        return cls.one_to_one_relationship('type', key='target_capability_type_fk',
+                                           backreference='')
 
-    target_node_type_name = Column(Text)
-    target_node_template_name = Column(Text)
     target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
-    target_capability_type_name = Column(Text)
     target_capability_name = Column(Text)
 
     @declared_attr
@@ -740,10 +738,31 @@ class RequirementTemplateBase(_TemplateModelMixin):
 
     # region foreign keys
 
+    __private_fields__ = ['target_node_type_fk',
+                          'target_node_template_fk',
+                          'target_capability_type_fk'
+                          'node_template_fk',
+                          'relationship_template_fk']
+
+    # RequirementTemplate many-to-one to Type
+    @declared_attr
+    def target_node_type_fk(cls):
+        return cls.foreign_key('type', nullable=True)
+
+    # RequirementTemplate one-to-one to NodeTemplate
+    @declared_attr
+    def target_node_template_fk(cls):
+        return cls.foreign_key('node_template', nullable=True)
+
+    # RequirementTemplate one-to-one to NodeTemplate
+    @declared_attr
+    def target_capability_type_fk(cls):
+        return cls.foreign_key('type', nullable=True)
+
     # NodeTemplate one-to-many to RequirementTemplate
     @declared_attr
     def node_template_fk(cls):
-        return cls.foreign_key('node_template', nullable=True)
+        return cls.foreign_key('node_template')
 
     # RequirementTemplate one-to-one to RelationshipTemplate
     @declared_attr
@@ -752,41 +771,32 @@ class RequirementTemplateBase(_TemplateModelMixin):
 
     # endregion
 
-    def instantiate(self, context, container):
-        raise NotImplementedError
-
     def find_target(self, context, source_node_template):
         # We might already have a specific node template, so we'll just verify it
-        if self.target_node_template_name is not None:
-            target_node_template = \
-                context.modeling.template.get_node_template(self.target_node_template_name)
-
-            if not source_node_template.is_target_node_valid(target_node_template):
+        if self.target_node_template is not None:
+            if not source_node_template.is_target_node_valid(self.target_node_template):
                 context.validation.report('requirement "{0}" of node template "{1}" is for node '
                                           'template "{2}" but it does not match constraints'.format(
                                               self.name,
                                               self.target_node_template_name,
                                               source_node_template.name),
                                           level=validation.Issue.BETWEEN_TYPES)
-                return None, None
-
-            if (self.target_capability_type_name is not None) \
+            if (self.target_capability_type is not None) \
                 or (self.target_capability_name is not None):
                 target_node_capability = self.find_target_capability(context,
                                                                      source_node_template,
-                                                                     target_node_template)
+                                                                     self.target_node_template)
                 if target_node_capability is None:
                     return None, None
             else:
                 target_node_capability = None
 
-            return target_node_template, target_node_capability
+            return self.target_node_template, target_node_capability
 
         # Find first node that matches the type
-        elif self.target_node_type_name is not None:
+        elif self.target_node_type is not None:
             for target_node_template in context.modeling.template.node_templates:
-                if not context.modeling.node_types.is_descendant(self.target_node_type_name,
-                                                                 target_node_template.type_name):
+                if self.target_node_type.get_descendant(target_node_template.type.name) is None:
                     continue
 
                 if not source_node_template.is_target_node_valid(target_node_template):
@@ -815,29 +825,13 @@ class RequirementTemplateBase(_TemplateModelMixin):
     def as_raw(self):
         return collections.OrderedDict((
             ('name', self.name),
-            ('target_node_type_name', self.target_node_type_name),
+            ('target_node_type_name', self.target_node_type.name),
             ('target_node_template_name', self.target_node_template_name),
             ('target_capability_type_name', self.target_capability_type_name),
             ('target_capability_name', self.target_capability_name),
             ('relationship_template', formatting.as_raw(self.relationship_template))))
 
     def validate(self, context):
-        node_types = context.modeling.node_types
-        capability_types = context.modeling.capability_types
-        if self.target_node_type_name \
-                and node_types.get_descendant(self.target_node_type_name) is None:
-            context.validation.report('requirement "{0}" refers to an unknown node type: {1}' \
-                                        .format(
-                                            self.name,
-                                            formatting.safe_repr(self.target_node_type_name)),
-                                      level=validation.Issue.BETWEEN_TYPES)
-        if self.target_capability_type_name and \
-                capability_types.get_descendant(self.target_capability_type_name is None):
-            context.validation.report('requirement "{0}" refers to an unknown capability type: '
-                                      '{1}'.format(
-                                          self.name,
-                                          formatting.safe_repr(self.target_capability_type_name)),
-                                      level=validation.Issue.BETWEEN_TYPES)
         if self.relationship_template:
             self.relationship_template.validate(context)
 
@@ -851,15 +845,15 @@ class RequirementTemplateBase(_TemplateModelMixin):
         else:
             console.puts('Requirement:')
         with context.style.indent:
-            if self.target_node_type_name is not None:
+            if self.target_node_type is not None:
                 console.puts('Target node type: {0}'.format(
-                    context.style.type(self.target_node_type_name)))
-            elif self.target_node_template_name is not None:
+                    context.style.type(self.target_node_type.name)))
+            elif self.target_node_template is not None:
                 console.puts('Target node template: {0}'.format(
-                    context.style.node(self.target_node_template_name)))
-            if self.target_capability_type_name is not None:
+                    context.style.node(self.target_node_template.name)))
+            if self.target_capability_type is not None:
                 console.puts('Target capability type: {0}'.format(
-                    context.style.type(self.target_capability_type_name)))
+                    context.style.type(self.target_capability_type.name)))
             elif self.target_capability_name is not None:
                 console.puts('Target capability name: {0}'.format(
                     context.style.node(self.target_capability_name)))
@@ -874,46 +868,56 @@ class RequirementTemplateBase(_TemplateModelMixin):
                     self.relationship_template.dump(context)
 
 
-class RelationshipTemplateBase(_TemplateModelMixin):
+class RelationshipTemplateBase(TemplateModelMixin):
     """
     Optional addition to a :class:`RequirementTemplate` in :class:`NodeTemplate` that can be applied
     when the requirement is matched with a capability.
 
-    :ivar type_name: Must be represented in the :class:`ModelingContext`
-    :ivar template_name: Must be represented in the :class:`ServiceTemplate`
     :ivar description: Description
     :ivar properties: Dict of :class:`Parameter`
     :ivar interface_templates: Dict of :class:`InterfaceTemplate`
     """
 
-    __tablename__ = 'relationship_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'relationship_template'
+
+    @declared_attr
+    def type(cls):
+        return cls.many_to_one_relationship('type')
 
-    type_name = Column(Text)
-    template_name = Column(Text)
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='properties',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls.one_to_many_relationship('interface_template', key_column_name='name')
+        return cls.one_to_many_relationship('interface_template', dict_key='name')
+
+    # region foreign keys
+
+    __private_fields__ = ['type_fk']
+
+    # RelationshipTemplate many-to-one to Type
+    @declared_attr
+    def type_fk(cls):
+        return cls.foreign_key('type', nullable=True)
+
+    # endregion
 
     @property
     def as_raw(self):
         return collections.OrderedDict((
-            ('type_name', self.type_name),
-            ('template_name', self.template_name),
+            ('type_name', self.type.name if self.type is not None else None),
+            ('name', self.name),
             ('description', self.description),
             ('properties', formatting.as_raw_dict(self.properties)),
             ('interface_templates', formatting.as_raw_list(self.interface_templates))))
 
     def instantiate(self, context, container):
         from . import models
-        relationship = models.Relationship(name=self.template_name,
-                                           type_name=self.type_name,
+        relationship = models.Relationship(type=self.type,
                                            relationship_template=self)
         utils.instantiate_dict(context, container,
                                relationship.properties, self.properties)
@@ -922,14 +926,7 @@ class RelationshipTemplateBase(_TemplateModelMixin):
         return relationship
 
     def validate(self, context):
-        if context.modeling.relationship_types.get_descendant(self.type_name) is None:
-            context.validation.report(
-                'relationship template "{0}" has an unknown type: {1}'.format(
-                    self.name,
-                    formatting.safe_repr(self.type_name)),  # pylint: disable=no-member
-                # TODO fix self.name reference
-                level=validation.Issue.BETWEEN_TYPES)
-
+        # TODO: either type or name must be set
         utils.validate_dict_values(context, self.properties)
         utils.validate_dict_values(context, self.interface_templates)
 
@@ -938,11 +935,11 @@ class RelationshipTemplateBase(_TemplateModelMixin):
         utils.coerce_dict_values(context, self, self.interface_templates, report_issues)
 
     def dump(self, context):
-        if self.type_name is not None:
-            console.puts('Relationship type: {0}'.format(context.style.type(self.type_name)))
+        if self.type is not None:
+            console.puts('Relationship type: {0}'.format(context.style.type(self.type.name)))
         else:
             console.puts('Relationship template: {0}'.format(
-                context.style.node(self.template_name)))
+                context.style.node(self.name)))
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
@@ -950,37 +947,47 @@ class RelationshipTemplateBase(_TemplateModelMixin):
             utils.dump_interfaces(context, self.interface_templates, 'Interface templates')
 
 
-class CapabilityTemplateBase(_TemplateModelMixin):
+class CapabilityTemplateBase(TemplateModelMixin):
     """
     A capability of a :class:`NodeTemplate`. Nodes expose zero or more capabilities that can be
     matched with :class:`Requirement` instances of other nodes.
 
     :ivar name: Name
     :ivar description: Description
-    :ivar type_name: Must be represented in the :class:`ModelingContext`
     :ivar min_occurrences: Minimum number of requirement matches required
     :ivar max_occurrences: Maximum number of requirement matches allowed
-    :ivar valid_source_node_type_names: Must be represented in the :class:`ModelingContext`
     :ivar properties: Dict of :class:`Parameter`
     """
 
-    __tablename__ = 'capability_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'capability_template'
 
-    __private_fields__ = ['node_template_fk']
+    @declared_attr
+    def type(cls):
+        return cls.many_to_one_relationship('type')
 
     description = Column(Text)
-    type_name = Column(Text)
     min_occurrences = Column(Integer, default=None)  # optional
     max_occurrences = Column(Integer, default=None)  # optional
-    valid_source_node_type_names = Column(modeling_types.StrictList(basestring))
+
+    @declared_attr
+    def valid_source_node_types(cls):
+        return cls.many_to_many_relationship('type', table_prefix='valid_sources')
 
     @declared_attr
     def properties(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='properties',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     # region foreign keys
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk']
+
+    # CapabilityTemplate many-to-one to Type
+    @declared_attr
+    def type_fk(cls):
+        return cls.foreign_key('type')
+
     # NodeTemplate one-to-many to CapabilityTemplate
     @declared_attr
     def node_template_fk(cls):
@@ -994,16 +1001,14 @@ class CapabilityTemplateBase(_TemplateModelMixin):
                               requirement,
                               target_node_template):
         # Do we match the required capability type?
-        capability_types = context.modeling.capability_types
-        if not capability_types.is_descendant(requirement.target_capability_type_name,
-                                              self.type_name):
+        if requirement.target_capability_type and \
+            requirement.target_capability_type.get_descendant(self.type.name) is None:
             return False
 
-        # Are we in valid_source_node_type_names?
-        if self.valid_source_node_type_names:
-            for valid_source_node_type_name in self.valid_source_node_type_names:
-                if not context.modeling.node_types.is_descendant(valid_source_node_type_name,
-                                                                 source_node_template.type_name):
+        # Are we in valid_source_node_types?
+        if self.valid_source_node_types:
+            for valid_source_node_type in self.valid_source_node_types:
+                if valid_source_node_type.get_descendant(source_node_template.type.name) is None:
                     return False
 
         # Apply requirement constraints
@@ -1019,7 +1024,7 @@ class CapabilityTemplateBase(_TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name),
             ('description', self.description),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('min_occurrences', self.min_occurrences),
             ('max_occurrences', self.max_occurrences),
             ('valid_source_node_type_names', self.valid_source_node_type_names),
@@ -1028,7 +1033,7 @@ class CapabilityTemplateBase(_TemplateModelMixin):
     def instantiate(self, context, container):
         from . import models
         capability = models.Capability(name=self.name,
-                                       type_name=self.type_name,
+                                       type=self.type,
                                        min_occurrences=self.min_occurrences,
                                        max_occurrences=self.max_occurrences,
                                        occurrences=0,
@@ -1037,12 +1042,6 @@ class CapabilityTemplateBase(_TemplateModelMixin):
         return capability
 
     def validate(self, context):
-        if context.modeling.capability_types.get_descendant(self.type_name) is None:
-            context.validation.report('capability "{0}" refers to an unknown type: {1}'.format(
-                self.name, formatting.safe_repr(self.type)),  # pylint: disable=no-member
-                                      #  TODO fix self.type reference
-                                      level=validation.Issue.BETWEEN_TYPES)
-
         utils.validate_dict_values(context, self.properties)
 
     def coerce_values(self, context, container, report_issues):
@@ -1053,50 +1052,58 @@ class CapabilityTemplateBase(_TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            console.puts('Type: {0}'.format(context.style.type(self.type_name)))
+            console.puts('Type: {0}'.format(context.style.type(self.type.name)))
             console.puts(
                 'Occurrences: {0:d}{1}'.format(
                     self.min_occurrences or 0,
                     ' to {0:d}'.format(self.max_occurrences)
                     if self.max_occurrences is not None
                     else ' or more'))
-            if self.valid_source_node_type_names:
+            if self.valid_source_node_types:
                 console.puts('Valid source node types: {0}'.format(
-                    ', '.join((str(context.style.type(v))
-                               for v in self.valid_source_node_type_names))))
+                    ', '.join((str(context.style.type(v.name))
+                               for v in self.valid_source_node_types))))
             utils.dump_parameters(context, self.properties)
 
 
-class InterfaceTemplateBase(_TemplateModelMixin):
+class InterfaceTemplateBase(TemplateModelMixin):
     """
     A typed set of :class:`OperationTemplate`.
 
     :ivar name: Name
     :ivar description: Description
-    :ivar type_name: Must be represented in the :class:`ModelingContext`
     :ivar inputs: Dict of :class:`Parameter`
     :ivar operation_templates: Dict of :class:`OperationTemplate`
     """
 
-    __tablename__ = 'interface_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'interface_template'
 
-    __private_fields__ = ['node_template_fk',
-                          'group_template_fk',
-                          'relationship_template_fk']
+    @declared_attr
+    def type(cls):
+        return cls.many_to_one_relationship('type')
 
     description = Column(Text)
-    type_name = Column(Text)
 
     @declared_attr
     def inputs(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='inputs',
-                                             key_column_name='name')
+                                             dict_key='name')
     @declared_attr
     def operation_templates(cls):
-        return cls.one_to_many_relationship('operation_template', key_column_name='name')
+        return cls.one_to_many_relationship('operation_template', dict_key='name')
 
     # region foreign keys
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk',
+                          'group_template_fk',
+                          'relationship_template_fk']
+
+    # InterfaceTemplate many-to-one to Type
+    @declared_attr
+    def type_fk(cls):
+        return cls.foreign_key('type')
+
     # NodeTemplate one-to-many to InterfaceTemplate
     @declared_attr
     def node_template_fk(cls):
@@ -1119,7 +1126,7 @@ class InterfaceTemplateBase(_TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name),
             ('description', self.description),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('inputs', formatting.as_raw_dict(self.inputs)),  # pylint: disable=no-member
             # TODO fix self.properties reference
             ('operation_templates', formatting.as_raw_list(self.operation_templates))))
@@ -1128,19 +1135,13 @@ class InterfaceTemplateBase(_TemplateModelMixin):
         from . import models
         interface = models.Interface(name=self.name,
                                      description=deepcopy_with_locators(self.description),
-                                     type_name=self.type_name,
+                                     type=self.type,
                                      interface_template=self)
         utils.instantiate_dict(context, container, interface.inputs, self.inputs)
         utils.instantiate_dict(context, container, interface.operations, self.operation_templates)
         return interface
 
     def validate(self, context):
-        if self.type_name:
-            if context.modeling.interface_types.get_descendant(self.type_name) is None:
-                context.validation.report('interface "{0}" has an unknown type: {1}'.format(
-                    self.name, formatting.safe_repr(self.type_name)),
-                                          level=validation.Issue.BETWEEN_TYPES)
-
         utils.validate_dict_values(context, self.inputs)
         utils.validate_dict_values(context, self.operation_templates)
 
@@ -1153,12 +1154,12 @@ class InterfaceTemplateBase(_TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            console.puts('Interface type: {0}'.format(context.style.type(self.type_name)))
+            console.puts('Interface type: {0}'.format(context.style.type(self.type.name)))
             utils.dump_parameters(context, self.inputs, 'Inputs')
             utils.dump_dict_values(context, self.operation_templates, 'Operation templates')
 
 
-class OperationTemplateBase(_TemplateModelMixin):
+class OperationTemplateBase(TemplateModelMixin):
     """
     An operation in a :class:`InterfaceTemplate`.
 
@@ -1172,11 +1173,7 @@ class OperationTemplateBase(_TemplateModelMixin):
     :ivar inputs: Dict of :class:`Parameter`
     """
 
-    __tablename__ = 'operation_template' # redundancy for PyLint: SqlAlchemy injects this
-
-    __private_fields__ = ['service_template_fk',
-                          'interface_template_fk',
-                          'plugin_fk']
+    __tablename__ = 'operation_template'
 
     description = Column(Text)
     implementation = Column(Text)
@@ -1188,7 +1185,7 @@ class OperationTemplateBase(_TemplateModelMixin):
     @declared_attr
     def inputs(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='inputs',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     @declared_attr
     def plugin(cls):
@@ -1200,6 +1197,10 @@ class OperationTemplateBase(_TemplateModelMixin):
 
     # region foreign keys
 
+    __private_fields__ = ['service_template_fk',
+                          'interface_template_fk',
+                          'plugin_fk']
+
     # ServiceTemplate one-to-many to OperationTemplate
     @declared_attr
     def service_template_fk(cls):
@@ -1270,13 +1271,12 @@ class OperationTemplateBase(_TemplateModelMixin):
             utils.dump_parameters(context, self.inputs, 'Inputs')
 
 
-class ArtifactTemplateBase(_TemplateModelMixin):
+class ArtifactTemplateBase(TemplateModelMixin):
     """
     A file associated with a :class:`NodeTemplate`.
 
     :ivar name: Name
     :ivar description: Description
-    :ivar type_name: Must be represented in the :class:`ModelingContext`
     :ivar source_path: Source path (CSAR or repository)
     :ivar target_path: Path at destination machine
     :ivar repository_url: Repository URL
@@ -1284,12 +1284,13 @@ class ArtifactTemplateBase(_TemplateModelMixin):
     :ivar properties: Dict of :class:`Parameter`
     """
 
-    __tablename__ = 'artifact_template' # redundancy for PyLint: SqlAlchemy injects this
+    __tablename__ = 'artifact_template'
 
-    __private_fields__ = ['node_template_fk']
+    @declared_attr
+    def type(cls):
+        return cls.many_to_one_relationship('type')
 
     description = Column(Text)
-    type_name = Column(Text)
     source_path = Column(Text)
     target_path = Column(Text)
     repository_url = Column(Text)
@@ -1298,10 +1299,18 @@ class ArtifactTemplateBase(_TemplateModelMixin):
     @declared_attr
     def properties(cls):
         return cls.many_to_many_relationship('parameter', table_prefix='properties',
-                                             key_column_name='name')
+                                             dict_key='name')
 
     # region foreign keys
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk']
+
+    # ArtifactTemplate many-to-one to Type
+    @declared_attr
+    def type_fk(cls):
+        return cls.foreign_key('type')
+
     # NodeTemplate one-to-many to ArtifactTemplate
     @declared_attr
     def node_template_fk(cls):
@@ -1314,7 +1323,7 @@ class ArtifactTemplateBase(_TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name),
             ('description', self.description),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('source_path', self.source_path),
             ('target_path', self.target_path),
             ('repository_url', self.repository_url),
@@ -1324,7 +1333,7 @@ class ArtifactTemplateBase(_TemplateModelMixin):
     def instantiate(self, context, container):
         from . import models
         artifact = models.Artifact(name=self.name,
-                                   type_name=self.type_name,
+                                   type=self.type,
                                    source_path=self.source_path,
                                    description=deepcopy_with_locators(self.description),
                                    target_path=self.target_path,
@@ -1335,11 +1344,6 @@ class ArtifactTemplateBase(_TemplateModelMixin):
         return artifact
 
     def validate(self, context):
-        if context.modeling.artifact_types.get_descendant(self.type_name) is None:
-            context.validation.report('artifact "{0}" has an unknown type: {1}'.format(
-                self.name, formatting.safe_repr(self.type_name)),
-                                      level=validation.Issue.BETWEEN_TYPES)
-
         utils.validate_dict_values(context, self.properties)
 
     def coerce_values(self, context, container, report_issues):
@@ -1350,7 +1354,7 @@ class ArtifactTemplateBase(_TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            console.puts('Artifact type: {0}'.format(context.style.type(self.type_name)))
+            console.puts('Artifact type: {0}'.format(context.style.type(self.type.name)))
             console.puts('Source path: {0}'.format(context.style.literal(self.source_path)))
             if self.target_path is not None:
                 console.puts('Target path: {0}'.format(context.style.literal(self.target_path)))
@@ -1363,102 +1367,6 @@ class ArtifactTemplateBase(_TemplateModelMixin):
             utils.dump_parameters(context, self.properties)
 
 
-
-class ParameterBase(_TemplateModelMixin):
-    """
-    Represents a typed value.
-
-    This class is used by both service template and service instance elements.
-
-    :ivar name: Name
-    :ivar type_name: Type name
-    :ivar value: Value
-    :ivar description: Description
-    """
-
-    __tablename__ = 'parameter' # redundancy for PyLint: SqlAlchemy injects this
-
-    name = Column(Text, nullable=False)
-    type_name = Column(Text, nullable=False)
-
-    # Check: value type
-    str_value = Column(Text)
-    description = Column(Text)
-
-    @property
-    def as_raw(self):
-        return collections.OrderedDict((
-            ('name', self.name),
-            ('type_name', self.type_name),
-            ('value', self.value),
-            ('description', self.description)))
-
-    @property
-    def value(self):
-        if self.str_value is None:
-            return None
-        if self.type_name is None:
-            return self.str_value
-        try:
-            type_name = self.type_name.lower()
-            if type_name in ('str', 'unicode'):
-                return self.str_value.decode('utf-8')
-            elif type_name == 'int':
-                return int(self.str_value)
-            elif type_name == 'bool':
-                return bool(self.str_value)
-            elif type_name == 'float':
-                return float(self.str_value)
-            else:
-                return self.str_value
-        except ValueError:
-            raise exceptions.StorageError('Trying to cast {0} to {1} failed'.format(self.str_value,
-                                                                                    self.type))
-
-    @value.setter
-    def value(self, value):
-        self.str_value = unicode(value)
-
-    def instantiate(self, context, container):
-        from . import models
-        return models.Parameter(name=self.name,
-                                type_name=self.type_name,
-                                str_value=self.str_value,
-                                description=self.description)
-
-    def coerce_values(self, context, container, report_issues):
-        if self.str_value is not None:
-            self.str_value = parser_utils.coerce_value(context, container, self.str_value,
-                                                       report_issues)
-
-
-class MetadataBase(_TemplateModelMixin):
-    """
-    Custom values associated with the service.
-
-    This class is used by both service template and service instance elements.
-
-    :ivar name: Name
-    :ivar value: Value
-    """
-
-    __tablename__ = 'metadata' # redundancy for PyLint: SqlAlchemy injects this
-
-    name = Column(Text, nullable=False)
-    value = Column(Text)
-
-    @property
-    def as_raw(self):
-        return collections.OrderedDict((
-            ('name', self.name),
-            ('value', self.value)))
-
-    def instantiate(self, context, container):
-        from . import models
-        return models.Metadata(name=self.name,
-                               value=self.value)
-
-
 def deepcopy_with_locators(value):
     """
     Like :code:`deepcopy`, but also copies over locators.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/modeling/types.py
----------------------------------------------------------------------
diff --git a/aria/modeling/types.py b/aria/modeling/types.py
index 2c6453b..10a58a7 100644
--- a/aria/modeling/types.py
+++ b/aria/modeling/types.py
@@ -177,6 +177,7 @@ class _MutableList(mutable.MutableList):
         except ValueError as e:
             raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
 
+
 _StrictDictID = namedtuple('_StrictDictID', 'key_cls, value_cls')
 _StrictValue = namedtuple('_StrictValue', 'type_cls, listener_cls')
 
@@ -214,6 +215,7 @@ class _StrictDict(object):
 
         return self._strict_map[strict_dict_map_key].type_cls
 
+
 StrictDict = _StrictDict()
 
 
@@ -249,6 +251,7 @@ class _StrictList(object):
 
         return self._strict_map[item_cls].type_cls
 
+
 StrictList = _StrictList()
 
 
@@ -274,6 +277,8 @@ def _mutable_association_listener(mapper, cls):
                 getattr(cls, prop.key))
         elif isinstance(column_type, List):
             _MutableList.associate_with_attribute(getattr(cls, prop.key))
+
+
 _LISTENER_ARGS = (mutable.mapper, 'mapper_configured', _mutable_association_listener)
 
 
@@ -299,4 +304,5 @@ def remove_mutable_association_listener():
     if event.contains(*_LISTENER_ARGS):
         event.remove(*_LISTENER_ARGS)
 
+
 _register_mutable_association_listener()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/orchestrator/__init__.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/__init__.py b/aria/orchestrator/__init__.py
index 097ee1d..0b57e4b 100644
--- a/aria/orchestrator/__init__.py
+++ b/aria/orchestrator/__init__.py
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 """
-Aria orchestrator
+ARIA orchestrator
 """
 from .decorators import workflow, operation, WORKFLOW_DECORATOR_RESERVED_ARGUMENTS
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/orchestrator/workflows/api/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/api/task.py b/aria/orchestrator/workflows/api/task.py
index 029a7ee..4f35ffc 100644
--- a/aria/orchestrator/workflows/api/task.py
+++ b/aria/orchestrator/workflows/api/task.py
@@ -94,8 +94,8 @@ class OperationTask(BaseTask):
             for k, v in inputs.iteritems():
                 if not isinstance(v, models.Parameter):
                     inputs[k] = models.Parameter(name=k,
-                                                 type_name='str',
-                                                 str_value=str(v))
+                                                 type_name='string',
+                                                 value=str(v) if v is not None else None)
 
         self.name = name
         self.actor = actor

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/orchestrator/workflows/builtin/utils.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/builtin/utils.py b/aria/orchestrator/workflows/builtin/utils.py
index e89ef3b..045d47b 100644
--- a/aria/orchestrator/workflows/builtin/utils.py
+++ b/aria/orchestrator/workflows/builtin/utils.py
@@ -45,7 +45,6 @@ def create_relationship_tasks(interface_name, operation_name, runs_on, node, dry
                 OperationTask.for_relationship(relationship=relationship,
                                                interface_name=interface_name,
                                                operation_name=operation_name,
-                                               edge='source',
                                                runs_on=runs_on,
                                                dry=dry))
         except exceptions.TaskException:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/orchestrator/workflows/core/events_handler.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/events_handler.py b/aria/orchestrator/workflows/core/events_handler.py
index c973ad9..a420d2b 100644
--- a/aria/orchestrator/workflows/core/events_handler.py
+++ b/aria/orchestrator/workflows/core/events_handler.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 """
-Aria's events Sub-Package
+ARIA's events Sub-Package
 Path: aria.events.storage_event_handler
 
 Implementation of storage handlers for workflow and operation events.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/orchestrator/workflows/dry.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/dry.py b/aria/orchestrator/workflows/dry.py
index 3903c55..240a9f2 100644
--- a/aria/orchestrator/workflows/dry.py
+++ b/aria/orchestrator/workflows/dry.py
@@ -28,7 +28,7 @@ def convert_to_dry(plugin, implementation, inputs): # pylint: disable=unused-arg
     dry_implementation = '{0}.{1}'.format(__name__, 'dry_operation')
     dry_inputs = OrderedDict()
     dry_inputs['_implementation'] = implementation
-    dry_inputs['_plugin'] = plugin
+    dry_inputs['_plugin'] = plugin.name if plugin is not None else None
     return None, dry_implementation, dry_inputs
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/orchestrator/workflows/events_logging.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/events_logging.py b/aria/orchestrator/workflows/events_logging.py
index 142ef74..5802987 100644
--- a/aria/orchestrator/workflows/events_logging.py
+++ b/aria/orchestrator/workflows/events_logging.py
@@ -15,7 +15,7 @@
 
 
 """
-Aria's events Sub-Package
+ARIA's events Sub-Package
 Path: aria.events.storage_event_handler
 
 Implementation of logger handlers for workflow and operation events.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/parser/consumption/style.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/style.py b/aria/parser/consumption/style.py
index 88ad934..72892b9 100644
--- a/aria/parser/consumption/style.py
+++ b/aria/parser/consumption/style.py
@@ -43,7 +43,7 @@ class Style(object):
 
     @staticmethod
     def literal(value):
-        return Colored.yellow(safe_repr(value), bold=True)
+        return Colored.magenta(safe_repr(value))
 
     @staticmethod
     def meta(value):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/parser/modeling/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/modeling/__init__.py b/aria/parser/modeling/__init__.py
index 0a743ad..df127cd 100644
--- a/aria/parser/modeling/__init__.py
+++ b/aria/parser/modeling/__init__.py
@@ -14,15 +14,9 @@
 # limitations under the License.
 
 from .context import IdType, ModelingContext
-from .types import TypeHierarchy, Type, RelationshipType, PolicyType, PolicyTriggerType
 
 
 __all__ = (
     'IdType',
-    'ModelingContext',
-    'TypeHierarchy',
-    'Type',
-    'RelationshipType',
-    'PolicyType',
-    'PolicyTriggerType',
+    'ModelingContext'
 )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/parser/modeling/context.py
----------------------------------------------------------------------
diff --git a/aria/parser/modeling/context.py b/aria/parser/modeling/context.py
index 1af788c..81c458b 100644
--- a/aria/parser/modeling/context.py
+++ b/aria/parser/modeling/context.py
@@ -18,7 +18,6 @@ import itertools
 from ...utils.collections import StrictDict, prune, OrderedDict
 from ...utils.formatting import as_raw
 from ...utils.console import puts
-from .types import TypeHierarchy
 from .utils import generate_id_string
 
 
@@ -54,12 +53,12 @@ class ModelingContext(object):
     * :code:`capability_types`: The generated hierarchy of capability types
     * :code:`relationship_types`: The generated hierarchy of relationship types
     * :code:`policy_types`: The generated hierarchy of policy types
-    * :code:`policy_trigger_types`: The generated hierarchy of policy trigger types
     * :code:`artifact_types`: The generated hierarchy of artifact types
     * :code:`interface_types`: The generated hierarchy of interface types
     """
 
     def __init__(self):
+        from ...modeling.models import Type
         self.template = None
         self.instance = None
         self.node_id_format = '{template}_{id}'
@@ -68,18 +67,30 @@ class ModelingContext(object):
         self.id_type = IdType.UNIVERSAL_RANDOM
         self.id_max_length = 63 # See: http://www.faqs.org/rfcs/rfc1035.html
         self.inputs = StrictDict(key_class=basestring)
-        self.node_types = TypeHierarchy()
-        self.group_types = TypeHierarchy()
-        self.capability_types = TypeHierarchy()
-        self.relationship_types = TypeHierarchy()
-        self.policy_types = TypeHierarchy()
-        self.policy_trigger_types = TypeHierarchy()
-        self.artifact_types = TypeHierarchy()
-        self.interface_types = TypeHierarchy()
+        self.node_types = Type()
+        self.group_types = Type()
+        self.capability_types = Type()
+        self.relationship_types = Type()
+        self.policy_types = Type()
+        self.artifact_types = Type()
+        self.interface_types = Type()
 
         self._serial_id_counter = itertools.count(1)
         self._locally_unique_ids = set()
 
+    def store(self, model_storage):
+        if self.template is not None:
+            model_storage.service_template.put(self.template)
+        if self.instance is not None:
+            model_storage.service.put(self.instance)
+        model_storage.type.put(self.node_types)
+        model_storage.type.put(self.group_types)
+        model_storage.type.put(self.capability_types)
+        model_storage.type.put(self.relationship_types)
+        model_storage.type.put(self.policy_types)
+        model_storage.type.put(self.artifact_types)
+        model_storage.type.put(self.interface_types)
+
     def generate_node_id(self, template_name):
         return self.node_id_format.format(
             template=template_name,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/storage/__init__.py
----------------------------------------------------------------------
diff --git a/aria/storage/__init__.py b/aria/storage/__init__.py
index 45af1be..bd7c8c1 100644
--- a/aria/storage/__init__.py
+++ b/aria/storage/__init__.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 """
-Aria's storage Sub-Package
+ARIA's storage Sub-Package
 Path: aria.storage
 
 Storage package is a generic abstraction over different storage types.
@@ -26,15 +26,15 @@ We define this abstraction with the following components:
 4. field: defines a field/item in the model.
 
 API:
-    * application_storage_factory - function, default Aria storage factory.
+    * application_storage_factory - function, default ARIA storage factory.
     * Storage - class, simple storage mapi.
-    * models - module, default Aria standard models.
-    * structures - module, default Aria structures - holds the base model,
+    * models - module, default ARIA standard models.
+    * structures - module, default ARIA structures - holds the base model,
                    and different fields types.
     * Model - class, abstract model implementation.
     * Field - class, base field implementation.
     * IterField - class, base iterable field implementation.
-    * drivers - module, a pool of Aria standard drivers.
+    * drivers - module, a pool of ARIA standard drivers.
     * StorageDriver - class, abstract model implementation.
 """
 from .core import (

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/aria/storage/core.py
----------------------------------------------------------------------
diff --git a/aria/storage/core.py b/aria/storage/core.py
index 0e189e6..bdd3a2e 100644
--- a/aria/storage/core.py
+++ b/aria/storage/core.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 """
-Aria's storage Sub-Package
+ARIA's storage Sub-Package
 Path: aria.storage
 
 Storage package is a generic abstraction over different storage types.
@@ -26,15 +26,15 @@ We define this abstraction with the following components:
 4. field: defines a field/item in the model.
 
 API:
-    * application_storage_factory - function, default Aria storage factory.
+    * application_storage_factory - function, default ARIA storage factory.
     * Storage - class, simple storage mapi.
-    * models - module, default Aria standard models.
-    * structures - module, default Aria structures - holds the base model,
+    * models - module, default ARIA standard models.
+    * structures - module, default ARIA structures - holds the base model,
                    and different fields types.
     * Model - class, abstract model implementation.
     * Field - class, base field implementation.
     * IterField - class, base iterable field implementation.
-    * drivers - module, a pool of Aria standard drivers.
+    * drivers - module, a pool of ARIA standard drivers.
     * StorageDriver - class, abstract model implementation.
 """
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/daa2d538/docs/requirements.txt
----------------------------------------------------------------------
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 2a7d4a7..7baba04 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -10,5 +10,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-Sphinx==1.5.2
-sphinx_rtd_theme==0.1.10b0
+Sphinx==1.5.3
+sphinx_rtd_theme==0.2.0