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/14 23:41:40 UTC

[1/3] incubator-ariatosca git commit: Many cleanups; use dict for many models

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-105-integrate-modeling f6da64acb -> 0f040a2b9


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/orchestrator/workflows/api/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/api/task.py b/aria/orchestrator/workflows/api/task.py
index 744d1b4..e4ebbda 100644
--- a/aria/orchestrator/workflows/api/task.py
+++ b/aria/orchestrator/workflows/api/task.py
@@ -59,17 +59,19 @@ class OperationTask(BaseTask):
     Represents an operation task in the task_graph
     """
 
-    NAME_FORMAT = '{interface}:{operation}@{type}:{id}'
+    NAME_FORMAT = '{interface}:{operation}@{type}:{name}'
 
     def __init__(self,
-                 name,
                  actor,
-                 implementation,
+                 name=None,
+                 actor_type=None,
+                 interface_name=None,
+                 operation_name=None,
+                 implementation=None,
                  max_attempts=None,
                  retry_interval=None,
                  ignore_failure=None,
                  inputs=None,
-                 plugin=None,
                  runs_on=None):
         """
         Creates an operation task using the name, details, node instance and any additional kwargs.
@@ -83,21 +85,7 @@ class OperationTask(BaseTask):
         assert (runs_on is None) or (runs_on in models.Task.RUNS_ON)
         super(OperationTask, self).__init__()
 
-        # Coerce inputs
-        if inputs is None:
-            inputs = {}
-        else:
-            for k, v in inputs.iteritems():
-                if not isinstance(v, models.Parameter):
-                    inputs[k] = models.Parameter(name=k,
-                                                 type_name=full_type_name(v),
-                                                 value=v)
-
-        self.name = name
         self.actor = actor
-        self.implementation = implementation
-        self.inputs = inputs
-        self.plugin = plugin
         self.max_attempts = (self.workflow_context._task_max_attempts
                              if max_attempts is None else max_attempts)
         self.retry_interval = (self.workflow_context._task_retry_interval
@@ -106,8 +94,51 @@ class OperationTask(BaseTask):
                                if ignore_failure is None else ignore_failure)
         self.runs_on = runs_on
 
+        # Coerce inputs
+        if inputs:
+            for k, v in inputs.iteritems():
+                if not isinstance(v, models.Parameter):
+                    inputs[k] = models.Parameter(name=k,
+                                                 type_name=full_type_name(v),
+                                                 value=v)
+
+        if interface_name or operation_name:
+            operation = OperationTask._get_operation(actor.interfaces, interface_name, operation_name)
+            if operation is None:
+                raise exceptions.TaskException(
+                    'Could not find operation "{0}" on interface "{1}" for {2} "{3}"'
+                    .format(operation_name, interface_name, actor_type, actor.name))
+
+            self.plugin = None
+            if operation.plugin_specification:
+                self.plugin = OperationTask._find_plugin(operation.plugin_specification)
+                if self.plugin is None:
+                    raise exceptions.TaskException(
+                        'Could not find plugin of operation "{0}" on interface "{1}" for {2} "{3}"'
+                        .format(operation_name, interface_name, actor_type, actor.name))
+
+            self.implementation = operation.implementation
+            self.inputs = OperationTask._merge_inputs(operation.inputs, inputs)
+
+            self.name = OperationTask.NAME_FORMAT.format(type=actor_type,
+                                                         name=actor.name,
+                                                         interface=interface_name,
+                                                         operation=operation_name)
+        else:
+            self.name = name
+            self.implementation = implementation
+            self.inputs = inputs or {}
+            self.plugin = None
+
     @classmethod
-    def for_node(cls, node, interface_name, operation_name, inputs=None, *args, **kwargs):
+    def for_node(cls,
+                 node,
+                 interface_name,
+                 operation_name,
+                 max_attempts=None,
+                 retry_interval=None,
+                 ignore_failure=None,
+                 inputs=None):
         """
         Creates an operation on a node.
 
@@ -118,36 +149,27 @@ class OperationTask(BaseTask):
         """
 
         assert isinstance(node, models.Node)
-        operation = cls._get_operation(node.interfaces, interface_name, operation_name)
-        if operation is None:
-            raise exceptions.TaskException(
-                'Could not find operation "{0}" on interface "{1}" for node "{2}"'.format(
-                    operation_name, interface_name, node.name))
-
-        plugin = None
-        if operation.plugin_specification:
-            plugin = cls._find_plugin(operation.plugin_specification, kwargs)
-            if plugin is None:
-                raise exceptions.TaskException(
-                    'Could not find plugin of operation "{0}" on interface "{1}" for node "{2}"'
-                    .format(operation_name, interface_name, node.name))
-
         return cls(
             actor=node,
-            name=cls.NAME_FORMAT.format(type='node',
-                                        id=node.name,
-                                        interface=interface_name,
-                                        operation=operation_name),
-            plugin=plugin,
-            implementation=operation.implementation,
-            inputs=cls._merge_inputs(operation.inputs, inputs),
-            runs_on=models.Task.RUNS_ON_NODE,
-            *args,
-            **kwargs)
+            actor_type='node',
+            interface_name=interface_name,
+            operation_name=operation_name,
+            max_attempts=max_attempts,
+            retry_interval=retry_interval,
+            ignore_failure=ignore_failure,
+            inputs=inputs,
+            runs_on=models.Task.RUNS_ON_NODE)
 
     @classmethod
