vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / parser / consumption / presentation.py
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py b/azure/aria/aria-extension-cloudify/src/aria/aria/parser/consumption/presentation.py
new file mode 100644 (file)
index 0000000..542b3f0
--- /dev/null
@@ -0,0 +1,137 @@
+# 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.
+
+
+from ...utils.threading import FixedThreadPoolExecutor
+from ...utils.formatting import json_dumps, yaml_dumps
+from ..loading import UriLocation
+from ..reading import AlreadyReadException
+from ..presentation import PresenterNotFoundError
+from .consumer import Consumer
+
+
+class Read(Consumer):
+    """
+    Reads the presentation, handling imports recursively.
+
+    It works by consuming a data source via appropriate :class:`~aria.parser.loading.Loader`,
+    :class:`~aria.parser.reading.Reader`, and :class:`~aria.parser.presentation.Presenter`
+    instances.
+
+    It supports agnostic raw data composition for presenters that have
+    ``_get_import_locations`` and ``_merge_import``.
+
+    To improve performance, loaders are called asynchronously on separate threads.
+
+    Note that parsing may internally trigger more than one loading/reading/presentation
+    cycle, for example if the agnostic raw data has dependencies that must also be parsed.
+    """
+
+    def consume(self):
+        if self.context.presentation.location is None:
+            self.context.validation.report('Presentation consumer: missing location')
+            return
+
+        presenter = None
+        imported_presentations = None
+
+        executor = FixedThreadPoolExecutor(size=self.context.presentation.threads,
+                                           timeout=self.context.presentation.timeout)
+        executor.print_exceptions = self.context.presentation.print_exceptions
+        try:
+            presenter = self._present(self.context.presentation.location, None, None, executor)
+            executor.drain()
+
+            # Handle exceptions
+            for e in executor.exceptions:
+                self._handle_exception(e)
+
+            imported_presentations = executor.returns
+        finally:
+            executor.close()
+
+        # Merge imports
+        if (imported_presentations is not None) and hasattr(presenter, '_merge_import'):
+            for imported_presentation in imported_presentations:
+                okay = True
+                if hasattr(presenter, '_validate_import'):
+                    okay = presenter._validate_import(self.context, imported_presentation)
+                if okay:
+                    presenter._merge_import(imported_presentation)
+
+        self.context.presentation.presenter = presenter
+
+    def dump(self):
+        if self.context.has_arg_switch('yaml'):
+            indent = self.context.get_arg_value_int('indent', 2)
+            raw = self.context.presentation.presenter._raw
+            self.context.write(yaml_dumps(raw, indent=indent))
+        elif self.context.has_arg_switch('json'):
+            indent = self.context.get_arg_value_int('indent', 2)
+            raw = self.context.presentation.presenter._raw
+            self.context.write(json_dumps(raw, indent=indent))
+        else:
+            self.context.presentation.presenter._dump(self.context)
+
+    def _handle_exception(self, e):
+        if isinstance(e, AlreadyReadException):
+            return
+        super(Read, self)._handle_exception(e)
+
+    def _present(self, location, origin_location, presenter_class, executor):
+        # Link the context to this thread
+        self.context.set_thread_local()
+
+        raw = self._read(location, origin_location)
+
+        if self.context.presentation.presenter_class is not None:
+            # The presenter class we specified in the context overrides everything
+            presenter_class = self.context.presentation.presenter_class
+        else:
+            try:
+                presenter_class = self.context.presentation.presenter_source.get_presenter(raw)
+            except PresenterNotFoundError:
+                if presenter_class is None:
+                    raise
+            # We'll use the presenter class we were given (from the presenter that imported us)
+            if presenter_class is None:
+                raise PresenterNotFoundError('presenter not found')
+
+        presentation = presenter_class(raw=raw)
+
+        if presentation is not None and hasattr(presentation, '_link_locators'):
+            presentation._link_locators()
+
+        # Submit imports to executor
+        if hasattr(presentation, '_get_import_locations'):
+            import_locations = presentation._get_import_locations(self.context)
+            if import_locations:
+                for import_location in import_locations:
+                    # The imports inherit the parent presenter class and use the current location as
+                    # their origin location
+                    import_location = UriLocation(import_location)
+                    executor.submit(self._present, import_location, location, presenter_class,
+                                    executor)
+
+        return presentation
+
+    def _read(self, location, origin_location):
+        if self.context.reading.reader is not None:
+            return self.context.reading.reader.read()
+        loader = self.context.loading.loader_source.get_loader(self.context.loading, location,
+                                                               origin_location)
+        reader = self.context.reading.reader_source.get_reader(self.context.reading, location,
+                                                               loader)
+        return reader.read()