-    def for_relationship(cls, relationship, interface_name, operation_name, inputs=None,
-                         runs_on=models.Task.RUNS_ON_SOURCE, *args, **kwargs):
+    def for_relationship(cls,
+                         relationship,
+                         interface_name,
+                         operation_name,
+                         max_attempts=None,
+                         retry_interval=None,
+                         ignore_failure=None,
+                         inputs=None,
+                         runs_on=models.Task.RUNS_ON_SOURCE):
         """
         Creates an operation on a relationship edge.
 
@@ -160,49 +182,31 @@ class OperationTask(BaseTask):
 
         assert isinstance(relationship, models.Relationship)
         assert runs_on in models.Task.RUNS_ON
-        operation = cls._get_operation(relationship.interfaces, interface_name, operation_name)
-        if operation is None:
-            raise exceptions.TaskException(
-                'Could not find operation "{0}" on interface "{1}" for relationship "{2}"'.format(
-                    operation_name, interface_name, relationship.name))
-
-        plugin = None
-        if operation.plugin_specification:
-            plugin = cls._find_plugin(operation.plugin_specification, kwargs)
-            if plugin is None:
-                raise exceptions.TaskException(
-                    'Could not find plugin of operation "{0}" on interface "{1}" for relationship '
-                    '"{2}"'.format(operation_name, interface_name, relationship.name))
-
         return cls(
             actor=relationship,
-            name=cls.NAME_FORMAT.format(type='relationship',
-                                        id=relationship.name,
-                                        interface=interface_name,
-                                        operation=operation_name),
-            plugin=plugin,
-            implementation=operation.implementation,
-            inputs=cls._merge_inputs(operation.inputs, inputs),
-            runs_on=runs_on,
-            *args,
-            **kwargs)
-
-    @classmethod
-    def _get_operation(cls, interfaces, interface_name, operation_name):
+            actor_type='relationship',
+            interface_name=interface_name,
+            operation_name=operation_name,
+            max_attempts=max_attempts,
+            retry_interval=retry_interval,
+            ignore_failure=ignore_failure,
+            inputs=inputs,
+            runs_on=runs_on)
+
+    @staticmethod
+    def _get_operation(interfaces, interface_name, operation_name):
         interface = interfaces.get(interface_name)
         if interface is not None:
             return interface.operations.get(operation_name)
         return None
 
-    @classmethod
-    def _find_plugin(cls, plugin_specification, kwargs):
-        workflow_context = kwargs.get('ctx') if kwargs else None
-        if workflow_context is None:
-            workflow_context = context.workflow.current.get()
+    @staticmethod
+    def _find_plugin(plugin_specification):
+        workflow_context = context.workflow.current.get()
         return plugin_specification.find_plugin(workflow_context.model.plugin.list())
 
-    @classmethod
-    def _merge_inputs(cls, operation_inputs, override_inputs=None):
+    @staticmethod
+    def _merge_inputs(operation_inputs, override_inputs=None):
         final_inputs = OrderedDict(operation_inputs)
         if override_inputs:
             final_inputs.update(override_inputs)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
index a7b2a11..ec5ba3b 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -86,15 +86,16 @@ def create_service_template_model(context): # pylint: disable=too-many-locals,to
     if policies:
         for policy in policies.itervalues():
             if model.policy_types.get_descendant(policy.type).role == 'plugin':
-                model.plugin_specifications.append(
-                    create_plugin_specification_model(context, policy))
+                plugin_specification = create_plugin_specification_model(context, policy)
+                model.plugin_specifications[plugin_specification.name] = plugin_specification
 
     # Node templates
     node_templates = context.presentation.get('service_template', 'topology_template',
                                               'node_templates')
     if node_templates:
         for node_template in node_templates.itervalues():
-            model.node_templates.append(create_node_template_model(context, model, node_template))
+            node_template_model = create_node_template_model(context, model, node_template)
+            model.node_templates[node_template_model.name] = node_template_model
         for node_template in node_templates.itervalues():
             fix_node_template_model(context, model, node_template)
 
@@ -102,13 +103,15 @@ def create_service_template_model(context): # pylint: disable=too-many-locals,to
     groups = context.presentation.get('service_template', 'topology_template', 'groups')
     if groups:
         for group in groups.itervalues():
-            model.group_templates.append(create_group_template_model(context, model, group))
+            group_template_model = create_group_template_model(context, model, group)
+            model.group_templates[group_template_model.name] = group_template_model
 
     # Policy templates
     policies = context.presentation.get('service_template', 'topology_template', 'policies')
     if policies:
         for policy in policies.itervalues():
-            model.policy_templates.append(create_policy_template_model(context, model, policy))
+            policy_template_model = create_policy_template_model(context, model, policy)
+            model.policy_templates[policy_template_model.name] = policy_template_model
 
     # Substitution template
     substitution_mappings = context.presentation.get('service_template', 'topology_template',
@@ -174,7 +177,7 @@ def create_node_template_model(context, service_template, node_template):
 def fix_node_template_model(context, service_template, node_template):
     # Requirements have to be created after all node templates have been created, because
     # requirements might reference another node template
-    model = service_template.get_node_template(node_template._name)
+    model = service_template.node_templates[node_template._name]
     requirements = node_template._get_requirements(context)
     if requirements:
         for _, requirement in requirements:
@@ -199,7 +202,7 @@ def create_group_template_model(context, service_template, group):
     members = group.members
     if members:
         for member in members:
-            node_template = service_template.get_node_template(member)
+            node_template = service_template.node_templates[member]
             assert node_template
             model.node_templates.append(node_template)
 
@@ -220,12 +223,12 @@ def create_policy_template_model(context, service_template, policy):
     node_templates, groups = policy._get_targets(context)
     if node_templates:
         for target in node_templates:
-            node_template = service_template.get_node_template(target._name)
+            node_template = service_template.node_templates[target._name]
             assert node_template
             model.node_templates.append(node_template)
     if groups:
         for target in groups:
-            group_template = service_template.get_group_template(target._name)
+            group_template = service_template.group_templates[target._name]
             assert group_template
             model.group_templates.append(group_template)
 
@@ -241,7 +244,7 @@ def create_requirement_template_model(context, service_template, requirement):
             node_type = service_template.node_types.get_descendant(node._name)
             model['target_node_type'] = node_type
         else:
-            node_template = service_template.get_node_template(node._name)
+            node_template = service_template.node_templates[node._name]
             model['target_node_template'] = node_template
 
     capability, capability_variant = requirement._get_capability(context)
@@ -402,7 +405,7 @@ def create_substitution_template_model(context, service_template, substitution_m
     if capabilities:
         for mapped_capability_name, capability in capabilities.iteritems():
             name = 'capability.' + mapped_capability_name
-            node_template_model = service_template.get_node_template(capability.node_template)
+            node_template_model = service_template.node_templates[capability.node_template]
             capability_template_model = \
                 node_template_model.capability_templates[capability.capability]
             model.mappings[name] = \
@@ -414,7 +417,7 @@ def create_substitution_template_model(context, service_template, substitution_m
     if requirements:
         for mapped_requirement_name, requirement in requirements.iteritems():
             name = 'requirement.' + mapped_requirement_name
-            node_template_model = service_template.get_node_template(requirement.node_template)
+            node_template_model = service_template.node_templates[requirement.node_template]
             requirement_template_model = None
             for a_model in node_template_model.requirement_templates:
                 if a_model.name == requirement.requirement:
@@ -435,8 +438,6 @@ def create_plugin_specification_model(context, policy):
         prop = properties.get(name)
         return prop.value if prop is not None else None
 
-    now = datetime.now()
-
     model = PluginSpecification(name=policy._name,
                                 archive_name=get('archive_name') or '',
                                 distribution=get('distribution'),
@@ -666,11 +667,7 @@ def parse_implementation_string(context, service_template, implementation):
     if plugin_name == 'execution':
         plugin_specification = None
     else:
-        plugin_specification = None
-        for a_plugin_specification in service_template.plugin_specifications:
-            if a_plugin_specification.name == plugin_name:
-                plugin_specification = a_plugin_specification
-                break
+        plugin_specification = service_template.plugin_specifications.get(plugin_name)
         if plugin_specification is None:
             raise ValueError('unknown plugin: "{0}"'.format(plugin_name))
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/end2end/test_orchestrator.py
----------------------------------------------------------------------
diff --git a/tests/end2end/test_orchestrator.py b/tests/end2end/test_orchestrator.py
index f25134f..7b8dc97 100644
--- a/tests/end2end/test_orchestrator.py
+++ b/tests/end2end/test_orchestrator.py
@@ -46,12 +46,7 @@ def _workflow(workflow_name):
         workflow_fn = import_fullname('aria.orchestrator.workflows.builtin.' + workflow_name)
         inputs = {}
     else:
-        workflow = None
-        for policy in context.modeling.instance.policies:
-            if policy.name == workflow_name:
-                workflow = policy
-                break
-
+        workflow = context.modeling.instance.policies[workflow_name]
         sys.path.append(workflow.properties['implementation'].value)
         workflow_fn = import_fullname(workflow.properties['function'].value)
         inputs = OrderedDict([

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/mock/models.py
----------------------------------------------------------------------
diff --git a/tests/mock/models.py b/tests/mock/models.py
index 483da7d..3ede242 100644
--- a/tests/mock/models.py
+++ b/tests/mock/models.py
@@ -80,7 +80,7 @@ def create_dependency_node_template(service_template):
         max_instances=1,
         service_template=service_template
     )
-    service_template.node_templates.append(node_template)
+    service_template.node_templates[node_template.name] = node_template
     return node_template
 
 
@@ -110,7 +110,7 @@ def create_dependent_node_template(service_template, dependency_node_template):
         requirement_templates=[requirement_template],
         service_template=service_template
     )
-    service_template.node_templates.append(node_template)
+    service_template.node_templates[node_template.name] = node_template
     return node_template
 
 
@@ -124,7 +124,7 @@ def create_dependency_node(dependency_node_template, service):
         state='',
         scaling_groups=[]
     )
-    service.nodes.append(node)
+    service.nodes[node.name] = node
     return node
 
 
@@ -138,7 +138,7 @@ def create_dependent_node(dependent_node_template, service):
         state='',
         scaling_groups=[],
     )
-    service.nodes.append(node)
+    service.nodes[node.name] = node
     return node
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/modeling/test_models.py
----------------------------------------------------------------------
diff --git a/tests/modeling/test_models.py b/tests/modeling/test_models.py
index c8d36e0..4627bc6 100644
--- a/tests/modeling/test_models.py
+++ b/tests/modeling/test_models.py
@@ -514,14 +514,14 @@ class TestNodeTemplate(object):
         'is_valid, name, default_instances, max_instances, min_instances, plugin_specifications, '
         'properties',
         [
-            (False, m_cls, 1, 1, 1, [], {}),
-            (False, 'name', m_cls, 1, 1, [], {}),
-            (False, 'name', 1, m_cls, 1, [], {}),
-            (False, 'name', 1, 1, m_cls, [], {}),
+            (False, m_cls, 1, 1, 1, {}, {}),
+            (False, 'name', m_cls, 1, 1, {}, {}),
+            (False, 'name', 1, m_cls, 1, {}, {}),
+            (False, 'name', 1, 1, m_cls, {}, {}),
             (False, 'name', 1, 1, 1, m_cls, {}),
             (False, 'name', 1, 1, 1, None, {}),
 
-            (True, 'name', 1, 1, 1, [], {}),
+            (True, 'name', 1, 1, 1, {}, {}),
         ]
     )
     def test_node_template_model_creation(self, service_storage, is_valid, name, default_instances,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/context/test_operation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_operation.py b/tests/orchestrator/context/test_operation.py
index 7817a90..e2f2421 100644
--- a/tests/orchestrator/context/test_operation.py
+++ b/tests/orchestrator/context/test_operation.py
@@ -84,7 +84,7 @@ def test_node_operation_task_execution(ctx, executor):
 
     operation_context = global_test_holder[api.task.OperationTask.NAME_FORMAT.format(
         type='node',
-        id=node.name,
+        name=node.name,
         interface=interface_name,
         operation=operation_name
     )]
@@ -95,7 +95,7 @@ def test_node_operation_task_execution(ctx, executor):
     assert operation_context.task.actor == node
     assert operation_context.task.name == api.task.OperationTask.NAME_FORMAT.format(
         type='node',
-        id=node.name,
+        name=node.name,
         interface=interface_name,
         operation=operation_name
     )
@@ -140,7 +140,7 @@ def test_relationship_operation_task_execution(ctx, executor):
 
     operation_context = global_test_holder[api.task.OperationTask.NAME_FORMAT.format(
         type='relationship',
-        id=relationship.name,
+        name=relationship.name,
         interface=interface_name,
         operation=operation_name
     )]
@@ -205,7 +205,7 @@ def test_invalid_task_operation_id(ctx, executor):
 
     op_node_id = global_test_holder[api.task.OperationTask.NAME_FORMAT.format(
         type='node',
-        id=node.name,
+        name=node.name,
         interface=interface_name,
         operation=operation_name
     )]
@@ -230,7 +230,7 @@ def test_plugin_workdir(ctx, executor, tmpdir):
             plugin_specification=plugin_specification)
     )
     node.interfaces[interface.name] = interface
-    node.plugin_specifications = [plugin_specification]
+    node.plugin_specifications[plugin_specification.name] = plugin_specification
     ctx.model.node.update(node)
 
     filename = 'test_file'

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/context/test_serialize.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_serialize.py b/tests/orchestrator/context/test_serialize.py
index 2ec999c..eee1743 100644
--- a/tests/orchestrator/context/test_serialize.py
+++ b/tests/orchestrator/context/test_serialize.py
@@ -54,7 +54,7 @@ def _mock_workflow(ctx, graph):
                               plugin_specification=plugin_specification)
     )
     node.interfaces[interface.name] = interface
-    node.plugin_specifications = [plugin_specification]
+    node.plugin_specifications[plugin_specification.name] = plugin_specification
     task = api.task.OperationTask.for_node(node=node, interface_name='test', operation_name='op')
     graph.add_tasks(task)
     return graph

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/context/test_toolbelt.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_toolbelt.py b/tests/orchestrator/context/test_toolbelt.py
index 0e35a26..cf82127 100644
--- a/tests/orchestrator/context/test_toolbelt.py
+++ b/tests/orchestrator/context/test_toolbelt.py
@@ -132,7 +132,7 @@ def test_relationship_tool_belt(workflow_context, executor):
 
     assert isinstance(global_test_holder.get(api.task.OperationTask.NAME_FORMAT.format(
         type='relationship',
-        id=relationship.name,
+        name=relationship.name,
         interface=interface_name,
         operation=operation_name
     )), RelationshipToolBelt)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/workflows/api/test_task.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/api/test_task.py b/tests/orchestrator/workflows/api/test_task.py
index 139d239..e749b78 100644
--- a/tests/orchestrator/workflows/api/test_task.py
+++ b/tests/orchestrator/workflows/api/test_task.py
@@ -56,7 +56,7 @@ class TestOperationTask(object):
 
         node = ctx.model.node.get_by_name(mock.models.DEPENDENT_NODE_NAME)
         node.interfaces = {interface.name: interface}
-        node.plugin_specifications = [plugin_specification]
+        node.plugin_specifications[plugin_specification.name] = plugin_specification
         ctx.model.node.update(node)
         inputs = {'test_input': True}
         max_attempts = 10
@@ -75,7 +75,7 @@ class TestOperationTask(object):
 
         assert api_task.name == api.task.OperationTask.NAME_FORMAT.format(
             type='node',
-            id=node.name,
+            name=node.name,
             interface=interface_name,
             operation=operation_name
         )
@@ -107,7 +107,8 @@ class TestOperationTask(object):
 
         relationship = ctx.model.relationship.list()[0]
         relationship.interfaces[interface.name] = interface
-        relationship.source_node.plugin_specifications = [plugin_specification]
+        relationship.source_node.plugin_specifications[plugin_specification.name] = \
+            plugin_specification
         inputs = {'test_input': True}
         max_attempts = 10
         retry_interval = 10
@@ -123,7 +124,7 @@ class TestOperationTask(object):
 
         assert api_task.name == api.task.OperationTask.NAME_FORMAT.format(
             type='relationship',
-            id=relationship.name,
+            name=relationship.name,
             interface=interface_name,
             operation=operation_name
         )
@@ -154,7 +155,8 @@ class TestOperationTask(object):
 
         relationship = ctx.model.relationship.list()[0]
         relationship.interfaces[interface.name] = interface
-        relationship.target_node.plugin_specifications = [plugin_specification]
+        relationship.target_node.plugin_specifications[plugin_specification.name] = \
+            plugin_specification
         inputs = {'test_input': True}
         max_attempts = 10
         retry_interval = 10
@@ -171,7 +173,7 @@ class TestOperationTask(object):
 
         assert api_task.name == api.task.OperationTask.NAME_FORMAT.format(
             type='relationship',
-            id=relationship.name,
+            name=relationship.name,
             interface=interface_name,
             operation=operation_name
         )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/workflows/builtin/test_execute_operation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/builtin/test_execute_operation.py b/tests/orchestrator/workflows/builtin/test_execute_operation.py
index e2a8ef0..360e17d 100644
--- a/tests/orchestrator/workflows/builtin/test_execute_operation.py
+++ b/tests/orchestrator/workflows/builtin/test_execute_operation.py
@@ -57,7 +57,7 @@ def test_execute_operation(ctx):
     assert len(execute_tasks) == 1
     assert execute_tasks[0].name == task.OperationTask.NAME_FORMAT.format(
         type='node',
-        id=node.name,
+        name=node.name,
         interface=interface_name,
         operation=operation_name
     )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/workflows/core/test_task.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/core/test_task.py b/tests/orchestrator/workflows/core/test_task.py
index 49f020f..f3ce92f 100644
--- a/tests/orchestrator/workflows/core/test_task.py
+++ b/tests/orchestrator/workflows/core/test_task.py
@@ -94,7 +94,8 @@ class TestOperationTask(object):
         ctx.model.plugin_specification.put(storage_plugin_specification)
         node = ctx.model.node.get_by_name(mock.models.DEPENDENCY_NODE_NAME)
         node_template = node.node_template
-        node_template.plugin_specifications = [storage_plugin_specification]
+        node_template.plugin_specifications[storage_plugin_specification.name] = \
+            storage_plugin_specification
         interface = mock.models.create_interface(
             node.service,
             NODE_INTERFACE_NAME,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/workflows/executor/test_process_executor_extension.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/executor/test_process_executor_extension.py b/tests/orchestrator/workflows/executor/test_process_executor_extension.py
index 0988fae..1c4cda6 100644
--- a/tests/orchestrator/workflows/executor/test_process_executor_extension.py
+++ b/tests/orchestrator/workflows/executor/test_process_executor_extension.py
@@ -55,8 +55,8 @@ def test_decorate_extension(context, executor):
     eng = engine.Engine(executor=executor, workflow_context=context, tasks_graph=graph)
     eng.execute()
     out = get_node(context).runtime_properties['out']
-    assert out['wrapper_inputs'] == inputs
-    assert out['function_inputs'] == inputs
+    assert out['wrapper_inputs'] == dict((k, v.value) for k, v in inputs.iteritems())
+    assert out['function_inputs'] == dict((k, v.value) for k, v in inputs.iteritems())
 
 
 @extension.process_executor

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/orchestrator/workflows/executor/test_process_executor_tracked_changes.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/executor/test_process_executor_tracked_changes.py b/tests/orchestrator/workflows/executor/test_process_executor_tracked_changes.py
index d84a153..e770b21 100644
--- a/tests/orchestrator/workflows/executor/test_process_executor_tracked_changes.py
+++ b/tests/orchestrator/workflows/executor/test_process_executor_tracked_changes.py
@@ -73,9 +73,9 @@ def test_apply_tracked_changes_during_an_operation(context, executor):
                         inputs=inputs)
 
     expected_after_update = expected_initial.copy()
-    expected_after_update.update(inputs['committed'])
+    expected_after_update.update(inputs['committed'].value)
     expected_after_change = expected_after_update.copy()
-    expected_after_change.update(inputs['changed_but_refreshed'])
+    expected_after_change.update(inputs['changed_but_refreshed'].value)
     expected_after_refresh = expected_after_update
 
     assert out['initial'] == expected_initial

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/tests/storage/test_resource_storage.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_resource_storage.py b/tests/storage/test_resource_storage.py
index 9b5f782..9f0c818 100644
--- a/tests/storage/test_resource_storage.py
+++ b/tests/storage/test_resource_storage.py
@@ -28,20 +28,20 @@ from . import TestFileSystem
 
 class TestResourceStorage(TestFileSystem):
     def _create(self, storage):
-        storage.register('blueprint')
+        storage.register('service_template')
 
     def _upload(self, storage, tmp_path, id):
         with open(tmp_path, 'w') as f:
             f.write('fake context')
 
-        storage.blueprint.upload(entry_id=id, source=tmp_path)
+        storage.service_template.upload(entry_id=id, source=tmp_path)
 
     def _upload_dir(self, storage, tmp_dir, tmp_file_name, id):
         file_source = os.path.join(tmp_dir, tmp_file_name)
         with open(file_source, 'w') as f:
             f.write('fake context')
 
-        storage.blueprint.upload(entry_id=id, source=tmp_dir)
+        storage.service_template.upload(entry_id=id, source=tmp_dir)
 
     def _create_storage(self):
         return ResourceStorage(FileSystemResourceAPI,
@@ -50,27 +50,27 @@ class TestResourceStorage(TestFileSystem):
     def test_name(self):
         api = FileSystemResourceAPI
         storage = ResourceStorage(FileSystemResourceAPI,
-                                  items=['blueprint'],
+                                  items=['service_template'],
                                   api_kwargs=dict(directory=self.path))
         assert repr(storage) == 'ResourceStorage(api={api})'.format(api=api)
         assert 'directory={resource_dir}'.format(resource_dir=self.path) in \
-               repr(storage.registered['blueprint'])
+               repr(storage.registered['service_template'])
 
     def test_create(self):
         storage = self._create_storage()
         self._create(storage)
-        assert os.path.exists(os.path.join(self.path, 'blueprint'))
+        assert os.path.exists(os.path.join(self.path, 'service_template'))
 
     def test_upload_file(self):
         storage = ResourceStorage(FileSystemResourceAPI, api_kwargs=dict(directory=self.path))
         self._create(storage)
         tmpfile_path = tempfile.mkstemp(suffix=self.__class__.__name__, dir=self.path)[1]
-        self._upload(storage, tmpfile_path, id='blueprint_id')
+        self._upload(storage, tmpfile_path, id='service_template_id')
 
         storage_path = os.path.join(
             self.path,
-            'blueprint',
-            'blueprint_id',
+            'service_template',
+            'service_template_id',
             os.path.basename(tmpfile_path))
         assert os.path.exists(storage_path)
 
@@ -82,11 +82,11 @@ class TestResourceStorage(TestFileSystem):
         self._create(storage)
         tmpfile_path = tempfile.mkstemp(suffix=self.__class__.__name__, dir=self.path)[1]
         tmpfile_name = os.path.basename(tmpfile_path)
-        self._upload(storage, tmpfile_path, 'blueprint_id')
+        self._upload(storage, tmpfile_path, 'service_template_id')
 
         temp_dir = tempfile.mkdtemp(dir=self.path)
-        storage.blueprint.download(
-            entry_id='blueprint_id',
+        storage.service_template.download(
+            entry_id='service_template_id',
             destination=temp_dir,
             path=tmpfile_name)
 
@@ -97,21 +97,21 @@ class TestResourceStorage(TestFileSystem):
         storage = self._create_storage()
         self._create(storage)
         with pytest.raises(exceptions.StorageError):
-            storage.blueprint.download(entry_id='blueprint_id', destination='', path='fake_path')
+            storage.service_template.download(entry_id='service_template_id', destination='', path='fake_path')
 
     def test_data_non_existing_file(self):
         storage = self._create_storage()
         self._create(storage)
         with pytest.raises(exceptions.StorageError):
-            storage.blueprint.read(entry_id='blueprint_id', path='fake_path')
+            storage.service_template.read(entry_id='service_template_id', path='fake_path')
 
     def test_data_file(self):
         storage = self._create_storage()
         self._create(storage)
         tmpfile_path = tempfile.mkstemp(suffix=self.__class__.__name__, dir=self.path)[1]
-        self._upload(storage, tmpfile_path, 'blueprint_id')
+        self._upload(storage, tmpfile_path, 'service_template_id')
 
-        assert storage.blueprint.read(entry_id='blueprint_id') == 'fake context'
+        assert storage.service_template.read(entry_id='service_template_id') == 'fake context'
 
     def test_upload_dir(self):
         storage = self._create_storage()
@@ -119,12 +119,12 @@ class TestResourceStorage(TestFileSystem):
         tmp_dir = tempfile.mkdtemp(suffix=self.__class__.__name__, dir=self.path)
         second_level_tmp_dir = tempfile.mkdtemp(dir=tmp_dir)
         tmp_filename = tempfile.mkstemp(dir=second_level_tmp_dir)[1]
-        self._upload_dir(storage, tmp_dir, tmp_filename, id='blueprint_id')
+        self._upload_dir(storage, tmp_dir, tmp_filename, id='service_template_id')
 
         destination = os.path.join(
             self.path,
-            'blueprint',
-            'blueprint_id',
+            'service_template',
+            'service_template_id',
             os.path.basename(second_level_tmp_dir),
             os.path.basename(tmp_filename))
 
@@ -136,21 +136,21 @@ class TestResourceStorage(TestFileSystem):
         tmp_dir = tempfile.mkdtemp(suffix=self.__class__.__name__, dir=self.path)
         second_level_tmp_dir = tempfile.mkdtemp(dir=tmp_dir)
         tmp_filename = tempfile.mkstemp(dir=second_level_tmp_dir)[1]
-        self._upload_dir(storage, tmp_dir, tmp_filename, id='blueprint_id')
+        self._upload_dir(storage, tmp_dir, tmp_filename, id='service_template_id')
 
         second_update_file = tempfile.mkstemp(dir=self.path)[1]
         with open(second_update_file, 'w') as f:
             f.write('fake context2')
 
-        storage.blueprint.upload(
-            entry_id='blueprint_id',
+        storage.service_template.upload(
+            entry_id='service_template_id',
             source=second_update_file,
             path=os.path.basename(second_level_tmp_dir))
 
         assert os.path.isfile(os.path.join(
             self.path,
-            'blueprint',
-            'blueprint_id',
+            'service_template',
+            'service_template_id',
             os.path.basename(second_level_tmp_dir),
             os.path.basename(second_update_file)))
 
@@ -160,11 +160,11 @@ class TestResourceStorage(TestFileSystem):
         tmp_dir = tempfile.mkdtemp(suffix=self.__class__.__name__, dir=self.path)
         second_level_tmp_dir = tempfile.mkdtemp(dir=tmp_dir)
         tmp_filename = tempfile.mkstemp(dir=second_level_tmp_dir)[1]
-        self._upload_dir(storage, tmp_dir, tmp_filename, id='blueprint_id')
+        self._upload_dir(storage, tmp_dir, tmp_filename, id='service_template_id')
 
         temp_destination_dir = tempfile.mkdtemp(dir=self.path)
-        storage.blueprint.download(
-            entry_id='blueprint_id',
+        storage.service_template.download(
+            entry_id='service_template_id',
             destination=temp_destination_dir)
 
         destination_file_path = os.path.join(
@@ -185,7 +185,7 @@ class TestResourceStorage(TestFileSystem):
         tempfile.mkstemp(dir=tmp_dir)
         tempfile.mkstemp(dir=tmp_dir)
 
-        storage.blueprint.upload(entry_id='blueprint_id', source=tmp_dir)
+        storage.service_template.upload(entry_id='service_template_id', source=tmp_dir)
 
         with pytest.raises(exceptions.StorageError):
-            storage.blueprint.read(entry_id='blueprint_id')
+            storage.service_template.read(entry_id='service_template_id')



[2/3] incubator-ariatosca git commit: Many cleanups; use dict for many models

Posted by em...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 613b371..13f355d 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -51,11 +51,11 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     :ivar meta_data: Custom annotations
     :vartype meta_data: {basestring: :class:`Metadata`}
     :ivar node: Nodes
-    :vartype node: [:class:`Node`]
+    :vartype node: {basestring: :class:`Node`}
     :ivar groups: Groups of nodes
-    :vartype groups: [:class:`Group`]
+    :vartype groups: {basestring: :class:`Group`}
     :ivar policies: Policies
-    :vartype policies: [:class:`Policy`]
+    :vartype policies: {basestring: :class:`Policy`]}
     :ivar substitution: The entire service can appear as a node
     :vartype substitution: :class:`Substitution`
     :ivar inputs: Externally provided parameters
@@ -88,48 +88,46 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     @declared_attr
     def service_template(cls):
-        return cls._create_many_to_one_relationship('service_template')
+        return cls._declare_many_to_one('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._create_many_to_many_relationship('metadata', dict_key='name')
+        return cls._declare_many_to_many('metadata', dict_key='name')
 
     @declared_attr
     def nodes(cls):
-        return cls._create_one_to_many_relationship('node')
+        return cls._declare_one_to_many('node', dict_key='name')
 
     @declared_attr
     def groups(cls):
-        return cls._create_one_to_many_relationship('group')
+        return cls._declare_one_to_many('group', dict_key='name')
 
     @declared_attr
     def policies(cls):
-        return cls._create_one_to_many_relationship('policy')
+        return cls._declare_one_to_many('policy', dict_key='name')
 
     @declared_attr
     def substitution(cls):
-        return cls._create_one_to_one_relationship('substitution')
+        return cls._declare_one_to_one('substitution')
 
     @declared_attr
     def inputs(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='inputs',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def outputs(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='outputs',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='outputs', dict_key='name')
 
     @declared_attr
     def workflows(cls):
-        return cls._create_one_to_many_relationship('operation', dict_key='name')
+        return cls._declare_one_to_many('operation', dict_key='name')
 
     @declared_attr
     def plugin_specifications(cls):
-        return cls._create_many_to_many_relationship('plugin_specification')
+        return cls._declare_many_to_many('plugin_specification')
 
     created_at = Column(DateTime, nullable=False, index=True)
     updated_at = Column(DateTime)
@@ -143,58 +141,43 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     # region foreign keys
 
-    __private_fields__ = ['substituion_fk',
-                          'service_template_fk']
-
-    # Service one-to-one to Substitution
     @declared_attr
     def substitution_fk(cls):
-        return cls._create_foreign_key('substitution', nullable=True)
+        """Service one-to-one to Substitution"""
+        return cls._declare_fk('substitution', nullable=True)
 
-    # Service many-to-one to ServiceTemplate
     @declared_attr
     def service_template_fk(cls):
-        return cls._create_foreign_key('service_template', nullable=True)
+        """For Service many-to-one to ServiceTemplate"""
+        return cls._declare_fk('service_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def service_template_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service_template', 'name')
 
     # endregion
 
     def satisfy_requirements(self):
         satisfied = True
-        for node in self.nodes:
+        for node in self.nodes.itervalues():
             if not node.satisfy_requirements():
                 satisfied = False
         return satisfied
 
     def validate_capabilities(self):
         satisfied = True
-        for node in self.nodes:
+        for node in self.nodes.itervalues():
             if not node.validate_capabilities():
                 satisfied = False
         return satisfied
 
-    def find_nodes(self, node_template_name):
-        nodes = []
-        for node in self.nodes:
-            if node.node_template.name == node_template_name:
-                nodes.append(node)
-        return collections.FrozenList(nodes)
-
-    def get_node_ids(self, node_template_name):
-        return collections.FrozenList((node.name for node in self.find_nodes(node_template_name)))
-
-    def find_groups(self, group_template_name):
-        groups = []
-        for group in self.groups:
-            if group.template_name == group_template_name:
-                groups.append(group)
-        return collections.FrozenList(groups)
-
-    def get_group_ids(self, group_template_name):
-        return collections.FrozenList((group.name
-                                       for group in self.find_groups(group_template_name)))
-
     def is_node_a_target(self, target_node):
-        for node in self.nodes:
+        for node in self.nodes.itervalues():
             if self._is_node_a_target(node, target_node):
                 return True
         return False
@@ -226,9 +209,9 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     def validate(self):
         utils.validate_dict_values(self.meta_data)
-        utils.validate_list_values(self.nodes)
-        utils.validate_list_values(self.groups)
-        utils.validate_list_values(self.policies)
+        utils.validate_dict_values(self.nodes)
+        utils.validate_dict_values(self.groups)
+        utils.validate_dict_values(self.policies)
         if self.substitution is not None:
             self.substitution.validate()
         utils.validate_dict_values(self.inputs)
@@ -237,9 +220,9 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     def coerce_values(self, container, report_issues):
         utils.coerce_dict_values(container, self.meta_data, report_issues)
-        utils.coerce_list_values(container, self.nodes, report_issues)
-        utils.coerce_list_values(container, self.groups, report_issues)
-        utils.coerce_list_values(container, self.policies, report_issues)
+        utils.coerce_dict_values(container, self.nodes, report_issues)
+        utils.coerce_dict_values(container, self.groups, report_issues)
+        utils.coerce_dict_values(container, self.policies, report_issues)
         if self.substitution is not None:
             self.substitution.coerce_values(container, report_issues)
         utils.coerce_dict_values(container, self.inputs, report_issues)
@@ -251,11 +234,11 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         if self.description is not None:
             console.puts(context.style.meta(self.description))
         utils.dump_dict_values(self.meta_data, 'Metadata')
-        for node in self.nodes:
+        for node in self.nodes.itervalues():
             node.dump()
-        for group in self.groups:
+        for group in self.groups.itervalues():
             group.dump()
-        for policy in self.policies:
+        for policy in self.policies.itervalues():
             policy.dump()
         if self.substitution is not None:
             self.substitution.dump()
@@ -264,7 +247,7 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         utils.dump_dict_values(self.workflows, 'Workflows')
 
     def dump_graph(self):
-        for node in self.nodes:
+        for node in self.nodes.itervalues():
             if not self.is_node_a_target(node):
                 self._dump_graph_node(node)
 
@@ -293,6 +276,10 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
                     with console.indent(3):
                         self._dump_graph_node(target_node)
 
+    __private_fields__ = ['substitution_fk',
+                          'service_template_fk',
+                          'service_template_name']
+
 
 class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     """
@@ -350,50 +337,47 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     @declared_attr
     def node_template(cls):
-        return cls._create_many_to_one_relationship('node_template')
+        return cls._declare_many_to_one('node_template')
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return cls._create_one_to_many_relationship('interface', dict_key='name')
+        return cls._declare_one_to_many('interface', dict_key='name')
 
     @declared_attr
     def artifacts(cls):
-        return cls._create_one_to_many_relationship('artifact', dict_key='name')
+        return cls._declare_one_to_many('artifact', dict_key='name')
 
     @declared_attr
     def capabilities(cls):
-        return cls._create_one_to_many_relationship('capability', dict_key='name')
+        return cls._declare_one_to_many('capability', dict_key='name')
 
     @declared_attr
     def outbound_relationships(cls):
-        return cls._create_one_to_many_relationship('relationship',
-                                                    foreign_key='source_node_fk',
-                                                    backreference='source_node')
+        return cls._declare_one_to_many('relationship', child_fk='source_node_fk',
+                                        child_property='source_node')
 
     @declared_attr
     def inbound_relationships(cls):
-        return cls._create_one_to_many_relationship('relationship',
-                                                    foreign_key='target_node_fk',
-                                                    backreference='target_node')
+        return cls._declare_one_to_many('relationship', child_fk='target_node_fk',
+                                        child_property='target_node')
 
     @declared_attr
     def plugin_specifications(cls):
-        return cls._create_many_to_many_relationship('plugin_specification')
+        return cls._declare_many_to_many('plugin_specification', dict_key='name')
 
     @declared_attr
     def host(cls):
-        return cls._create_relationship_to_self('host_fk')
+        return cls._declare_one_to_one_self('host_fk')
 
     # region orchestration
 
@@ -402,10 +386,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     state = Column(Text, nullable=False)
     version = Column(Integer, default=1)
 
-    @declared_attr
-    def service_name(cls):
-        return association_proxy('service', 'name')
-
     @property
     def ip(self):
         # TODO: totally broken
@@ -424,30 +404,34 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     # region foreign_keys
 
-    __private_fields__ = ['type_fk',
-                          'host_fk',
-                          'service_fk',
-                          'node_template_fk']
-
-    # Node many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For Node many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # Node one-to-one to Node
     @declared_attr
     def host_fk(cls):
-        return cls._create_foreign_key('node', nullable=True)
+        """For Node one-to-one to Node"""
+        return cls._declare_fk('node', nullable=True)
 
-    # Service one-to-many to Node
     @declared_attr
     def service_fk(cls):
-        return cls._create_foreign_key('service')
+        """For Service one-to-many to Node"""
+        return cls._declare_fk('service')
 
-    # Node many-to-one to NodeTemplate
     @declared_attr
     def node_template_fk(cls):
-        return cls._create_foreign_key('node_template', nullable=True)
+        """For Node many-to-one to NodeTemplate"""
+        return cls._declare_fk('node_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def service_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service', 'name')
 
     # endregion
 
@@ -475,7 +459,7 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         from . import models
         context = ConsumptionContext.get_thread_local()
         # Find target nodes
-        target_nodes = context.modeling.instance.find_nodes(target_node_template.name)
+        target_nodes = target_node_template.nodes.all()
         if target_nodes:
             target_node = None
             target_capability = None
@@ -539,7 +523,7 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     def as_raw(self):
         return collections.OrderedDict((
             ('name', self.name),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('properties', formatting.as_raw_dict(self.properties)),
             ('interfaces', formatting.as_raw_list(self.interfaces)),
             ('artifacts', formatting.as_raw_list(self.artifacts)),
@@ -583,6 +567,12 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
             utils.dump_dict_values(self.capabilities, 'Capabilities')
             utils.dump_list_values(self.outbound_relationships, 'Relationships')
 
+    __private_fields__ = ['type_fk',
+                          'host_fk',
+                          'service_fk',
+                          'node_template_fk',
+                          'service_name']
+
 
 class GroupBase(InstanceModelMixin):
     """
@@ -613,47 +603,42 @@ class GroupBase(InstanceModelMixin):
 
     @declared_attr
     def group_template(cls):
-        return cls._create_many_to_one_relationship('group_template')
+        return cls._declare_many_to_one('group_template')
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def nodes(cls):
-        return cls._create_many_to_many_relationship('node')
+        return cls._declare_many_to_many('node')
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return cls._create_one_to_many_relationship('interface', dict_key='name')
+        return cls._declare_one_to_many('interface', dict_key='name')
 
     # region foreign_keys
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'group_template_fk']
-
-    # Group many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For Group many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # Service one-to-many to Group
     @declared_attr
     def service_fk(cls):
-        return cls._create_foreign_key('service')
+        """For Service one-to-many to Group"""
+        return cls._declare_fk('service')
 
-    # Group many-to-one to GroupTemplate
     @declared_attr
     def group_template_fk(cls):
-        return cls._create_foreign_key('group_template', nullable=True)
+        """For Group many-to-one to GroupTemplate"""
+        return cls._declare_fk('group_template', nullable=True)
 
     # endregion
 
@@ -685,6 +670,10 @@ class GroupBase(InstanceModelMixin):
                     for node in self.nodes:
                         console.puts(context.style.node(node.name))
 
+    __private_fields__ = ['type_fk',
+                          'service_fk',
+                          'group_template_fk']
+
 
 class PolicyBase(InstanceModelMixin):
     """
@@ -713,47 +702,42 @@ class PolicyBase(InstanceModelMixin):
 
     @declared_attr
     def policy_template(cls):
-        return cls._create_many_to_one_relationship('policy_template')
+        return cls._declare_many_to_one('policy_template')
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def nodes(cls):
-        return cls._create_many_to_many_relationship('node')
+        return cls._declare_many_to_many('node')
 
     @declared_attr
     def groups(cls):
-        return cls._create_many_to_many_relationship('group')
+        return cls._declare_many_to_many('group')
 
     # region foreign_keys
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'policy_template_fk']
-
-    # Policy many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For Policy many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # Service one-to-many to Policy
     @declared_attr
     def service_fk(cls):
-        return cls._create_foreign_key('service')
+        """For Service one-to-many to Policy"""
+        return cls._declare_fk('service')
 
-    # Policy many-to-one to PolicyTemplate
     @declared_attr
     def policy_template_fk(cls):
-        return cls._create_foreign_key('policy_template', nullable=True)
+        """For Policy many-to-one to PolicyTemplate"""
+        return cls._declare_fk('policy_template', nullable=True)
 
     # endregion
 
@@ -761,7 +745,7 @@ class PolicyBase(InstanceModelMixin):
     def as_raw(self):
         return collections.OrderedDict((
             ('name', self.name),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('properties', formatting.as_raw_dict(self.properties))))
 
     def validate(self):
@@ -787,6 +771,10 @@ class PolicyBase(InstanceModelMixin):
                     for group in self.groups:
                         console.puts(context.style.node(group.name))
 
+    __private_fields__ = ['type_fk',
+                          'service_fk',
+                          'policy_template_fk']
+
 
 class SubstitutionBase(InstanceModelMixin):
     """
@@ -809,30 +797,27 @@ class SubstitutionBase(InstanceModelMixin):
 
     @declared_attr
     def substitution_template(cls):
-        return cls._create_many_to_one_relationship('substitution_template')
+        return cls._declare_many_to_one('substitution_template')
 
     @declared_attr
     def node_type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     @declared_attr
     def mappings(cls):
-        return cls._create_one_to_many_relationship('substitution_mapping', dict_key='name')
+        return cls._declare_one_to_many('substitution_mapping', dict_key='name')
 
     # region foreign_keys
 
-    __private_fields__ = ['node_type_fk',
-                          'substitution_template_fk']
-
-    # Substitution many-to-one to Type
     @declared_attr
     def node_type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For Substitution many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # Substitution many-to-one to SubstitutionTemplate
     @declared_attr
     def substitution_template_fk(cls):
-        return cls._create_foreign_key('substitution_template', nullable=True)
+        """For Substitution many-to-one to SubstitutionTemplate"""
+        return cls._declare_fk('substitution_template', nullable=True)
 
     # endregion
 
@@ -855,6 +840,9 @@ class SubstitutionBase(InstanceModelMixin):
             console.puts('Node type: {0}'.format(context.style.type(self.node_type.name)))
             utils.dump_dict_values(self.mappings, 'Mappings')
 
+    __private_fields__ = ['node_type_fk',
+                          'substitution_template_fk']
+
 
 class SubstitutionMappingBase(InstanceModelMixin):
     """
@@ -881,42 +869,37 @@ class SubstitutionMappingBase(InstanceModelMixin):
 
     @declared_attr
     def node(cls):
-        return cls._create_one_to_one_relationship('node')
+        return cls._declare_one_to_one('node')
 
     @declared_attr
     def capability(cls):
-        return cls._create_one_to_one_relationship('capability')
+        return cls._declare_one_to_one('capability')
 
     @declared_attr
     def requirement_template(cls):
-        return cls._create_one_to_one_relationship('requirement_template')
+        return cls._declare_one_to_one('requirement_template')
 
     # region foreign keys
 
-    __private_fields__ = ['substitution_fk',
-                          'node_fk',
-                          'capability_fk',
-                          'requirement_template_fk']
-
-    # Substitution one-to-many to SubstitutionMapping
     @declared_attr
     def substitution_fk(cls):
-        return cls._create_foreign_key('substitution')
+        """For Substitution one-to-many to SubstitutionMapping"""
+        return cls._declare_fk('substitution')
 
-    # Substitution one-to-one to NodeTemplate
     @declared_attr
     def node_fk(cls):
-        return cls._create_foreign_key('node')
+        """For Substitution one-to-one to NodeTemplate"""
+        return cls._declare_fk('node')
 
-    # Substitution one-to-one to Capability
     @declared_attr
     def capability_fk(cls):
-        return cls._create_foreign_key('capability', nullable=True)
+        """For Substitution one-to-one to Capability"""
+        return cls._declare_fk('capability', nullable=True)
 
-    # Substitution one-to-one to RequirementTemplate
     @declared_attr
     def requirement_template_fk(cls):
-        return cls._create_foreign_key('requirement_template', nullable=True)
+        """For Substitution one-to-one to RequirementTemplate"""
+        return cls._declare_fk('requirement_template', nullable=True)
 
     # endregion
 
@@ -943,6 +926,11 @@ class SubstitutionMappingBase(InstanceModelMixin):
                                if self.capability
                                else self.requirement_template.name)))
 
+    __private_fields__ = ['substitution_fk',
+                          'node_fk',
+                          'capability_fk',
+                          'requirement_template_fk']
+
 
 class RelationshipBase(InstanceModelMixin):
     """
@@ -982,28 +970,27 @@ class RelationshipBase(InstanceModelMixin):
 
     @declared_attr
     def relationship_template(cls):
-        return cls._create_many_to_one_relationship('relationship_template')
+        return cls._declare_many_to_one('relationship_template')
 
     @declared_attr
     def requirement_template(cls):
-        return cls._create_many_to_one_relationship('requirement_template')
+        return cls._declare_many_to_one('requirement_template')
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     @declared_attr
     def target_capability(cls):
-        return cls._create_one_to_one_relationship('capability')
+        return cls._declare_one_to_one('capability')
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return cls._create_one_to_many_relationship('interface', dict_key='name')
+        return cls._declare_one_to_many('interface', dict_key='name')
 
     # region orchestration
 
@@ -1014,42 +1001,49 @@ class RelationshipBase(InstanceModelMixin):
 
     # region foreign keys
 
-    __private_fields__ = ['type_fk',
-                          'source_node_fk',
-                          'target_node_fk',
-                          'target_capability_fk',
-                          'requirement_template_fk',
-                          'relationship_template_fk']
-
-    # Relationship many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type', nullable=True)
+        """For Relationship many-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    # Node one-to-many to Relationship
     @declared_attr
     def source_node_fk(cls):
-        return cls._create_foreign_key('node')
+        """For Node one-to-many to Relationship"""
+        return cls._declare_fk('node')
 
-    # Node one-to-many to Relationship
     @declared_attr
     def target_node_fk(cls):
-        return cls._create_foreign_key('node')
+        """For Node one-to-many to Relationship"""
+        return cls._declare_fk('node')
 
-    # Relationship one-to-one to Capability
     @declared_attr
     def target_capability_fk(cls):
-        return cls._create_foreign_key('capability', nullable=True)
+        """For Relationship one-to-one to Capability"""
+        return cls._declare_fk('capability', nullable=True)
 
-    # Relationship many-to-one to RequirementTemplate
     @declared_attr
     def requirement_template_fk(cls):
-        return cls._create_foreign_key('requirement_template', nullable=True)
+        """For Relationship many-to-one to RequirementTemplate"""
+        return cls._declare_fk('requirement_template', nullable=True)
 
-    # Relationship many-to-one to RelationshipTemplate
     @declared_attr
     def relationship_template_fk(cls):
-        return cls._create_foreign_key('relationship_template', nullable=True)
+        """For Relationship many-to-one to RelationshipTemplate"""
+        return cls._declare_fk('relationship_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def source_node_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('source_node', 'name')
+
+    @declared_attr
+    def target_node_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('target_node', 'name')
 
     # endregion
 
@@ -1058,8 +1052,10 @@ class RelationshipBase(InstanceModelMixin):
         return collections.OrderedDict((
             ('name', self.name),
             ('target_node_id', self.target_node.name),
-            ('type_name', self.type_name),
-            ('template_name', self.template_name),
+            ('type_name', self.type.name
+             if self.type is not None else None),
+            ('template_name', self.relationship_template.name
+             if self.relationship_template is not None else None),
             ('properties', formatting.as_raw_dict(self.properties)),
             ('interfaces', formatting.as_raw_list(self.interfaces))))
 
@@ -1090,6 +1086,15 @@ class RelationshipBase(InstanceModelMixin):
             utils.dump_dict_values(self.properties, 'Properties')
             utils.dump_interfaces(self.interfaces, 'Interfaces')
 
+    __private_fields__ = ['type_fk',
+                          'source_node_fk',
+                          'target_node_fk',
+                          'target_capability_fk',
+                          'requirement_template_fk',
+                          'relationship_template_fk',
+                          'source_node_name',
+                          'target_node_name']
+
 
 class CapabilityBase(InstanceModelMixin):
     """
@@ -1124,11 +1129,11 @@ class CapabilityBase(InstanceModelMixin):
 
     @declared_attr
     def capability_template(cls):
-        return cls._create_many_to_one_relationship('capability_template')
+        return cls._declare_many_to_one('capability_template')
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     min_occurrences = Column(Integer, default=None)
     max_occurrences = Column(Integer, default=None)
@@ -1136,29 +1141,24 @@ class CapabilityBase(InstanceModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     # region foreign_keys
 
-    __private_fields__ = ['capability_fk',
-                          'node_fk',
-                          'capability_template_fk']
-
-    # Capability many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For Capability many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # Node one-to-many to Capability
     @declared_attr
     def node_fk(cls):
-        return cls._create_foreign_key('node')
+        """For Node one-to-many to Capability"""
+        return cls._declare_fk('node')
 
-    # Capability many-to-one to CapabilityTemplate
     @declared_attr
     def capability_template_fk(cls):
-        return cls._create_foreign_key('capability_template', nullable=True)
+        """For Capability many-to-one to CapabilityTemplate"""
+        return cls._declare_fk('capability_template', nullable=True)
 
     # endregion
 
@@ -1179,7 +1179,7 @@ class CapabilityBase(InstanceModelMixin):
     def as_raw(self):
         return collections.OrderedDict((
             ('name', self.name),
-            ('type_name', self.type_name),
+            ('type_name', self.type.name),
             ('properties', formatting.as_raw_dict(self.properties))))
 
     def validate(self):
@@ -1201,6 +1201,10 @@ class CapabilityBase(InstanceModelMixin):
                 else ' or more'))
             utils.dump_dict_values(self.properties, 'Properties')
 
+    __private_fields__ = ['capability_fk',
+                          'node_fk',
+                          'capability_template_fk']
+
 
 class InterfaceBase(InstanceModelMixin):
     """
@@ -1233,55 +1237,48 @@ class InterfaceBase(InstanceModelMixin):
 
     @declared_attr
     def interface_template(cls):
-        return cls._create_many_to_one_relationship('interface_template')
+        return cls._declare_many_to_one('interface_template')
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def inputs(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='inputs',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def operations(cls):
-        return cls._create_one_to_many_relationship('operation', dict_key='name')
+        return cls._declare_one_to_many('operation', dict_key='name')
 
     # region foreign_keys
 
-    __private_fields__ = ['type_fk',
-                          'node_fk',
-                          'group_fk',
-                          'relationship_fk',
-                          'interface_template_fk']
-
-    # Interface many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For Interface many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # Node one-to-many to Interface
     @declared_attr
     def node_fk(cls):
-        return cls._create_foreign_key('node', nullable=True)
+        """For Node one-to-many to Interface"""
+        return cls._declare_fk('node', nullable=True)
 
-    # Group one-to-many to Interface
     @declared_attr
     def group_fk(cls):
-        return cls._create_foreign_key('group', nullable=True)
+        """For Group one-to-many to Interface"""
+        return cls._declare_fk('group', nullable=True)
 
-    # Relationship one-to-many to Interface
     @declared_attr
     def relationship_fk(cls):
-        return cls._create_foreign_key('relationship', nullable=True)
+        """For Relationship one-to-many to Interface"""
+        return cls._declare_fk('relationship', nullable=True)
 
-    # Interface many-to-one to InterfaceTemplate
     @declared_attr
     def interface_template_fk(cls):
-        return cls._create_foreign_key('interface_template', nullable=True)
+        """For Interface many-to-one to InterfaceTemplate"""
+        return cls._declare_fk('interface_template', nullable=True)
 
     # endregion
 
@@ -1290,7 +1287,7 @@ class InterfaceBase(InstanceModelMixin):
         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)),
             ('operations', formatting.as_raw_list(self.operations))))
 
@@ -1312,6 +1309,12 @@ class InterfaceBase(InstanceModelMixin):
             utils.dump_dict_values(self.inputs, 'Inputs')
             utils.dump_dict_values(self.operations, 'Operations')
 
+    __private_fields__ = ['type_fk',
+                          'node_fk',
+                          'group_fk',
+                          'relationship_fk',
+                          'interface_template_fk']
+
 
 class OperationBase(InstanceModelMixin):
     """
@@ -1350,21 +1353,20 @@ class OperationBase(InstanceModelMixin):
 
     @declared_attr
     def operation_template(cls):
-        return cls._create_many_to_one_relationship('operation_template')
+        return cls._declare_many_to_one('operation_template')
 
     description = Column(Text)
 
     @declared_attr
     def plugin_specification(cls):
-        return cls._create_one_to_one_relationship('plugin_specification')
+        return cls._declare_one_to_one('plugin_specification')
 
     implementation = Column(Text)
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
 
     @declared_attr
     def inputs(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='inputs',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
 
     executor = Column(Text)
     max_retries = Column(Integer)
@@ -1372,30 +1374,25 @@ class OperationBase(InstanceModelMixin):
 
     # region foreign_keys
 
-    __private_fields__ = ['service_fk',
-                          'interface_fk',
-                          'plugin_fk',
-                          'operation_template_fk']
-
-    # Service one-to-many to Operation
     @declared_attr
     def service_fk(cls):
-        return cls._create_foreign_key('service', nullable=True)
+        """For Service one-to-many to Operation"""
+        return cls._declare_fk('service', nullable=True)
 
-    # Interface one-to-many to Operation
     @declared_attr
     def interface_fk(cls):
-        return cls._create_foreign_key('interface', nullable=True)
+        """For Interface one-to-many to Operation"""
+        return cls._declare_fk('interface', nullable=True)
 
-    # Operation one-to-one to PluginSpecification
     @declared_attr
     def plugin_specification_fk(cls):
-        return cls._create_foreign_key('plugin_specification', nullable=True)
+        """For Operation one-to-one to PluginSpecification"""
+        return cls._declare_fk('plugin_specification', nullable=True)
 
-    # Operation many-to-one to OperationTemplate
     @declared_attr
     def operation_template_fk(cls):
-        return cls._create_foreign_key('operation_template', nullable=True)
+        """For Operation many-to-one to OperationTemplate"""
+        return cls._declare_fk('operation_template', nullable=True)
 
     # endregion
 
@@ -1440,6 +1437,11 @@ class OperationBase(InstanceModelMixin):
                     context.style.literal(self.retry_interval)))
             utils.dump_dict_values(self.inputs, 'Inputs')
 
+    __private_fields__ = ['service_fk',
+                          'interface_fk',
+                          'plugin_fk',
+                          'operation_template_fk']
+
 
 class ArtifactBase(InstanceModelMixin):
     """
@@ -1474,11 +1476,11 @@ class ArtifactBase(InstanceModelMixin):
 
     @declared_attr
     def artifact_template(cls):
-        return cls._create_many_to_one_relationship('artifact_template')
+        return cls._declare_many_to_one('artifact_template')
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
     source_path = Column(Text)
@@ -1488,29 +1490,24 @@ class ArtifactBase(InstanceModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     # region foreign_keys
 
-    __private_fields__ = ['type_fk',
-                          'node_fk',
-                          'artifact_template_fk']
-
-    # Artifact many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For Artifact many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # Node one-to-many to Artifact
     @declared_attr
     def node_fk(cls):
-        return cls._create_foreign_key('node')
+        """For Node one-to-many to Artifact"""
+        return cls._declare_fk('node')
 
-    # Artifact many-to-one to ArtifactTemplate
     @declared_attr
     def artifact_template_fk(cls):
-        return cls._create_foreign_key('artifact_template', nullable=True)
+        """For Artifact many-to-one to ArtifactTemplate"""
+        return cls._declare_fk('artifact_template', nullable=True)
 
     # endregion
 
@@ -1519,7 +1516,7 @@ class ArtifactBase(InstanceModelMixin):
         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),
@@ -1549,3 +1546,7 @@ class ArtifactBase(InstanceModelMixin):
                 console.puts('Repository credential: {0}'.format(
                     context.style.literal(self.repository_credential)))
             utils.dump_dict_values(self.properties, 'Properties')
+
+    __private_fields__ = ['type_fk',
+                          'node_fk',
+                          'artifact_template_fk']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index d2d6c4b..b365720 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -27,6 +27,7 @@ from sqlalchemy import (
     DateTime
 )
 from sqlalchemy.ext.declarative import declared_attr
+from sqlalchemy.ext.associationproxy import association_proxy
 
 from ..parser import validation
 from ..parser.consumption import ConsumptionContext
@@ -38,8 +39,6 @@ from . import (
     types as modeling_types
 )
 
-from . import relationship
-
 
 class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public-methods
     """
@@ -57,11 +56,11 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
     :ivar meta_data: Custom annotations
     :vartype meta_data: {basestring: :class:`Metadata`}
     :ivar node_templates: Templates for creating nodes
-    :vartype node_templates: [:class:`NodeTemplate`]
+    :vartype node_templates: {basestring: :class:`NodeTemplate`}
     :ivar group_templates: Templates for creating groups
-    :vartype group_templates: [:class:`GroupTemplate`]
+    :vartype group_templates: {basestring: :class:`GroupTemplate`}
     :ivar policy_templates: Templates for creating policies
-    :vartype policy_templates: [:class:`PolicyTemplate`]
+    :vartype policy_templates: {basestring: :class:`PolicyTemplate`}
     :ivar substitution_template: The entire service can appear as a node
     :vartype substitution_template: :class:`SubstitutionTemplate`
     :ivar inputs: Externally provided parameters
@@ -102,70 +101,70 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
     description = Column(Text)
     main_file_name = Column(Text)
 
-    @relationship.many_to_many('metadata', dict_key='name')
+    @declared_attr
     def meta_data(cls):
         # Warning! We cannot use the attr name "metadata" because it's used by SqlAlchemy!
-        pass
+        return cls._declare_many_to_many('metadata', dict_key='name')
 
-    @relationship.one_to_many('node_template')
+    @declared_attr
     def node_templates(cls):
-        pass
+        return cls._declare_one_to_many('node_template', dict_key='name')
 
-    @relationship.one_to_many('group_template')
+    @declared_attr
     def group_templates(cls):
-        pass
+        return cls._declare_one_to_many('group_template', dict_key='name')
 
-    @relationship.one_to_many('policy_template')
+    @declared_attr
     def policy_templates(cls):
-        pass
+        return cls._declare_one_to_many('policy_template', dict_key='name')
 
-    @relationship.one_to_one('substitution_template')
+    @declared_attr
     def substitution_template(cls):
-        pass
+        return cls._declare_one_to_one('substitution_template')
 
-    @relationship.many_to_many('parameter', prefix='inputs', dict_key='name')
+    @declared_attr
     def inputs(cls):
-        pass
+        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
 
-    @relationship.many_to_many('parameter', prefix='outputs', dict_key='name')
+    @declared_attr
     def outputs(cls):
-        pass
+        return cls._declare_many_to_many('parameter', prefix='outputs', dict_key='name')
 
-    @relationship.one_to_many('operation_template', dict_key='name')
+    @declared_attr
     def workflow_templates(cls):
-        pass
+        return cls._declare_one_to_many('operation_template', dict_key='name')
 
-    @relationship.one_to_many('plugin_specification')
+    @declared_attr
     def plugin_specifications(cls):
-        pass
+        return cls._declare_one_to_many('plugin_specification', dict_key='name')
 
-    @relationship.one_to_one('type', fk='node_type_fk', other_property=False)
+    @declared_attr
     def node_types(cls):
-        pass
+        return cls._declare_one_to_one('type', fk='node_type_fk', other_property=False)
 
-    @relationship.one_to_one('type', fk='group_type_fk', other_property=False)
+    @declared_attr
     def group_types(cls):
-        pass
+        return cls._declare_one_to_one('type', fk='group_type_fk', other_property=False)
 
-    @relationship.one_to_one('type', fk='policy_type_fk', other_property=False)
+    @declared_attr
     def policy_types(cls):
-        pass
+        return cls._declare_one_to_one('type', fk='policy_type_fk', other_property=False)
 
-    @relationship.one_to_one('type', fk='relationship_type_fk', other_property=False)
+    @declared_attr
     def relationship_types(cls):
-        pass
+        return cls._declare_one_to_one('type', fk='relationship_type_fk', other_property=False)
 
-    @relationship.one_to_one('type', fk='capability_type_fk', other_property=False)
+    @declared_attr
     def capability_types(cls):
-        pass
+        return cls._declare_one_to_one('type', fk='capability_type_fk', other_property=False)
 
-    @relationship.one_to_one('type', fk='interface_type_fk', other_property=False)
+    @declared_attr
     def interface_types(cls):
-        pass
+        return cls._declare_one_to_one('type', fk='interface_type_fk', other_property=False)
 
-    @relationship.one_to_one('type', fk='artifact_type_fk', other_property=False)
+    @declared_attr
     def artifact_types(cls):
-        pass
+        return cls._declare_one_to_one('type', fk='artifact_type_fk', other_property=False)
 
     # region orchestration
 
@@ -176,54 +175,48 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
 
     # region foreign keys
 
-    @relationship.fk('substitution_template', nullable=True)
+    @declared_attr
     def substitution_template_fk(cls):
         """For ServiceTemplate one-to-one to SubstitutionTemplate"""
+        return cls._declare_fk('substitution_template', nullable=True)
 
-    @relationship.fk('type', nullable=True)
+    @declared_attr
     def node_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    @relationship.fk('type', nullable=True)
+    @declared_attr
     def group_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    @relationship.fk('type', nullable=True)
+    @declared_attr
     def policy_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    @relationship.fk('type', nullable=True)
+    @declared_attr
     def relationship_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    @relationship.fk('type', nullable=True)
+    @declared_attr
     def capability_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    @relationship.fk('type', nullable=True)
+    @declared_attr
     def interface_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    @relationship.fk('type', nullable=True)
+    @declared_attr
     def artifact_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
     # endregion
 
-    def get_node_template(self, node_template_name):
-        if self.node_templates:
-            for node_template in self.node_templates:
-                if node_template.name == node_template_name:
-                    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((
@@ -262,13 +255,13 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
 
         utils.instantiate_dict(self, service.meta_data, self.meta_data)
 
-        for node_template in self.node_templates:
+        for node_template in self.node_templates.itervalues():
             for _ in range(node_template.default_instances):
                 node = node_template.instantiate(container)
-                service.nodes.append(node)
+                service.nodes[node.name] = node
 
-        utils.instantiate_list(self, service.groups, self.group_templates)
-        utils.instantiate_list(self, service.policies, self.policy_templates)
+        utils.instantiate_dict(self, service.groups, self.group_templates)
+        utils.instantiate_dict(self, service.policies, self.policy_templates)
         utils.instantiate_dict(self, service.workflows, self.workflow_templates)
 
         if self.substitution_template is not None:
@@ -287,9 +280,9 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
 
     def validate(self):
         utils.validate_dict_values(self.meta_data)
-        utils.validate_list_values(self.node_templates)
-        utils.validate_list_values(self.group_templates)
-        utils.validate_list_values(self.policy_templates)
+        utils.validate_dict_values(self.node_templates)
+        utils.validate_dict_values(self.group_templates)
+        utils.validate_dict_values(self.policy_templates)
         if self.substitution_template is not None:
             self.substitution_template.validate()
         utils.validate_dict_values(self.inputs)
@@ -312,9 +305,9 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
 
     def coerce_values(self, container, report_issues):
         utils.coerce_dict_values(container, self.meta_data, report_issues)
-        utils.coerce_list_values(container, self.node_templates, report_issues)
-        utils.coerce_list_values(container, self.group_templates, report_issues)
-        utils.coerce_list_values(container, self.policy_templates, report_issues)
+        utils.coerce_dict_values(container, self.node_templates, report_issues)
+        utils.coerce_dict_values(container, self.group_templates, report_issues)
+        utils.coerce_dict_values(container, self.policy_templates, report_issues)
         if self.substitution_template is not None:
             self.substitution_template.coerce_values(container, report_issues)
         utils.coerce_dict_values(container, self.inputs, report_issues)
@@ -322,19 +315,15 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
         utils.coerce_dict_values(container, self.workflow_templates, report_issues)
 
     def dump(self):
-        #print dir(self)
-        #from inspect import getdoc
-        #print getdoc(self.__class__.substitution_template_fk)
-        #exit()
         context = ConsumptionContext.get_thread_local()
         if self.description is not None:
             console.puts(context.style.meta(self.description))
         utils.dump_dict_values(self.meta_data, 'Metadata')
-        for node_template in self.node_templates:
+        for node_template in self.node_templates.itervalues():
             node_template.dump()
-        for group_template in self.group_templates:
+        for group_template in self.group_templates.itervalues():
             group_template.dump()
-        for policy_template in self.policy_templates:
+        for policy_template in self.policy_templates.itervalues():
             policy_template.dump()
         if self.substitution_template is not None:
             self.substitution_template.dump()
@@ -365,6 +354,15 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
             console.puts('Interface types:')
             self.interface_types.dump()
 
+    __private_fields__ = ['substitution_template_fk',
+                          'node_type_fk',
+                          'group_type_fk',
+                          'policy_type_fk',
+                          'relationship_type_fk',
+                          'capability_type_fk',
+                          'interface_type_fk',
+                          'artifact_type_fk']
+
 
 class NodeTemplateBase(TemplateModelMixin):
     """
@@ -414,7 +412,7 @@ class NodeTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
     default_instances = Column(Integer, default=1)
@@ -423,47 +421,51 @@ class NodeTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls._create_one_to_many_relationship('interface_template', dict_key='name')
+        return cls._declare_one_to_many('interface_template', dict_key='name')
 
     @declared_attr
     def artifact_templates(cls):
-        return cls._create_one_to_many_relationship('artifact_template', dict_key='name')
+        return cls._declare_one_to_many('artifact_template', dict_key='name')
 
     @declared_attr
     def capability_templates(cls):
-        return cls._create_one_to_many_relationship('capability_template', dict_key='name')
+        return cls._declare_one_to_many('capability_template', dict_key='name')
 
     @declared_attr
     def requirement_templates(cls):
-        return cls._create_one_to_many_relationship('requirement_template',
-                                                    foreign_key='node_template_fk',
-                                                    backreference='node_template')
+        return cls._declare_one_to_many('requirement_template', child_fk='node_template_fk',
+                                        child_property='node_template')
 
     target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
 
     @declared_attr
     def plugin_specifications(cls):
-        return cls._create_many_to_many_relationship('plugin_specification')
+        return cls._declare_many_to_many('plugin_specification', dict_key='name')
 
     # region foreign_keys
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk']
-
-    # NodeTemplate many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For NodeTemplate many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # ServiceTemplate one-to-many to NodeTemplate
     @declared_attr
     def service_template_fk(cls):
-        return cls._create_foreign_key('service_template')
+        """For ServiceTemplate one-to-many to NodeTemplate"""
+        return cls._declare_fk('service_template')
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def service_template_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service_template', 'name')
 
     # endregion
 
@@ -537,6 +539,10 @@ class NodeTemplateBase(TemplateModelMixin):
             utils.dump_dict_values(self.capability_templates, 'Capability templates')
             utils.dump_list_values(self.requirement_templates, 'Requirement templates')
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk',
+                          'service_template_name']
+
 
 class GroupTemplateBase(TemplateModelMixin):
     """
@@ -569,37 +575,33 @@ class GroupTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def node_templates(cls):
-        return cls._create_many_to_many_relationship('node_template')
+        return cls._declare_many_to_many('node_template')
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls._create_one_to_many_relationship('interface_template', dict_key='name')
+        return cls._declare_one_to_many('interface_template', dict_key='name')
 
     # region foreign keys
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk']
-
-    # GroupTemplate many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For GroupTemplate many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # ServiceTemplate one-to-many to GroupTemplate
     @declared_attr
     def service_template_fk(cls):
-        return cls._create_foreign_key('service_template')
+        """For ServiceTemplate one-to-many to GroupTemplate"""
+        return cls._declare_fk('service_template')
 
     # endregion
 
@@ -646,6 +648,9 @@ class GroupTemplateBase(TemplateModelMixin):
                 console.puts('Member node templates: {0}'.format(', '.join(
                     (str(context.style.node(v.name)) for v in self.node_templates))))
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk']
+
 
 class PolicyTemplateBase(TemplateModelMixin):
     """
@@ -675,37 +680,33 @@ class PolicyTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def node_templates(cls):
-        return cls._create_many_to_many_relationship('node_template')
+        return cls._declare_many_to_many('node_template')
 
     @declared_attr
     def group_templates(cls):
-        return cls._create_many_to_many_relationship('group_template')
+        return cls._declare_many_to_many('group_template')
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     # region foreign keys
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk']
-
-    # PolicyTemplate many-to-one to Type
     @declared_attr
     def type_fk(cls):
-        return cls._create_foreign_key('type')
+        """For PolicyTemplate many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # ServiceTemplate one-to-many to PolicyTemplate
     @declared_attr
     def service_template_fk(cls):
-        return cls._create_foreign_key('service_template')
+        """For ServiceTemplate one-to-many to PolicyTemplate"""
+        return cls._declare_fk('service_template')
 
     # endregion
 
@@ -753,6 +754,9 @@ class PolicyTemplateBase(TemplateModelMixin):
                 console.puts('Target group templates: {0}'.format(', '.join(
                     (str(context.style.node(v.name)) for v in self.group_templates))))
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk']
+
 
 class SubstitutionTemplateBase(TemplateModelMixin):
     """
@@ -773,21 +777,18 @@ class SubstitutionTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def node_type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     @declared_attr
     def mappings(cls):
-        return cls._create_one_to_many_relationship('substitution_template_mapping',
-                                                    dict_key='name')
+        return cls._declare_one_to_many('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._create_foreign_key('type')
+        """For SubstitutionTemplate many-to-one to Type"""
+        return cls._declare_fk('type')
 
     # endregion
 
@@ -817,6 +818,8 @@ class SubstitutionTemplateBase(TemplateModelMixin):
             console.puts('Node type: {0}'.format(context.style.type(self.node_type.name)))
             utils.dump_dict_values(self.mappings, 'Mappings')
 
+    __private_fields__ = ['node_type_fk']
+
 
 class SubstitutionTemplateMappingBase(TemplateModelMixin):
     """
@@ -841,42 +844,37 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
 
     @declared_attr
     def node_template(cls):
-        return cls._create_one_to_one_relationship('node_template')
+        return cls._declare_one_to_one('node_template')
 
     @declared_attr
     def capability_template(cls):
-        return cls._create_one_to_one_relationship('capability_template')
+        return cls._declare_one_to_one('capability_template')
 
     @declared_attr
     def requirement_template(cls):
-        return cls._create_one_to_one_relationship('requirement_template')
+        return cls._declare_one_to_one('requirement_template')
 
     # 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):
-        return cls._create_foreign_key('substitution_template')
+        """For SubstitutionTemplate one-to-many to SubstitutionTemplateMapping"""
+        return cls._declare_fk('substitution_template')
 
-    # SubstitutionTemplate one-to-one to NodeTemplate
     @declared_attr
     def node_template_fk(cls):
-        return cls._create_foreign_key('node_template')
+        """For SubstitutionTemplate one-to-one to NodeTemplate"""
+        return cls._declare_fk('node_template')
 
-    # SubstitutionTemplate one-to-one to CapabilityTemplate
     @declared_attr
     def capability_template_fk(cls):
-        return cls._create_foreign_key('capability_template', nullable=True)
+        """For SubstitutionTemplate one-to-one to CapabilityTemplate"""
+        return cls._declare_fk('capability_template', nullable=True)
 
-    # SubstitutionTemplate one-to-one to RequirementTemplate
     @declared_attr
     def requirement_template_fk(cls):
-        return cls._create_foreign_key('requirement_template', nullable=True)
+        """For SubstitutionTemplate one-to-one to RequirementTemplate"""
+        return cls._declare_fk('requirement_template', nullable=True)
 
     # endregion
 
@@ -888,15 +886,15 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
     def instantiate(self, container):
         from . import models
         context = ConsumptionContext.get_thread_local()
-        nodes = context.modeling.instance.find_nodes(self.node_template.name)
+        nodes = self.node_template.nodes.all()
         if len(nodes) == 0:
             context.validation.report(
                 'mapping "{0}" refers to node template "{1}" but there are no '
                 'node instances'.format(self.mapped_name, self.node_template.name),
                 level=validation.Issue.BETWEEN_INSTANCES)
             return None
-        # The TOSCA spec does not provide a way to choose the node, so we will just pick the first
-        # one
+        # The TOSCA spec does not provide a way to choose the node,
+        # so we will just pick the first one
         node = nodes[0]
         capability = None
         if self.capability_template:
@@ -926,6 +924,11 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
                                if self.capability_template
                                else self.requirement_template.name)))
 
+    __private_fields__ = ['substitution_template_fk',
+                          'node_template_fk',
+                          'capability_template_fk',
+                          'requirement_template_fk']
+
 
 class RequirementTemplateBase(TemplateModelMixin):
     """
@@ -962,58 +965,50 @@ class RequirementTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def target_node_type(cls):
-        return cls._create_many_to_one_relationship('type', key='target_node_type_fk',
-                                                    backreference=False)
+        return cls._declare_many_to_one('type', fk='target_node_type_fk', parent_property=False)
 
     @declared_attr
     def target_node_template(cls):
-        return cls._create_one_to_one_relationship('node_template', key='target_node_template_fk',
-                                                   backreference=False)
+        return cls._declare_one_to_one('node_template', fk='target_node_template_fk',
+                                       other_property=False)
 
     @declared_attr
     def target_capability_type(cls):
-        return cls._create_one_to_one_relationship('type', key='target_capability_type_fk',
-                                                   backreference=False)
+        return cls._declare_one_to_one('type', fk='target_capability_type_fk', other_property=False)
 
     target_capability_name = Column(Text)
     target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
 
     @declared_attr
     def relationship_template(cls):
-        return cls._create_one_to_one_relationship('relationship_template')
+        return cls._declare_one_to_one('relationship_template')
 
     # 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._create_foreign_key('type', nullable=True)
+        """For RequirementTemplate many-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
-    # RequirementTemplate one-to-one to NodeTemplate
     @declared_attr
     def target_node_template_fk(cls):
-        return cls._create_foreign_key('node_template', nullable=True)
+        """For RequirementTemplate one-to-one to NodeTemplate"""
+        return cls._declare_fk('node_template', nullable=True)
 
-    # RequirementTemplate one-to-one to NodeTemplate
     @declared_attr
     def target_capability_type_fk(cls):
-        return cls._create_foreign_key('type', nullable=True)
+        """For RequirementTemplate one-to-one to NodeTemplate"""
+        return cls._declare_fk('type', nullable=True)
 
-    # NodeTemplate one-to-many to RequirementTemplate
     @declared_attr
     def node_template_fk(cls):
-        return cls._create_foreign_key('node_template')
+        """For NodeTemplate one-to-many to RequirementTemplate"""
+        return cls._declare_fk('node_template')
 
-    # RequirementTemplate one-to-one to RelationshipTemplate
     @declared_attr
     def relationship_template_fk(cls):
-        return cls._create_foreign_key('relationship_template', nullable=True)
+        """For RequirementTemplate one-to-one to RelationshipTemplate"""
+        return cls._declare_fk('relationship_template', nullable=True)
 
     # endregion
 
@@ -1042,7 +1037,7 @@ class RequirementTemplateBase(TemplateModelMixin):
 
         # Find first node that matches the type
         elif self.target_node_type is not None:
-            for target_node_template in context.modeling.template.node_templates:
+            for target_node_template in context.modeling.template.node_templates.itervalues():
                 if self.target_node_type.get_descendant(target_node_template.type.name) is None:
                     continue
 
@@ -1070,9 +1065,12 @@ class RequirementTemplateBase(TemplateModelMixin):
     def as_raw(self):
         return collections.OrderedDict((
             ('name', self.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_node_type_name', self.target_node_type.name
+             if self.target_node_type is not None else None),
+            ('target_node_template_name', self.target_node_template.name
+             if self.target_node_template is not None else None),
+            ('target_capability_type_name', self.target_capability_type.name
+             if self.target_capability_type is not None else None),
             ('target_capability_name', self.target_capability_name),
             ('relationship_template', formatting.as_raw(self.relationship_template))))
 
@@ -1113,6 +1111,12 @@ class RequirementTemplateBase(TemplateModelMixin):
                 with context.style.indent:
                     self.relationship_template.dump()
 
+    __private_fields__ = ['target_node_type_fk',
+                          'target_node_template_fk',
+                          'target_capability_type_fk'
+                          'node_template_fk',
+                          'relationship_template_fk']
+
 
 class RelationshipTemplateBase(TemplateModelMixin):
     """
@@ -1144,27 +1148,24 @@ class RelationshipTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls._create_one_to_many_relationship('interface_template', dict_key='name')
+        return cls._declare_one_to_many('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._create_foreign_key('type', nullable=True)
+        """For RelationshipTemplate many-to-one to Type"""
+        return cls._declare_fk('type', nullable=True)
 
     # endregion
 
@@ -1209,6 +1210,8 @@ class RelationshipTemplateBase(TemplateModelMixin):
             utils.dump_dict_values(self.properties, 'Properties')
             utils.dump_interfaces(self.interface_templates, 'Interface templates')
 
+    __private_fields__ = ['type_fk']
+
 
 class CapabilityTemplateBase(TemplateModelMixin):
     """
@@ -1242,7 +1245,7 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
     min_occurrences = Column(Integer, default=None)  # optional
@@ -1250,27 +1253,23 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def valid_source_node_types(cls):
-        return cls._create_many_to_many_relationship('type', table_prefix='valid_sources')
+        return cls._declare_many_to_many('type', prefix='valid_sources')
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', 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._create_foreign_key('type')
+        """For CapabilityTemplate many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # NodeTemplate one-to-many to CapabilityTemplate
     @declared_attr
     def node_template_fk(cls):
-        return cls._create_foreign_key('node_template')
+        """For NodeTemplate one-to-many to CapabilityTemplate"""
+        return cls._declare_fk('node_template')
 
     # endregion
 
@@ -1305,7 +1304,7 @@ class CapabilityTemplateBase(TemplateModelMixin):
             ('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),
+            ('valid_source_node_types', [v.name for v in self.valid_source_node_types]),
             ('properties', formatting.as_raw_dict(self.properties))))
 
     def instantiate(self, container):
@@ -1344,6 +1343,9 @@ class CapabilityTemplateBase(TemplateModelMixin):
                                for v in self.valid_source_node_types))))
             utils.dump_dict_values(self.properties, 'Properties')
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk']
+
 
 class InterfaceTemplateBase(TemplateModelMixin):
     """
@@ -1374,44 +1376,39 @@ class InterfaceTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
 
     @declared_attr
     def inputs(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='inputs',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+
     @declared_attr
     def operation_templates(cls):
-        return cls._create_one_to_many_relationship('operation_template', dict_key='name')
+        return cls._declare_one_to_many('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._create_foreign_key('type')
+        """For InterfaceTemplate many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # NodeTemplate one-to-many to InterfaceTemplate
     @declared_attr
     def node_template_fk(cls):
-        return cls._create_foreign_key('node_template', nullable=True)
+        """For NodeTemplate one-to-many to InterfaceTemplate"""
+        return cls._declare_fk('node_template', nullable=True)
 
-    # GroupTemplate one-to-many to InterfaceTemplate
     @declared_attr
     def group_template_fk(cls):
-        return cls._create_foreign_key('group_template', nullable=True)
+        """For GroupTemplate one-to-many to InterfaceTemplate"""
+        return cls._declare_fk('group_template', nullable=True)
 
-    # RelationshipTemplate one-to-many to InterfaceTemplate
     @declared_attr
     def relationship_template_fk(cls):
-        return cls._create_foreign_key('relationship_template', nullable=True)
+        """For RelationshipTemplate one-to-many to InterfaceTemplate"""
+        return cls._declare_fk('relationship_template', nullable=True)
 
     # endregion
 
@@ -1453,6 +1450,11 @@ class InterfaceTemplateBase(TemplateModelMixin):
             utils.dump_dict_values(self.inputs, 'Inputs')
             utils.dump_dict_values(self.operation_templates, 'Operation templates')
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk',
+                          'group_template_fk',
+                          'relationship_template_fk']
+
 
 class OperationTemplateBase(TemplateModelMixin):
     """
@@ -1493,15 +1495,14 @@ class OperationTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def plugin_specification(cls):
-        return cls._create_one_to_one_relationship('plugin_specification')
+        return cls._declare_one_to_one('plugin_specification')
 
     implementation = Column(Text)
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
 
     @declared_attr
     def inputs(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='inputs',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
 
     executor = Column(Text)
     max_retries = Column(Integer)
@@ -1509,24 +1510,20 @@ 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):
-        return cls._create_foreign_key('service_template', nullable=True)
+        """For ServiceTemplate one-to-many to OperationTemplate"""
+        return cls._declare_fk('service_template', nullable=True)
 
-    # InterfaceTemplate one-to-many to OperationTemplate
     @declared_attr
     def interface_template_fk(cls):
-        return cls._create_foreign_key('interface_template', nullable=True)
+        """For InterfaceTemplate one-to-many to OperationTemplate"""
+        return cls._declare_fk('interface_template', nullable=True)
 
-    # OperationTemplate one-to-one to PluginSpecification
     @declared_attr
     def plugin_specification_fk(cls):
-        return cls._create_foreign_key('plugin_specification', nullable=True)
+        """For OperationTemplate one-to-one to PluginSpecification"""
+        return cls._declare_fk('plugin_specification', nullable=True)
 
     # endregion
 
@@ -1583,6 +1580,10 @@ class OperationTemplateBase(TemplateModelMixin):
                     context.style.literal(self.retry_interval)))
             utils.dump_dict_values(self.inputs, 'Inputs')
 
+    __private_fields__ = ['service_template_fk',
+                          'interface_template_fk',
+                          'plugin_fk']
+
 
 class ArtifactTemplateBase(TemplateModelMixin):
     """
@@ -1615,7 +1616,7 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._create_many_to_one_relationship('type')
+        return cls._declare_many_to_one('type')
 
     description = Column(Text)
     source_path = Column(Text)
@@ -1625,23 +1626,19 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='properties',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='properties', 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._create_foreign_key('type')
+        """For ArtifactTemplate many-to-one to Type"""
+        return cls._declare_fk('type')
 
-    # NodeTemplate one-to-many to ArtifactTemplate
     @declared_attr
     def node_template_fk(cls):
-        return cls._create_foreign_key('node_template')
+        """For NodeTemplate one-to-many to ArtifactTemplate"""
+        return cls._declare_fk('node_template')
 
     # endregion
 
@@ -1693,3 +1690,6 @@ class ArtifactTemplateBase(TemplateModelMixin):
                 console.puts('Repository credential: {0}'.format(
                     context.style.literal(self.repository_credential)))
             utils.dump_dict_values(self.properties, 'Properties')
+
+    __private_fields__ = ['type_fk',
+                          'node_template_fk']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/types.py
----------------------------------------------------------------------
diff --git a/aria/modeling/types.py b/aria/modeling/types.py
index 10a58a7..90a1773 100644
--- a/aria/modeling/types.py
+++ b/aria/modeling/types.py
@@ -23,7 +23,7 @@ from sqlalchemy import (
 )
 from sqlalchemy.ext import mutable
 
-from ..storage import exceptions
+from . import exceptions
 
 
 class _MutableType(TypeDecorator):
@@ -78,7 +78,7 @@ class _StrictDictMixin(object):
             else:
                 return value
         except ValueError as e:
-            raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
+            raise exceptions.ValueFormatException('could not coerce to MutableDict', cause=e)
 
     def __setitem__(self, key, value):
         self._assert_strict_key(key)
@@ -99,16 +99,14 @@ class _StrictDictMixin(object):
     @classmethod
     def _assert_strict_key(cls, key):
         if cls._key_cls is not None and not isinstance(key, cls._key_cls):
-            raise exceptions.StorageError("Key type was set strictly to {0}, but was {1}".format(
-                cls._key_cls, type(key)
-            ))
+            raise exceptions.ValueFormatException('key type was set strictly to {0}, but was {1}'
+                                                  .format(cls._key_cls, type(key)))
 
     @classmethod
     def _assert_strict_value(cls, value):
         if cls._value_cls is not None and not isinstance(value, cls._value_cls):
-            raise exceptions.StorageError("Value type was set strictly to {0}, but was {1}".format(
-                cls._value_cls, type(value)
-            ))
+            raise exceptions.ValueFormatException('value type was set strictly to {0}, but was {1}'
+                                                  .format(cls._value_cls, type(value)))
 
 
 class _MutableDict(mutable.MutableDict):
@@ -122,7 +120,7 @@ class _MutableDict(mutable.MutableDict):
         try:
             return mutable.MutableDict.coerce(key, value)
         except ValueError as e:
-            raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
+            raise exceptions.ValueFormatException('could not coerce value', cause=e)
 
 
 class _StrictListMixin(object):
@@ -140,7 +138,7 @@ class _StrictListMixin(object):
             else:
                 return value
         except ValueError as e:
-            raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
+            raise exceptions.ValueFormatException('could not coerce to MutableDict', cause=e)
 
     def __setitem__(self, index, value):
         """Detect list set events and emit change events."""
@@ -162,9 +160,8 @@ class _StrictListMixin(object):
     @classmethod
     def _assert_item(cls, item):
         if cls._item_cls is not None and not isinstance(item, cls._item_cls):
-            raise exceptions.StorageError("Key type was set strictly to {0}, but was {1}".format(
-                cls._item_cls, type(item)
-            ))
+            raise exceptions.ValueFormatException('key type was set strictly to {0}, but was {1}'
+                                                  .format(cls._item_cls, type(item)))
 
 
 class _MutableList(mutable.MutableList):
@@ -175,13 +172,12 @@ class _MutableList(mutable.MutableList):
         try:
             return mutable.MutableList.coerce(key, value)
         except ValueError as e:
-            raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
+            raise exceptions.ValueFormatException('could not coerce to MutableDict', cause=e)
 
 
 _StrictDictID = namedtuple('_StrictDictID', 'key_cls, value_cls')
 _StrictValue = namedtuple('_StrictValue', 'type_cls, listener_cls')
 
-
 class _StrictDict(object):
     """
     This entire class functions as a factory for strict dicts and their listeners.
@@ -195,7 +191,7 @@ class _StrictDict(object):
         if strict_dict_map_key not in self._strict_map:
             key_cls_name = getattr(key_cls, '__name__', str(key_cls))
             value_cls_name = getattr(value_cls, '__name__', str(value_cls))
-            # Creating the type class itself. this class would be returned (used by the sqlalchemy
+            # Creating the type class itself. this class would be returned (used by the SqlAlchemy
             # Column).
             strict_dict_cls = type(
                 'StrictDict_{0}_{1}'.format(key_cls_name, value_cls_name),
@@ -231,7 +227,7 @@ class _StrictList(object):
 
         if item_cls not in self._strict_map:
             item_cls_name = getattr(item_cls, '__name__', str(item_cls))
-            # Creating the type class itself. this class would be returned (used by the sqlalchemy
+            # Creating the type class itself. this class would be returned (used by the SqlAlchemy
             # Column).
             strict_list_cls = type(
                 'StrictList_{0}'.format(item_cls_name),


[3/3] incubator-ariatosca git commit: Many cleanups; use dict for many models

Posted by em...@apache.org.
Many cleanups; use dict for many models


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/0f040a2b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/0f040a2b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/0f040a2b

Branch: refs/heads/ARIA-105-integrate-modeling
Commit: 0f040a2b9a72cd7ed66b067a69df63d0bb367f0d
Parents: f6da64a
Author: Tal Liron <ta...@gmail.com>
Authored: Tue Mar 14 18:40:55 2017 -0500
Committer: Tal Liron <ta...@gmail.com>
Committed: Tue Mar 14 18:40:55 2017 -0500

----------------------------------------------------------------------
 aria/cli/commands.py                            |   7 +-
 aria/cli/dry.py                                 |   2 +-
 aria/modeling/mixins.py                         | 398 +++++++++------
 aria/modeling/orchestration.py                  |  97 ++--
 aria/modeling/relationship.py                   | 421 ----------------
 aria/modeling/service_changes.py                |  79 +--
 aria/modeling/service_common.py                 |  30 +-
 aria/modeling/service_instance.py               | 493 ++++++++++---------
 aria/modeling/service_template.py               | 460 ++++++++---------
 aria/modeling/types.py                          |  30 +-
 aria/orchestrator/workflows/api/task.py         | 162 +++---
 .../simple_v1_0/modeling/__init__.py            |  35 +-
 tests/end2end/test_orchestrator.py              |   7 +-
 tests/mock/models.py                            |   8 +-
 tests/modeling/test_models.py                   |  10 +-
 tests/orchestrator/context/test_operation.py    |  10 +-
 tests/orchestrator/context/test_serialize.py    |   2 +-
 tests/orchestrator/context/test_toolbelt.py     |   2 +-
 tests/orchestrator/workflows/api/test_task.py   |  14 +-
 .../workflows/builtin/test_execute_operation.py |   2 +-
 tests/orchestrator/workflows/core/test_task.py  |   3 +-
 .../executor/test_process_executor_extension.py |   4 +-
 .../test_process_executor_tracked_changes.py    |   4 +-
 tests/storage/test_resource_storage.py          |  58 +--
 24 files changed, 1029 insertions(+), 1309 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/cli/commands.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands.py b/aria/cli/commands.py
index f9d3053..1eef61d 100644
--- a/aria/cli/commands.py
+++ b/aria/cli/commands.py
@@ -235,12 +235,7 @@ class WorkflowCommand(BaseCommand):
                 workflow_name))
             inputs = {}
         else:
-            workflow = None
-            for policy in context.modeling.instance.policies:
-                if policy.name == workflow_name:
-                    workflow = policy
-                    break
-
+            workflow = context.modeling.instance.policies.get(workflow_name)
             if workflow is None:
                 raise AttributeError('workflow policy does not exist: "{0}"'.format(workflow_name))
             if workflow.type.role != 'workflow':

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/cli/dry.py
----------------------------------------------------------------------
diff --git a/aria/cli/dry.py b/aria/cli/dry.py
index 114ab7a..82faf42 100644
--- a/aria/cli/dry.py
+++ b/aria/cli/dry.py
@@ -34,7 +34,7 @@ def convert_to_dry(service):
     for workflow in service.workflows:
         convert_operation_to_dry(workflow)
 
-    for node in service.nodes:
+    for node in service.nodes.itervalues():
         for interface in node.interfaces.itervalues():
             for oper in interface.operations.itervalues():
                 convert_operation_to_dry(oper)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/mixins.py
----------------------------------------------------------------------
diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py
index 9133a85..06f2497 100644
--- a/aria/modeling/mixins.py
+++ b/aria/modeling/mixins.py
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# pylint: disable=invalid-name
+
 """
 ARIA's storage.structures module
 Path: aria.storage.structures
@@ -35,13 +37,13 @@ from sqlalchemy import (
     Table,
 )
 
-from . import utils
+from .utils import classproperty
 from ..utils import formatting
 
 
 class ModelMixin(object):
 
-    @utils.classproperty
+    @classproperty
     def __modelname__(cls):                                                                         # pylint: disable=no-self-argument
         return getattr(cls, '__mapiname__', cls.__tablename__)
 
@@ -57,9 +59,9 @@ class ModelMixin(object):
         """
         Return a dict representation of the model
 
-        :param suppress_error: If set to True, sets `None` to attributes that
-                               it's unable to retrieve (e.g., if a relationship wasn't established
-                               yet, and so it's impossible to access a property through it)
+        :param suppress_error: If set to True, sets `None` to attributes that it's unable to
+                               retrieve (e.g., if a relationship wasn't established yet, and so it's
+                               impossible to access a property through it)
         """
 
         res = dict()
@@ -95,22 +97,64 @@ class ModelMixin(object):
         return fields - set(getattr(cls, '__private_fields__', []))
 
     @classmethod
-    def _create_foreign_key(cls, parent_table, nullable=False):
+    def _iter_association_proxies(cls):
+        for col, value in vars(cls).items():
+            if isinstance(value, associationproxy.AssociationProxy):
+                yield col
+
+    def __repr__(self):
+        return '<{cls} id=`{id}`>'.format(
+            cls=self.__class__.__name__,
+            id=getattr(self, self.name_column_name()))
+
+    # Model property declaration helpers
+
+    @classmethod
+    def _declare_fk(cls,
+                    other_table,
+                    nullable=False):
         """
-        Return a ForeignKey object.
+        Declare a foreign key property, which will also create a foreign key column in the table
+        with the name of the property. By convention the property name should end in "_fk".
 
-        :param parent_table: Parent table name
-        :param nullable: Should the column be allowed to remain empty
+        You are required to explicitly create foreign keys in order to allow for one-to-one,
+        one-to-many, and many-to-one relationships (but not for many-to-many relationships). If you
+        do not do so, SqlAlchemy will fail to create the relationship property and raise an
+        exception with a clear error message.
+
+        You should normally not have to access this property directly, but instead use the
+        associated relationship properties.
+
+        *This utility method should only be used during class creation.*
+
+        :param other_table: Other table name
+        :type other_table: basestring
+        :param nullable: True to allow null values (meaning that there is no relationship)
+        :type nullable: bool
         """
+
         return Column(Integer,
-                      ForeignKey('{table}.id'.format(table=parent_table),
-                                 ondelete='CASCADE'),
+                      ForeignKey('{table}.id'.format(table=other_table), ondelete='CASCADE'),
                       nullable=nullable)
 
     @classmethod
-    def _create_relationship_to_self(cls,
-                                     column_name,
-                                     relationship_kwargs=None):
+    def _declare_one_to_one_self(cls,
+                                 fk,
+                                 relationship_kwargs=None):
+        """
+        Declare a one-to-one relationship property. The property value would be an instance of
+        the same model.
+
+        You will need an associated foreign key to our own table.
+
+        *This utility method should only be used during class creation.*
+
+        :param fk: Foreign key name
+        :type fk: basestring
+        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+        :type relationship_kwargs: {}
+        """
+
         relationship_kwargs = relationship_kwargs or {}
 
         remote_side = '{cls}.{remote_column}'.format(
@@ -121,11 +165,11 @@ class ModelMixin(object):
         primaryjoin = '{remote_side} == {cls}.{column}'.format(
             remote_side=remote_side,
             cls=cls.__name__,
-            column=column_name
+            column=fk
         )
 
         return relationship(
-            cls._get_cls_by_tablename(cls.__tablename__).__name__,
+            cls._get_class_for_table(cls.__tablename__).__name__,
             primaryjoin=primaryjoin,
             remote_side=remote_side,
             post_update=True,
@@ -133,100 +177,197 @@ class ModelMixin(object):
         )
 
     @classmethod
-    def _create_one_to_many_relationship_to_self(cls,
-                                                 key,
-                                                 dict_key=None,
-                                                 relationship_kwargs=None):
+    def _declare_one_to_many_self(cls,
+                                  fk,
+                                  dict_key=None,
+                                  relationship_kwargs=None):
+        """
+        Declare a one-to-many relationship property. The property value would be a list or dict
+        of instances of the same model.
+
+        You will need an associated foreign key to our own table.
+
+        *This utility method should only be used during class creation.*
+
+        :param fk: Foreign key name
+        :type fk: basestring
+        :param dict_key: If set the value will be a dict with this key as the dict key; otherwise
+                         will be a list
+        :type dict_key: basestring
+        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+        :type relationship_kwargs: {}
+        """
+
         relationship_kwargs = relationship_kwargs or {}
 
         relationship_kwargs.setdefault('remote_side', '{cls}.{remote_column}'.format(
             cls=cls.__name__,
-            remote_column=key
+            remote_column=fk
         ))
 
-        return cls._create_relationship(cls.__tablename__, None, relationship_kwargs,
-                                        backreference=False, dict_key=dict_key)
+        return cls._declare_relationship(cls.__tablename__, None, relationship_kwargs,
+                                         other_property=False, dict_key=dict_key)
 
     @classmethod
-    def _create_one_to_one_relationship(cls,
-                                        other_table,
-                                        key=None,
-                                        backreference=None,
-                                        backref_kwargs=None,
-                                        relationship_kwargs=None):
+    def _declare_one_to_one(cls,
+                            other_table,
+                            fk=None,
+                            other_fk=None,
+                            other_property=None,
+                            relationship_kwargs=None,
+                            backref_kwargs=None):
+        """
+        Declare a one-to-one relationship property. The property value would be an instance of
+        the other table's model.
+
+        You have two options for the foreign key. Either this table can have an associated key to
+        the other table (use the `fk` argument) or the other table can have an associated foreign
+        key to this our table (use the `other_fk` argument).
+
+        *This utility method should only be used during class creation.*
+
+        :param other_table: Other table name
+        :type other_table: basestring
+        :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
+        :type fk: basestring
+        :param other_fk: Foreign key name at the other table (no need specify if there's no
+                         ambiguity)
+        :type other_fk: basestring
+        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+        :type relationship_kwargs: {}
+        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+        :type backref_kwargs: {}
+        """
+
         backref_kwargs = backref_kwargs or {}
         backref_kwargs.setdefault('uselist', False)
 
-        return cls._create_relationship(other_table, backref_kwargs, relationship_kwargs,
-                                        backreference, key=key)
+        return cls._declare_relationship(other_table, backref_kwargs, relationship_kwargs,
+                                         other_property, fk=fk, other_fk=other_fk)
 
     @classmethod
-    def _create_one_to_many_relationship(cls,
-                                         child_table,
-                                         key=None,
-                                         foreign_key=None,
-                                         dict_key=None,
-                                         backreference=None,
-                                         backref_kwargs=None,
-                                         relationship_kwargs=None):
+    def _declare_one_to_many(cls,
+                             child_table,
+                             child_fk=None,
+                             dict_key=None,
+                             child_property=None,
+                             relationship_kwargs=None,
+                             backref_kwargs=None):
+        """
+        Declare a one-to-many relationship property. The property value would be a list or dict
+        of instances of the child table's model.
+
+        The child table will need an associated foreign key to our table.
+
+        The declaration will automatically create a matching many-to-one property at the child
+        model, named after our table name. Use the `child_property` argument to override this name.
+
+        *This utility method should only be used during class creation.*
+
+        :param child_table: Child table name
+        :type child_table: basestring
+        :param child_fk: Foreign key name at the child table (no need specify if there's no
+                         ambiguity)
+        :type child_fk: basestring
+        :param dict_key: If set the value will be a dict with this key as the dict key; otherwise
+                         will be a list
+        :type dict_key: basestring
+        :param child_property: Override name of matching many-to-one property at child table; set to
+                               false to disable
+        :type child_property: basestring|bool
+        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+        :type relationship_kwargs: {}
+        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+        :type backref_kwargs: {}
+        """
+
         backref_kwargs = backref_kwargs or {}
         backref_kwargs.setdefault('uselist', False)
 
-        return cls._create_relationship(child_table, backref_kwargs, relationship_kwargs,
-                                        backreference, key=key, foreign_key=foreign_key,
-                                        dict_key=dict_key)
+        return cls._declare_relationship(child_table, backref_kwargs, relationship_kwargs,
+                                         child_property, other_fk=child_fk, dict_key=dict_key)
 
     @classmethod
-    def _create_many_to_one_relationship(cls,
-                                         parent_table,
-                                         key=None,
-                                         foreign_key=None,
-                                         backreference=None,
-                                         backref_kwargs=None,
-                                         relationship_kwargs=None):
+    def _declare_many_to_one(cls,
+                             parent_table,
+                             fk=None,
+                             parent_fk=None,
+                             parent_property=None,
+                             relationship_kwargs=None,
+                             backref_kwargs=None):
         """
-        Return a one-to-many SQL relationship object
-        Meant to be used from inside the *child* object
+        Declare a many-to-one relationship property. The property value would be an instance of
+        the parent table's model.
+
+        You will need an associated foreign key to the parent table.
+
+        The declaration will automatically create a matching one-to-many property at the child
+        model, named after the plural form of our table name. Use the `parent_property` argument to
+        override this name. Note: the automatic property will always be a SqlAlchemy query object;
+        if you need a Python collection then use :meth:`_declare_one_to_many` at that model.
+
+        *This utility method should only be used during class creation.*
 
-        :param parent_table: Name of the parent table
-        :param foreign_key: The column of the foreign key (from the child table)
-        :param backreference: The name to give to the reference to the child (on the parent table)
+        :param parent_table: Parent table name
+        :type parent_table: basestring
+        :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
+        :type fk: basestring
+        :param parent_property: Override name of matching one-to-many property at parent table; set
+                                to false to disable
+        :type parent_property: basestring|bool
+        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+        :type relationship_kwargs: {}
+        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+        :type backref_kwargs: {}
         """
 
-        if backreference is None:
-            backreference = formatting.pluralize(cls.__tablename__)
+        if parent_property is None:
+            parent_property = formatting.pluralize(cls.__tablename__)
 
         backref_kwargs = backref_kwargs or {}
         backref_kwargs.setdefault('uselist', True)
         backref_kwargs.setdefault('lazy', 'dynamic')
-        # The following line make sure that when the *parent* is deleted, all its connected children
-        # are deleted as well
-        backref_kwargs.setdefault('cascade', 'all')
+        backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
 
-        return cls._create_relationship(parent_table, backref_kwargs, relationship_kwargs,
-                                        backreference, key=key, foreign_key=foreign_key)
+        return cls._declare_relationship(parent_table, backref_kwargs, relationship_kwargs,
+                                         parent_property, fk=fk, other_fk=parent_fk)
 
     @classmethod
-    def _create_many_to_many_relationship(cls,
-                                          other_table,
-                                          table_prefix=None,
-                                          key=None,
-                                          dict_key=None,
-                                          backreference=None,
-                                          backref_kwargs=None,
-                                          relationship_kwargs=None):
+    def _declare_many_to_many(cls,
+                              other_table,
+                              prefix=None,
+                              dict_key=None,
+                              other_property=None,
+                              relationship_kwargs=None,
+                              backref_kwargs=None):
         """
-        Return a many-to-many SQL relationship object
+        Declare a many-to-many relationship property. The property value would be a list or dict
+        of instances of the other table's model.
+
+        You do not need associated foreign keys for this relationship. Instead, an extra table will
+        be created for you.
 
-        Notes:
+        The declaration will automatically create a matching many-to-many property at the other
+        model, named after the plural form of our table name. Use the `other_property` argument to
+        override this name. Note: the automatic property will always be a SqlAlchemy query object;
+        if you need a Python collection then use :meth:`_declare_many_to_many` again at that model.
 
-        1. The backreference name is the current table's table name
-        2. This method creates a new helper table in the DB
+        *This utility method should only be used during class creation.*
 
-        :param cls: The class of the table we're connecting from
-        :param other_table: The class of the table we're connecting to
-        :param table_prefix: Custom prefix for the helper table name and the backreference name
-        :param dict_key: If provided, will use a dict class with this column as the key
+        :param parent_table: Parent table name
+        :type parent_table: basestring
+        :param prefix: Optional prefix for extra table name as well as for `other_property`
+        :type prefix: basestring
+        :param dict_key: If set the value will be a dict with this key as the dict key; otherwise
+                         will be a list
+        :type dict_key: basestring
+        :param other_property: Override name of matching many-to-many property at other table; set
+                               to false to disable
+        :type other_property: basestring|bool
+        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+        :type relationship_kwargs: {}
+        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+        :type backref_kwargs: {}
         """
 
         this_table = cls.__tablename__
@@ -236,87 +377,87 @@ class ModelMixin(object):
         other_column_name = '{0}_id'.format(other_table)
         other_foreign_key = '{0}.id'.format(other_table)
 
-        helper_table = '{0}_{1}'.format(this_table, other_table)
+        secondary_table = '{0}_{1}'.format(this_table, other_table)
 
-        if backreference is None:
-            backreference = formatting.pluralize(this_table)
-            if table_prefix:
-                helper_table = '{0}_{1}'.format(table_prefix, helper_table)
-                backreference = '{0}_{1}'.format(table_prefix, backreference)
+        if other_property is None:
+            other_property = formatting.pluralize(this_table)
+            if prefix is not None:
+                secondary_table = '{0}_{1}'.format(prefix, secondary_table)
+                other_property = '{0}_{1}'.format(prefix, other_property)
 
         backref_kwargs = backref_kwargs or {}
         backref_kwargs.setdefault('uselist', True)
 
         relationship_kwargs = relationship_kwargs or {}
-        relationship_kwargs.setdefault('secondary', cls._get_secondary_table(
+        relationship_kwargs.setdefault('secondary', ModelMixin._get_secondary_table(
             cls.metadata,
-            helper_table,
+            secondary_table,
             this_column_name,
             other_column_name,
             this_foreign_key,
             other_foreign_key
         ))
 
-        return cls._create_relationship(other_table, backref_kwargs, relationship_kwargs,
-                                        backreference, key=key, dict_key=dict_key)
+        return cls._declare_relationship(other_table, backref_kwargs, relationship_kwargs,
+                                         other_property, dict_key=dict_key)
 
     @classmethod
-    def _create_relationship(cls, table, backref_kwargs, relationship_kwargs, backreference,
-                             key=None, foreign_key=None, dict_key=None):
+    def _declare_relationship(cls, other_table, backref_kwargs, relationship_kwargs,
+                              other_property, fk=None, other_fk=None, dict_key=None):
         relationship_kwargs = relationship_kwargs or {}
 
-        if key:
+        if fk:
             relationship_kwargs.setdefault('foreign_keys',
                                            lambda: getattr(
-                                               cls._get_cls_by_tablename(cls.__tablename__),
-                                               key))
+                                               cls._get_class_for_table(cls.__tablename__),
+                                               fk))
 
-        elif foreign_key:
+        elif other_fk:
             relationship_kwargs.setdefault('foreign_keys',
                                            lambda: getattr(
-                                               cls._get_cls_by_tablename(table),
-                                               foreign_key))
+                                               cls._get_class_for_table(other_table),
+                                               other_fk))
 
         if dict_key:
             relationship_kwargs.setdefault('collection_class',
                                            attribute_mapped_collection(dict_key))
 
-        if backreference is False:
+        if other_property is False:
+            # No backref
             return relationship(
-                lambda: cls._get_cls_by_tablename(table),
+                lambda: cls._get_class_for_table(other_table),
                 **relationship_kwargs
             )
         else:
-            if backreference is None:
-                backreference = cls.__tablename__
+            if other_property is None:
+                other_property = cls.__tablename__
             backref_kwargs = backref_kwargs or {}
             return relationship(
-                lambda: cls._get_cls_by_tablename(table),
-                backref=backref(backreference, **backref_kwargs),
+                lambda: cls._get_class_for_table(other_table),
+                backref=backref(other_property, **backref_kwargs),
                 **relationship_kwargs
             )
 
+    @classmethod
+    def _get_class_for_table(cls, tablename):
+        if tablename in (cls.__name__, cls.__tablename__):
+            return cls
+
+        for table_cls in cls._decl_class_registry.values():
+            if tablename == getattr(table_cls, '__tablename__', None):
+                return table_cls
+
+        raise ValueError('unknown table: {0}'.format(tablename))
+
     @staticmethod
     def _get_secondary_table(metadata,
-                             helper_table,
+                             name,
                              first_column,
                              second_column,
                              first_foreign_key,
                              second_foreign_key):
-        """
-        Create a helper table for a many-to-many relationship
-
-        :param helper_table: The name of the table
-        :param first_column_name: The name of the first column in the table
-        :param second_column_name: The name of the second column in the table
-        :param first_foreign_key: The string representing the first foreign key,
-               for example `blueprint.storage_id`, or `tenants.id`
-        :param second_foreign_key: The string representing the second foreign key
-        :return: A Table object
-        """
-
         return Table(
-            helper_table,
+            name,
             metadata,
             Column(
                 first_column,
@@ -330,33 +471,6 @@ class ModelMixin(object):
             )
         )
 
-    @classmethod
-    def _iter_association_proxies(cls):
-        for col, value in vars(cls).items():
-            if isinstance(value, associationproxy.AssociationProxy):
-                yield col
-
-    @classmethod
-    def _get_cls_by_tablename(cls, tablename):
-        """
-        Return class reference mapped to table.
-
-        :param tablename: String with name of table.
-        :return: Class reference or None.
-        """
-
-        if tablename in (cls.__name__, cls.__tablename__):
-            return cls
-
-        for table_cls in cls._decl_class_registry.values():
-            if tablename == getattr(table_cls, '__tablename__', None):
-                return table_cls
-
-    def __repr__(self):
-        return '<{cls} id=`{id}`>'.format(
-            cls=self.__class__.__name__,
-            id=getattr(self, self.name_column_name()))
-
 
 class ModelIDMixin(object):
     id = Column(Integer, primary_key=True, autoincrement=True)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index d8bdd3c..683c526 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -100,28 +100,33 @@ class ExecutionBase(ModelMixin):
     workflow_name = Column(Text)
 
     @declared_attr
-    def service_template(cls):
-        return association_proxy('service', 'service_template')
+    def service(cls):
+        return cls._declare_many_to_one('service')
+
+    # region foreign keys
 
     @declared_attr
-    def service(cls):
-        return cls._create_many_to_one_relationship('service')
+    def service_fk(cls):
+        return cls._declare_fk('service')
+
+    # endregion
+
+    # region association proxies
 
     @declared_attr
     def service_name(cls):
+        """Required for use by SqlAlchemy queries"""
         return association_proxy('service', cls.name_column_name())
 
     @declared_attr
-    def service_template_name(cls):
-        return association_proxy('service', 'service_template_name')
-
-    # region foreign keys
-
-    __private_fields__ = ['service_fk']
+    def service_template(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service', 'service_template')
 
     @declared_attr
-    def service_fk(cls):
-        return cls._create_foreign_key('service')
+    def service_template_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service', 'service_template_name')
 
     # endregion
 
@@ -132,6 +137,11 @@ class ExecutionBase(ModelMixin):
             self.status
         )
 
+    __private_fields__ = ['service_fk',
+                          'service_name',
+                          'service_template',
+                          'service_template_name']
+
 
 class PluginBase(ModelMixin):
     """
@@ -186,37 +196,24 @@ class TaskBase(ModelMixin):
     INFINITE_RETRIES = -1
 
     @declared_attr
-    def node_name(cls):
-        return association_proxy('node', cls.name_column_name())
-
-    @declared_attr
     def node(cls):
-        return cls._create_many_to_one_relationship('node')
-
-    @declared_attr
-    def relationship_name(cls):
-        return association_proxy('relationship', cls.name_column_name())
+        return cls._declare_many_to_one('node')
 
     @declared_attr
     def relationship(cls):
-        return cls._create_many_to_one_relationship('relationship')
+        return cls._declare_many_to_one('relationship')
 
     @declared_attr
     def plugin(cls):
-        return cls._create_many_to_one_relationship('plugin')
+        return cls._declare_many_to_one('plugin')
 
     @declared_attr
     def execution(cls):
-        return cls._create_many_to_one_relationship('execution')
-
-    @declared_attr
-    def execution_name(cls):
-        return association_proxy('execution', cls.name_column_name())
+        return cls._declare_many_to_one('execution')
 
     @declared_attr
     def inputs(cls):
-        return cls._create_many_to_many_relationship('parameter', table_prefix='inputs',
-                                                     dict_key='name')
+        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
 
     status = Column(Enum(*STATES, name='status'), default=PENDING)
 
@@ -260,26 +257,40 @@ class TaskBase(ModelMixin):
 
     # region foreign keys
 
-    __private_fields__ = ['node_fk',
-                          'relationship_fk',
-                          'plugin_fk',
-                          'execution_fk']
-
     @declared_attr
     def node_fk(cls):
-        return cls._create_foreign_key('node', nullable=True)
+        return cls._declare_fk('node', nullable=True)
 
     @declared_attr
     def relationship_fk(cls):
-        return cls._create_foreign_key('relationship', nullable=True)
+        return cls._declare_fk('relationship', nullable=True)
 
     @declared_attr
     def plugin_fk(cls):
-        return cls._create_foreign_key('plugin', nullable=True)
+        return cls._declare_fk('plugin', nullable=True)
 
     @declared_attr
     def execution_fk(cls):
-        return cls._create_foreign_key('execution', nullable=True)
+        return cls._declare_fk('execution', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def node_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('node', cls.name_column_name())
+
+    @declared_attr
+    def relationship_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('relationship', cls.name_column_name())
+
+    @declared_attr
+    def execution_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('execution', cls.name_column_name())
 
     # endregion
 
@@ -298,3 +309,11 @@ class TaskBase(ModelMixin):
     @staticmethod
     def retry(message=None, retry_interval=None):
         raise TaskRetryException(message, retry_interval=retry_interval)
+
+    __private_fields__ = ['node_fk',
+                          'relationship_fk',
+                          'plugin_fk',
+                          'execution_fk',
+                          'node_name',
+                          'relationship_name',
+                          'execution_name']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/relationship.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py
deleted file mode 100644
index 2fdbe0c..0000000
--- a/aria/modeling/relationship.py
+++ /dev/null
@@ -1,421 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# pylint: disable=invalid-name, redefined-outer-name, unused-argument
-
-from functools import wraps
-
-from sqlalchemy.orm import relationship, backref
-from sqlalchemy.orm.collections import attribute_mapped_collection
-from sqlalchemy.ext.declarative import declared_attr
-from sqlalchemy import (
-    Column,
-    ForeignKey,
-    Integer,
-    Table
-)
-
-from ..utils import formatting
-
-
-def fk(other_table,
-       nullable=False):
-    """
-    Decorator for a foreign key property, which will also create a foreign key column in the table
-    with the name of the property. By convention the property name should end in "_fk".
-
-    You are required to explicitly create foreign keys in order to allow for one-to-one,
-    one-to-many, and many-to-one relationships. If you do not do so, SqlAlchemy will fail to create
-    the relationship and raise an exception with a clear error message.
-
-    You should normally not have to access this property directly, but instead use the
-    associated relationship properties.
-
-    :param other_table: Other table name
-    :type other_table: basestring
-    :param nullable: True to allow null values (meaning that there is no relationship)
-    :type nullable: bool
-    """
-
-    def decorator(fn):
-        @declared_attr
-        @wraps(fn)
-        def attr(cls):
-            if not hasattr(cls, '__private_fields__'):
-                cls.__private_fields__ = []
-            cls.__private_fields__.append(fn.__name__)
-            return Column(Integer,
-                          ForeignKey('{table}.id'.format(table=other_table), ondelete='CASCADE'),
-                          nullable=nullable)
-        return attr
-    return decorator
-
-
-def one_to_one_self(fk,
-                    relationship_kwargs=None):
-    """
-    Decorator for a one-to-one relationship property. The property value would be an instance of
-    the same model.
-
-    You will need an associated foreign key to our own table.
-
-    :param fk: Foreign key name
-    :type fk: basestring
-    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-    :type relationship_kwargs: {}
-    """
-
-    scope = locals()
-    def decorator(fn):
-        @declared_attr
-        @wraps(fn)
-        def attr(cls):
-            relationship_kwargs = scope['relationship_kwargs'] or {}
-
-            remote_side = '{cls}.{remote_column}'.format(
-                cls=cls.__name__,
-                remote_column=cls.id_column_name()
-            )
-
-            primaryjoin = '{remote_side} == {cls}.{column}'.format(
-                remote_side=remote_side,
-                cls=cls.__name__,
-                column=fk
-            )
-
-            return relationship(
-                _get_class_for_table(cls, cls.__tablename__).__name__,
-                primaryjoin=primaryjoin,
-                remote_side=remote_side,
-                post_update=True,
-                **relationship_kwargs
-            )
-        return attr
-    return decorator
-
-
-def one_to_many_self(fk,
-                     dict_key=None,
-                     relationship_kwargs=None):
-    """
-    Decorator for a one-to-many relationship property. The property value would be a list or dict
-    of instances of the same model.
-
-    You will need an associated foreign key to our own table.
-
-    :param fk: Foreign key name
-    :type fk: basestring
-    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
-                     be a list
-    :type dict_key: basestring
-    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-    :type relationship_kwargs: {}
-    """
-
-    scope = locals()
-    def decorator(fn):
-        @declared_attr
-        @wraps(fn)
-        def attr(cls):
-            relationship_kwargs = scope['relationship_kwargs'] or {}
-
-            relationship_kwargs.setdefault('remote_side', '{cls}.{remote_column}'.format(
-                cls=cls.__name__,
-                remote_column=fk
-            ))
-
-            return _create_relationship(cls, cls.__tablename__, None, relationship_kwargs,
-                                        other_property=False, dict_key=dict_key)
-        return attr
-    return decorator
-
-
-def one_to_one(other_table,
-               fk=None,
-               other_fk=None,
-               other_property=None,
-               relationship_kwargs=None,
-               backref_kwargs=None):
-    """
-    Decorator for a one-to-one relationship property. The property value would be an instance of
-    the other table's model.
-
-    You have two options for the foreign key. Either this table can have an associated key to the
-    other table (use the `fk` argument) or the other table can have an associated foreign key to
-    this our table (use the `other_fk` argument).
-
-    :param other_table: Other table name
-    :type other_table: basestring
-    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
-    :type fk: basestring
-    :param other_fk: Foreign key name at the other table (no need specify if there's no ambiguity)
-    :type other_fk: basestring
-    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    scope = locals()
-    def decorator(fn):
-        @declared_attr
-        @wraps(fn)
-        def attr(cls):
-            backref_kwargs = scope['backref_kwargs'] or {}
-            backref_kwargs.setdefault('uselist', False)
-
-            return _create_relationship(cls, other_table, backref_kwargs, relationship_kwargs,
-                                        other_property, fk=fk, other_fk=other_fk)
-        return attr
-    return decorator
-
-
-def one_to_many(child_table,
-                child_fk=None,
-                dict_key=None,
-                child_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
-    """
-    Decorator for a one-to-many relationship property. The property value would be a list or dict
-    of instances of the child table's model.
-
-    The child table will need an associated foreign key to our table.
-
-    The decorator will automatically create a matching many-to-one property at the child model,
-    named after our table name. Use the `child_property` argument to override this name.
-
-    :param child_table: Child table name
-    :type child_table: basestring
-    :param child_fk: Foreign key name at the child table (no need specify if there's no ambiguity)
-    :type child_fk: basestring
-    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
-                     be a list
-    :type dict_key: basestring
-    :param child_property: Override name of matching many-to-one property at child table; set to
-                           false to disable
-    :type child_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    scope = locals()
-    def decorator(fn):
-        @declared_attr
-        @wraps(fn)
-        def attr(cls):
-            backref_kwargs = scope['backref_kwargs'] or {}
-            backref_kwargs.setdefault('uselist', False)
-
-            return _create_relationship(cls, child_table, backref_kwargs, relationship_kwargs,
-                                        child_property, other_fk=child_fk, dict_key=dict_key)
-        return attr
-    return decorator
-
-
-def many_to_one(parent_table,
-                fk=None,
-                parent_fk=None,
-                parent_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
-    """
-    Decorator for a many-to-one relationship property. The property value would be an instance of
-    the parent table's model.
-
-    You will need an associated foreign key to the parent table.
-
-    The decorator will automatically create a matching one-to-many property at the child model,
-    named after the plural form of our table name. Use the `parent_property` argument to override
-    this name. Note: the automatic property will always be a list; if you need it to be a dict, use
-    the :func:`one_to_many` decorator on that model instead.
-
-    :param parent_table: Parent table name
-    :type parent_table: basestring
-    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
-    :type fk: basestring
-    :param parent_property: Override name of matching one-to-many property at parent table; set to
-                            false to disable
-    :type parent_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    scope = locals()
-    def decorator(fn):
-        @declared_attr
-        @wraps(fn)
-        def attr(cls):
-            parent_property = scope['parent_property']
-            if parent_property is None:
-                parent_property = formatting.pluralize(cls.__tablename__)
-
-            backref_kwargs = scope['backref_kwargs'] or {}
-            backref_kwargs.setdefault('uselist', True)
-            backref_kwargs.setdefault('lazy', 'dynamic')
-            backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
-
-            return _create_relationship(cls, parent_table, backref_kwargs, relationship_kwargs,
-                                        parent_property, fk=fk, other_fk=parent_fk)
-        return attr
-    return decorator
-
-
-def many_to_many(other_table,
-                 prefix=None,
-                 dict_key=None,
-                 other_property=None,
-                 relationship_kwargs=None,
-                 backref_kwargs=None):
-    """
-    Decorator for a many-to-many relationship property. The property value would be a list or dict
-    of instances of the other table's model.
-
-    You do not need associated foreign keys for this relationship. Instead, an extra table will be
-    created for you.
-
-    The decorator will automatically create a matching many-to-many property at the other model,
-    named after the plural form of our table name. Use the `other_property` argument to override
-    this name. Note: the automatic property will always be a list; if you need it to be a dict, use
-    the `many_to_many` decorator again on that model.
-
-    :param parent_table: Parent table name
-    :type parent_table: basestring
-    :param prefix: Optional prefix for extra table name as well as for `other_property`
-    :type prefix: basestring
-    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
-                     be a list
-    :type dict_key: basestring
-    :param other_property: Override name of matching many-to-many property at other table; set to
-                           false to disable
-    :type other_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    scope = locals()
-    def decorator(fn):
-        @declared_attr
-        @wraps(fn)
-        def attr(cls):
-            this_table = cls.__tablename__
-            this_column_name = '{0}_id'.format(this_table)
-            this_foreign_key = '{0}.id'.format(this_table)
-
-            other_column_name = '{0}_id'.format(other_table)
-            other_foreign_key = '{0}.id'.format(other_table)
-
-            secondary_table = '{0}_{1}'.format(this_table, other_table)
-
-            other_property = scope['other_property']
-            if other_property is None:
-                other_property = formatting.pluralize(this_table)
-                if prefix is not None:
-                    secondary_table = '{0}_{1}'.format(prefix, secondary_table)
-                    other_property = '{0}_{1}'.format(prefix, other_property)
-
-            backref_kwargs = scope['backref_kwargs'] or {}
-            backref_kwargs.setdefault('uselist', True)
-
-            relationship_kwargs = scope['relationship_kwargs'] or {}
-            relationship_kwargs.setdefault('secondary', _get_secondary_table(
-                cls.metadata,
-                secondary_table,
-                this_column_name,
-                other_column_name,
-                this_foreign_key,
-                other_foreign_key
-            ))
-
-            return _create_relationship(cls, other_table, backref_kwargs, relationship_kwargs,
-                                        other_property, dict_key=dict_key)
-        return attr
-    return decorator
-
-
-def _create_relationship(cls, other_table, backref_kwargs, relationship_kwargs, other_property,
-                         fk=None, other_fk=None, dict_key=None):
-    relationship_kwargs = relationship_kwargs or {}
-
-    if fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(cls, cls.__tablename__),
-                                           fk))
-
-    elif other_fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(cls, other_table),
-                                           other_fk))
-
-    if dict_key:
-        relationship_kwargs.setdefault('collection_class',
-                                       attribute_mapped_collection(dict_key))
-
-    if other_property is False:
-        # No backref
-        return relationship(
-            lambda: _get_class_for_table(cls, other_table),
-            **relationship_kwargs
-        )
-    else:
-        if other_property is None:
-            other_property = cls.__tablename__
-        backref_kwargs = backref_kwargs or {}
-        return relationship(
-            lambda: _get_class_for_table(cls, other_table),
-            backref=backref(other_property, **backref_kwargs),
-            **relationship_kwargs
-        )
-
-
-def _get_secondary_table(metadata,
-                         name,
-                         first_column,
-                         second_column,
-                         first_foreign_key,
-                         second_foreign_key):
-    return Table(
-        name,
-        metadata,
-        Column(
-            first_column,
-            Integer,
-            ForeignKey(first_foreign_key)
-        ),
-        Column(
-            second_column,
-            Integer,
-            ForeignKey(second_foreign_key)
-        )
-    )
-
-
-def _get_class_for_table(cls, tablename):
-    if tablename in (cls.__name__, cls.__tablename__):
-        return cls
-
-    for table_cls in cls._decl_class_registry.values():
-        if tablename == getattr(table_cls, '__tablename__', None):
-            return table_cls
-
-    raise ValueError('unknown table: {0}'.format(tablename))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/service_changes.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_changes.py b/aria/modeling/service_changes.py
index b83a376..eb7bb27 100644
--- a/aria/modeling/service_changes.py
+++ b/aria/modeling/service_changes.py
@@ -65,33 +65,35 @@ class ServiceUpdateBase(ModelMixin):
 
     @declared_attr
     def execution(cls):
-        return cls._create_many_to_one_relationship('execution')
+        return cls._declare_many_to_one('execution')
 
     @declared_attr
-    def execution_name(cls):
-        return association_proxy('execution', cls.name_column_name())
+    def service(cls):
+        return cls._declare_many_to_one('service', parent_property='updates')
+
+    # region foreign keys
 
     @declared_attr
-    def service(cls):
-        return cls._create_many_to_one_relationship('service',
-                                                    backreference='updates')
+    def execution_fk(cls):
+        return cls._declare_fk('execution', nullable=True)
 
     @declared_attr
-    def service_name(cls):
-        return association_proxy('service', cls.name_column_name())
+    def service_fk(cls):
+        return cls._declare_fk('service')
 
-    # region foreign keys
+    # endregion
 
-    __private_fields__ = ['service_fk',
-                          'execution_fk']
+    # region association proxies
 
     @declared_attr
-    def execution_fk(cls):
-        return cls._create_foreign_key('execution', nullable=True)
+    def execution_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('execution', cls.name_column_name())
 
     @declared_attr
-    def service_fk(cls):
-        return cls._create_foreign_key('service')
+    def service_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service', cls.name_column_name())
 
     # endregion
 
@@ -101,6 +103,11 @@ class ServiceUpdateBase(ModelMixin):
         dep_update_dict['steps'] = [step.to_dict() for step in self.steps]
         return dep_update_dict
 
+    __private_fields__ = ['service_fk',
+                          'execution_fk',
+                          'execution_name',
+                          'service_name']
+
 
 class ServiceUpdateStepBase(ModelMixin):
     """
@@ -133,20 +140,22 @@ class ServiceUpdateStepBase(ModelMixin):
 
     @declared_attr
     def service_update(cls):
-        return cls._create_many_to_one_relationship('service_update',
-                                                    backreference='steps')
+        return cls._declare_many_to_one('service_update', parent_property='steps')
+
+    # region foreign keys
 
     @declared_attr
-    def service_update_name(cls):
-        return association_proxy('service_update', cls.name_column_name())
+    def service_update_fk(cls):
+        return cls._declare_fk('service_update')
 
-    # region foreign keys
+    # endregion
 
-    __private_fields__ = ['service_update_fk']
+    # region association proxies
 
     @declared_attr
-    def service_update_fk(cls):
-        return cls._create_foreign_key('service_update')
+    def service_update_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service_update', cls.name_column_name())
 
     # endregion
 
@@ -177,6 +186,9 @@ class ServiceUpdateStepBase(ModelMixin):
             return self.entity_type == 'relationship' and other.entity_type == 'node'
         return False
 
+    __private_fields__ = ['service_update_fk',
+                          'service_update_name']
+
 
 class ServiceModificationBase(ModelMixin):
     """
@@ -201,19 +213,24 @@ class ServiceModificationBase(ModelMixin):
 
     @declared_attr
     def service(cls):
-        return cls._create_many_to_one_relationship('service',
-                                                    backreference='modifications')
+        return cls._declare_many_to_one('service', parent_property='modifications')
+
+    # region foreign keys
 
     @declared_attr
-    def service_name(cls):
-        return association_proxy('service', cls.name_column_name())
+    def service_fk(cls):
+        return cls._declare_fk('service')
 
-    # region foreign keys
+    # endregion
 
-    __private_fields__ = ['service_fk']
+    # region association proxies
 
     @declared_attr
-    def service_fk(cls):
-        return cls._create_foreign_key('service')
+    def service_name(cls):
+        """Required for use by SqlAlchemy queries"""
+        return association_proxy('service', cls.name_column_name())
 
     # endregion
+
+    __private_fields__ = ['service_fk',
+                          'service_name']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/0f040a2b/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 7422211..6214bb2 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -16,7 +16,6 @@
 # pylint: disable=no-self-argument, no-member, abstract-method
 
 import cPickle as pickle
-import logging
 
 from sqlalchemy import (
     Column,
@@ -68,9 +67,9 @@ class ParameterBase(TemplateModelMixin):
             return None
         try:
             return pickle.loads(self._value)
-        except BaseException:
+        except BaseException as e:
             raise exceptions.ValueFormatException('bad format for parameter of type "{0}": {1}'
-                                                  .format(self.type_name, self._value))
+                                                  .format(self.type_name, self._value), cause=e)
 
     @value.setter
     def value(self, value):
@@ -79,9 +78,9 @@ class ParameterBase(TemplateModelMixin):
         else:
             try:
                 self._value = pickle.dumps(value)
-            except (pickle.PicklingError, TypeError):
-                logging.getLogger('aria').warn('Could not pickle parameter of type "{0}": {1}'
-                                               .format(self.type_name, value))
+            except (pickle.PicklingError, TypeError) as e:
+                #raise exceptions.ValueFormatException('bad format for parameter of type "{0}": {1}'
+                #                                      .format(self.type_name, self.value), cause=e)
                 self._value = pickle.dumps(str(value))
 
     def instantiate(self, container):
@@ -124,20 +123,18 @@ class TypeBase(InstanceModelMixin):
 
     @declared_attr
     def parent(cls):
-        return cls._create_relationship_to_self('parent_type_fk')
+        return cls._declare_one_to_one_self('parent_type_fk')
 
     @declared_attr
     def children(cls):
-        return cls._create_one_to_many_relationship_to_self('parent_type_fk')
+        return cls._declare_one_to_many_self('parent_type_fk')
 
     # region foreign keys
 
-    __private_fields__ = ['parent_type_fk']
-
-    # Type one-to-many to Type
     @declared_attr
     def parent_type_fk(cls):
-        return cls._create_foreign_key('type', nullable=True)
+        """For Type one-to-many to Type"""
+        return cls._declare_fk('type', nullable=True)
 
     # endregion
 
@@ -206,6 +203,8 @@ class TypeBase(InstanceModelMixin):
             types.append(raw_child)
             child._append_raw_children(types)
 
+    __private_fields__ = ['parent_type_fk']
+
 
 class MetadataBase(TemplateModelMixin):
     """
@@ -258,11 +257,10 @@ class PluginSpecificationBase(InstanceModelMixin):
 
     # region foreign keys
 
-    __private_fields__ = ['service_template_fk']
-
     @declared_attr
     def service_template_fk(cls):
-        return cls._create_foreign_key('service_template', nullable=True)
+        """For ServiceTemplate one-to-many to PluginSpecification"""
+        return cls._declare_fk('service_template', nullable=True)
 
     # endregion
 
@@ -272,3 +270,5 @@ class PluginSpecificationBase(InstanceModelMixin):
             if plugin.name == self.name:
                 return plugin
         return None
+
+    __private_fields__ = ['service_template_fk']