aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authormmis <michael.morris@ericsson.com>2018-10-08 15:54:36 +0100
committermmis <michael.morris@ericsson.com>2018-10-09 11:50:06 +0000
commitd4e7632aa00b42c544406fe9d83621c50831fe8e (patch)
treea975f9729746a0d95e2c9e79c0e73e1d8b059558 /docs
parent88ca44387f65cae61b500f4219d985bd9a1687a9 (diff)
Added documentation for readthedocs
Issue-ID: POLICY-1161 Change-Id: I8a3ac2b8fbfccacd04cfd5cb3bc649d9674ec59b Signed-off-by: mmis <michael.morris@ericsson.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/APEX-Developer-Guide.rst1471
-rw-r--r--docs/APEX-Install-Guide.rst1418
-rw-r--r--docs/APEX-Introduction.rst545
-rw-r--r--docs/APEX-Policy-Guide.rst2133
-rw-r--r--docs/APEX-User-Manual.rst8071
-rw-r--r--docs/images/apex-intro/ApexEcosystem.pngbin0 -> 231634 bytes
-rw-r--r--docs/images/apex-intro/ApexEngineConfig.pngbin0 -> 390824 bytes
-rw-r--r--docs/images/apex-intro/ApexPolicyMatrix.pngbin0 -> 347429 bytes
-rw-r--r--docs/images/apex-intro/ApexSimple.pngbin0 -> 89870 bytes
-rw-r--r--docs/images/apex-intro/ApexStatesAndContext.pngbin0 -> 103233 bytes
-rw-r--r--docs/images/apex-intro/UpeeClusterOptions.pngbin0 -> 169938 bytes
-rw-r--r--docs/images/apex-intro/UpeeDeploymentOptions.pngbin0 -> 230061 bytes
-rw-r--r--docs/images/apex-policy-model/ConceptsKeys.pngbin0 -> 42740 bytes
-rw-r--r--docs/images/apex-policy-model/UmlPolicyModels.pngbin0 -> 197515 bytes
-rw-r--r--docs/images/howto-config/ApexEngineConfig.pngbin0 -> 390824 bytes
-rw-r--r--docs/images/install-guide/rest-loaded.pngbin0 -> 197739 bytes
-rw-r--r--docs/images/install-guide/rest-start.pngbin0 -> 103420 bytes
-rw-r--r--docs/images/install-guide/win-extract-tar-gz.pngbin0 -> 200361 bytes
-rw-r--r--docs/images/install-guide/win-extract-tar.pngbin0 -> 202887 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_exportPolicyModel1.pngbin0 -> 8703 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newEvent1.pngbin0 -> 15574 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newEvent2.pngbin0 -> 22460 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newEvent3.pngbin0 -> 26489 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newItemSchema1.pngbin0 -> 14500 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newItemSchema2.pngbin0 -> 23052 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newPolicy1.pngbin0 -> 31495 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newPolicyModel1.pngbin0 -> 8490 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newPolicyModel2.pngbin0 -> 12696 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newState1.pngbin0 -> 41125 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newState2.pngbin0 -> 50884 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newTask1.pngbin0 -> 22442 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newTask2.pngbin0 -> 27079 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_newTask3.pngbin0 -> 37331 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P1_validatePolicyModel.pngbin0 -> 9031 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P2_editPolicy1.pngbin0 -> 26097 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P2_editState1.pngbin0 -> 97378 bytes
-rw-r--r--docs/images/mfp/MyFirstPolicy_P2_newTask1.pngbin0 -> 113275 bytes
-rw-r--r--docs/index.rst12
38 files changed, 13650 insertions, 0 deletions
diff --git a/docs/APEX-Developer-Guide.rst b/docs/APEX-Developer-Guide.rst
new file mode 100644
index 000000000..d5f16d56c
--- /dev/null
+++ b/docs/APEX-Developer-Guide.rst
@@ -0,0 +1,1471 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+
+APEX Developer Guide
+********************
+
+.. contents::
+ :depth: 3
+
+Build APEX from Source
+^^^^^^^^^^^^^^^^^^^^^^
+
+Introduction to building APEX
+-----------------------------
+
+ .. container:: paragraph
+
+ APEX is written 100% in Java and uses `Apache
+ Maven <https://maven.apache.org/>`__ as the build system.
+ The requirements for building APEX are:
+
+ .. container:: ulist
+
+ - An installed Java development kit for Java version 8
+ or higher
+
+ .. container:: ulist
+
+ - To install a Java SDK please follow these
+ guidelines `Oracle Java 8
+ SDK <https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html>`__.
+
+ - Maven 3
+
+ .. container:: ulist
+
+ - To get Maven 3 running please follow the
+ guidelines for
+ `Download <https://maven.apache.org/download.cgi>`__
+ and
+ `Install <https://maven.apache.org/install.html>`__,
+ and `Run <https://maven.apache.org/run.html>`__
+ Maven
+
+ - A clone of the APEX source repositories
+
+ .. container:: paragraph
+
+ To get a clone of the APEX source repositories, please
+ see the APEX Installation Guide or the APEX User manual.
+
+ .. container:: paragraph
+
+ One all requirements are in place, APEX can be build.
+ There are several different artifacts one can create
+ building APEX, most of them defined in their own
+ *profile*. APEX can also be build in a standard way with
+ standard tests (``mvn clean install``) or without
+ standard tests (``mvn clean install -DskipTests``).
+
+ .. container:: paragraph
+
+ The examples in this document assume that the APEX source
+ repositories are cloned to:
+
+ .. container:: ulist
+
+ - Unix, Cygwin: ``/usr/local/src/apex``
+
+ - Windows: ``C:\dev\apex``
+
+ - Cygwin: ``/cygdrive/c/dev/apex``
+
+ .. important::
+ A Build requires ONAP Nexus
+ APEX has a dependency to ONAP parent projects. You might need to adjust your Maven M2 settings. The most current
+ settings can be found in the ONAP oparent repo: `Settings <https://git.onap.org/oparent/plain/settings.xml>`__.
+
+ .. important::
+
+ A Build needs Space
+ Building APEX requires approximately 2-3 GB of hard disc space, 1 GB for the actual build with full
+ distribution and 1-2 GB for the downloaded dependencies
+
+ .. important::
+ A Build requires Internet (for first build to download all dependencies and plugins)
+ During the build, several (a lot) of Maven dependencies will be downloaded and stored in the configured local Maven
+ repository. The first standard build (and any first specific build) requires Internet access to download those
+ dependencies.
+
+ .. important::
+ Building RPM distributions
+ RPM images are only build if the ``rpm`` package is installed (Unix). To install ``rpm``
+ run ``sudo apt-get install rpm``, then build APEX.
+
+Standard Build
+--------------
+
+ .. container:: paragraph
+
+ Use Maven to for a standard build without any tests.
+
+ +-----------------------------------+------------------------------------+
+ | Unix, Cygwin | Windows |
+ +===================================+====================================+
+ | :: | :: |
+ | | |
+ | >c: | # cd /usr/local/src/apex |
+ | >cd \dev\apex | # mvn clean install -DskipTests |
+ | >mvn clean install -DskipTests | |
+ | | |
+ +-----------------------------------+------------------------------------+
+
+.. container:: paragraph
+
+ The build takes about 6 minutes on a standard development laptop. It
+ should run through without errors, but with a lot of messages from
+ the build process.
+
+.. container:: paragraph
+
+ When Maven is finished with the build, the final screen should look
+ similar to this (omitting some ``success`` lines):
+
+.. container:: listingblock
+
+ .. code:: bash
+ :number-lines:
+
+ [INFO] tools .............................................. SUCCESS [ 0.248 s]
+ [INFO] tools-common ....................................... SUCCESS [ 0.784 s]
+ [INFO] simple-wsclient .................................... SUCCESS [ 3.303 s]
+ [INFO] model-generator .................................... SUCCESS [ 0.644 s]
+ [INFO] packages ........................................... SUCCESS [ 0.336 s]
+ [INFO] apex-pdp-package-full .............................. SUCCESS [01:10 min]
+ [INFO] Policy APEX PDP - Docker build 2.0.0-SNAPSHOT ...... SUCCESS [ 10.307 s]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] BUILD SUCCESS
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Total time: 03:43 min
+ [INFO] Finished at: 2018-09-03T11:56:01+01:00
+ [INFO] ------------------------------------------------------------------------
+
+.. container:: paragraph
+
+ The build will have created all artifacts required for an APEX
+ installation. The following example show how to change to the target
+ directory and how it should look like.
+
++-----------------------------------------------------------------------------------------------------------------------------+
+| Unix, Cygwin |
++=============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. code:: bash |
+| :number-lines: |
+| |
+| # cd packages/apex-pdp-package-full/target |
+| # ls -l |
+| -rwxrwx---+ 1 esvevan Domain Users 772 Sep 3 11:55 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes* |
+| -rwxrwx---+ 1 esvevan Domain Users 146328082 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT.deb* |
+| -rwxrwx---+ 1 esvevan Domain Users 15633 Sep 3 11:54 apex-pdp-package-full-2.0.0-SNAPSHOT.jar* |
+| -rwxrwx---+ 1 esvevan Domain Users 146296819 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 archive-tmp/ |
+| -rwxrwx---+ 1 esvevan Domain Users 89 Sep 3 11:54 checkstyle-cachefile* |
+| -rwxrwx---+ 1 esvevan Domain Users 10621 Sep 3 11:54 checkstyle-checker.xml* |
+| -rwxrwx---+ 1 esvevan Domain Users 584 Sep 3 11:54 checkstyle-header.txt* |
+| -rwxrwx---+ 1 esvevan Domain Users 86 Sep 3 11:54 checkstyle-result.xml* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 classes/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 dependency-maven-plugin-markers/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 etc/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 examples/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:55 install_hierarchy/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 maven-archiver/ |
++-----------------------------------------------------------------------------------------------------------------------------+
+
++-----------------------------------------------------------------------------------------------------------------------------+
+| Windows |
++=============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. code:: bash |
+| :number-lines: |
+| |
+| >cd packages\apex-pdp-package-full\target |
+| >dir |
+| |
+| 03/09/2018 11:55 <DIR> . |
+| 03/09/2018 11:55 <DIR> .. |
+| 03/09/2018 11:55 146,296,819 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz |
+| 03/09/2018 11:55 146,328,082 apex-pdp-package-full-2.0.0-SNAPSHOT.deb |
+| 03/09/2018 11:54 15,633 apex-pdp-package-full-2.0.0-SNAPSHOT.jar |
+| 03/09/2018 11:55 772 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes |
+| 03/09/2018 11:54 <DIR> archive-tmp |
+| 03/09/2018 11:54 89 checkstyle-cachefile |
+| 03/09/2018 11:54 10,621 checkstyle-checker.xml |
+| 03/09/2018 11:54 584 checkstyle-header.txt |
+| 03/09/2018 11:54 86 checkstyle-result.xml |
+| 03/09/2018 11:54 <DIR> classes |
+| 03/09/2018 11:54 <DIR> dependency-maven-plugin-markers |
+| 03/09/2018 11:54 <DIR> etc |
+| 03/09/2018 11:54 <DIR> examples |
+| 03/09/2018 11:55 <DIR> install_hierarchy |
+| 03/09/2018 11:54 <DIR> maven-archiver |
+| 8 File(s) 292,652,686 bytes |
+| 9 Dir(s) 14,138,720,256 bytes free |
++-----------------------------------------------------------------------------------------------------------------------------+
+
+
+Checkstyle with Maven
+---------------------
+
+ .. container:: paragraph
+
+ The codestyle for all APEX java projects can be checked
+ automatically. The checks include empty or non-existing Javadocs.
+ Any checkstyle run should complete without any errors, some
+ warnings are acceptable.
+
+ .. container:: paragraph
+
+ To run checkstyle on an APEX Maven project use:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ mvn checkstyle:check
+
+ .. container:: paragraph
+
+ To run checkstyle on all modules use:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ mvn checkstyle:checkstyle -DapexAll
+
+Build with standard Tests
+-------------------------
+
+ .. container:: paragraph
+
+ Use Maven to for a standard build with standard tests.
+
+ .. important::
+ Some tests have specific timing Requirements
+ Some of the tests have very specific timing requirements. If run on a low-powered build machine, or if the build
+ machine is on high load, those tests might fail and the whole build might fail as well. If this happens, reduce the load
+ on your build machine and restart the build.
+
+ +-----------------------------------+-----------------------------------+
+ | Unix, Cygwin | Windows |
+ +===================================+===================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | >c: | # cd /usr/local/src/apex |
+ | >cd \dev\apex | # mvn clean install |
+ | >mvn clean install | |
+ +-----------------------------------+-----------------------------------+
+
+
+.. container:: paragraph
+
+ The build takes about 10 minutes with tests on a standard development
+ laptop. It should run through without errors, but with a lot of
+ messages from the build process. If build with tests (i.e. without
+ ``-DskipTests``), there will be error messages and stack trace prints
+ from some tests. This is normal, as long as the build finishes
+ successful.
+
+Build with all Tests
+--------------------
+
+ .. container:: paragraph
+
+ Use Maven to for a standard build with *all* tests.
+
+ .. important::
+ Some tests have specific timing Requirements.
+ Some of the tests have very specific timing requirements. If run on a low-powered build machine, or if the build
+ machine is on high load, those tests might fail and the whole build might fail as well. If this happens, reduce the load
+ on your build machine and restart the build.
+
+ .. important::
+ Might require specific software.
+ When running all tests, some modules require specific software installed on the build machine. For instance,
+ testing the full capabilities of context (with distribution and persistence) will require Hazelcast and Infinispan
+ installed on the build machine.
+
+ +----------------------------------------------+----------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +==============================================+==============================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | >c: | # cd /usr/local/src/apex |
+ | >cd \dev\apex | # mvn clean install -DallTests |
+ | >mvn clean install -DallTests | |
+ +----------------------------------------------+----------------------------------------------+
+
+Build with all Components
+-------------------------
+
+ .. container:: paragraph
+
+ A standard APEX build will not build all components. Some parts
+ are for specific deployments, only. Use Maven to for a standard
+ build with *all* components.
+
+ .. important::
+ Might require specific software.
+ When building all components, some modules require specific software installed on the build machine.
+
+ +----------------------------------------------+----------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +==============================================+==============================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | >c: | # cd /usr/local/src/apex |
+ | >cd \dev\apex | # mvn clean install -DapexAll |
+ | >mvn clean install -DapexAll | |
+ +----------------------------------------------+----------------------------------------------+
+
+
+Build the APEX Documentation
+----------------------------
+
+ .. container:: paragraph
+
+ The APEX Maven build also includes stand-alone documentations,
+ such as the HowTo documents, the Installation Guide, and the User
+ Manual. Use Maven to build the APEX Documentation. The Maven
+ options ``-N`` prevents Maven to go through all APEX modules,
+ which is not necessary for the documentation. The final documents
+ will be in ``target/generated-docs`` (Windows:
+ ``target\generated-docs``). The *HTML* documents are in the
+ ``html/`` folder, the *PDF* documents are in the ``pdf/`` folder.
+ Once the documentation is build, copy the *HTML* and *PDF*
+ documents to a folder of choice
+
+ +-------------------------------------------------------+--------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=======================================================+========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | >c: | # cd /usr/local/src/apex |
+ | >cd \dev\apex | # mvn clean generate-resources -N -DapexDocs |
+ | >mvn clean generate-resources -N -DapexDocs | |
+ +-------------------------------------------------------+--------------------------------------------------------+
+
+Build APEX Site
+---------------
+
+ .. container:: paragraph
+
+ The APEX Maven build comes with full support to build a web site
+ using Maven Site. Use Maven to build the APEX Site. Stage the APEX
+ web site. The target folder for the staged site is
+
+ .. container:: ulist
+
+ - Unix: ``/usr/local/src/apex/target/ad-site``
+
+ - Windows: ``C:\dev\apex\target\ad-site``
+
+ - Cygwin: ``/cygdrive/c/dev/apex/target/ad-site``
+
+ .. container:: paragraph
+
+ Once the web site is staged, copy the full site to a folder of
+ choice or into a web server.
+
+ .. important::
+ Building a Site takes Time.
+ Building and staging the APEX web site can take very long. The stand-alone documentation will take about 2 minutes. The
+ sites for all modules and projects and the main APEX site can take between 10-30 minutes depending on your build machine (~10 minutes
+ without generating source and test-source reports, closer to 30 minutes with all reports).
+
+ .. container:: paragraph
+
+ Start the build deleting the staging directory that might have
+ been created by a previous site build. Then go to the APEX
+ packaging directory.
+
+ +--------------------------------+-----------------------------------+----------------------------------+
+ | Unix | Windows | Cygwin |
+ +================================+===================================+==================================+
+ | .. container:: | .. container:: | .. container:: |
+ | | | |
+ | .. container:: content | .. container:: content | .. container:: content |
+ | | | |
+ | .. code:: bash | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: | :number-lines: |
+ | | | |
+ | cd /usr/local/src/apex | c: | cd /cygdrive/c/dev/apex |
+ | rm -fr target/ad-site | cd \dev\apex | rm -fr target/ad-site |
+ | | rmdir /s/q target\ad-site | |
+ +--------------------------------+-----------------------------------+----------------------------------+
+
+ .. container:: paragraph
+
+ the workflow for building a complete site then is as follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ mvn clean -DapexAll (1)
+ mvn install -DskipTests (2)
+ mvn generate-resources -N -DapexDocs (3)
+ mvn initialize site:attach-descriptor site site:stage -DapexSite (4)
+
+ .. container:: olist arabic
+
+ #. First clean all modules to remove any site artifacts, use the
+ *apexXtext* profile to make sure these modules are processed as
+ well
+
+ #. Next run a simple install without tests
+
+ #. Now generate the APEX stand -alone documentation, they are in
+ the local package only so we can use the *-N* switch
+
+ #. Last build the actual sites and stage (copy to the staging
+ directory) with the profile *apexSite* (do not forget the
+ initialize goal, otherwise the staging directory will not be
+ correctly set and sites are staged in every model in a
+ directory called ``docs``).
+
+ .. container:: paragraph
+
+ If you want to build the site for a particular project for
+ testing, the Maven command is simpler. Since only the main project
+ has APEX documentation (stand-alone), you can use Maven as follow.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ mvn clean site -DapexSite
+
+ .. container:: paragraph
+
+ If you want to stage the tested site, then use
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ mvn clean initialize site:attach-descriptor site site:stage -DapexSite
+
+APEX Codestyle
+^^^^^^^^^^^^^^
+
+Introduction: APEX Codestyle
+----------------------------
+
+ .. container:: paragraph
+
+ This page describes how to apply a code style to the APEX
+ Java projects. The provided code templates are guidelines
+ and are provided for references and as examples. We will not
+ engage in "holy war" on style for coding. As long as the
+ style of a particular block of code is understandable,
+ consistent, and readable, please feel free to adapt or
+ modify these guides or use other guides as you see fit.
+
+ .. container:: paragraph
+
+ The JAutoDoc and Checkstyle Eclipse Plugins and tools are
+ useful and remove a lot of the tedium from code
+ documentation. Use them to check your code and please fix
+ any issues they identify with your code.
+
+ .. container:: paragraph
+
+ Since APEX is part of ONAP, the general ONAP rules and
+ guideliness for development do apply. Please see `ONAP
+ Wiki <https://wiki.onap.org/display/DW/Developing+ONAP>`__
+ for details.
+
+Java coding Rules
+-----------------
+
+ .. container:: ulist
+
+ - APEX is (in large parts) a platform (or middleware), so
+ `Software Design
+ Patterns <https://en.wikipedia.org/wiki/Software_design_pattern>`__
+ are a good thing
+
+ - The `Solid
+ Principles <https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)>`__
+ apply
+
+ - Avoid class fields scoped as ``protected``
+
+ .. container:: ulist
+
+ - They break a lot of good design rules, e.g. most
+ SOLID rules
+
+ - For a discussion see this `Stackoverflow
+ Question <https://softwareengineering.stackexchange.com/questions/162643/why-is-clean-code-suggesting-avoiding-protected-variables>`__
+
+ - If you absolutely need ``protected`` class fields they
+ should be ``final``
+
+ - Avoid ``default`` scope for class fields and methods
+
+ .. container:: ulist
+
+ - For fields: use ``public`` or ``private`` (see also
+ above)
+
+ - For methods: use ``public`` for general use,
+ ``protected`` for specialization using inheritance
+ (ideally ``final``), ``private`` for everything
+ else
+
+ - Method parameters that are not changed in the method
+ should be marked ``final``
+
+ - Every package must have a ``package-info.java`` file with
+ an appropriate description, minimum a descriptive one
+ liner
+
+ - Every class must have
+
+ .. container:: ulist
+
+ - The common header (copyright, file, date)
+
+ - Javadoc header for the class with description of
+ the class and author
+
+ - Javadoc for *all public\_* fields
+
+ - If possible, Javadoc for *private* fields, at least
+ some documentation for private fields
+
+ - Javadoc for *all* methods
+
+ - All project must build with all tests on Unix, Windows,
+ *and* Cygwin
+
+ .. container:: ulist
+
+ - Support all line endings in files, e.g. ``\n`` and
+ ``\r\n``
+
+ - Be aware of potential differences in exception
+ messages, if testing against a message
+
+ - Support all types of paths: Unix with ``/``,
+ Windows with an optinal drive ``C:\`` and ``\``,
+ Cygwin with mixed paths
+
+Eclipse Plugin: JAutodoc
+------------------------
+
+ .. container:: paragraph
+
+ This plugin is a helper plugin for writing Javadoc. It will
+ automatically create standard headers on files, create
+ package-info.java files and will put in remarkably good stub
+ Javadoc comments in your code, using class names and method
+ names as hints.
+
+ .. container:: paragraph
+
+ Available from the Eclipse Marketplace. In Eclipse
+ Help→Eclipse Marketplace…​ and type ``JAutodoc``. Select
+ JAutodoc when the search returns and install it.
+
+ .. container:: paragraph
+
+ You must configure JAutoDoc in order to get the most out of
+ it. Ideally JAutoDoc should be configured with templates
+ that cooperate with the inbuilt Eclipse Code Formatter for
+ best results.
+
+Eclipse Plugin: Checkstyle
+--------------------------
+
+ .. container:: paragraph
+
+ This plugin integrates
+ `Checkstyle <http://checkstyle.sourceforge.net/>`__ into
+ Eclipse. It will check your code and flag any checkstyle
+ issues as warnings in the code.
+
+ .. container:: paragraph
+
+ Available from the Eclipse Marketplace. In Eclipse
+ Help→Eclipse Marketplace…​ and type "Checkstyle". Select
+ "Checkstyle Plug-in" when the search returns and install it.
+ Note that "Checkstyle Plug-in" may not be the first result
+ in the list of items returned.
+
+ .. container:: paragraph
+
+ For APEX, the ONAP checkstyle rules do apply. The
+ configuration is part of the ONAP parent. See `ONAP
+ Git <https://git.onap.org/oparent/plain/checkstyle/src/main/resources/onap-checkstyle/>`__
+ for details and updates. All settings for checkstyle are
+ already part of the code (POM files).
+
+Configure Eclipse
+-----------------
+
+ .. container:: ulist
+
+ - Set the template for Eclipse code clean up
+
+ .. container:: olist arabic
+
+ #. Eclipse  Window  Preferences  Java  Code Style 
+ Clean Up → Import…​
+
+ #. Select your template file
+ (``ApexCleanUpTemplate.xml``) and apply it
+
+ - Set the Eclipse code templates
+
+ .. container:: olist arabic
+
+ #. Eclipse  Window  Preferences  Java  Code Style 
+ Code Templates → Import…​
+
+ #. Select your templates file
+ (``ApexCodeTemplates.xml``) and apply it
+
+ .. container:: ulist
+
+ - Make sure to set your email address in
+ generated comments by selecting
+ "Comments→Types" in the "Configure generated
+ code and comments:" pane, then change the
+ email address on the @author tag to be your
+ email address
+
+ - Set the Eclipse Formatter profile
+
+ .. container:: olist arabic
+
+ #. Eclipse  Window  Preferences  Java  Code Style 
+ Formatter → Import…​
+
+ #. Select your formatter profile file
+ (``ApexFormatterProfile.xml``) and apply it
+
+ .. container:: paragraph
+
+ The templates mentioned above can be found in
+ ``apex-model/apex-model.build-tools/src/main/resources/eclipse``
+
+Configure JAutodoc (Eclipse)
+----------------------------
+
+ .. container:: paragraph
+
+ Import the settings for JAutodoc:
+
+ .. container:: olist arabic
+
+ #. Eclipse  Window  Preferences  Java  JAutodoc → Import
+ All…​ (at bottom of the JAutodoc preferences window)
+
+ #. Leave all the preferences ticked to import all
+ preferences, browse to the JAutodoc setting file
+ (``ApexJautodocSettings.xml``) and press OK
+
+ #. Set your email address in the package Javadoc template
+
+ .. container:: ulist
+
+ - Press Edit Template…​ in the Package Javadoc area
+ of the JAutodoc preferences window, and change the
+ email address on the ``@author`` tag to be your
+ email address
+
+ #. Now, apply the JAutodoc settings
+
+ .. container:: paragraph
+
+ The templates mentioned above can be found in
+ ``apex-model/apex-model.build-tools/src/main/resources/eclipse``
+
+Configure Checkstyle (Maven)
+----------------------------
+
+ .. container:: paragraph
+
+ When using a custom style configuration with Checkstyle, the
+ definition of that style must of course be available to
+ Checkstyle. In order not to have to distribute style files
+ for checkstyle into all Maven modules, it is recommended
+ that a special Maven module be built that contains the
+ checkstyle style definition. That module is then used as a
+ dependency in the *POM* for all other modules that wish to
+ use that checkstyle style. For a full explanation see `the
+ explanation of Checkstyle multi-module
+ configuration <https://maven.apache.org/plugins/maven-checkstyle-plugin/examples/multi-module-config.html>`__.
+
+ .. container:: paragraph
+
+ For APEX, the ONAP checkstyle rules do apply. The
+ configuration is part of the ONAP parent. See `ONAP
+ Git <https://git.onap.org/oparent/plain/checkstyle/src/main/resources/onap-checkstyle/>`__
+ for details and updates.
+
+Run Checkstyle (Maven)
+----------------------
+
+ .. container:: paragraph
+
+ Run Checkstyle using Maven on the command line with the
+ command:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ mvn checkstyle:check
+
+ .. container:: paragraph
+
+ On the main APEX project, run a full checkstyle check as:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ mvn checkstyle:checkstyle -DapexAll
+
+Configure Checkstyle (Eclipse, globally)
+----------------------------------------
+
+ .. container:: olist arabic
+
+ #. Set up a module with the Checkstyle style files (see
+ above)
+
+ #. In Eclipse  Window  Preferences go to Checkstyle
+
+ #. Import the settings for Checkstyle
+
+ .. container:: ulist
+
+ - Press New…​ to create a new *Global Check
+ Configurations* entry
+
+ - Give the configuration a name such as *Apex
+ Checkstyle Configuration* and select the *External
+ Configuration File* form in the *Type* drop down
+ menu
+
+ - Browse to the Checckstyle setting file
+ (``ApexCheckstyleSettings.xml``) and press OK
+
+ #. Press OK
+
+ .. container:: ulist
+
+ - You may now get an *Unresolved Properties found*
+ dialogue
+
+ - This is because there is a second Checkstyle
+ configuration file required to check file headers
+
+ #. Press Edit Properties…​ and press Find unresolved
+ properties on the next dialogue window
+
+ #. The plugin will find the ``${checkstyle.header.file}``
+ property is unresolved and will ask should it be added to
+ the properties, click yes
+
+ #. Now, select the row on the dialogue for the
+ ``checkstyle.header.file property`` and click Edit…​
+
+ #. Set the value of the ``checkstyle.header.file property``
+ to
+ ``<your-apex-git-location>/apex-model/apex-model.build-tools/src/main/resources/checkstyle/apex_header.txt``
+
+ .. container:: ulist
+
+ - Of course replacing the tag
+ ``<your-apex-git-location>`` with the location of
+ your Apex GIT repository
+
+ #. Press OK, OK, OK to back out to the main Checkstyle
+ properties window
+
+ #. Select the *Apex Checkstyle Configuration* as your
+ default configuration by selecting its line in the
+ *Global Check Configuraitons* list and clicking Set as
+ Default
+
+ #. Press Apply and Close to finish Checkstyle global
+ configuration
+
+ .. container:: paragraph
+
+ The templates mentioned above can be found in
+ ``apex-model/apex-model.build-tools/src/main/resources/eclipse``
+
+2.10. Configure Checkstyle Blueprint
+------------------------------------
+
+ .. container:: paragraph
+
+ As well as being configured globally, Checkstyle must be
+ configured and activated for each project in Eclipse. In
+ order to make this process less tedious, set up the first
+ project you apply Checkstye to as a blueprint project and
+ then use this blueprint for all other projects.
+
+ .. container:: olist arabic
+
+ #. Select the project you want to use as a blueprint
+
+ .. container:: ulist
+
+ - For example, ``apex-model.basic-model`` in ``apex``
+ and enter the project properties by right clicking
+ and selecting **Properties**
+
+ #. Click *Checkstyle* on the properties to get the
+ Checkstyle project configuration window
+
+ #. Click the box *Checkstyle active for this project* and in
+ the *Exclude from checking…​* list check the boxes:
+
+ .. container:: ulist checklist
+
+ - *files outside source directories*
+
+ - *derived (generated) files*
+
+ - *files from packages:*
+
+ #. Now, in order to turn off checking on resource
+ directories and on JUnit tests
+
+ .. container:: ulist
+
+ - Select the line *files from packages:* in the
+ *Exclude from checking…​* list and click Change…​
+
+ #. On the *Filter packages* dialogue
+
+ .. container:: ulist
+
+ - Check all the boxes except the top box, which is
+ the box for *src/main/java*
+
+ - Ensure that the *recursively exclude sub-packages*
+ check box is ticked
+
+ .. container:: ulist checklist
+
+ - *recursively exclude sub-packages*
+
+ - Press OK
+
+ #. Press Apply and Close to apply the changes
+
+Use Eclipse Source Operations
+-----------------------------
+
+ .. container:: paragraph
+
+ Eclipse Source Operations can be carried out on individual
+ files or on all the files in a package but do not recurse
+ into sub-packages. They are available as a menu in Eclipse
+ by selecting a file or package and right clicking on
+ *Source*. Note that running *Clean Up…​* with the Apex clean
+ up profile will run *Format* and *Organize Imports*. So if
+ you run a clean up on a file or package, you need not run
+ *Format* or *Organize Imports*.
+
+ .. container:: paragraph
+
+ We recommend you use the following Eclipse Source
+ Operations:
+
+ .. container:: olist arabic
+
+ #. *Format* applies the current format definition to the
+ file or all files in a package
+
+ #. *Organize Imports* sorts the imports on each file in
+ standard order
+
+ #. *Clean Up* runs a number of cleaning operations on each
+ file. The Apex clean up template
+
+ .. container:: ulist
+
+ - Remove ``this`` qualifier for non static field
+ accesses
+
+ - Change non static accesses to static members using
+ declaring type
+
+ - Change indirect accesses to static members to
+ direct accesses (accesses through subtypes)
+
+ - Convert control statement bodies to block
+
+ - Convert ``for`` loops to enhanced ``for`` loops
+
+ - Add final modifier to private fields
+
+ - Add final modifier to local variables
+
+ - Remove unused imports
+
+ - Remove unused private methods
+
+ - Remove unused private constructors
+
+ - Remove unused private types
+
+ - Remove unused private fields
+
+ - Remove unused local variables
+
+ - Add missing ``@Override`` annotations
+
+ - Add missing ``@Override`` annotations to
+ implementations of interface methods
+
+ - Add missing ``@Deprecated`` annotations
+
+ - Add missing serial version ID (generated)
+
+ - Remove unnecessary casts
+
+ - Remove unnecessary ``$NON-NLS$`` tags
+
+ - Organize imports
+
+ - Format source code
+
+ - Remove trailing white spaces on all lines
+
+ - Correct indentation
+
+ - Remove redundant type arguments
+
+ - Add file header (JAutodoc)
+
+Using JAutodoc
+--------------
+
+ .. container:: paragraph
+
+ Similar to Eclipse Source Operations, JAutodoc operations
+ can be carried out on individual files or on all the files
+ in a package but do not recurse into sub-packages. The
+ JAutodoc operations are available by selecting a file or
+ package and right clicking on *JAutodoc*:
+
+ .. container:: olist arabic
+
+ #. To add a ``package-info.java`` file to a package, select
+ the package and right-click Jautodoc  Add Package Javadoc
+
+ #. To add headers to files select on a file (or on the
+ package to do all files) and right click JAutodoc  Add
+ Header
+
+ #. To add JAutodoc stubs to a files, select on a file (or on
+ the package to do all files) and right click JAutodoc 
+ Add Javadoc
+
+Using Checkstyle
+----------------
+
+ .. container:: paragraph
+
+ In order to use Checkstyle, you must configure it per
+ project and then activate it per project. The easiest way to
+ do this is to set up one project as a blueprint and use that
+ blueprint for other projects (see above). Once you have a
+ blueprint project, you can use Checkstyle on other projects
+ as follows
+
+ .. container:: olist arabic
+
+ #. Set up Checkstyle on projects by selecting one or more
+ projects
+
+ .. container:: ulist
+
+ - Right clicking and selecting Checkstyle  Configure
+ project(s) from *blueprint…​* and then selecting
+ your blueprint project
+
+ - (for example ``apex-model.basic-model``) from the
+ list of projects and pressing OK
+
+ #. Activate Checkstyle on projects by selecting one or more
+ projects
+
+ .. container:: ulist
+
+ - Right clicking and selecting Checkstyle  Activate
+ Checkstyle
+
+ - Now Checkstyle warnings will appear on the selected
+ projects if they have warnings
+
+ #. You can disable Checkstyle checking on a file or a
+ package (recursively) by selecting a file or package
+
+ .. container:: ulist
+
+ - Right clicking and selecting Checkstyle  Clear
+ Checkstyle violations
+
+ #. You can enable Checkstyle checking on a file or a package
+ (recursively) by selecting a file or package
+
+ .. container:: ulist
+
+ - Right clicking and selecting Checkstyle  Check Code
+ with Checkstyle
+
+ #. On individual files, you can apply fixes that clear some
+ Checkstyle warnings
+
+ .. container:: ulist
+
+ - Select the file, right click and select **Apply
+ Checkstyle fixes**
+
+Disable Eclipse Formatting (partially)
+--------------------------------------
+
+ .. container:: paragraph
+
+ Sometimes, the Eclipse code formatting results in correct
+ but untidy indentation, for example when Java Persistence
+ annotations or long sequences of lined-up assignments are
+ formatted. You can disable formatting for sections of code.
+
+ .. container:: olist arabic
+
+ #. Ensure that Off/On Tags are enabled in Eclipse
+
+ #. In Eclipse  Window  Preferences  Java  Code Style 
+ Formatter window press Edit…​
+
+ #. Click on the *Off/On Tags* tab
+
+ #. Ensure that the *Enable Off/On Tags* checkbox is checked
+
+ #. Surround the section of code that you do not want the
+ formatter to act on with comments containing the Off/On
+ tags
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ // @formatter:off
+ // Plugin Parameters
+ private DistributorParameters distributorParameters = new DistributorParameters();
+ private SchemaParameters schemaParameters = new SchemaParameters();
+ private LockManagerParameters lockManagerParameters = new LockManagerParameters();
+ private PersistorParameters persistorParameters = new PersistorParameters();
+ // @formatter:on
+
+Supress Checkstyle (partially)
+------------------------------
+
+ .. container:: paragraph
+
+ Sometimes Checkstyle checks identify code that does not comply
+ with Checkstyle rules. In limited cases Checkstyle rules can be
+ suppressed, for example where it is impossible to design the code
+ in a way that complies with Checkstyle or where the Checkstyle
+ rule is impossible to apply. Checkstyle rules are suppressed as is
+ explained in this `Stackoverflow
+ post <https://stackoverflow.com/questions/4023185/how-to-disable-a-particular-checkstyle-rule-for-a-particular-line-of-code>`__.
+
+ .. container:: paragraph
+
+ The example below illustrates how to suppress a Checkstyle rule
+ that specifies all methods must have seven parameters or less.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ // CHECKSTYLE:OFF: checkstyle:ParameterNumber
+ public myMethod(final int par1, final int par2, final int par3, final int par4,
+ final int par5, final int par6, final int par7, final int par8) {
+ }
+ // CHECKSTYLE:ON: checkstyle:ParameterNumber
+
+apex-apps.utilities
+^^^^^^^^^^^^^^^^^^^
+
+CLI Example
+-----------
+
+ .. container:: paragraph
+
+ Using the APEX CLI utilities can be done as follows. First,
+ add the dependency of the utility project to your POM file.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ <dependency>
+ <groupId>org.onap.policy.apex-pdp.tools</groupId>
+ <artifactId>tools-common</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
+
+ .. container:: paragraph
+
+ Now, create a new application project, for instance
+ ``MyApp``. In this project, create a new main application
+ class as ``Application.java``. In this class, create a new
+ main method as ``public static void main(String[] args)``.
+
+ .. container:: paragraph
+
+ No use the provided ``CliOptions`` and ``CliParser``.
+ Manually importing means to add the following lines to the
+ start of your application (in Eclipse this import will be
+ done automatically):
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ import org.onap.policy.apex.tools.common.CliOptions;
+ import org.onap.policy.apex.tools.common.CliParser;
+
+.. container:: paragraph
+
+ Now, inside your ``main()`` method, start setting some general
+ application properties. Important are the application name and some
+ description of your application. For instance:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ String appName = "test-app";
+ final String appDescription = "a test app for documenting how to use the CLI utilities";
+
+.. container:: paragraph
+
+ Next, create a new CLI Parser and add a few CLI options from the
+ standard ``CliOptions``. The following example adds options for help,
+ version, and a model file:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ final CliParser cli = new CliParser();
+ cli.addOption(CliOptions.HELP);
+ cli.addOption(CliOptions.VERSION);
+ cli.addOption(CliOptions.MODELFILE);
+
+.. container:: paragraph
+
+ Next, parse the given CLI arguments:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ final CommandLine cmd = cli.parseCli(args);
+
+.. container:: paragraph
+
+ Once the command line is parsed, we can look into the individual
+ options, check if they are set, and then act accordingly. We start
+ with the option for *help*. If the option is present, we print a help
+ screen and return:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ // help is an exit option, print usage and exit
+ if (cmd.hasOption('h') || cmd.hasOption("help")) {
+ final HelpFormatter formatter = new HelpFormatter();
+ LOGGER.info(appName + " v" + cli.getAppVersion() + " - " + appDescription);
+ formatter.printHelp(appName, cli.getOptions());
+ return;
+ }
+
+.. container:: paragraph
+
+ Next, we process the option for *version*. Here, we want to print a
+ version for our application and return. The CLI Parser already
+ provides a method to obtain the correct version for an APEX build, so
+ we use that:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ // version is an exit option, print version and exit
+ if (cmd.hasOption('v') || cmd.hasOption("version")) {
+ LOGGER.info(appName + " " + cli.getAppVersion());
+ return;
+ }
+
+.. container:: paragraph
+
+ Once help and version arguments are processed, we can proceed to look
+ at all other options. We have added an option for a model file, so
+ check this option and test if we can actually load a model file with
+ the given argument. If we can load a model, everything is ok. If we
+ cannot load a model, we print an error and return.
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ String modelFile = cmd.getOptionValue('m');
+ if (modelFile == null) {
+ modelFile = cmd.getOptionValue("model");
+ }
+ if (modelFile == null) {
+ LOGGER.error(appName + ": no model file given, cannot proceed (try -h for help)");
+ return;
+ }
+
+.. container:: paragraph
+
+ With a model file being loadable, we finish parsing command line
+ arguments. We also print some status messages to note that the
+ application now is ready to start:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ LOGGER.info(appName + ": starting");
+ LOGGER.info(" --> model file: " + modelFile);
+
+.. container:: paragraph
+
+ The last action now is to run the actual application. The example
+ below is taken from a version of the ``Model2Cli`` application, which
+ creates a new object and runs it in a ``try`` block, since exceptions
+ might be thrown by the object:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ // your code for the application here
+ // e.g.
+ // try {
+ // Model2Cli app = new Model2Cli(modelFile, !cmd.hasOption("sv"), appName);
+ // app.runApp();
+ // }
+ // catch(ApexException aex) {
+ // LOGGER.error(appName + ": caught APEX exception with message: " + aex.getMessage());
+ // }
+
+.. container:: paragraph
+
+ If this new application is now called with the command line ``-h`` or
+ ``--help`` it will print the following help screen:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ test-app v2.0.0-SNAPSHOT - a test app for documenting how to use the CLI utilities
+ usage: test-app
+ -h,--help prints this help and usage screen
+ -m,--model <MODEL-FILE> set the input policy model file
+ -v,--version prints the application version
+
+.. container:: paragraph
+
+ If this new application is called with the option ``-v`` or
+ ``--version`` it will print its version information as:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ test-app 2.0.0-SNAPSHOT
+
+Autoversioning an Application
+-----------------------------
+
+ .. container:: paragraph
+
+ The APEX utilities project provides means to versioning an
+ application automatically towards the APEX version it is written
+ for. This is realized by generating a file called
+ ``app-version.txt`` that includes the Maven project version. This
+ file is then automatically deployed in the folder ``etc`` of a
+ full APEX distribution. The CLI Parser here provides a mthod to
+ access this version for an application.
+
+ .. container:: paragraph
+
+ First, create a new CLI Parser object, add some options (in the
+ example an option for version, but any options will do), then
+ parse the command line:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ final CliParser cli = new CliParser();
+ cli.addOption(CliOptions.VERSION);
+ final CommandLine cmd = cli.parseCli(args);
+
+.. container:: paragraph
+
+ Next, we check if the version option was used in the command line and
+ print application name and version if it was used:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ // version is an exit option, print version and exit
+ if (cmd.hasOption('v') || cmd.hasOption("version")) {
+ LOGGER.info("myApp" + " " + cli.getAppVersion());
+ return;
+ }
+
+.. container:: paragraph
+
+ The output will be:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+
+ myApp 2.0.0-SNAPSHOT
+
+.. container:: paragraph
+
+ The auto-version information comes from the method call
+ ``cli.getAppVersion()`` in line 2 in the example above. The method is
+ defined in the ``CliParser`` class as:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: java
+ :number-lines:
+
+ public String getAppVersion() {
+ return new Scanner(CliParser.class.getResourceAsStream("/app-version.txt"), "UTF-8").useDelimiter("\\A").next();
+ }
+
+.. container:: paragraph
+
+ The file ``app-version.txt`` is automatically added to an APEX full
+ distribution, as described above (for details on this see the POM
+ files in the APEX application packaging projects).
+
+.. container::
+ :name: footer
+
+ .. container::
+ :name: footer-text
+
+ 2.0.0-SNAPSHOT
+ Last updated 2018-09-04 16:04:24 IST
diff --git a/docs/APEX-Install-Guide.rst b/docs/APEX-Install-Guide.rst
new file mode 100644
index 000000000..3ac1eb238
--- /dev/null
+++ b/docs/APEX-Install-Guide.rst
@@ -0,0 +1,1418 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+
+APEX Installation Guide
+***********************
+
+.. contents::
+ :depth: 3
+
+Requirements
+^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ APEX is 100% written in Java and runs on any platform that
+ supports a JVM, e.g. Windows, Unix, Cygwin. Some APEX
+ applications (such as the monitoring application) come as
+ web archives, they do require a war-capable web server
+ installed.
+
+Installation Requirements
+-------------------------
+
+ .. container:: ulist
+
+ - Downloaded distribution: JAVA runtime environment
+ (JRE, Java 8 or later, APEX is tested with the Oracle
+ Java)
+
+ - Building from source: JAVA development kit (JDK, Java
+ 8 or later, APEX is tested with the Oracle Java)
+
+ - A web archive capable webserver, for instance for the
+ monitoring application
+
+ .. container:: ulist
+
+ - for instance `Apache
+ Tomcat <https://tomcat.apache.org/>`__
+
+ - Sufficient rights to install APEX on the system
+
+ - Installation tools depending on the installation
+ method used:
+
+ .. container:: ulist
+
+ - ZIP to extract from a ZIP distribution
+
+ .. container:: ulist
+
+ - Windows for instance
+ `7Zip <http://www.7-zip.org/>`__
+
+ - TAR and GZ to extract from that TAR.GZ
+ distribution
+
+ .. container:: ulist
+
+ - Windows for instance
+ `7Zip <http://www.7-zip.org/>`__
+
+ - RPM to install from the RPM distribution
+
+ .. container:: ulist
+
+ - Install: ``sudo apt-get install rpm``
+
+ - DPKG to install from the DEB distribution
+
+ .. container:: ulist
+
+ - Install: ``sudo apt-get install dpkg``
+
+Feature Requirements
+--------------------
+
+ .. container:: paragraph
+
+ APEX supports a number of features that require extra
+ software being installed.
+
+ .. container:: ulist
+
+ - `Apache Kafka <https://kafka.apache.org/>`__ to
+ connect APEX to a Kafka message bus
+
+ - `Hazelcast <https://hazelcast.com/>`__ to use
+ distributed hash maps for context
+
+ - `Infinispan <http://infinispan.org/>`__ for
+ distributed context and persistence
+
+ - `Docker <https://www.docker.com/>`__ to run APEX
+ inside a Docker container
+
+Build (Install from Source) Requirements
+----------------------------------------
+
+ .. container:: paragraph
+
+ Installation from source requires a few development tools
+
+ .. container:: ulist
+
+ - GIT to retrieve the source code
+
+ - Java SDK, Java version 8 or later
+
+ - Apache Maven 3 (the APEX build environment)
+
+Get the APEX Source Code
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ The first APEX source code was hosted on Github in January
+ 2018. By the end of 2018, APEX was added as a project in the
+ ONAP Policy Framework, released later in the ONAP Casablanca
+ release.
+
+ .. container:: paragraph
+
+ The APEX source code is hosted in ONAP as project APEX. The
+ current stable version is in the master branch. Simply clone
+ the master branch from ONAP using HTTPS.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ git clone https://gerrit.onap.org/r/policy/apex-pdp
+
+Build APEX
+^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ The examples in this document assume that the APEX source
+ repositories are cloned to:
+
+ .. container:: ulist
+
+ - Unix, Cygwin: ``/usr/local/src/apex-pdp``
+
+ - Windows: ``C:\dev\apex-pdp``
+
+ - Cygwin: ``/cygdrive/c/dev/apex-pdp``
+
+ .. important::
+ A Build requires ONAP Nexus
+ APEX has a dependency to ONAP parent projects. You might need to adjust your Maven M2 settings. The most current
+ settings can be found in the ONAP oparent repo: `Settings <https://git.onap.org/oparent/plain/settings.xml>`__.
+
+ .. important::
+ A Build needs Space
+ Building APEX requires approximately 2-3 GB of hard disc space, 1 GB for the actual build with full distribution and 1-2 GB for
+ the downloaded dependencies
+
+ .. important::
+ A Build requires Internet (for first build)
+ During the build, several (a lot) of Maven dependencies will be downloaded and stored in the configured local Maven
+ repository. The first standard build (and any first specific build) requires Internet access to download those dependencies.
+
+ .. important::
+ Building RPM distributions
+ RPM images are only build if the ``rpm`` package is installed (Unix). To install ``rpm`` run ``sudo apt-get install rpm``,
+ then build APEX.
+
+ .. container:: paragraph
+
+ Use Maven to for a standard build without any tests.
+
+ +-------------------------------------------------------+--------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=======================================================+========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | >c: | # cd /usr/local/src/apex-pdp |
+ | >cd \dev\apex | # mvn clean install -DskipTest |
+ | >mvn clean install -DskipTests | |
+ +-------------------------------------------------------+--------------------------------------------------------+
+
+.. container:: paragraph
+
+ The build takes 2-3 minutes on a standard development laptop. It
+ should run through without errors, but with a lot of messages from
+ the build process.
+
+.. container:: paragraph
+
+ When Maven is finished with the build, the final screen should look
+ similar to this (omitting some ``success`` lines):
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ [INFO] tools .............................................. SUCCESS [ 0.248 s]
+ [INFO] tools-common ....................................... SUCCESS [ 0.784 s]
+ [INFO] simple-wsclient .................................... SUCCESS [ 3.303 s]
+ [INFO] model-generator .................................... SUCCESS [ 0.644 s]
+ [INFO] packages ........................................... SUCCESS [ 0.336 s]
+ [INFO] apex-pdp-package-full .............................. SUCCESS [01:10 min]
+ [INFO] Policy APEX PDP - Docker build 2.0.0-SNAPSHOT ...... SUCCESS [ 10.307 s]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] BUILD SUCCESS
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Total time: 03:43 min
+ [INFO] Finished at: 2018-09-03T11:56:01+01:00
+ [INFO] ------------------------------------------------------------------------
+
+.. container:: paragraph
+
+ The build will have created all artifacts required for an APEX
+ installation. The following example show how to change to the target
+ directory and how it should look like.
+
++----------------------------------------------------------------------------------------------------------------------------+
+| Unix, Cygwin |
++============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. container:: content |
+| |
+| .. code:: bash |
+| :number-lines: |
+| |
+| -rwxrwx---+ 1 esvevan Domain Users 772 Sep 3 11:55 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes* |
+| -rwxrwx---+ 1 esvevan Domain Users 146328082 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT.deb* |
+| -rwxrwx---+ 1 esvevan Domain Users 15633 Sep 3 11:54 apex-pdp-package-full-2.0.0-SNAPSHOT.jar* |
+| -rwxrwx---+ 1 esvevan Domain Users 146296819 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 archive-tmp/ |
+| -rwxrwx---+ 1 esvevan Domain Users 89 Sep 3 11:54 checkstyle-cachefile* |
+| -rwxrwx---+ 1 esvevan Domain Users 10621 Sep 3 11:54 checkstyle-checker.xml* |
+| -rwxrwx---+ 1 esvevan Domain Users 584 Sep 3 11:54 checkstyle-header.txt* |
+| -rwxrwx---+ 1 esvevan Domain Users 86 Sep 3 11:54 checkstyle-result.xml* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 classes/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 dependency-maven-plugin-markers/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 etc/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 examples/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:55 install_hierarchy/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 maven-archiver/ |
++----------------------------------------------------------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------------------------+
+| Windows |
++========================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. container:: content |
+| |
+| .. code:: bash |
+| :number-lines: |
+| |
+| 03/09/2018 11:55 <DIR> . |
+| 03/09/2018 11:55 <DIR> .. |
+| 03/09/2018 11:55 146,296,819 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz |
+| 03/09/2018 11:55 146,328,082 apex-pdp-package-full-2.0.0-SNAPSHOT.deb |
+| 03/09/2018 11:54 15,633 apex-pdp-package-full-2.0.0-SNAPSHOT.jar |
+| 03/09/2018 11:55 772 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes |
+| 03/09/2018 11:54 <DIR> archive-tmp |
+| 03/09/2018 11:54 89 checkstyle-cachefile |
+| 03/09/2018 11:54 10,621 checkstyle-checker.xml |
+| 03/09/2018 11:54 584 checkstyle-header.txt |
+| 03/09/2018 11:54 86 checkstyle-result.xml |
+| 03/09/2018 11:54 <DIR> classes |
+| 03/09/2018 11:54 <DIR> dependency-maven-plugin-markers |
+| 03/09/2018 11:54 <DIR> etc |
+| 03/09/2018 11:54 <DIR> examples |
+| 03/09/2018 11:55 <DIR> install_hierarchy |
+| 03/09/2018 11:54 <DIR> maven-archiver |
+| 8 File(s) 292,652,686 bytes |
+| 9 Dir(s) 14,138,720,256 bytes free |
++--------------------------------------------------------------------------------------------------------+
+
+Install APEX
+^^^^^^^^^^^^
+
+ .. container:: paragraph
+
+ APEX can be installed in different ways:
+
+ .. container:: ulist
+
+ - Unix: automatically using ``rpm`` or ``dpkg`` from ``.rpm``
+ or ``.deb`` archive
+
+ - Windows, Unix, Cygwin: manually from a ``.tar.gz`` archive
+
+ - Windows, Unix, Cygwin: build from source using Maven, then
+ install manually
+
+Install with RPM and DPKG
+-------------------------
+
+ .. container:: paragraph
+
+ The install distributions of APEX automatically install the
+ system. The installation directory is
+ ``/opt/app/policy/apex-pdp``. Log files are located in
+ ``/var/log/onap/policy/apex-pdp``. The latest APEX version
+ will be available as ``/opt/app/policy/apex-pdp/apex-pdp``.
+
+ .. container:: paragraph
+
+ For the installation, a new user ``apexuser`` and a new
+ group ``apexuser`` will be created. This user owns the
+ installation directories and the log file location. The user
+ is also used by the standard APEX start scripts to run APEX
+ with this user’s permissions.
+
+ +-----------------------------------------------------------------------+
+ | RPM Installation |
+ +=======================================================================+
+ | .. container:: |
+ | |
+ | .. container:: listingblock |
+ | |
+ | .. container:: content |
+ | |
+ | .. code:: bash |
+ | :number-lines: |
+ | |
+ | # sudo rpm -i apex-pdp-package-full-2.0.0-SNAPSHOT.rpm |
+ | ********************preinst******************* |
+ | arguments 1 |
+ | ********************************************** |
+ | creating group apexuser . . . |
+ | creating user apexuser . . . |
+ | ********************postinst**************** |
+ | arguments 1 |
+ | *********************************************** |
+ +-----------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------+
+| DPKG Installation |
++======================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. container:: content |
+| |
+| .. code:: bash |
+| :number-lines: |
+| |
+| # sudo dpkg -i apex-pdp-package-full-2.0.0-SNAPSHOT.deb |
+| Selecting previously unselected package apex-uservice. |
+| (Reading database ... 288458 files and directories currently installed.) |
+| Preparing to unpack apex-pdp-package-full-2.0.0-SNAPSHOT.deb ... |
+| ********************preinst******************* |
+| arguments install |
+| ********************************************** |
+| creating group apexuser . . . |
+| creating user apexuser . . . |
+| Unpacking apex-uservice (2.0.0-SNAPSHOT) ... |
+| Setting up apex-uservice (2.0.0-SNAPSHOT) ... |
+| ********************postinst**************** |
+| arguments configure |
+| *********************************************** |
++--------------------------------------------------------------------------------------+
+
+.. container:: paragraph
+
+ Once the installation is finished, APEX is fully installed and ready
+ to run.
+
+Install Manually from Archive (Unix, Cygwin)
+--------------------------------------------
+
+ .. container:: paragraph
+
+ Download a ``tar.gz`` archive. Create a directory where APEX
+ should be installed. Extract the ``tar`` archive. The following
+ example shows how to install APEX in ``/opt/apex`` and create a
+ link to ``/opt/apex/apex`` for the most recent installation.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ # cd /opt
+ # mkdir apex
+ # cd apex
+ # mkdir apex-full-2.0.0-SNAPSHOT
+ # tar xvfz ~/Downloads/apex-pdp-package-full-2.0.0-SNAPSHOT.tar.gz -C apex-full-2.0.0-SNAPSHOT
+ # ln -s apex apex-pdp-package-full-2.0.0-SNAPSHOT
+
+Install Manually from Archive (Windows, 7Zip, GUI)
+--------------------------------------------------
+
+ .. container:: paragraph
+
+ Download a ``tar.gz`` archive and copy the file into the install
+ folder (in this example ``C:\apex``). Assuming you are using 7Zip,
+ right click on the file and extract the ``tar`` archive. Note: the
+ screenshots might show an older version than you have.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Extract the TAR archive|
+
+ .. container:: paragraph
+
+ The right-click on the new created TAR file and extract the actual
+ APEX distribution.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Extract the APEX distribution|
+
+ .. container:: paragraph
+
+ Inside the new APEX folder you see the main directories: ``bin``,
+ ``etc``, ``examples``, ``lib``, and ``war``
+
+ .. container:: paragraph
+
+ Once extracted, please rename the created folder to
+ ``apex-full-2.0.0-SNAPSHOT``. This will keep the directory name in
+ line with the rest of this documentation.
+
+Install Manually from Archive (Windows, 7Zip, CMD)
+--------------------------------------------------
+
+ .. container:: paragraph
+
+ Download a ``tar.gz`` archive and copy the file into the install
+ folder (in this example ``C:\apex``). Start ``cmd``, for instance
+ typing ``Windows+R`` and then ``cmd`` in the dialog. Assuming
+ ``7Zip`` is installed in the standard folder, simply run the
+ following commands (for APEX version 2.0.0-SNAPSHOT full
+ distribution)
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ >c:
+ >cd \apex
+ >"\Program Files\7-Zip\7z.exe" x apex-pdp-package-full-2.0.0-SNAPSHOT.tar.gz -so | "\Program Files\7-Zip\7z.exe" x -aoa -si -ttar -o"apex-full-2.0.0-SNAPSHOT"
+
+.. container:: paragraph
+
+ APEX is now installed in the folder
+ ``C:\apex\apex-full-2.0.0-SNAPSHOT``.
+
+Build from Source
+^^^^^^^^^^^^^^^^^
+
+Build and Install Manually (Unix, Windows, Cygwin)
+--------------------------------------------------
+
+ .. container:: paragraph
+
+ Clone the APEX GIT repositories into a directory. Go to that
+ directory. Use Maven to build APEX (all details on building
+ APEX from source can be found in *APEX HowTo: Build*).
+ Install from the created artifacts (``rpm``, ``deb``,
+ ``tar.gz``, or copying manually).
+
+ .. important::
+ Building RPM distributions
+ RPM images are only build if the ``rpm`` package is installed (Unix). To install ``rpm`` run ``sudo apt-get install rpm``,
+ then build APEX.
+
+ .. container:: paragraph
+
+ The following example shows how to build the APEX system,
+ without tests (``-DskipTests``) to safe some time. It
+ assumes that the APX GIT repositories are cloned to:
+
+ .. container:: ulist
+
+ - Unix, Cygwin: ``/usr/local/src/apex``
+
+ - Windows: ``C:\dev\apex``
+
+ +-------------------------------------------------------+--------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=======================================================+========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | >c: | # cd /usr/local/src/apex |
+ | >cd \dev\apex | # mvn clean install -DskipTests |
+ | >mvn clean install -DskipTests | |
+ +-------------------------------------------------------+--------------------------------------------------------+
+
+.. container:: paragraph
+
+ The build takes about 2 minutes without test and about 4-5 minutes
+ with tests on a standard development laptop. It should run through
+ without errors, but with a lot of messages from the build process. If
+ build with tests (i.e. without ``-DskipTests``), there will be error
+ messages and stack trace prints from some tests. This is normal, as
+ long as the build finishes successful.
+
+.. container:: paragraph
+
+ When Maven is finished with the build, the final screen should look
+ similar to this (omitting some ``success`` lines):
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ [INFO] tools .............................................. SUCCESS [ 0.248 s]
+ [INFO] tools-common ....................................... SUCCESS [ 0.784 s]
+ [INFO] simple-wsclient .................................... SUCCESS [ 3.303 s]
+ [INFO] model-generator .................................... SUCCESS [ 0.644 s]
+ [INFO] packages ........................................... SUCCESS [ 0.336 s]
+ [INFO] apex-pdp-package-full .............................. SUCCESS [01:10 min]
+ [INFO] Policy APEX PDP - Docker build 2.0.0-SNAPSHOT ...... SUCCESS [ 10.307 s]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] BUILD SUCCESS
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Total time: 03:43 min
+ [INFO] Finished at: 2018-09-03T11:56:01+01:00
+ [INFO] ------------------------------------------------------------------------
+
+.. container:: paragraph
+
+ The build will have created all artifacts required for an APEX
+ installation. The following example show how to change to the target
+ directory and how it should look like.
+
++-----------------------------------------------------------------------------------------------------------------------------+
+| Unix, Cygwin |
++=============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. code:: bash |
+| :number-lines: |
+| |
+| # cd packages/apex-pdp-package-full/target |
+| # ls -l |
+| -rwxrwx---+ 1 esvevan Domain Users 772 Sep 3 11:55 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes* |
+| -rwxrwx---+ 1 esvevan Domain Users 146328082 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT.deb* |
+| -rwxrwx---+ 1 esvevan Domain Users 15633 Sep 3 11:54 apex-pdp-package-full-2.0.0-SNAPSHOT.jar* |
+| -rwxrwx---+ 1 esvevan Domain Users 146296819 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 archive-tmp/ |
+| -rwxrwx---+ 1 esvevan Domain Users 89 Sep 3 11:54 checkstyle-cachefile* |
+| -rwxrwx---+ 1 esvevan Domain Users 10621 Sep 3 11:54 checkstyle-checker.xml* |
+| -rwxrwx---+ 1 esvevan Domain Users 584 Sep 3 11:54 checkstyle-header.txt* |
+| -rwxrwx---+ 1 esvevan Domain Users 86 Sep 3 11:54 checkstyle-result.xml* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 classes/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 dependency-maven-plugin-markers/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 etc/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 examples/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:55 install_hierarchy/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 maven-archiver/ |
++-----------------------------------------------------------------------------------------------------------------------------+
+
++-----------------------------------------------------------------------------------------------------------------------------+
+| Windows |
++=============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. code:: bash |
+| :number-lines: |
+| |
+| >cd packages\apex-pdp-package-full\target |
+| >dir |
+| 03/09/2018 11:55 <DIR> . |
+| 03/09/2018 11:55 <DIR> .. |
+| 03/09/2018 11:55 146,296,819 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz |
+| 03/09/2018 11:55 146,328,082 apex-pdp-package-full-2.0.0-SNAPSHOT.deb |
+| 03/09/2018 11:54 15,633 apex-pdp-package-full-2.0.0-SNAPSHOT.jar |
+| 03/09/2018 11:55 772 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes |
+| 03/09/2018 11:54 <DIR> archive-tmp |
+| 03/09/2018 11:54 89 checkstyle-cachefile |
+| 03/09/2018 11:54 10,621 checkstyle-checker.xml |
+| 03/09/2018 11:54 584 checkstyle-header.txt |
+| 03/09/2018 11:54 86 checkstyle-result.xml |
+| 03/09/2018 11:54 <DIR> classes |
+| 03/09/2018 11:54 <DIR> dependency-maven-plugin-markers |
+| 03/09/2018 11:54 <DIR> etc |
+| 03/09/2018 11:54 <DIR> examples |
+| 03/09/2018 11:55 <DIR> install_hierarchy |
+| 03/09/2018 11:54 <DIR> maven-archiver |
+| 8 File(s) 292,652,686 bytes |
+| 9 Dir(s) 14,138,720,256 bytes free |
++-----------------------------------------------------------------------------------------------------------------------------+
+
+.. container:: paragraph
+
+ Now, take the ``.deb`` or the ``.tar.gz`` file and install APEX.
+ Alternatively, copy the content of the folder ``install_hierarchy``
+ to your APEX directory.
+
+Installation Layout
+^^^^^^^^^^^^^^^^^^^
+
+ .. container:: paragraph
+
+ A full installation of APEX comes with the following layout.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ ::
+
+ $APEX_HOME
+ ├───bin (1)
+ ├───etc (2)
+ │ ├───editor
+ │ ├───hazelcast
+ │ ├───infinispan
+ │ └───META-INF
+ ├───examples (3)
+ │ ├───config (4)
+ │ ├───docker (5)
+ │ ├───events (6)
+ │ ├───html (7)
+ │ ├───models (8)
+ │ └───scripts (9)
+ ├───lib (10)
+ │ └───applications (11)
+ └───war (12)
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | binaries, mainly scripts (bash |
+ | | and bat) to start the APEX engine |
+ | | and applications |
+ +-----------------------------------+-----------------------------------+
+ | **2** | configuration files, such as |
+ | | logback (logging) and third party |
+ | | library configurations |
+ +-----------------------------------+-----------------------------------+
+ | **3** | example policy models to get |
+ | | started |
+ +-----------------------------------+-----------------------------------+
+ | **4** | configurations for the examples |
+ | | (with sub directories for |
+ | | individual examples) |
+ +-----------------------------------+-----------------------------------+
+ | **5** | Docker files and additional |
+ | | Docker instructions for the |
+ | | exampples |
+ +-----------------------------------+-----------------------------------+
+ | **6** | example events for the examples |
+ | | (with sub directories for |
+ | | individual examples) |
+ +-----------------------------------+-----------------------------------+
+ | **7** | HTML files for some examples, |
+ | | e.g. the Decisionmaker example |
+ +-----------------------------------+-----------------------------------+
+ | **8** | the policy models, generated for |
+ | | each example (with sub |
+ | | directories for individual |
+ | | examples) |
+ +-----------------------------------+-----------------------------------+
+ | **9** | additional scripts for the |
+ | | examples (with sub directories |
+ | | for individual examples) |
+ +-----------------------------------+-----------------------------------+
+ | **10** | the library folder with all Java |
+ | | JAR files |
+ +-----------------------------------+-----------------------------------+
+ | **11** | applications, also known as jar |
+ | | with dependencies (or fat jars), |
+ | | individually deployable |
+ +-----------------------------------+-----------------------------------+
+ | **12** | WAR files for web applications |
+ +-----------------------------------+-----------------------------------+
+
+System Configuration
+^^^^^^^^^^^^^^^^^^^^
+
+ .. container:: paragraph
+
+ Once APEX is installed, a few configurations need to be done:
+
+ .. container:: ulist
+
+ - Create an APEX user and an APEX group (optional, if not
+ installed using RPM and DPKG)
+
+ - Create environment settings for ``APEX_HOME`` and
+ ``APEX_USER``, required by the start scripts
+
+ - Change settings of the logging framework (optional)
+
+ - Create directories for logging, required (execution might
+ fail if directories do not exist or cannot be created)
+
+APEX User and Group
+-------------------
+
+ .. container:: paragraph
+
+ On smaller installations and test systems, APEX can run as
+ any user or group.
+
+ .. container:: paragraph
+
+ However, if APEX is installed in production, we strongly
+ recommend you set up a dedicated user for running APEX. This
+ will isolate the execution of APEX to that user. We
+ recommend you use the userid ``apexuser`` but you may use
+ any user you choose.
+
+ .. container:: paragraph
+
+ The following example, for UNIX, creates a group called
+ ``apexuser``, an APEX user called ``apexuser``, adds the
+ group to the user, and changes ownership of the APEX
+ installation to the user. Substitute ``<apex-dir>`` with the
+ directory where APEX is installed.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ # sudo groupadd apexuser
+ # sudo useradd -g apexuser apexuser
+ # sudo chown -R apexuser:apexuser <apex-dir>
+
+.. container:: paragraph
+
+ For other operating systems please consult your manual or system
+ administrator.
+
+Environment Settings: APEX_HOME and APEX_USER
+---------------------------------------------
+
+ .. container:: paragraph
+
+ The provided start scripts for APEX require two environment
+ variables being set:
+
+ .. container:: ulist
+
+ - ``APEX_USER`` with the user under whos name and permission APEX
+ should be started (Unix only)
+
+ - ``APEX_HOME`` with the directory where APEX is installed (Unix,
+ Windows, Cygwin)
+
+ .. container:: paragraph
+
+ The first row in the following table shows how to set these
+ environment variables temporary (assuming the user is
+ ``apexuser``). The second row shows how to verify the settings.
+ The last row explains how to set those variables permanently.
+
+ +------------------------------------------------+---------------------------------------------------------+
+ | Unix, Cygwin (bash/tcsh) | Windows |
+ +================================================+=========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | # export APEX_USER=apexuser | >set APEX_HOME=C:\apex\apex-full-2.0.0-SNAPSHOT |
+ | # cd /opt/app/policy/apex-pdp | |
+ | # export APEX_HOME=`pwd` | |
+ | | |
+ +------------------------------------------------+ |
+ | .. container:: | |
+ | | |
+ | .. container:: content | |
+ | | |
+ | .. code:: tcsh | |
+ | :number-lines: | |
+ | | |
+ | # setenv APEX_USER apexuser | |
+ | # cd /opt/app/policy/apex-pdp | |
+ | # setenv APEX_HOME `pwd` | |
+ | | |
+ +------------------------------------------------+---------------------------------------------------------+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | # env | grep APEX | >set APEX_HOME |
+ | # APEX_USER=apexuser | APEX_HOME=\apex\apex-full-2.0.0-SNAPSHOT |
+ | # APEX_HOME=/opt/app/policy/apex-pdp | |
+ | | |
+ +------------------------------------------------+---------------------------------------------------------+
+
+
+Making Environment Settings Permanent (Unix, Cygwin)
+####################################################
+
+ .. container:: paragraph
+
+ For a per-user setting, edit the a user’s ``bash`` or ``tcsh``
+ settings in ``~/.bashrc`` or ``~/.tcshrc``. For system-wide
+ settings, edit ``/etc/profiles`` (requires permissions).
+
+
+Making Environment Settings Permanent (Windows)
+###############################################
+
+ .. container:: paragraph
+
+ On Windows 7 do
+
+ .. container:: ulist
+
+ - Click on the **Start** Menu
+
+ - Right click on **Computer**
+
+ - Select **Properties**
+
+ .. container:: paragraph
+
+ On Windows 8/10 do
+
+ .. container:: ulist
+
+ - Click on the **Start** Menu
+
+ - Select **System**
+
+ .. container:: paragraph
+
+ Then do the following
+
+ .. container:: ulist
+
+ - Select **Advanced System Settings**
+
+ - On the **Advanced** tab, click the **Environment Variables**
+ button
+
+ - Edit an existing variable, or create a new System variable:
+ 'Variable name'="APEX_HOME", 'Variable
+ value'="C:\apex\apex-full-2.0.0-SNAPSHOT"
+
+ .. container:: paragraph
+
+ For the settings to take effect, an application needs to be
+ restarted (e.g. any open ``cmd`` window).
+
+Edit the APEX Logging Settings
+------------------------------
+
+ .. container:: paragraph
+
+ Configure the APEX logging settings to your requirements, for
+ instance:
+
+ .. container:: ulist
+
+ - change the directory where logs are written to, or
+
+ - change the log levels
+
+ .. container:: paragraph
+
+ Edit the file ``$APEX_HOME/etc/logback.xml`` for any required
+ changes. To change the log directory change the line
+
+ .. container:: paragraph
+
+ ``<property name="VAR_LOG" value="/var/log/onap/policy/apex-pdp/" />``
+
+ .. container:: paragraph
+
+ to
+
+ .. container:: paragraph
+
+ ``<property name="VAR_LOG" value="/PATH/TO/LOG/DIRECTORY/" />``
+
+ .. container:: paragraph
+
+ On Windows, it is recommended to change the log directory to:
+
+ .. container:: paragraph
+
+ ``<property name="VAR_LOG" value="C:/apex/apex-full-2.0.0-SNAPSHOT/logs" />``
+
+ .. container:: paragraph
+
+ Note: Be careful about when to use ``\`` vs. ``/`` as the path
+ separator!
+
+Create Directories for Logging
+------------------------------
+
+ .. container:: paragraph
+
+ Make sure that the log directory exists. This is important when
+ APEX was installed manually or when the log directory was changed
+ in the settings (see above).
+
+ +------------------------------------------------------------------+-------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +==================================================================+=======================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | mkdir -p /var/log/onap/policy/apex-pdp | >mkdir C:\apex\apex-full-2.0.0-SNAPSHOT\logs |
+ | chown -R apexuser:apexuser /var/log/onap/policy/apex-pdp | |
+ +------------------------------------------------------------------+-------------------------------------------------------+
+
+Verify the APEX Installation
+############################
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ When APEX is installed and all settings are realized, the
+ installation can be verified.
+
+Verify Installation - run Engine
+--------------------------------
+
+ .. container:: paragraph
+
+ A simple verification of an APEX installation can be done by
+ simply starting the APEX engine without any configuration.
+ On Unix (or Cygwin) start the engine using
+ ``$APEX_HOME/bin/apexEngine.sh``. On Windows start the
+ engine using ``%APEX_HOME%\bin\apexEngine.bat``. The engine
+ will fail to fully start. However, if the output looks
+ similar to the following line, the APEX installation is
+ realized.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ Starting Apex service with parameters [] . . .
+ start of Apex service failed: Apex configuration file was not specified as an argument
+ 2018-09-03 13:11:33,914 Apex [main] ERROR o.o.p.a.service.engine.main.ApexMain - start of Apex service failed
+ org.onap.policy.apex.model.basicmodel.concepts.ApexException: Apex configuration file was not specified as an argument
+ at org.onap.policy.apex.service.engine.main.ApexCommandLineArguments.validateReadableFile(ApexCommandLineArguments.java:267)
+ at org.onap.policy.apex.service.engine.main.ApexCommandLineArguments.validate(ApexCommandLineArguments.java:161)
+ at org.onap.policy.apex.service.engine.main.ApexMain.<init>(ApexMain.java:68)
+ at org.onap.policy.apex.service.engine.main.ApexMain.main(ApexMain.java:165)
+ usage: org.onap.policy.apex.service.engine.main.ApexMain [options...]
+ options
+ -c,--config-file <CONFIG_FILE>the full path to the configuration file to use, the configuration file must be a Json file
+ containing the Apex configuration parameters
+ -h,--help outputs the usage of this command
+ -m,--model-file <MODEL_FILE> the full path to the model file to use, if set it overrides the model file set in the
+ configuration file
+ -v,--version outputs the version of Apex
+
+Verify Installation - run an Example
+------------------------------------
+
+ .. container:: paragraph
+
+ A full APEX installation comes with several examples. Here, we can
+ fully verify the installation by running one of the examples.
+
+ .. container:: paragraph
+
+ We use the example called *SampleDomain* and configure the engine
+ to use standard in and standard out for events. Run the engine
+ with the provided configuration. Note: Cygwin executes scripts as
+ Unix scripts but runs Java as a Windows application, thus the
+ configuration file must be given as a Windows path.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ # $APEX_HOME/bin/apexEngine.sh -c $APEX_HOME/examples/config/SampleDomain/Stdin2StdoutJsonEventJava.json (1)
+ # $APEX_HOME/bin/apexEngine.sh -c C:/apex/apex-full-2.0.0-SNAPSHOT/examples/config/SampleDomain/Stdin2StdoutJsonEventJava.json (2)
+ >%APEX_HOME%\bin\apexEngine.bat -c %APEX_HOME%\examples\config\SampleDomain\Stdin2StdoutJsonEventJava.json :: (3)
+
+.. container:: colist arabic
+
+ +-------+---------+
+ | **1** | UNIX |
+ +-------+---------+
+ | **2** | Cygwin |
+ +-------+---------+
+ | **3** | Windows |
+ +-------+---------+
+
+.. container:: paragraph
+
+ The engine should start successfully. Assuming the logging levels are
+ not change (default level is ``info``), the output should look
+ similar to this (last few lines)
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ Starting Apex service with parameters [-c, v:/dev/ericsson/apex/onap/apex-pdp/packages/apex-pdp-package-full/target/install_hierarchy/examples/config/SampleDomain/Stdin2StdoutJsonEventJava.json] . . .
+ 2018-09-05 15:16:42,800 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-0:0.0.1 .
+ 2018-09-05 15:16:42,804 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-1:0.0.1 .
+ 2018-09-05 15:16:42,804 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-2:0.0.1 .
+ 2018-09-05 15:16:42,805 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-3:0.0.1 .
+ 2018-09-05 15:16:42,805 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - APEX service created.
+ 2018-09-05 15:16:43,962 Apex [main] INFO o.o.p.a.s.e.e.EngDepMessagingService - engine<-->deployment messaging starting . . .
+ 2018-09-05 15:16:43,963 Apex [main] INFO o.o.p.a.s.e.e.EngDepMessagingService - engine<-->deployment messaging started
+ 2018-09-05 15:16:44,987 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-0:0.0.1
+ 2018-09-05 15:16:45,112 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-1:0.0.1
+ 2018-09-05 15:16:45,113 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-2:0.0.1
+ 2018-09-05 15:16:45,113 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-3:0.0.1
+ 2018-09-05 15:16:45,120 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Added the action listener to the engine
+ Started Apex service
+
+.. container:: paragraph
+
+ Important are the last two line, stating that APEX has added the
+ final action listener to the engine and that the engine is started.
+
+.. container:: paragraph
+
+ The engine is configured to read events from standard input and write
+ produced events to standard output. The policy model is a very simple
+ policy.
+
+.. container:: paragraph
+
+ The following table shows an input event in the left column and an
+ output event in the right column. Past the input event into the
+ console where APEX is running, and the output event should appear in
+ the console. Pasting the input event multiple times will produce
+ output events with different values.
+
++-------------------------------------------------------------+-------------------------------------------------------------+
+| Input Event | Example Output Event |
++=============================================================+=============================================================+
+| .. container:: | .. container:: |
+| | |
+| .. container:: content | .. container:: content |
+| | |
+| .. code:: bash | .. code:: bash |
+| :number-lines: | :number-lines: |
+| | |
+| { | { |
+| "nameSpace": "org.onap.policy.apex.sample.events", | "name": "Event0004", |
+| "name": "Event0000", | "version": "0.0.1", |
+| "version": "0.0.1", | "nameSpace": "org.onap.policy.apex.sample.events", |
+| "source": "test", | "source": "Act", |
+| "target": "apex", | "target": "Outside", |
+| "TestSlogan": "Test slogan for External Event0", | "TestActCaseSelected": 2, |
+| "TestMatchCase": 0, | "TestActStateTime": 1536157104627, |
+| "TestTimestamp": 1469781869269, | "TestDecideCaseSelected": 0, |
+| "TestTemperature": 9080.866 | "TestDecideStateTime": 1536157104625, |
+| } | "TestEstablishCaseSelected": 0, |
+| | "TestEstablishStateTime": 1536157104623, |
+| | "TestMatchCase": 0, |
+| | "TestMatchCaseSelected": 1, |
+| | "TestMatchStateTime": 1536157104620, |
+| | "TestSlogan": "Test slogan for External Event0", |
+| | "TestTemperature": 9080.866, |
+| | "TestTimestamp": 1469781869269 |
+| | } |
++-------------------------------------------------------------+-------------------------------------------------------------+
+
+.. container:: paragraph
+
+ Terminate APEX by simply using ``CTRL+C`` in the console.
+
+Verify a Full Installation - REST Editor
+----------------------------------------
+
+ .. container:: paragraph
+
+ APEX has a REST application for viewing policy models. The
+ application can also be used to create new policy models close to
+ the engine native policy language. Start the REST editor as
+ follows.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ # $APEX_HOME/bin/apexApps.sh rest-editor
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ >%APEX_HOME%\bin\apexApps.bat rest-editor
+
+.. container:: paragraph
+
+ The script will start a simple web server
+ (`Grizzly <https://javaee.github.io/grizzly/>`__) and deploy a
+ ``war`` web archive in it. Once the editor is started, it will be
+ available on ``localhost:18989``. The last few line of the messages
+ should be:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ Apex Editor REST endpoint (ApexEditorMain: Config=[ApexEditorParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=READY) starting at http://localhost:18989/apexservices/ . . .
+ Sep 05, 2018 10:35:57 PM org.glassfish.grizzly.http.server.NetworkListener start
+ INFO: Started listener bound to [localhost:18989]
+ Sep 05, 2018 10:35:57 PM org.glassfish.grizzly.http.server.HttpServer start
+ INFO: [HttpServer] Started.
+ Apex Editor REST endpoint (ApexEditorMain: Config=[ApexEditorParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=RUNNING) started at http://localhost:18989/apexservices/
+
+.. container:: paragraph
+
+ Now open a browser (Firefox, Chrome, Opera, Internet Explorer) and
+ use the URL ``http://localhost:18989/``. This will connect the
+ browser to the started REST editor. The start screen should be as
+ follows.
+
+.. container:: imageblock
+
+ .. container:: content
+
+ |REST Editor Start Screen|
+
+ .. container:: title
+
+ Figure 1. REST Editor Start Screen
+
+.. container:: paragraph
+
+ Now load a policy model by clicking the menu ``File`` and then
+ ``Open``. In the opened dialog, go to the directory where APEX is
+ installed, then ``examples``, ``models``, ``SampleDomain``, and there
+ select the file ``SamplePolicyModelJAVA.json``. This will load the
+ policy model used to verify the policy engine (see above). Once
+ loaded, the screen should look as follows.
+
+.. container:: imageblock
+
+ .. container:: content
+
+ |REST Editor with loaded SampleDomain Policy Model|
+
+ .. container:: title
+
+ Figure 2. REST Editor with loaded SampleDomain Policy Model
+
+.. container:: paragraph
+
+ Now you can use the REST editor. To finish this verification, simply
+ terminate your browser (or the tab), and then use ``CTRL+C`` in the
+ console where you started the REST editor.
+
+Installing WAR Applications
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ APEX comes with a set of WAR files. These are complete
+ applications that can be installed and run in an application
+ server. All of these applications are realized as servlets. You
+ can find the WAR applications in ``$APEX_HOME/war`` (UNIX,
+ Cygwin) or ``%APEX_HOME%\war`` (Windows).
+
+ .. container:: paragraph
+
+ Installing and using the WAR applications requires a web server
+ that can execute ``war`` web archives. We recommend to use
+ `Apache Tomcat <https://tomcat.apache.org/>`__, however other
+ web servers can be used as well.
+
+ .. container:: paragraph
+
+ Install Apache Tomcat including the ``Manager App``, see `V9.0
+ Docs <https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html#Configuring_Manager_Application_Access>`__
+ for details. Start the Tomcat service, or make sure that Tomcat
+ is running.
+
+ .. container:: paragraph
+
+ There are multiple ways to install the APEX WAR applications:
+
+ .. container:: ulist
+
+ - copy the ``.war`` file into the Tomcat ``webapps`` folder
+
+ - use the Tomcat ``Manager App`` to deploy via the web
+ interface
+
+ - deploy using a REST call to Tomcat
+
+ .. container:: paragraph
+
+ For details on how to install ``war`` files please consult the
+ `Tomcat
+ Documentation <https://tomcat.apache.org/tomcat-9.0-doc/index.html>`__
+ or the `Manager App
+ HOW-TO <https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html>`__.
+ Once you installed an APEX WAR application (and wait for
+ sufficient time for Tomcat to finalize the installation), open
+ the ``Manager App`` in Tomcat. You should see the APEX WAR
+ application being installed and running.
+
+ .. container:: paragraph
+
+ In case of errors, examine the log files in the Tomcat log
+ directory. In a conventional install, those log files are in
+ the logs directory where Tomcat is installed.
+
+ .. container:: paragraph
+
+ The current APEX version provides the following WAR
+ applications:
+
+ .. container:: ulist
+
+ - client-deployment-2.0.0-SNAPSHOT.war - a client to deploy
+ new policy models to a running engine
+
+ - client-editor-2.0.0-SNAPSHOT.war - the standard policy REST
+ editor GUI
+
+ - client-monitoring-2.0.0-SNAPSHOT.war - a client for
+ monitoring a running APEX engine
+
+ - client-full-2.0.0-SNAPSHOT.war - a full client with a
+ one-stop-access to deployment, monitoring, and REST editor
+
+ - examples-servlet-2.0.0-SNAPSHOT.war - an example APEX
+ servlet
+
+Running APEX in Docker
+^^^^^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ Since APEX is in ONAP, we provide a full virtualization
+ environment for the engine.
+
+Run in ONAP
+-----------
+
+ .. container:: paragraph
+
+ Running APEX from the ONAP docker repository only requires 2
+ commands:
+
+ .. container:: olist arabic
+
+ #. Log into the ONAP docker repo
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ ::
+
+ docker login -u docker -p docker nexus3.onap.org:10003
+
+ .. container:: olist arabic
+
+ #. Run the APEX docker image
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ ::
+
+ docker run -it --rm nexus3.onap.org:10003/onap/policy-apex-pdp:latest
+
+
+Build a Docker Image
+--------------------
+
+ .. container:: paragraph
+
+ Alternatively, one can use the Dockerfile defined in the
+ Docker package to build an image.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ APEX Dockerfile
+
+ .. container:: content
+
+ .. code:: bash
+ :number-lines:
+
+ #
+ # Docker file to build an image that runs APEX on Java 8 in Ubuntu
+ #
+ FROM ubuntu:16.04
+
+ RUN apt-get update && \
+ apt-get upgrade -y && \
+ apt-get install -y software-properties-common && \
+ add-apt-repository ppa:openjdk-r/ppa -y && \
+ apt-get update && \
+ apt-get install -y openjdk-8-jdk
+
+ # Create apex user and group
+ RUN groupadd apexuser
+ RUN useradd --create-home -g apexuser apexuser
+
+ # Add Apex-specific directories and set ownership as the Apex admin user
+ RUN mkdir -p /opt/app/policy/apex-pdp
+ RUN mkdir -p /var/log/onap/policy/apex-pdp
+ RUN chown -R apexuser:apexuser /var/log/onap/policy/apex-pdp
+
+ # Unpack the tarball
+ RUN mkdir /packages
+ COPY apex-pdp-package-full.tar.gz /packages
+ RUN tar xvfz /packages/apex-pdp-package-full.tar.gz --directory /opt/app/policy/apex-pdp
+ RUN rm /packages/apex-pdp-package-full.tar.gz
+
+ # Ensure everything has the correct permissions
+ RUN find /opt/app -type d -perm 755
+ RUN find /opt/app -type f -perm 644
+ RUN chmod a+x /opt/app/policy/apex-pdp/bin/*
+
+ # Copy examples to Apex user area
+ RUN cp -pr /opt/app/policy/apex-pdp/examples /home/apexuser
+
+ RUN apt-get clean
+
+ RUN chown -R apexuser:apexuser /home/apexuser/*
+
+ USER apexuser
+ ENV PATH /opt/app/policy/apex-pdp/bin:$PATH
+ WORKDIR /home/apexuser
+
+.. container::
+ :name: footer
+
+ .. container::
+ :name: footer-text
+
+ 2.0.0-SNAPSHOT
+ Last updated 2018-09-10 15:38:16 IST
+
+.. |Extract the TAR archive| image:: images/install-guide/win-extract-tar-gz.png
+.. |Extract the APEX distribution| image:: images/install-guide/win-extract-tar.png
+.. |REST Editor Start Screen| image:: images/install-guide/rest-start.png
+.. |REST Editor with loaded SampleDomain Policy Model| image:: images/install-guide/rest-loaded.png
+
diff --git a/docs/APEX-Introduction.rst b/docs/APEX-Introduction.rst
new file mode 100644
index 000000000..90dd9e747
--- /dev/null
+++ b/docs/APEX-Introduction.rst
@@ -0,0 +1,545 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+
+A short Introduction to APEX
+*****************************
+
+.. contents::
+ :depth: 3
+
+Introduction to APEX
+^^^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ APEX stand for Adaptive Policy EXecution. It is a
+ lightweight engine for execution of policies. APEX allows
+ you to specify logic as a policy, logic that you can adapt
+ on the fly as your system executes. The APEX policies you
+ design can be really simple, with a single snippet of logic,
+ or can be very complex, with many states and tasks. APEX
+ policies can even be designed to self-adapt at execution
+ time, the choice is yours!
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Simple APEX Overview|
+
+ .. container:: title
+
+ Figure 1. Simple APEX Overview
+
+ .. container:: paragraph
+
+ The Adaptive Policy Engine in APEX runs your policies. These
+ policies are triggered by incoming events. The logic of the
+ policies executes and produces a response event. The
+ *Incoming Context* on the incoming event and the *Outgoing
+ Context* on the outgoing event are simply the fields and
+ attributes of the event. You design the policies that APEX
+ executes and the trigger and action events that your
+ policies accept and produce. Events are fed in and sent out
+ as JSON or XML events over Kafka, a Websocket, a file or
+ named pipe, or even standard input. If you run APEX as a
+ library in your application, you can even feed and receive
+ events over a Java API.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX States and Context|
+
+ .. container:: title
+
+ Figure 2. APEX States and Context
+
+ .. container:: paragraph
+
+ You design your policy as a chain of states, with each state
+ being fed by the state before. The simplest policy can have
+ just one state. We provide specific support for the
+ four-state `MEDA (Match Establish Decide
+ Act) <https://www.researchgate.net/publication/303564082_Apex_An_Engine_for_Dynamic_Adaptive_Policy_Execution>`__
+ policy state model and the three-state `ECA (Event Condition
+ Action) <https://en.wikipedia.org/wiki/Event_condition_action>`__
+ policy state model. APEX is fully distributed. You can
+ decide how many APEX engine instances to run for your
+ application and on which real or virtual hosts to run them.
+
+ .. container:: paragraph
+
+ In APEX, you also have control of the *Context* used by your
+ policies. Context is simply the state information and data
+ used by your policies. You define what context your policies
+ use and what the scope of that context is. *Policy Context*
+ is private to a particular policy and is accessible only to
+ whatever APEX engines are running that particular policy.
+ *Global Context* is available to all policies. *External
+ Context* is read-only context such as weather or topology
+ information that is provided by other systems. APEX keeps
+ context coordinated across all the the instances running a
+ particular policy. If a policy running in an APEX engine
+ changes the value of a piece of context, that value is is
+ available to all other APEX engines that use that piece of
+ context. APEX takes care of distribution, locking, writing
+ of context to persistent storage, and monitoring of context.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |The APEX Eco-System|
+
+ .. container:: title
+
+ Figure 3. The APEX Eco-System
+
+ .. container:: paragraph
+
+ The APEX engine (AP-EN) is available as a Java library for
+ inclusion in your application, as a microservice running in
+ a Docker container, or as a stand-alone service available
+ for integration into your system. APEX also includes a
+ policy editor (AP-AUTH) that allows you to design your
+ policies and a web-based policy management console you use
+ to deploy policies and to keep track of the state of
+ policies and context in policies. Context handling (AP-CTX)
+ is integrated into the APEX engine and policy deployment
+ (AP-DEP) is provided as a servlet running under a web
+ framework such as `Apache
+ Tomcat <http://tomcat.apache.org/>`__.
+
+APEX Configuration
+^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ An APEX engine can be configured to use various combinations
+ of event input handlers, event output handlers, event
+ protocols, context handlers, and logic executors. The system
+ is build using a plugin architecture. Each configuration
+ option is realized by a plugin, which can be loaded and
+ configured when the engine is started. New plugins can be
+ added to the system at any time, though to benefit from a
+ new plugin an engine will need to be restarted.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX Configuration Matrix|
+
+ .. container:: title
+
+ Figure 4. APEX Configuration Matrix
+
+ .. container:: paragraph
+
+ The APEX distribution already comes with a number of
+ plugins. The figure above shows the provided plugins. Any
+ combination of input, output, event protocol, context
+ handlers, and executors is possible.
+
+APEX Policy Matrix
+^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ APEX offers a lot of flexibility for defining, deploying,
+ and executing policies. Based on a theoretic model, it
+ supports virtually any policy model and allows to translate
+ legacy policies into the APEX execution format. However, the
+ most important aspect for using APEX is to decide what
+ policy is needed, what underlying policy concepts should be
+ used, and how the decision logic should be realized. Once
+ these aspects are decided, APEX can be used to execute the
+ policies. If the policy evolves, say from a simple decision
+ table to a fully adaptable policy, only the policy
+ definition requires change. APEX supports all of that.
+
+ .. container:: paragraph
+
+ The figure below shows a (non-exhaustive) matrix, which will
+ help to decide what policy is required to solve your
+ problem. Read the matrix from left to right choosing one
+ cell in each column.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX Policy Matrix|
+
+ .. container:: title
+
+ Figure 5. APEX Policy Matrix
+
+ .. container:: paragraph
+
+ The policy can support one of a number of stimuli with an
+ associated purpose/model of the policy, for instance:
+
+ .. container:: ulist
+
+ - Configuration, i.e. what should happen. An example is an
+ event that states an intended network configuration and
+ the policy should provide the detailed actions for it.
+ The policy can be realized for instance as an obligation
+ policy, a promise or an intent.
+
+ - Report, i.e. something did happen. An example is an event
+ about an error or fault and the policy needs to repair
+ that problem. The policy would usually be an obligation,
+ utility function, or goal policy.
+
+ - Monitoring, i.e. something does happen. An example is a
+ notification about certain network conditions, to which
+ the policy might (or might not) react. The policy will
+ mitigate the monitored events or permit (deny) related
+ actions as an obligation or authorization.
+
+ - Analysis, i.e. why did something happen. An example is an
+ analytic component sends insights of a situation
+ requiring a policy to act on it. The policy can solve the
+ problem, escalate it, or delegate it as a refrain or
+ delegation policy.
+
+ - Prediction, i.e. what will happen next. An example are
+ events that a policy uses to predict a future network
+ condition. The policy can prevent or enforce the
+ prediction as an adaptive policy, a utility function, or
+ a goal.
+
+ - Feedback, i.e. why did something happen or not happen.
+ Similar to analysis, but here the feedback will be in the
+ input event and the policy needs to something with that
+ information. Feedback can be related to history or
+ experience, for instance a previous policy execution. The
+ policy needs to be context-aware or be a meta-policy.
+
+ .. container:: paragraph
+
+ Once the purpose of the policy is decided, the next step is
+ to look into what context information the policy will
+ require to do its job. This can range from very simple to a
+ lot of different information, for instance:
+
+ .. container:: ulist
+
+ - No context, nothing but a trigger event, e.g. a string or
+ a number, is required
+
+ - Event context, the incoming event provides all
+ information (more than a string or number) for the policy
+
+ - Policy context (read only), the policy has access to
+ additional information related to its class but cannot
+ change/alter them
+
+ - Policy context (read and write), the policy has access to
+ additional information related to its class and can alter
+ this information (for instance to record historic
+ information)
+
+ - Global context (read only), the policy has access to
+ additional information of any kind but cannot
+ change/alter them
+
+ - Global context (read and write), the policy the policy
+ has access to additional information of any kind and can
+ alter this information (for instance to record historic
+ information)
+
+ .. container:: paragraph
+
+ The next step is to decide how the policy should do its job,
+ i.e. what flavor it has, how many states are needed, and how
+ many tasks. There are many possible combinations, for
+ instance:
+
+ .. container:: ulist
+
+ - Simple / God: a simple policy with 1 state and 1 task,
+ which is doing everything for the decision-making. This
+ is the ideal policy for simple situation, e.g. deciding
+ on configuration parameters or simple access control.
+
+ - Simple sequence: a simple policy with a number of states
+ each having a single task. This is a very good policy for
+ simple decision-making with different steps. For
+ instance, a classic action policy (ECA) would have 3
+ states (E, C, and A) with some logic (1 task) in each
+ state.
+
+ - Simple selective: a policy with 1 state but more than one
+ task. Here, the appropriate task (and it’s logic) will be
+ selected at execution time. This policy is very good for
+ dealing with similar (or the same) situation in different
+ contexts. For instance, the tasks can be related to
+ available external software, or to current work load on
+ the compute node, or to time of day.
+
+ - Selective: any number of states having any number of
+ tasks (usually more than 1 task). This is a combination
+ of the two policies above, for instance an ECA policy
+ with more than one task in E, C, and A.
+
+ - Classic directed: a policy with more than one state, each
+ having one task, but a non-sequential execution. This
+ means that the sequence of the states is not pre-defined
+ in the policy (as would be for all cases above) but
+ calculated at runtime. This can be good to realize
+ decision trees based on contextual information.
+
+ - Super Adaptive: using the full potential of the APEX
+ policy model, states and tasks and state execution are
+ fully flexible and calculated at runtime (per policy
+ execution). This policy is very close to a general
+ programming system (with only a few limitations), but can
+ solve very hard problems.
+
+ .. container:: paragraph
+
+ The final step is to select a response that the policy
+ creates. Possible responses have been discussed in the
+ literature for a very long time. A few examples are:
+
+ .. container:: ulist
+
+ - Obligation (deontic for what should happen)
+
+ - Authorization (e.g. for rule-based or other access
+ control or security systems)
+
+ - Intent (instead of providing detailed actions the
+ response is an intent statement and a further system
+ processes that)
+
+ - Delegation (hand the problem over to someone else,
+ possibly with some information or instructions)
+
+ - Fail / Error (the policy has encountered a problem, and
+ reports it)
+
+ - Feedback (why did the policy make a certain decision)
+
+Flexible Deployment
+^^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ APEX can be deployed in various ways. The following figure
+ shows a few of these deployment options. Engine and (policy)
+ executors are named UPe (universal policy engine, APEX
+ engine) and UPx (universal policy executor, the APEX
+ internal state machine executor).
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX Deployment Options|
+
+ .. container:: title
+
+ Figure 6. APEX Deployment Options
+
+ .. container:: olist loweralpha
+
+ a. For an interface or class
+
+ .. container:: ulist
+
+ - Either UPx or UPe as association
+
+ b. For an application
+
+ .. container:: ulist
+
+ - UPx as object for single policies
+
+ - UPe as object for multiple policies
+
+ c. For a component (as service)
+
+ .. container:: ulist
+
+ - UPe as service for requests
+
+ - UPec as service for requests
+
+ d. As a service (PolaS)
+
+ .. container:: ulist
+
+ - One or more UPe with service i/f
+
+ - One or more Upec/UPec with service i/f
+
+ - One or more Upec/UPec with service i/f
+
+ e. In a control loop
+
+ .. container:: ulist
+
+ - UPe as decision making part
+
+ - UPec as decision making part
+
+ f. On cloud compute nodes
+
+ .. container:: ulist
+
+ - Nodes with only UPe or Upec
+
+ - Nodes with any combination of UPe, UPec
+
+ g. A cloud example
+
+ .. container:: ulist
+
+ - Left: 2 UPec managing several UPe on different
+ cloud nodes
+
+ - Right: 2 large UPec with different UPe/UPec
+ deployments
+
+Flexible Clustering
+^^^^^^^^^^^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: paragraph
+
+ APEX can be clustered in various ways. The following figure
+ shows a few of these clustering options. Cluster, engine and
+ (policy) executors are named UPec (universal policy
+ cluster), UPe (universal policy engine, APEX engine) and UPx
+ (universal policy executor, the APEX internal state machine
+ executor).
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX Clustering Options|
+
+ .. container:: title
+
+ Figure 7. APEX Clustering Options
+
+ .. container:: olist loweralpha
+
+ a. Single source/target, single UPx
+
+ .. container:: ulist
+
+ - Simple forward
+
+ b. Multiple sources/targets, single UPx
+
+ .. container:: ulist
+
+ - Simple forward
+
+ c. Single source/target, multiple UPx
+
+ .. container:: ulist
+
+ - Multithreading (MT) in UPe
+
+ d. Multiple sources/targets, multiple UPx instances
+
+ .. container:: ulist
+
+ - Simple forward & MT in UPe
+
+ e. Multiple non-MT UPe in UPec
+
+ .. container:: ulist
+
+ - Simple event routing
+
+ f. Multiple MT UPe in UPec
+
+ .. container:: ulist
+
+ - Simple event routing
+
+ g. Mixed UPe in UPec
+
+ .. container:: ulist
+
+ - Simple event routing
+
+ h. Multiple non-MT UPec in UPec
+
+ .. container:: ulist
+
+ - Intelligent event routing
+
+ i. Multiple mixed UPec in UPec
+
+ .. container:: ulist
+
+ - Intelligent event routing
+
+ .. container:: olist loweralpha
+
+ k. Mix of UPec in multiple UPec
+
+ .. container:: ulist
+
+ - External intelligent event routing
+
+ - Optimized with UPec internal routing
+
+Resources
+^^^^^^^^^
+
+ .. container:: sectionbody
+
+ .. container:: ulist
+
+ - APEX Documentation hosted on Github:
+ https://ericsson.github.io/apex-docs
+
+ - APEX source code repository hosted by ONAP:
+ https://gerrit.onap.org/r/#/admin/projects/policy/apex-pdp
+
+ - Issue Management (source and documentation, ONAP JIRA,
+ requires a Linux Foundation ID):
+ https://jira.onap.org/projects/POLICY/issues
+
+ - List of APEX publications:
+ https://ericsson.github.io/apex-docs/apex-publications.html
+
+.. container::
+ :name: footer
+
+ .. container::
+ :name: footer-text
+
+ 2.0.0-SNAPSHOT
+ Last updated 2018-09-04 16:04:24 IST
+
+.. |Simple APEX Overview| image:: images/apex-intro/ApexSimple.png
+.. |APEX States and Context| image:: images/apex-intro/ApexStatesAndContext.png
+.. |The APEX Eco-System| image:: images/apex-intro/ApexEcosystem.png
+.. |APEX Configuration Matrix| image:: images/apex-intro/ApexEngineConfig.png
+.. |APEX Policy Matrix| image:: images/apex-intro/ApexPolicyMatrix.png
+.. |APEX Deployment Options| image:: images/apex-intro/UpeeDeploymentOptions.png
+.. |APEX Clustering Options| image:: images/apex-intro/UpeeClusterOptions.png
+
diff --git a/docs/APEX-Policy-Guide.rst b/docs/APEX-Policy-Guide.rst
new file mode 100644
index 000000000..392f31c7b
--- /dev/null
+++ b/docs/APEX-Policy-Guide.rst
@@ -0,0 +1,2133 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+
+APEX Policy Guide
+*****************************
+
+.. contents::
+ :depth: 3
+
+APEX Policy Matrix
+^^^^^^^^^^^^^^^^^^
+
+APEX Policy Matrix
+------------------
+
+ .. container:: paragraph
+
+ APEX offers a lot of flexibility for defining, deploying,
+ and executing policies. Based on a theoretic model, it
+ supports virtually any policy model and allows to
+ translate legacy policies into the APEX execution format.
+ However, the most important aspect for using APEX is to
+ decide what policy is needed, what underlying policy
+ concepts should be used, and how the decision logic
+ should be realized. Once these aspects are decided, APEX
+ can be used to execute the policies. If the policy
+ evolves, say from a simple decision table to a fully
+ adaptable policy, only the policy definition requires
+ change. APEX supports all of that.
+
+ .. container:: paragraph
+
+ The figure below shows a (non-exhaustive) matrix, which
+ will help to decide what policy is required to solve your
+ problem. Read the matrix from left to right choosing one
+ cell in each column.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX Policy Matrix|
+
+ .. container:: title
+
+ Figure 1. APEX Policy Matrix
+
+ .. container:: paragraph
+
+ The policy can support one of a number of stimuli with an
+ associated purpose/model of the policy, for instance:
+
+ .. container:: ulist
+
+ - Configuration, i.e. what should happen. An example is
+ an event that states an intended network configuration
+ and the policy should provide the detailed actions for
+ it. The policy can be realized for instance as an
+ obligation policy, a promise or an intent.
+
+ - Report, i.e. something did happen. An example is an
+ event about an error or fault and the policy needs to
+ repair that problem. The policy would usually be an
+ obligation, utility function, or goal policy.
+
+ - Monitoring, i.e. something does happen. An example is
+ a notification about certain network conditions, to
+ which the policy might (or might not) react. The
+ policy will mitigate the monitored events or permit
+ (deny) related actions as an obligation or
+ authorization.
+
+ - Analysis, i.e. why did something happen. An example is
+ an analytic component sends insights of a situation
+ requiring a policy to act on it. The policy can solve
+ the problem, escalate it, or delegate it as a refrain
+ or delegation policy.
+
+ - Prediction, i.e. what will happen next. An example are
+ events that a policy uses to predict a future network
+ condition. The policy can prevent or enforce the
+ prediction as an adaptive policy, a utility function,
+ or a goal.
+
+ - Feedback, i.e. why did something happen or not happen.
+ Similar to analysis, but here the feedback will be in
+ the input event and the policy needs to something with
+ that information. Feedback can be related to history
+ or experience, for instance a previous policy
+ execution. The policy needs to be context-aware or be
+ a meta-policy.
+
+ .. container:: paragraph
+
+ Once the purpose of the policy is decided, the next step
+ is to look into what context information the policy will
+ require to do its job. This can range from very simple to
+ a lot of different information, for instance:
+
+ .. container:: ulist
+
+ - No context, nothing but a trigger event, e.g. a string
+ or a number, is required
+
+ - Event context, the incoming event provides all
+ information (more than a string or number) for the
+ policy
+
+ - Policy context (read only), the policy has access to
+ additional information related to its class but cannot
+ change/alter them
+
+ - Policy context (read and write), the policy has access
+ to additional information related to its class and can
+ alter this information (for instance to record
+ historic information)
+
+ - Global context (read only), the policy has access to
+ additional information of any kind but cannot
+ change/alter them
+
+ - Global context (read and write), the policy the policy
+ has access to additional information of any kind and
+ can alter this information (for instance to record
+ historic information)
+
+ .. container:: paragraph
+
+ The next step is to decide how the policy should do its
+ job, i.e. what flavor it has, how many states are needed,
+ and how many tasks. There are many possible combinations,
+ for instance:
+
+ .. container:: ulist
+
+ - Simple / God: a simple policy with 1 state and 1 task,
+ which is doing everything for the decision-making.
+ This is the ideal policy for simple situation, e.g.
+ deciding on configuration parameters or simple access
+ control.
+
+ - Simple sequence: a simple policy with a number of
+ states each having a single task. This is a very good
+ policy for simple decision-making with different
+ steps. For instance, a classic action policy (ECA)
+ would have 3 states (E, C, and A) with some logic (1
+ task) in each state.
+
+ - Simple selective: a policy with 1 state but more than
+ one task. Here, the appropriate task (and it’s logic)
+ will be selected at execution time. This policy is
+ very good for dealing with similar (or the same)
+ situation in different contexts. For instance, the
+ tasks can be related to available external software,
+ or to current work load on the compute node, or to
+ time of day.
+
+ - Selective: any number of states having any number of
+ tasks (usually more than 1 task). This is a
+ combination of the two policies above, for instance an
+ ECA policy with more than one task in E, C, and A.
+
+ - Classic directed: a policy with more than one state,
+ each having one task, but a non-sequential execution.
+ This means that the sequence of the states is not
+ pre-defined in the policy (as would be for all cases
+ above) but calculated at runtime. This can be good to
+ realize decision trees based on contextual
+ information.
+
+ - Super Adaptive: using the full potential of the APEX
+ policy model, states and tasks and state execution are
+ fully flexible and calculated at runtime (per policy
+ execution). This policy is very close to a general
+ programming system (with only a few limitations), but
+ can solve very hard problems.
+
+ .. container:: paragraph
+
+ The final step is to select a response that the policy
+ creates. Possible responses have been discussed in the
+ literature for a very long time. A few examples are:
+
+ .. container:: ulist
+
+ - Obligation (deontic for what should happen)
+
+ - Authorization (e.g. for rule-based or other access
+ control or security systems)
+
+ - Intent (instead of providing detailed actions the
+ response is an intent statement and a further system
+ processes that)
+
+ - Delegation (hand the problem over to someone else,
+ possibly with some information or instructions)
+
+ - Fail / Error (the policy has encountered a problem,
+ and reports it)
+
+ - Feedback (why did the policy make a certain decision)
+
+APEX Policy Model
+^^^^^^^^^^^^^^^^^
+
+Introduction
+------------
+
+ .. container:: paragraph
+
+ The APEX policy model is shown in UML notation in the
+ figure below. A policy model can be stored in JSON or XML
+ format in a file or can be held in a database. The APEX
+ editor creates and modifies APEX policy models. APEX
+ deployment deploys policy models, and a policy model is
+ loaded into APEX engines so that the engines can run the
+ policies in the policy model.
+
+ .. container:: paragraph
+
+ The figure shows four different views of the policy
+ model:
+
+ .. container:: ulist
+
+ - The general model view shows the main parts of a
+ policy: state, state output, event, and task. A task
+ can also have parameters. Data types can be defined on
+ a per-model basis using either standard atomic types
+ (such as character, string, numbers) or complex types
+ from a policy domain.
+
+ - The logic model view emphasizes how decision-making
+ logic is injected into a policy. There are essentially
+ three different types of logic: task logic (for
+ decision making in a task), task selection logic (to
+ select a task if more than one is defined in a state),
+ and state finalizer logic (to compute the final output
+ event of a state and select an appropriate next state
+ from the policy model).
+
+ - The context model view shows how context is injected
+ into a policy. States collect all context from their
+ tasks. A task can define what context it requires for
+ the decision making, i.e. what context the task logic
+ will process. Context itself is a collection of items
+ (individual context information) with data types.
+ Context can be templated.
+
+ - The event and field model view shows the events in the
+ policy model. Tasks define what information they
+ consume (input) and produce (output). This information
+ is modeled as fields, essentially a key/type tuple in
+ the model and a key/type/value triple at execution.
+ Events then are collection of fields.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX Policy Model for Execution|
+
+ .. container:: title
+
+ Figure 2. APEX Policy Model for Execution
+
+Concepts and Keys
+#################
+
+ .. container:: paragraph
+
+ Each element of the policy model is called a
+ *concept*. Each *concept* is a subclass of the
+ abstract *Concept* class, as shown in the next figure.
+ Every concept implements the following abstract
+ methods:
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Concepts and Keys|
+
+ .. container:: title
+
+ Figure 3. Concepts and Keys
+
+ .. container:: ulist
+
+ - ``getKey()`` - gets the unique key for this concept
+ instance in the system
+
+ - ``validate()`` - validates the structure of this
+ concept, its sub-concepts and its relationships
+
+ - ``clean()`` - carries out housekeeping on the
+ concept such as trimming strings, remove any
+ hanging references
+
+ - ``clone()`` - creates a deep copy of an instance of
+ this concept
+
+ - ``equals()`` - checks if two instances of this
+ concept are equal
+
+ - ``toString()`` - returns a string representation of
+ the concept
+
+ - ``hashCode()`` - returns a hash code for the
+ concept
+
+ - ``copyTo()`` - carries out a deep copy of one
+ instance of the concept to another instance,
+ overwriting the target fields.
+
+ .. container:: paragraph
+
+ All concepts must have a *key*, which uniquely
+ identifies a concept instance. The *key* of a subclass
+ of an *Concept* must either be an ``ArtifactKey`` or
+ an ``ReferenceKey``. Concepts that have a stand-alone
+ independent existence such as *Policy*, *Task*, and
+ *Event* must have an ``ArtifctKey`` key. Concepts that
+ are contained in other concepts, that do not exist as
+ stand-alone concepts must have an ``ReferenceKey``
+ key. Examples of such concepts are *State* and
+ *EventParameter*.
+
+ .. container:: paragraph
+
+ An ``ArticactKey`` has two fields; the *Name* of the
+ concept it is the key for and the concept’s *Version*.
+ A concept’s name must be unique in a given
+ PolicyModel. A concept version is represented using
+ the well known *major.minor.path* scheme as used in
+ semantic versioning.
+
+ .. container:: paragraph
+
+ A ``ReferenceKey`` has three fields. The *UserKeyName*
+ and *UserKeyVersion* fields identify the
+ ``ArtifactKey`` of the concept in which the concept
+ keyed by the ``ReferenceKey`` is contained. The
+ *LocalName* field identifies the contained concept
+ instance. The *LocalName* must be unique in the
+ concepts of a given type contained by a parent.
+
+ .. container:: paragraph
+
+ For example, a policy called ``SalesPolicy`` with a
+ Version of ``1.12.4`` has a state called ``Decide``.
+ The ``Decide`` state is linked to the ``SalesPolicy``
+ with a ``ReferenceKey`` with fields *UserKeyName* of
+ ``SalesPolicy``, *UserKeyVersion* of ``1.12.4``, and
+ *LocalName* of ``Decide``. There must not be another
+ state called ``Decide`` in the policy ``SalesPolicy``.
+ However, there may well be a state called ``Decide``
+ in some other policy called ``PurchasingPolicy``.
+
+ .. container:: paragraph
+
+ Each concept in the model is also a JPA (`Java
+ Persistence
+ API <https://en.wikipedia.org/wiki/Java_Persistence_API>`__)
+ Entity. This means that every concept can be
+ individually persisted or the entire model can be
+ persisted en-bloc to any persistence mechanism using
+ an JPA framework such as
+ `Hibernate <http://hibernate.org/>`__ or
+ `EclipseLink <http://www.eclipse.org/eclipselink/>`__.
+
+Concept: PolicyModel
+####################
+
+ .. container:: paragraph
+
+ The *PolicyModel* concept is a container that holds
+ the definition of a set of policies and their
+ associated events, context maps, and tasks. A
+ *PolicyModel* is implemented as four maps for
+ policies, events, context maps, and tasks. Each map is
+ indexed by the key of the policy, event, context map,
+ or task. Any non-empty policy model must have at least
+ one entry in its policy, event, and task map because
+ all policies must have at least one input and output
+ event and must execute at least one task.
+
+ .. container:: paragraph
+
+ A *PolicyModel* concept is keyed with an
+ ``ArtifactKey key``. Because a *PolicyModel* is an
+ ``AxConcept``, calling the ``validate()`` method on a
+ policy model validates the concepts, structure, and
+ relationships of the entire policy model.
+
+Concept: DataType
+#################
+
+ .. container:: paragraph
+
+ Data types are tightly controlled in APEX in order to
+ provide a very high degree of consistency in policies
+ and to facilitate tracking of changes to context as
+ policies execute. All context is modeled as a
+ *DataType* concept. Each DataType concept instance is
+ keyed with an ``ArtifactKey`` key. The DataType field
+ identifies the Java class of objects that is used to
+ represent concept instances that use this data type.
+ All context has a *DataType*; incoming and outgoing
+ context is represented by *EventField* concepts and
+ all other context is represented by *ContextItem*
+ concepts.
+
+Concept: Event
+##############
+
+ .. container:: paragraph
+
+ An *Event* defines the structure of a message that
+ passes into or out of an APEX engine or that passes
+ between two states in an APEX engine. APEX supports
+ message reception and sending in many formats and all
+ messages are translated into an *Event* prior to
+ processing by an APEX engine. Event concepts are keyed
+ with an ``ArtifactKey`` key. The parameters of an
+ event are held as a map of *EventField* concept
+ instances with each parameter indexed by the
+ *LocalName* of its ``ReferenceKey``. An *Event* has
+ three fields:
+
+ .. container:: ulist
+
+ - The *NameSpace* identifies the domain of
+ application of the event
+
+ - The *Source* of the event identifies the system
+ that emitted the event
+
+ - The *Target* of the event identifies the system
+ that the event was sent to
+
+ .. container:: paragraph
+
+ A *PolicyModel* contains a map of all the events known
+ to a given policy model. Although an empty model may
+ have no events in its event map, any sane policy model
+ must have at least one *Event* defined.
+
+Concept: EventField
+###################
+
+ .. container:: paragraph
+
+ The incoming context and outgoing context of an event
+ are the fields of the event. Each field representing a
+ single piece of incoming or outgoing context. Each
+ field of an *Event* is represented by an instance of
+ the *EventField* concept. Each *EventField* concept
+ instance in an event is keyed with a ``ReferenceKey``
+ key, which references the event. The *LocalName* field
+ of the ``ReferenceKey`` holds the name of the field A
+ reference to a *DataType* concept defines the data
+ type that values of this parameter have at run time.
+
+Concept: ContextMap
+###################
+
+ .. container:: paragraph
+
+ The set of context that is available for use by the
+ policies of a *PolicyModel* is defined as *ContextMap*
+ concept instances. The *PolicyModel* holds a map of
+ all the *ContextMap* definitions. A *ContextMap* is
+ itself a container for a group of related context
+ items, each of which is represented by a *ContextItem*
+ concept instance. *ContextMap* concepts are keyed with
+ an ``ArtifactKey`` key. A developer can use the APEX
+ Policy Editor to create context maps for their
+ application domain.
+
+ .. container:: paragraph
+
+ A *ContextMap* uses a map to hold the context items.
+ The ContextItem concept instances in the map are
+ indexed by the *LocalName* of their ``ReferenceKey``.
+
+ .. container:: paragraph
+
+ The *ContextMapType* field of a *ContextMap* defines
+ the type of a context map. The type can have either of
+ two values:
+
+ .. container:: ulist
+
+ - A *BAG* context map is a context map with fixed
+ content. Each possible context item in the context
+ map is defined at design time and is held in the
+ *ContextMap* context instance as *ContextItem*
+ concept definitions and only the values of the
+ context items in the context map can be changed at
+ run time. The context items in a *BAG* context map
+ have mixed types and distinct *ContextItem* concept
+ instances of the same type can be defined. A *BAG*
+ context map is convenient for defining a group of
+ context items that are diverse but are related by
+ domain, such as the characteristics of a device. A
+ fully defined *BAG* context map has a fully
+ populated *ContextItem* map but its
+ *ContextItemTemplate* reference is not defined.
+
+ - A *SAMETYPE* context map is used to represent a
+ group of *ContextItem* instances of the same type.
+ Unlike a *BAG* context map, the *ContextItem*
+ concept instances of a *SAMETYPE* context map can
+ be added, modified, and deleted at runtime. All
+ *ContextItem* concept instances in a *SAMETYPE*
+ context map must be of the same type, and that
+ context item is defined as a single
+ *ContextItemTemplate* concept instances at design
+ time. At run time, the *ContextItemTemplate*
+ definition is used to create new *ContextItem*
+ concept instances for the context map on demand. A
+ fully defined *SAMETYPE context map has an empty
+ ContextItem map and its ContextItemTemplate\_*
+ reference is defined.
+
+ .. container:: paragraph
+
+ The *Scope* of a *ContextMap* defines the range of
+ applicability of a context map in APEX. The following
+ scopes of applicability are defined:
+
+ .. container:: ulist
+
+ - *EPHEMERAL* scope means that the context map is
+ owned, used, and modified by a single application,
+ but the context map only exists while that
+ application is running
+
+ - *APPLICATION* scope specifies that the context map
+ is owned, used, and modified by a single
+ application, the context map is persistent
+
+ - *GLOBAL* scope specifies that the context map is
+ globally owned and is used and modified by any
+ application, the context map is persistent
+
+ - *EXTERNAL* scope specifies that the context map is
+ owned by an external system and may be used in a
+ read-only manner by any application, the context
+ map is persistent
+
+ .. container:: paragraph
+
+ A much more sophisticated scoping mechanism for
+ context maps is envisaged for Apex in future work. In
+ such a mechanism, the scope of a context map would
+ work somewhat like the way roles work in security
+ authentication systems.
+
+Concept: ContextItem
+####################
+
+ .. container:: paragraph
+
+ Each piece of context in a *ContextMap* is represented
+ by an instance of the *ContextItem* concept. Each
+ *ContextItem* concept instance in a context map keyed
+ with a ``ReferenceKey`` key, which references the
+ context map of the context item. The *LocalName* field
+ of the ``ReferenceKey`` holds the name of the context
+ item in the context map A reference to a *DataType*
+ concept defines the data type that values of this
+ context item have at run time. The *WritableFlag*
+ indicates if the context item is read only or
+ read-write at run time.
+
+Concept: ContextItemTemplate
+############################
+
+ .. container:: paragraph
+
+ In a *SAMETYPE* *ContextMap*, the
+ *ContextItemTemplate* definition provides a template
+ for the *ContextItem* instances that will be created
+ on the context map at run time. Each *ContextItem*
+ concept instance in the context map is created using
+ the *ContextItemTemplate* template. It is keyed with a
+ ``ReferenceKey`` key, which references the context map
+ of the context item. The *LocalName* field of the
+ ``ReferenceKey``, supplied by the creator of the
+ context item at run time, holds the name of the
+ context item in the context map. A reference to a
+ *DataType* concept defines the data type that values
+ of this context item have at run time. The
+ *WritableFlag* indicates if the context item is read
+ only or read-write at run time.
+
+Concept: Task
+#############
+
+ .. container:: paragraph
+
+ The smallest unit of logic in a policy is a *Task*. A
+ task encapsulates a single atomic unit of logic, and
+ is designed to be a single indivisible unit of
+ execution. A task may be invoked by a single policy or
+ by many policies. A task has a single trigger event,
+ which is sent to the task when it is invoked. Tasks
+ emit one or more outgoing events, which carry the
+ result of the task execution. Tasks may use or modify
+ context as they execute.
+
+ .. container:: paragraph
+
+ The Task concept definition captures the definition of
+ an APEX task. Task concepts are keyed with an
+ ``ArtifactKey`` key. The Trigger of the task is a
+ reference to the *Event* concept that triggers the
+ task. The *OutgoingEvents* of a task are a set of
+ references to *Event* concepts that may be emitted by
+ the task.
+
+ .. container:: paragraph
+
+ All tasks have logic, some code that is programmed to
+ execute the work of the task. The *Logic* concept of
+ the task holds the definition of that logic.
+
+ .. container:: paragraph
+
+ The *Task* definition holds a set of *ContextItem* and
+ *ContextItemTemplate* context items that the task is
+ allow to access, as defined by the task developer at
+ design time. The type of access (read-only or read
+ write) that a task has is determined by the
+ *WritableFlag* flag on the individual context item
+ definitions. At run time, a task may only access the
+ context items specified in its context item set, the
+ APEX engine makes only the context items in the task
+ context item set is available to the task.
+
+ .. container:: paragraph
+
+ A task can be configured with startup parameters. The
+ set of parameters that can be configured on a task are
+ defined as a set of *TaskParameter* concept
+ definitions.
+
+Concept: TaskParameter
+######################
+
+ .. container:: paragraph
+
+ Each configuration parameter of a task are represented
+ as a *Taskparameter* concept keyed with a
+ ``ReferenceKey`` key, which references the task. The
+ *LocalName* field of the ``ReferenceKey`` holds the
+ name of the parameter. The *DefaultValue* field
+ defines the default value that the task parameter is
+ set to. The value of *TaskParameter* instances can be
+ overridden at deployment time by specifying their
+ values in the configuration information passed to APEX
+ engines.
+
+Concept: Logic
+##############
+
+ .. container:: paragraph
+
+ The *Logic* concept instance holds the actual
+ programmed task logic for a task defined in a *Task*
+ concept or the programmed task selection logic for a
+ state defined in a *State* concept. It is keyed with a
+ ``ReferenceKey`` key, which references the task or
+ state that owns the logic. The *LocalName* field of
+ the Logic concept is the name of the logic.
+
+ .. container:: paragraph
+
+ The *LogicCode* field of a Logic concept definition is
+ a string that holds the program code that is to be
+ executed at run time. The *LogicType* field defines
+ the language of the code. The standard values are the
+ logic languages supported by APEX:
+ `JAVASCRIPT <https://en.wikipedia.org/wiki/JavaScript>`__,
+ `JAVA <https://java.com/en/>`__,
+ `JYTHON <http://www.jython.org/>`__,
+ `JRUBY <http://jruby.org/>`__, or
+ `MVEL <https://en.wikibooks.org/wiki/Transwiki:MVEL_Language_Guide>`__.
+
+ .. container:: paragraph
+
+ The APEX engine uses the *LogicType* field value to
+ decide which language interpreter to use for a task
+ and then sends the logic defined in the *LogicCode*
+ field to that interpreter.
+
+Concept: Policy
+###############
+
+ .. container:: paragraph
+
+ The *Policy* concept defines a policy in APEX. The
+ definition is rather straightforward. A policy is made
+ up of a set of states with the flavor of the policy
+ determining the structure of the policy states and the
+ first state defining what state in the policy executes
+ first. *Policy* concepts are keyed with an
+ ``ArtifactKey`` key.
+
+ .. container:: paragraph
+
+ The *PolicyFlavour* of a *Policy* concept specifies
+ the structure that will be used for the states in the
+ policy. A number of commonly used policy patterns are
+ supported as APEX policy flavors. The standard policy
+ flavors are:
+
+ .. container:: ulist
+
+ - The *MEDA* flavor supports policies written to the
+ `MEDA policy
+ pattern <https://www.researchgate.net/publication/282576518_Dynamically_Adaptive_Policies_for_Dynamically_Adaptive_Telecommunications_Networks>`__
+ and require a sequence of four states: namely
+ *Match*, *Establish*, *Decide* and *Act*.
+
+ - The *OODA* flavor supports policies written to the
+ `OODA loop
+ pattern <https://en.wikipedia.org/wiki/OODA_loop>`__
+ and require a sequence of four states: namely
+ *Observe*, *Orient*, *Decide* and *Act*.
+
+ - The *ECA* flavor supports policies written to the
+ `ECA active rule
+ pattern <https://en.wikipedia.org/wiki/Event_condition_action>`__
+ and require a sequence of three states: namely
+ *Event*, *Condition* and *Action*
+
+ - The *XACML* flavor supports policies written in
+ `XACML <https://en.wikipedia.org/wiki/XACML>`__ and
+ require a single state: namely *XACML*
+
+ - The *FREEFORM* flavor supports policies written in
+ an arbitrary style. A user can define a *FREEFORM*
+ policy as an arbitrarily long chain of states.
+
+ .. container:: paragraph
+
+ The *FirstState* field of a *Policy* definition is the
+ starting point for execution of a policy. Therefore,
+ the trigger event of the state referenced in the
+ *FirstState* field is also the trigger event for the
+ entire policy.
+
+Concept: State
+##############
+
+ .. container:: paragraph
+
+ The *State* concept represents a phase or a stage in a
+ policy, with a policy being composed of a series of
+ states. Each state has at least one but may have many
+ tasks and, on each run of execution, a state executes
+ one and only one of its tasks. If a state has more
+ than one task, then its task selection logic is used
+ to select which task to execute. Task selection logic
+ is programmable logic provided by the state designer.
+ That logic can use incoming, policy, global, and
+ external context to select which task best
+ accomplishes the purpose of the state in a give
+ situation if more than one task has been specified on
+ a state. A state calls one and only one task when it
+ is executed.
+
+ .. container:: paragraph
+
+ Each state is triggered by an event, which means that
+ all tasks of a state must also be triggered by that
+ same event. The set of output events for a state is
+ the union of all output events from all tasks for that
+ task. In practice at the moment, because a state can
+ only have a single input event, a state that is not
+ the final state of a policy may only output a single
+ event and all tasks of that state may also only output
+ that single event. In future work, the concept of
+ having a less restrictive trigger pattern will be
+ examined.
+
+ .. container:: paragraph
+
+ A *State* concept is keyed with a ``ReferenceKey``
+ key, which references the *Policy* concept that owns
+ the state. The *LocalName* field of the
+ ``ReferenceKey`` holds the name of the state. As a
+ state is part of a chain of states, the *NextState*
+ field of a state holds the ``ReferenceKey`` key of the
+ state in the policy to execute after this state.
+
+ .. container:: paragraph
+
+ The *Trigger* field of a state holds the
+ ``ArtifactKey`` of the event that triggers this state.
+ The *OutgoingEvents* field holds the ``ArtifactKey``
+ references of all possible events that may be output
+ from the state. This is a set that is the union of all
+ output events of all tasks of the state.
+
+ .. container:: paragraph
+
+ The *Task* concepts that hold the definitions of the
+ task for the state are held as a set of
+ ``ArtifactKey`` references in the state. The
+ *DefaultTask* field holds a reference to the default
+ task for the state, a task that is executed if no task
+ selection logic is specified. If the state has only
+ one task, that task is the default task.
+
+ .. container:: paragraph
+
+ The *Logic* concept referenced by a state holds the
+ task selection logic for a state. The task selection
+ logic uses the incoming context (parameters of the
+ incoming event) and other context to determine the
+ best task to use to execute its goals. The state holds
+ a set of references to *ContextItem* and
+ *ContextItemTemplate* definitions for the context used
+ by its task selection logic.
+
+Writing Logic
+^^^^^^^^^^^^^
+
+Writing APEX Task Logic
+-----------------------
+
+ .. container:: paragraph
+
+ Task logic specifies the behavior of an Apex Task. This
+ logic can be specified in a number of ways, exploiting
+ Apex’s plug-in architecture to support a range of logic
+ executors. In Apex scripted Task Logic can be written in
+ any of these languages:
+
+ .. container:: ulist
+
+ - ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__,
+
+ - ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__,
+
+ - ```JRuby`` <https://en.wikipedia.org/wiki/JRuby>`__ or
+
+ - ```Jython`` <https://en.wikipedia.org/wiki/Jython>`__.
+
+ .. container:: paragraph
+
+ These languages were chosen because the scripts can be
+ compiled into Java bytecode at runtime and then
+ efficiently executed natively in the JVM. Task Logic an
+ also be written directly in Java but needs to be
+ compiled, with the resulting classes added to the
+ classpath. There are also a number of other Task Logic
+ types (e.g. Fuzzy Logic), but these are not supported as
+ yet. This guide will focus on the scripted Task Logic
+ approaches, with MVEL and JavaScript being our favorite
+ languages. In particular this guide will focus on the
+ Apex aspects of the scripts. However, this guide does not
+ attempt to teach you about the scripting languages
+ themselves …​ that is up to you!
+
+ .. tip::
+ JVM-based scripting languages
+ For more more information on scripting for the Java platform see: https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/index.html
+
+ .. note::
+ What do Tasks do?
+ The function of an Apex Task is to provide the logic that can be executed for an Apex State as one of the steps in
+ an Apex Policy. Each task receives some *incoming fields*, executes some logic (e.g: make a decision based on
+ *shared state* or *context*, *incoming fields*, *external context*, etc.), perhaps set some *shared state* or
+ *context* and then emits *outgoing fields*. The state that uses the task is responsible for extracting the
+ *incoming fields* from the state input event. The state also has an *output mapper* associated with the task, and
+ this *output mapper* is responsible for mapping the *outgoing fields* from the task into an appropriate
+ output event for the state.
+
+ .. container:: paragraph
+
+ First lets start with a sample task, drawn from the "My
+ First Apex Policy" example: The task "MorningBoozeCheck"
+ from the "My First Apex Policy" example is available in
+ both MVEL and JavaScript:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ Javascript code for the ``MorningBoozeCheck`` task
+
+ .. container:: content
+
+ .. code:: javascript
+ :number-lines:
+
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+ var returnValueType = Java.type("java.lang.Boolean");
+ var returnValue = new returnValueType(true);
+
+ // Load compatibility script for imports etc
+ load("nashorn:mozilla_compat.js");
+ importPackage(java.text);
+ importClass(java.text.SimpleDateFormat);
+
+ executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+ executor.outFields.put("amount" , executor.inFields.get("amount"));
+ executor.outFields.put("assistant_ID", executor.inFields.get("assistant_ID"));
+ executor.outFields.put("notes" , executor.inFields.get("notes"));
+ executor.outFields.put("quantity" , executor.inFields.get("quantity"));
+ executor.outFields.put("branch_ID" , executor.inFields.get("branch_ID"));
+ executor.outFields.put("item_ID" , executor.inFields.get("item_ID"));
+ executor.outFields.put("time" , executor.inFields.get("time"));
+ executor.outFields.put("sale_ID" , executor.inFields.get("sale_ID"));
+
+ item_id = executor.inFields.get("item_ID");
+
+ //All times in this script are in GMT/UTC since the policy and events assume time is in GMT.
+ var timenow_gmt = new Date(Number(executor.inFields.get("time")));
+
+ var midnight_gmt = new Date(Number(executor.inFields.get("time")));
+ midnight_gmt.setUTCHours(0,0,0,0);
+
+ var eleven30_gmt = new Date(Number(executor.inFields.get("time")));
+ eleven30_gmt.setUTCHours(11,30,0,0);
+
+ var timeformatter = new java.text.SimpleDateFormat("HH:mm:ss z");
+
+ var itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol
+ && timenow_gmt.getTime() >= midnight_gmt.getTime()
+ && timenow_gmt.getTime() < eleven30_gmt.getTime()) {
+
+ executor.outFields.put("authorised", false);
+ executor.outFields.put("message", "Sale not authorised by policy task " +
+ executor.subject.taskName+ " for time " + timeformatter.format(timenow_gmt.getTime()) +
+ ". Alcohol can not be sold between " + timeformatter.format(midnight_gmt.getTime()) +
+ " and " + timeformatter.format(eleven30_gmt.getTime()));
+ }
+ else{
+ executor.outFields.put("authorised", true);
+ executor.outFields.put("message", "Sale authorised by policy task " +
+ executor.subject.taskName + " for time "+timeformatter.format(timenow_gmt.getTime()));
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
+ authorised. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID value between 1000 and
+ 2000 are all alcoholic drinks :-)
+ */
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ MVEL code for the ``MorningBoozeCheck`` task
+
+ .. container:: content
+
+ .. code:: javascript
+ :number-lines:
+
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+ import java.util.Date;
+ import java.util.Calendar;
+ import java.util.TimeZone;
+ import java.text.SimpleDateFormat;
+
+ logger.info("Task Execution: '"+subject.id+"'. Input Fields: '"+inFields+"'");
+
+ outFields.put("amount" , inFields.get("amount"));
+ outFields.put("assistant_ID", inFields.get("assistant_ID"));
+ outFields.put("notes" , inFields.get("notes"));
+ outFields.put("quantity" , inFields.get("quantity"));
+ outFields.put("branch_ID" , inFields.get("branch_ID"));
+ outFields.put("item_ID" , inFields.get("item_ID"));
+ outFields.put("time" , inFields.get("time"));
+ outFields.put("sale_ID" , inFields.get("sale_ID"));
+
+ item_id = inFields.get("item_ID");
+
+ //The events used later to test this task use GMT timezone!
+ gmt = TimeZone.getTimeZone("GMT");
+ timenow = Calendar.getInstance(gmt);
+ df = new SimpleDateFormat("HH:mm:ss z");
+ df.setTimeZone(gmt);
+ timenow.setTimeInMillis(inFields.get("time"));
+
+ midnight = timenow.clone();
+ midnight.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),0,0,0);
+ eleven30 = timenow.clone();
+ eleven30.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),11,30,0);
+
+ itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol
+ && timenow.after(midnight) && timenow.before(eleven30)){
+ outFields.put("authorised", false);
+ outFields.put("message", "Sale not authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime())+
+ ". Alcohol can not be sold between "+df.format(midnight.getTime())+
+ " and "+df.format(eleven30.getTime()));
+ return true;
+ }
+ else{
+ outFields.put("authorised", true);
+ outFields.put("message", "Sale authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime()));
+ return true;
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
+ authorised. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID value between 1000 and
+ 2000 are all alcoholic drinks :-)
+ */
+
+ .. container:: paragraph
+
+ The role of the task in this simple example is to copy
+ the values in the incoming fields into the outgoing
+ fields, then examine the values in some incoming fields
+ (``item_id`` and ``time``), then set the values in some
+ other outgoing fields (``authorised`` and ``message``).
+
+ .. container:: paragraph
+
+ Both MVEL and JavaScript like most JVM-based scripting
+ languages can use standard Java libraries to perform
+ complex tasks. Towards the top of the scripts you will
+ see how to import Java classes and packages to be used
+ directly in the logic. Another thing to notice is that
+ Task Logic should return a ``java.lang.Boolean`` value
+ ``true`` if the logic executed correctly. If the logic
+ fails for some reason then ``false`` can be returned, but
+ this will cause the policy invoking this task will fail
+ and exit.
+
+ .. note::
+ How to return a value from task logic
+ Some languages explicitly support returning values from the script (e.g. MVEL and JRuby) using an explicit
+ return statement (e.g. ``return true``), other languages do not (e.g. JavaScript and Jython). For
+ languages that do not support the ``return`` statement, a special field called ``returnValue`` must be
+ created to hold the result of the task logic operation (i.e. assign a ``java.lang.Boolean``
+ value to the ``returnValue`` field before completing the task).
+ Also, in MVEL if there is no explicit return statement then the return value of the last executed statement will return
+ (e.g. the statement a=(1+2) will return the value 3).
+
+ .. container:: paragraph
+
+ Besides these imported classes and normal language
+ features Apex provides some natively available parameters
+ and functions that can be used directly. At run-time
+ these parameters are populated by the Apex execution
+ environment and made natively available to logic scripts
+ each time the logic script is invoked. (These can be
+ accessed using the ``executor`` keyword for most
+ languages, or can be accessed directly without the
+ ``executor`` keyword in MVEL):
+
+ Table 1. The ``executor`` Fields / Methods
+
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| Name | Type | Java type | Description |
++============+=============+================================+=====================================================================================+
+| inFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
+| | | | |
+| | | | The incoming task fields. This is implemented as a standard Java |
+| | | | Java (unmodifiable) Map |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.logger.debug("Incoming fields: " |
+| | | | +executor.inFields.entrySet()); |
+| | | | var item_id = executor.incomingFields["item_ID"]; |
+| | | | if (item_id >=1000) { ... } |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| outFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
+| | | | |
+| | | | The outgoing task fields. This is implemented as a standard initially empty Java |
+| | | | (modifiable) Map. To create a new schema-compliant instance of a field object |
+| | | | see the utility method subject.getOutFieldSchemaHelper() below |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.outFields["authorised"] = false; |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| logger | Logger | org.slf4j.ext.XLogger | .. container:: paragraph |
+| | | | |
+| | | | A helpful logger |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.logger.info("Executing task: " |
+| | | | +executor.subject.id); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| TRUE/FALSE | boolean | java.lang.Boolean | .. container:: paragraph |
+| | | | |
+| | | | 2 helpful constants. These are useful to retrieve correct return values for the |
+| | | | task logic |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | var returnValue = executor.isTrue; |
+| | | | var returnValueType = Java.type("java.lang.Boolean"); |
+| | | | var returnValue = new returnValueType(true); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| subject | Task | TaskFacade | .. container:: paragraph |
+| | | | |
+| | | | This provides some useful information about the task that contains this task |
+| | | | logic. This object has some useful fields and methods : |
+| | | | |
+| | | | .. container:: ulist |
+| | | | |
+| | | | - **AxTask task** to get access to the full task definition of |
+| | | | the host task |
+| | | | |
+| | | | - **String getTaskName()** to get the name of the host task |
+| | | | |
+| | | | - **String getId()** to get the ID of the host task |
+| | | | |
+| | | | - **SchemaHelper getInFieldSchemaHelper( String fieldName )** to |
+| | | | get a ``SchemaHelper`` helper object to manipulate incoming |
+| | | | task fields in a schema-aware manner |
+| | | | |
+| | | | - **SchemaHelper getOutFieldSchemaHelper( String fieldName )** to |
+| | | | get a ``SchemaHelper`` helper object to manipulate outgoing |
+| | | | task fields in a schema-aware manner, e.g. to instantiate new |
+| | | | schema-compliant field objects to populate the |
+| | | | ``executor.outFields`` outgoing fields map |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.logger.info("Task name: " |
+| | | | +executor.subject.getTaskName()); |
+| | | | executor.logger.info("Task id: " |
+| | | | +executor.subject.getId()); |
+| | | | executor.logger.info("Task inputs definitions: " |
+| | | | +"executor.subject.task.getInputFieldSet()); |
+| | | | executor.logger.info("Task outputs definitions: " |
+| | | | +"executor.subject.task.getOutputFieldSet()); |
+| | | | executor.outFields["authorised"] = executor.subject |
+| | | | .getOutFieldSchemaHelper("authorised") |
+| | | | .createNewInstance("false"); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| ContextAlbum getContextAlbum(String ctxtAlbumName ) | .. container:: paragraph |
+| | |
+| | A utility method to retrieve a ``ContextAlbum`` for use in the task. |
+| | This is how you access the context used by the task. The returned |
+| | ``ContextAlbum`` implements the ``java.util.Map <String,Object>`` |
+| | interface to get and set context as appropriate. The returned |
+| | ``ContextAlbum`` also has methods to lock context albums, get |
+| | information about the schema of the items to be stored in a context |
+| | album, and get a ``SchemaHelper`` to manipulate context album items. How |
+| | to define and use context in a task is described in the Apex |
+| | Programmer’s Guide and in the My First Apex Policy guide. |
+| | |
+| | .. container:: |
+| | |
+| | .. container:: content |
+| | |
+| | .. container:: paragraph |
+| | |
+| | **Example:** |
+| | |
+| | .. code:: javascript |
+| | |
+| | var bkey = executor.inFields.get("branch_ID"); |
+| | var cnts = executor.getContextMap("BranchCounts"); |
+| | cnts.lockForWriting(bkey); |
+| | cnts.put(bkey, cnts.get(bkey) + 1); |
+| | cnts.unlockForWriting(bkey); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+
+Writing APEX Task Selection Logic
+---------------------------------
+
+ .. container:: paragraph
+
+ The function of Task Selection Logic is to choose which task
+ should be executed for an Apex State as one of the steps in an
+ Apex Policy. Since each state must define a default task there is
+ no need for Task Selection Logic unless the state uses more than
+ one task. This logic can be specified in a number of ways,
+ exploiting Apex’s plug-in architecture to support a range of logic
+ executors. In Apex scripted Task Selection Logic can be written in
+ any of these languages:
+
+ .. container:: ulist
+
+ - ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__,
+
+ - ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__,
+
+ - ```JRuby`` <https://en.wikipedia.org/wiki/JRuby>`__ or
+
+ - ```Jython`` <https://en.wikipedia.org/wiki/Jython>`__.
+
+ .. container:: paragraph
+
+ These languages were chosen because the scripts can be compiled
+ into Java bytecode at runtime and then efficiently executed
+ natively in the JVM. Task Selection Logic an also be written
+ directly in Java but needs to be compiled, with the resulting
+ classes added to the classpath. There are also a number of other
+ Task Selection Logic types but these are not supported as yet.
+ This guide will focus on the scripted Task Selection Logic
+ approaches, with MVEL and JavaScript being our favorite languages.
+ In particular this guide will focus on the Apex aspects of the
+ scripts. However, this guide does not attempt to teach you about
+ the scripting languages themselves …​ that is up to you!
+
+ .. tip::
+ JVM-based scripting languages
+ For more more information on Scripting for the Java platform see:
+ https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/index.html
+
+ .. note::
+ What does Task Selection Logic do?
+ When an Apex state references multiple tasks, there must be a way to dynamically decide
+ which task should be chosen and executed. This can depend on the many factors, e.g. the
+ *incoming event for the state*, *shared state* or *context*, *external context*,
+ etc.. This is the function of a state’s Task Selection Logic. Obviously, if there is
+ only one task then Task only one task then Task Selection Logic is not needed.
+ Each state must also select one of the tasks a the *default state*. If the Task
+ Selection Logic is unable to select an appropriate task, then it should select the
+ *default task*. Once the task has been selected the Apex Engine will then execute that
+ task.
+
+ .. container:: paragraph
+
+ First lets start with some simple Task Selection Logic, drawn from
+ the "My First Apex Policy" example: The Task Selection Logic from
+ the "My First Apex Policy" example is specified in JavaScript
+ here:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ Javascript code for the "My First Policy" Task Selection Logic
+
+ .. container:: content
+
+ .. code:: javascript
+
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+
+ var returnValueType = Java.type("java.lang.Boolean");
+ var returnValue = new returnValueType(true);
+
+ executor.logger.info("Task Selection Execution: '"+executor.subject.id+
+ "'. Input Event: '"+executor.inFields+"'");
+
+ branchid = executor.inFields.get("branch_ID");
+ taskorig = executor.subject.getTaskKey("MorningBoozeCheck");
+ taskalt = executor.subject.getTaskKey("MorningBoozeCheckAlt1");
+ taskdef = executor.subject.getDefaultTaskKey();
+
+ if(branchid >=0 && branchid <1000){
+ taskorig.copyTo(executor.selectedTask);
+ }
+ else if (branchid >=1000 && branchid <2000){
+ taskalt.copyTo(executor.selectedTask);
+ }
+ else{
+ taskdef.copyTo(executor.selectedTask);
+ }
+
+ /*
+ This task selection logic selects task "MorningBoozeCheck" for branches with
+ 0<=branch_ID<1000 and selects task "MorningBoozeCheckAlt1" for branches with
+ 1000<=branch_ID<2000. Otherwise the default task is selected.
+ In this case the default task is also "MorningBoozeCheck"
+ */
+
+ .. container:: paragraph
+
+ The role of the Task Selection Logic in this simple example is to
+ examine the value in one incoming field (``branchid``), then
+ depending on that field’s value set the value for the selected
+ task to the appropriate task (``MorningBoozeCheck``,
+ ``MorningBoozeCheckAlt1``, or the default task).
+
+ .. container:: paragraph
+
+ Another thing to notice is that Task Selection Logic should return
+ a ``java.lang.Boolean`` value ``true`` if the logic executed
+ correctly. If the logic fails for some reason then ``false`` can
+ be returned, but this will cause the policy invoking this task
+ will fail and exit.
+
+ .. note::
+ How to return a value from Task Selection Logic
+ Some languages explicitly support returning values from the script (e.g. MVEL and
+ JRuby) using an explicit return statement (e.g. ``return true``), other languages do not (e.g.
+ JavaScript and Jython). For languages that do not support the ``return`` statement, a special field called
+ ``returnValue`` must be created to hold the result of the task logic operation (i.e. assign a ``java.lang.Boolean``
+ value to the ``returnValue`` field before completing the task).
+ Also, in MVEL if there is not explicit return statement then the return value of the last executed statement will
+ return (e.g. the statement a=(1+2) will return the value 3).
+
+ .. container:: paragraph
+
+ Each of the scripting languages used in Apex can import and use
+ standard Java libraries to perform complex tasks. Besides imported
+ classes and normal language features Apex provides some natively
+ available parameters and functions that can be used directly. At
+ run-time these parameters are populated by the Apex execution
+ environment and made natively available to logic scripts each time
+ the logic script is invoked. (These can be accessed using the
+ ``executor`` keyword for most languages, or can be accessed
+ directly without the ``executor`` keyword in MVEL):
+
+ Table 2. The ``executor`` Fields / Methods
+ +-------------------------------------------------------+--------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=======================================================+========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: bash | .. code:: bash |
+ | :number-lines: | :number-lines: |
+ | | |
+ | >c: | # cd /usr/local/src/apex-pdp |
+ | >cd \dev\apex | # mvn clean install -DskipTest |
+ | >mvn clean install -DskipTests | |
+ +-------------------------------------------------------+--------------------------------------------------------+
+
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| Name | Type | Java type | Description |
++============+=============+================================+=====================================================================================+
+| inFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
+| | | | |
+| | | | All fields in the state’s incoming event. This is implemented as a standard Java |
+| | | | Java (unmodifiable) Map |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.logger.debug("Incoming fields: " |
+| | | | +executor.inFields.entrySet()); |
+| | | | var item_id = executor.incomingFields["item_ID"]; |
+| | | | if (item_id >=1000) { ... } |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| outFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
+| | | | |
+| | | | The outgoing task fields. This is implemented as a standard initially empty Java |
+| | | | (modifiable) Map. To create a new schema-compliant instance of a field object |
+| | | | see the utility method subject.getOutFieldSchemaHelper() below |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.outFields["authorised"] = false; |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| logger | Logger | org.slf4j.ext.XLogger | .. container:: paragraph |
+| | | | |
+| | | | A helpful logger |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.logger.info("Executing task: " |
+| | | | +executor.subject.id); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| TRUE/FALSE | boolean | java.lang.Boolean | .. container:: paragraph |
+| | | | |
+| | | | 2 helpful constants. These are useful to retrieve correct return values for the |
+| | | | task logic |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | var returnValue = executor.isTrue; |
+| | | | var returnValueType = Java.type("java.lang.Boolean"); |
+| | | | var returnValue = new returnValueType(true); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| subject | Task | TaskFacade | .. container:: paragraph |
+| | | | |
+| | | | This provides some useful information about the task that contains this task |
+| | | | logic. This object has some useful fields and methods : |
+| | | | |
+| | | | .. container:: ulist |
+| | | | |
+| | | | - **AxTask task** to get access to the full task definition of |
+| | | | the host task |
+| | | | |
+| | | | - **String getTaskName()** to get the name of the host task |
+| | | | |
+| | | | - **String getId()** to get the ID of the host task |
+| | | | |
+| | | | - **SchemaHelper getInFieldSchemaHelper( String fieldName )** to |
+| | | | get a ``SchemaHelper`` helper object to manipulate incoming |
+| | | | task fields in a schema-aware manner |
+| | | | |
+| | | | - **SchemaHelper getOutFieldSchemaHelper( String fieldName )** to |
+| | | | get a ``SchemaHelper`` helper object to manipulate outgoing |
+| | | | task fields in a schema-aware manner, e.g. to instantiate new |
+| | | | schema-compliant field objects to populate the |
+| | | | ``executor.outFields`` outgoing fields map |
+| | | | |
+| | | | .. container:: |
+| | | | |
+| | | | .. container:: content |
+| | | | |
+| | | | .. container:: paragraph |
+| | | | |
+| | | | **Example:** |
+| | | | |
+| | | | .. code:: javascript |
+| | | | |
+| | | | executor.logger.info("Task name: " |
+| | | | +executor.subject.getTaskName()); |
+| | | | executor.logger.info("Task id: " |
+| | | | +executor.subject.getId()); |
+| | | | executor.logger.info("Task inputs definitions: " |
+| | | | +"executor.subject.task.getInputFieldSet()); |
+| | | | executor.logger.info("Task outputs definitions: " |
+| | | | +"executor.subject.task.getOutputFieldSet()); |
+| | | | executor.outFields["authorised"] = executor.subject |
+| | | | .getOutFieldSchemaHelper("authorised") |
+| | | | .createNewInstance("false"); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+| ContextAlbum getContextAlbum(String ctxtAlbumName ) | .. container:: paragraph |
+| | |
+| | A utility method to retrieve a ``ContextAlbum`` for use in the task. |
+| | This is how you access the context used by the task. The returned |
+| | ``ContextAlbum`` implements the ``java.util.Map <String,Object>`` |
+| | interface to get and set context as appropriate. The returned |
+| | ``ContextAlbum`` also has methods to lock context albums, get |
+| | information about the schema of the items to be stored in a context |
+| | album, and get a ``SchemaHelper`` to manipulate context album items. How |
+| | to define and use context in a task is described in the Apex |
+| | Programmer’s Guide and in the My First Apex Policy guide. |
+| | |
+| | .. container:: |
+| | |
+| | .. container:: content |
+| | |
+| | .. container:: paragraph |
+| | |
+| | **Example:** |
+| | |
+| | .. code:: javascript |
+| | |
+| | var bkey = executor.inFields.get("branch_ID"); |
+| | var cnts = executor.getContextMap("BranchCounts"); |
+| | cnts.lockForWriting(bkey); |
+| | cnts.put(bkey, cnts.get(bkey) + 1); |
+| | cnts.unlockForWriting(bkey); |
++------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
+
+Logic Cheatsheet
+----------------
+
+ .. container:: paragraph
+
+ Examples given here use Javascript (if not stated otherwise),
+ other execution environments will be similar.
+
+Add Nashorn
+###########
+
+ .. container:: paragraph
+
+ First line in the logic use this import.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Nashorn
+
+ .. container:: content
+
+ .. code:: javascript
+
+ load("nashorn:mozilla_compat.js");
+
+Finish Logic with Success or Error
+##################################
+
+ .. container:: paragraph
+
+ To finish logic, i.e. return to APEX, with success use the
+ following lines close to the end of the logic.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Success
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var returnValueType = Java.type("java.lang.Boolean");
+ var returnValue = new returnValueType(true);
+
+ .. container:: paragraph
+
+ To notify a problem, finish with an error.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Fail
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var returnValueType = Java.type("java.lang.Boolean");
+ var returnValue = new returnValueType(false);
+
+Logic Logging
+#############
+
+ .. container:: paragraph
+
+ Logging can be made easy using a local variable for the logger.
+ Line 1 below does that. Then we start with a trace log with the
+ task (or task logic) identifier followed by the infields.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Logging
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var logger = executor.logger;
+ logger.trace("start: " + executor.subject.id);
+ logger.trace("-- infields: " + executor.inFields);
+
+ .. container:: paragraph
+
+ For larger logging blocks you can use the standard logging API
+ to detect log levels, for instance:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Logging Blocks
+
+ .. container:: content
+
+ .. code:: javascript
+
+ if(logger.isTraceEnabled()){
+ // trace logging block here
+ }
+
+ .. container:: paragraph
+
+ Note: the shown logger here logs to
+ ``org.onap.policy.apex.executionlogging``. The behavior of the
+ actual logging can be specified in the
+ ``$APEX_HOME/etc/logback.xml``.
+
+ .. container:: paragraph
+
+ If you want to log into the APEX root logger (which is
+ sometimes necessary to report serious logic errors to the top),
+ then import the required class and use this logger.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Root Logger
+
+ .. container:: content
+
+ .. code:: javascript
+
+ importClass(org.slf4j.LoggerFactory);
+ var rootLogger = LoggerFactory.getLogger(logger.ROOT_LOGGER_NAME);
+
+ rootLogger.error("Serious error in logic detected: " + executor.subject.id);
+
+Local Variable for Infields
+###########################
+
+ .. container:: paragraph
+
+ It is a good idea to use local variables for ``infields``. This
+ avoids long code lines and policy evolution. The following
+ example assumes infields named ``nodeName`` and ``nodeAlias``.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Infields Local Var
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var ifNodeName = executor.inFields["nodeName"];
+ var ifNodeAlias = executor.inFields["nodeAlias"];
+
+Local Variable for Context Albums
+#################################
+
+ .. container:: paragraph
+
+ Similar to the ``infields`` it is good practice to use local
+ variables for context albums as well. The following example
+ assumes that a task can access a context album
+ ``albumTopoNodes``. The second line gets a particular node from
+ this context album.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Infields Local Var
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var albumTopoNodes = executor.getContextAlbum("albumTopoNodes");
+ var ctxtNode = albumTopoNodes.get(ifNodeName);
+
+Set Outfields in Logic
+######################
+
+ .. container:: paragraph
+
+ The task logic needs to set outfields with content generated.
+ The exception are outfields that are a direct copy from an
+ infield of the same name, APEX does that autmatically.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Set Outfields
+
+ .. container:: content
+
+ .. code:: javascript
+
+ executor.outFields["report"] = "node ctxt :: added node " + ifNodeName;
+
+Create a instance of an Outfield using Schemas
+##############################################
+
+ .. container:: paragraph
+
+ If an outfield is not an atomic type (string, integer, etc.)
+ but uses a complex schema (with a Java or Avro backend), APEX
+ can help to create new instances. The ``executor`` provides a
+ field called ``subject``, which provides a schem helper with an
+ API for this. The complete API of the schema helper is
+ documented here: `API Doc:
+ SchemaHelper <https://ericsson.github.io/apex-docs/javadocs/index.html>`__.
+
+ .. container:: paragraph
+
+ If the backend is Avro, then an import of the Avro schema
+ library is required:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Import Avro
+
+ .. container:: content
+
+ .. code:: javascript
+
+ importClass(org.apache.avro.generic.GenericData.Array);
+ importClass(org.apache.avro.generic.GenericRecord);
+ importClass(org.apache.avro.Schema);
+
+ .. container:: paragraph
+
+ If the backend is Java, then the Java class implementing the
+ schema needs to be imported.
+
+ .. container:: paragraph
+
+ The following example assumes an outfield ``situation``. The
+ ``subject`` method ``getOutFieldSchemaHelper()`` is used to
+ create a new instance.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Outfield Instance with Schema
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var situation = executor.subject.getOutFieldSchemaHelper("situation").createNewInstance();
+
+ .. container:: paragraph
+
+ If the schema backend is Java, the new instance will be as
+ implemented in the Java class. If the schema backend is Avro,
+ the new instance will have all fields from the Avro schema
+ specification, but set to ``null``. So any entry here needs to
+ be done separately. For instance, the ``situation`` schema has
+ a field ``problemID`` which we set.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Outfield Instance with Schema, set
+
+ .. container:: content
+
+ .. code:: javascript
+
+ situation.put("problemID", "my-problem");
+
+Create a instance of an Context Album entry using Schemas
+#########################################################
+
+ .. container:: paragraph
+
+ Context album instances can be created using very similar to
+ the outfields. Here, the schema helper comes from the context
+ album directly. The API of the schema helper is the same as for
+ outfields, see `API Doc:
+ SchemaHelper <https://ericsson.github.io/apex-docs/javadocs/index.html>`__.
+
+ .. container:: paragraph
+
+ If the backend is Avro, then an import of the Avro schema
+ library is required:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Import Avro
+
+ .. container:: content
+
+ .. code:: javascript
+
+ importClass(org.apache.avro.generic.GenericData.Array);
+ importClass(org.apache.avro.generic.GenericRecord);
+ importClass(org.apache.avro.Schema);
+
+ .. container:: paragraph
+
+ If the backend is Java, then the Java class implementing the
+ schema needs to be imported.
+
+ .. container:: paragraph
+
+ The following example creates a new instance of a context album
+ instance named ``albumProblemMap``.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Outfield Instance with Schema
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var albumProblemMap = executor.getContextAlbum("albumProblemMap");
+ var linkProblem = albumProblemMap.getSchemaHelper().createNewInstance();
+
+ .. container:: paragraph
+
+ This can of course be also done in a single call without the
+ local variable for the context album.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Outfield Instance with Schema, one line
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var linkProblem = executor.getContextAlbum("albumProblemMap").getSchemaHelper().createNewInstance();
+
+ .. container:: paragraph
+
+ If the schema backend is Java, the new instance will be as
+ implemented in the Java class. If the schema backend is Avro,
+ the new instance will have all fields from the Avro schema
+ specification, but set to ``null``. So any entry here needs to
+ be done separately (see above in outfields for an example).
+
+Enumerates
+##########
+
+ .. container:: paragraph
+
+ When dealing with enumerates (Avro or Java defined), it is
+ sometimes and in some execution environments necessary to
+ convert them to a string. For example, assume an Avro enumerate
+ schema as:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ Avro Enumerate Schema
+
+ .. container:: content
+
+ .. code:: javascript
+
+ {
+ "type": "enum",
+ "name": "Status",
+ "symbols" : [
+ "UP",
+ "DOWN"
+ ]
+ }
+
+ .. container:: paragraph
+
+ Using a switch over a field initialized with this enumerate in
+ Javascript will fail. Instead, use the ``toString`` method, for
+ example:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Outfield Instance with Schema, one line
+
+ .. container:: content
+
+ .. code:: javascript
+
+ var switchTest = executor.inFields["status"];
+ switch(switchTest.toString()){
+ case "UP": ...; break;
+ case "DOWN": ...; break;
+ default: ...;
+ }
+
+MVEL Initialize Outfields First!
+################################
+
+ .. container:: paragraph
+
+ In MVEL, we observed a problem when accessing (setting)
+ outfields without a prior access to them. So in any MVEL task
+ logic, before setting any outfield, simply do a get (with any
+ string), to load the outfields into the MVEL cache.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ MVEL Outfield Initialization
+
+ .. container:: content
+
+ .. code:: javascript
+
+ outFields.get("initialize outfields");
+
+Using Java in Scripting Logic
+#############################
+
+ .. container:: paragraph
+
+ Since APEX executes the logic inside a JVM, most scripting
+ languages provide access to all standard Java classes. Simply
+ add an import for the required class and then use it as in
+ actual Java.
+
+ .. container:: paragraph
+
+ The following example imports ``java.util.arraylist`` into a
+ Javascript logic, and then creates a new list.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JS Import ArrayList
+
+ .. container:: content
+
+ .. code:: javascript
+
+ importClass(java.util.ArrayList);
+ var myList = new ArrayList();
+
+Policy Examples
+^^^^^^^^^^^^^^^
+
+My First Policy
+---------------
+
+ .. container:: paragraph
+
+ A good starting point is the ``My First Policy`` example. It
+ describes a sales problem, to which policy can be applied.
+ The example details the policy background, shows how to use
+ the REST Editor to create a policy, and provides details for
+ running the policies. The documentation can be found:
+
+ .. container:: ulist
+
+ - `My-First-Policy on the APEX
+ site <https://ericsson.github.io/apex-docs/modules/examples/examples-myfirstpolicy/MyFirstPolicyHowto.html>`__
+
+ - `Stand-alone
+ HTML <https://ericsson.github.io/apex-docs/docs-apex/html/HowTo-MyFirstPolicy.html>`__
+
+ - `Stand-alone
+ PDF <https://ericsson.github.io/apex-docs/docs-apex/pdf/HowTo-MyFirstPolicy.pdf>`__
+
+VPN SLA
+-------
+
+ .. container:: paragraph
+
+ The domain Policy-controlled Video Streaming (PCVS) contains
+ a policy for controlling video streams with different
+ strategies. It also provides details for installing an
+ actual testbed with off-the-shelve software (Mininet,
+ Floodlight, Kafka, Zookeeper). The policy model here
+ demonstrates virtually all APEX features: local context and
+ policies controlling it, task selection logic and multiple
+ tasks in a single state, AVRO schemas for context, AVOR
+ schemas for events (trigger and local), and a CLI editor
+ specification of the policy. The documentation can be found:
+
+ .. container:: ulist
+
+ - `VPN SLA Policy on the APEX
+ site <https://ericsson.github.io/apex-docs/modules/examples/examples-pcvs/vpnsla/policy.html>`__
+
+Decision Maker
+--------------
+
+ .. container:: paragraph
+
+ The domain Decision Maker shows a very simple policy for
+ decisions. Interesting here is that the it creates a Docker
+ image to run the policy and that it uses the APEX REST
+ applications to update the policy on the-fly. It also has
+ local context to remember past decisions, and shows how to
+ use that to no make the same decision twice in a row. The
+ documentation can be found:
+
+ .. container:: ulist
+
+ - `Decision Maker on APEX
+ site <https://ericsson.github.io/apex-docs/modules/examples/examples-decisionmaker/index.html>`__
+
+.. container::
+ :name: footer
+
+ .. container::
+ :name: footer-text
+
+ 2.0.0-SNAPSHOT
+ Last updated 2018-09-04 16:04:24 IST
+
+.. |APEX Policy Matrix| image:: images/apex-intro/ApexPolicyMatrix.png
+.. |APEX Policy Model for Execution| image:: images/apex-policy-model/UmlPolicyModels.png
+.. |Concepts and Keys| image:: images/apex-policy-model/ConceptsKeys.png
+
diff --git a/docs/APEX-User-Manual.rst b/docs/APEX-User-Manual.rst
new file mode 100644
index 000000000..9f7b1489b
--- /dev/null
+++ b/docs/APEX-User-Manual.rst
@@ -0,0 +1,8071 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+
+APEX User Manual
+****************
+
+.. contents::
+ :depth: 3
+
+Installation
+^^^^^^^^^^^^
+
+Requirements
+------------
+
+ .. container:: paragraph
+
+ APEX is 100% written in Java and runs on any platform
+ that supports a JVM, e.g. Windows, Unix, Cygwin. Some
+ APEX applications (such as the monitoring application)
+ come as web archives, they do require a war-capable web
+ server installed.
+
+Installation Requirements
+#########################
+
+ .. container:: ulist
+
+ - Downloaded distribution: JAVA runtime environment
+ (JRE, Java 8 or later, APEX is tested with the
+ Oracle Java)
+
+ - Building from source: JAVA development kit (JDK,
+ Java 8 or later, APEX is tested with the Oracle
+ Java)
+
+ - A web archive capable webserver, for instance for
+ the monitoring application
+
+ .. container:: ulist
+
+ - for instance `Apache
+ Tomcat <https://tomcat.apache.org/>`__
+
+ - Sufficient rights to install APEX on the system
+
+ - Installation tools depending on the installation
+ method used:
+
+ .. container:: ulist
+
+ - ZIP to extract from a ZIP distribution
+
+ .. container:: ulist
+
+ - Windows for instance
+ `7Zip <http://www.7-zip.org/>`__
+
+ - TAR and GZ to extract from that TAR.GZ
+ distribution
+
+ .. container:: ulist
+
+ - Windows for instance
+ `7Zip <http://www.7-zip.org/>`__
+
+ - RPM to install from the RPM distribution
+
+ .. container:: ulist
+
+ - Install: ``sudo apt-get install rpm``
+
+ - DPKG to install from the DEB distribution
+
+ .. container:: ulist
+
+ - Install: ``sudo apt-get install dpkg``
+
+Feature Requirements
+####################
+
+ .. container:: paragraph
+
+ APEX supports a number of features that require extra
+ software being installed.
+
+ .. container:: ulist
+
+ - `Apache Kafka <https://kafka.apache.org/>`__ to
+ connect APEX to a Kafka message bus
+
+ - `Hazelcast <https://hazelcast.com/>`__ to use
+ distributed hash maps for context
+
+ - `Infinispan <http://infinispan.org/>`__ for
+ distributed context and persistence
+
+ - `Docker <https://www.docker.com/>`__ to run APEX
+ inside a Docker container
+
+Build (Install from Source) Requirements
+########################################
+
+ .. container:: paragraph
+
+ Installation from source requires a few development
+ tools
+
+ .. container:: ulist
+
+ - GIT to retrieve the source code
+
+ - Java SDK, Java version 8 or later
+
+ - Apache Maven 3 (the APEX build environment)
+
+Get the APEX Source Code
+------------------------
+
+ .. container:: paragraph
+
+ The first APEX source code was hosted on Github in
+ January 2018. By the end of 2018, APEX was added as a
+ project in the ONAP Policy Framework, released later in
+ the ONAP Casablanca release.
+
+ .. container:: paragraph
+
+ The APEX source code is hosted in ONAP as project APEX.
+ The current stable version is in the master branch.
+ Simply clone the master branch from ONAP using HTTPS.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ git clone https://gerrit.onap.org/r/policy/apex-pdp
+
+Build APEX
+----------
+
+ .. container:: paragraph
+
+ The examples in this document assume that the APEX source
+ repositories are cloned to:
+
+ .. container:: ulist
+
+ - Unix, Cygwin: ``/usr/local/src/apex-pdp``
+
+ - Windows: ``C:\dev\apex-pdp``
+
+ - Cygwin: ``/cygdrive/c/dev/apex-pdp``
+
+ .. important::
+ A Build requires ONAP Nexus
+ APEX has a dependency to ONAP parent projects. You might need to adjust your Maven M2 settings. The most current
+ settings can be found in the ONAP oparent repo: `Settings <https://git.onap.org/oparent/plain/settings.xml>`__.
+
+ .. important::
+ A Build needs Space
+ Building APEX requires approximately 2-3 GB of hard disc space, 1 GB for the actual build with full
+ distribution and 1-2 GB for the downloaded dependencies
+
+ .. important::
+ A Build requires Internet (for first build)
+ During the build, several (a lot) of Maven dependencies will be downloaded and stored in the configured local Maven
+ repository. The first standard build (and any first specific build) requires Internet access to download those
+ dependencies.
+
+ .. important::
+ Building RPM distributions
+ RPM images are only build if the ``rpm`` package is installed (Unix). To install ``rpm`` run ``sudo apt-get install rpm``,
+ then build APEX.
+
+ .. container:: paragraph
+
+ Use Maven to for a standard build without any tests.
+
+ +-------------------------------------------------------+--------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=======================================================+========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | :number-lines: | :number-lines: |
+ | | |
+ | # cd /usr/local/src/apex-pdp | >c: |
+ | # mvn clean install -DskipTest | >cd \dev\apex |
+ | | >mvn clean install -DskipTests |
+ +-------------------------------------------------------+--------------------------------------------------------+
+
+.. container:: paragraph
+
+ The build takes 2-3 minutes on a standard development laptop. It
+ should run through without errors, but with a lot of messages from
+ the build process.
+
+.. container:: paragraph
+
+ When Maven is finished with the build, the final screen should look
+ similar to this (omitting some ``success`` lines):
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ [INFO] tools .............................................. SUCCESS [ 0.248 s]
+ [INFO] tools-common ....................................... SUCCESS [ 0.784 s]
+ [INFO] simple-wsclient .................................... SUCCESS [ 3.303 s]
+ [INFO] model-generator .................................... SUCCESS [ 0.644 s]
+ [INFO] packages ........................................... SUCCESS [ 0.336 s]
+ [INFO] apex-pdp-package-full .............................. SUCCESS [01:10 min]
+ [INFO] Policy APEX PDP - Docker build 2.0.0-SNAPSHOT ...... SUCCESS [ 10.307 s]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] BUILD SUCCESS
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Total time: 03:43 min
+ [INFO] Finished at: 2018-09-03T11:56:01+01:00
+ [INFO] ------------------------------------------------------------------------
+
+.. container:: paragraph
+
+ The build will have created all artifacts required for an APEX
+ installation. The following example show how to change to the target
+ directory and how it should look like.
+
++----------------------------------------------------------------------------------------------------------------------------+
+| Unix, Cygwin |
++============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. container:: content |
+| |
+| .. code:: |
+| :number-lines: |
+| |
+| -rwxrwx---+ 1 esvevan Domain Users 772 Sep 3 11:55 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes* |
+| -rwxrwx---+ 1 esvevan Domain Users 146328082 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT.deb* |
+| -rwxrwx---+ 1 esvevan Domain Users 15633 Sep 3 11:54 apex-pdp-package-full-2.0.0-SNAPSHOT.jar* |
+| -rwxrwx---+ 1 esvevan Domain Users 146296819 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 archive-tmp/ |
+| -rwxrwx---+ 1 esvevan Domain Users 89 Sep 3 11:54 checkstyle-cachefile* |
+| -rwxrwx---+ 1 esvevan Domain Users 10621 Sep 3 11:54 checkstyle-checker.xml* |
+| -rwxrwx---+ 1 esvevan Domain Users 584 Sep 3 11:54 checkstyle-header.txt* |
+| -rwxrwx---+ 1 esvevan Domain Users 86 Sep 3 11:54 checkstyle-result.xml* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 classes/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 dependency-maven-plugin-markers/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 etc/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 examples/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:55 install_hierarchy/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 maven-archiver/ |
++----------------------------------------------------------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------------------------+
+| Windows |
++========================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. container:: content |
+| |
+| .. code:: |
+| :number-lines: |
+| |
+| 03/09/2018 11:55 <DIR> . |
+| 03/09/2018 11:55 <DIR> .. |
+| 03/09/2018 11:55 146,296,819 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz |
+| 03/09/2018 11:55 146,328,082 apex-pdp-package-full-2.0.0-SNAPSHOT.deb |
+| 03/09/2018 11:54 15,633 apex-pdp-package-full-2.0.0-SNAPSHOT.jar |
+| 03/09/2018 11:55 772 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes |
+| 03/09/2018 11:54 <DIR> archive-tmp |
+| 03/09/2018 11:54 89 checkstyle-cachefile |
+| 03/09/2018 11:54 10,621 checkstyle-checker.xml |
+| 03/09/2018 11:54 584 checkstyle-header.txt |
+| 03/09/2018 11:54 86 checkstyle-result.xml |
+| 03/09/2018 11:54 <DIR> classes |
+| 03/09/2018 11:54 <DIR> dependency-maven-plugin-markers |
+| 03/09/2018 11:54 <DIR> etc |
+| 03/09/2018 11:54 <DIR> examples |
+| 03/09/2018 11:55 <DIR> install_hierarchy |
+| 03/09/2018 11:54 <DIR> maven-archiver |
+| 8 File(s) 292,652,686 bytes |
+| 9 Dir(s) 14,138,720,256 bytes free |
++--------------------------------------------------------------------------------------------------------+
+
+Install APEX
+------------
+
+ .. container:: paragraph
+
+ APEX can be installed in different ways:
+
+ .. container:: ulist
+
+ - Unix: automatically using ``rpm`` or ``dpkg`` from ``.rpm`` or
+ ``.deb`` archive
+
+ - Windows, Unix, Cygwin: manually from a ``.tar.gz`` archive
+
+ - Windows, Unix, Cygwin: build from source using Maven, then
+ install manually
+
+Install with RPM and DPKG
+#########################
+
+ .. container:: paragraph
+
+ The install distributions of APEX automatically install the
+ system. The installation directory is
+ ``/opt/app/policy/apex-pdp``. Log files are located in
+ ``/var/log/onap/policy/apex-pdp``. The latest APEX version will
+ be available as ``/opt/app/policy/apex-pdp/apex-pdp``.
+
+ .. container:: paragraph
+
+ For the installation, a new user ``apexuser`` and a new group
+ ``apexuser`` will be created. This user owns the installation
+ directories and the log file location. The user is also used by
+ the standard APEX start scripts to run APEX with this user’s
+ permissions.
+
+ +-----------------------------------------------------------------------+
+ | RPM Installation |
+ +=======================================================================+
+ | .. container:: |
+ | |
+ | .. container:: listingblock |
+ | |
+ | .. container:: content |
+ | |
+ | .. code:: |
+ | :number-lines: |
+ | |
+ | # sudo rpm -i apex-pdp-package-full-2.0.0-SNAPSHOT.rpm |
+ | ********************preinst******************* |
+ | arguments 1 |
+ | ********************************************** |
+ | creating group apexuser . . . |
+ | creating user apexuser . . . |
+ | ********************postinst**************** |
+ | arguments 1 |
+ | *********************************************** |
+ +-----------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------+
+| DPKG Installation |
++======================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. container:: content |
+| |
+| .. code:: |
+| :number-lines: |
+| |
+| # sudo dpkg -i apex-pdp-package-full-2.0.0-SNAPSHOT.deb |
+| Selecting previously unselected package apex-uservice. |
+| (Reading database ... 288458 files and directories currently installed.) |
+| Preparing to unpack apex-pdp-package-full-2.0.0-SNAPSHOT.deb ... |
+| ********************preinst******************* |
+| arguments install |
+| ********************************************** |
+| creating group apexuser . . . |
+| creating user apexuser . . . |
+| Unpacking apex-uservice (2.0.0-SNAPSHOT) ... |
+| Setting up apex-uservice (2.0.0-SNAPSHOT) ... |
+| ********************postinst**************** |
+| arguments configure |
+| *********************************************** |
++--------------------------------------------------------------------------------------+
+
+.. container:: paragraph
+
+ Once the installation is finished, APEX is fully installed and ready
+ to run.
+
+Install Manually from Archive (Unix, Cygwin)
+############################################
+
+ .. container:: paragraph
+
+ Download a ``tar.gz`` archive. Create a directory where APEX
+ should be installed. Extract the ``tar`` archive. The following
+ example shows how to install APEX in ``/opt/apex`` and create a
+ link to ``/opt/apex/apex`` for the most recent installation.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ # cd /opt
+ # mkdir apex
+ # cd apex
+ # mkdir apex-full-2.0.0-SNAPSHOT
+ # tar xvfz ~/Downloads/apex-pdp-package-full-2.0.0-SNAPSHOT.tar.gz -C apex-full-2.0.0-SNAPSHOT
+ # ln -s apex apex-pdp-package-full-2.0.0-SNAPSHOT
+
+Install Manually from Archive (Windows, 7Zip, GUI)
+##################################################
+
+ .. container:: paragraph
+
+ Download a ``tar.gz`` archive and copy the file into the install
+ folder (in this example ``C:\apex``). Assuming you are using 7Zip,
+ right click on the file and extract the ``tar`` archive. Note: the
+ screenshots might show an older version than you have.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Extract the TAR archive|
+
+ .. container:: paragraph
+
+ The right-click on the new created TAR file and extract the actual
+ APEX distribution.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Extract the APEX distribution|
+
+ .. container:: paragraph
+
+ Inside the new APEX folder you see the main directories: ``bin``,
+ ``etc``, ``examples``, ``lib``, and ``war``
+
+ .. container:: paragraph
+
+ Once extracted, please rename the created folder to
+ ``apex-full-2.0.0-SNAPSHOT``. This will keep the directory name in
+ line with the rest of this documentation.
+
+Install Manually from Archive (Windows, 7Zip, CMD)
+##################################################
+
+ .. container:: paragraph
+
+ Download a ``tar.gz`` archive and copy the file into the install
+ folder (in this example ``C:\apex``). Start ``cmd``, for instance
+ typing ``Windows+R`` and then ``cmd`` in the dialog. Assuming
+ ``7Zip`` is installed in the standard folder, simply run the
+ following commands (for APEX version 2.0.0-SNAPSHOT full
+ distribution)
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ >c:
+ >cd \apex
+ >"\Program Files\7-Zip\7z.exe" x apex-pdp-package-full-2.0.0-SNAPSHOT.tar.gz -so | "\Program Files\7-Zip\7z.exe" x -aoa -si -ttar -o"apex-full-2.0.0-SNAPSHOT"
+
+.. container:: paragraph
+
+ APEX is now installed in the folder
+ ``C:\apex\apex-full-2.0.0-SNAPSHOT``.
+
+Build from Source
+-----------------
+
+Build and Install Manually (Unix, Windows, Cygwin)
+##################################################
+
+ .. container:: paragraph
+
+ Clone the APEX GIT repositories into a directory. Go to that
+ directory. Use Maven to build APEX (all details on building
+ APEX from source can be found in *APEX HowTo: Build*). Install
+ from the created artifacts (``rpm``, ``deb``, ``tar.gz``, or
+ copying manually).
+
+ .. important::
+ Building RPM distributions
+ RPM images are only build if the ``rpm`` package is installed (Unix). To install ``rpm`` run
+ ``sudo apt-get install rpm``, then build APEX.
+
+ .. container:: paragraph
+
+ The following example shows how to build the APEX system,
+ without tests (``-DskipTests``) to safe some time. It assumes
+ that the APX GIT repositories are cloned to:
+
+ .. container:: ulist
+
+ - Unix, Cygwin: ``/usr/local/src/apex``
+
+ - Windows: ``C:\dev\apex``
+
+ +-------------------------------------------------------+--------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=======================================================+========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | :number-lines: | :number-lines: |
+ | | |
+ | # cd /usr/local/src/apex | >c: |
+ | # mvn clean install -DskipTests | >cd \dev\apex |
+ | | >mvn clean install -DskipTests |
+ +-------------------------------------------------------+--------------------------------------------------------+
+
+.. container:: paragraph
+
+ The build takes about 2 minutes without test and about 4-5 minutes
+ with tests on a standard development laptop. It should run through
+ without errors, but with a lot of messages from the build process. If
+ build with tests (i.e. without ``-DskipTests``), there will be error
+ messages and stack trace prints from some tests. This is normal, as
+ long as the build finishes successful.
+
+.. container:: paragraph
+
+ When Maven is finished with the build, the final screen should look
+ similar to this (omitting some ``success`` lines):
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ [INFO] tools .............................................. SUCCESS [ 0.248 s]
+ [INFO] tools-common ....................................... SUCCESS [ 0.784 s]
+ [INFO] simple-wsclient .................................... SUCCESS [ 3.303 s]
+ [INFO] model-generator .................................... SUCCESS [ 0.644 s]
+ [INFO] packages ........................................... SUCCESS [ 0.336 s]
+ [INFO] apex-pdp-package-full .............................. SUCCESS [01:10 min]
+ [INFO] Policy APEX PDP - Docker build 2.0.0-SNAPSHOT ...... SUCCESS [ 10.307 s]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] BUILD SUCCESS
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Total time: 03:43 min
+ [INFO] Finished at: 2018-09-03T11:56:01+01:00
+ [INFO] ------------------------------------------------------------------------
+
+.. container:: paragraph
+
+ The build will have created all artifacts required for an APEX
+ installation. The following example show how to change to the target
+ directory and how it should look like.
+
++-----------------------------------------------------------------------------------------------------------------------------+
+| Unix, Cygwin |
++=============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. code:: |
+| :number-lines: |
+| |
+| # cd packages/apex-pdp-package-full/target |
+| # ls -l |
+| -rwxrwx---+ 1 esvevan Domain Users 772 Sep 3 11:55 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes* |
+| -rwxrwx---+ 1 esvevan Domain Users 146328082 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT.deb* |
+| -rwxrwx---+ 1 esvevan Domain Users 15633 Sep 3 11:54 apex-pdp-package-full-2.0.0-SNAPSHOT.jar* |
+| -rwxrwx---+ 1 esvevan Domain Users 146296819 Sep 3 11:55 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 archive-tmp/ |
+| -rwxrwx---+ 1 esvevan Domain Users 89 Sep 3 11:54 checkstyle-cachefile* |
+| -rwxrwx---+ 1 esvevan Domain Users 10621 Sep 3 11:54 checkstyle-checker.xml* |
+| -rwxrwx---+ 1 esvevan Domain Users 584 Sep 3 11:54 checkstyle-header.txt* |
+| -rwxrwx---+ 1 esvevan Domain Users 86 Sep 3 11:54 checkstyle-result.xml* |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 classes/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 dependency-maven-plugin-markers/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 etc/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 examples/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:55 install_hierarchy/ |
+| drwxrwx---+ 1 esvevan Domain Users 0 Sep 3 11:54 maven-archiver/ |
++-----------------------------------------------------------------------------------------------------------------------------+
+
++-----------------------------------------------------------------------------------------------------------------------------+
+| Windows |
++=============================================================================================================================+
+| .. container:: |
+| |
+| .. container:: listingblock |
+| |
+| .. code:: |
+| :number-lines: |
+| |
+| >cd packages\apex-pdp-package-full\target |
+| >dir |
+| 03/09/2018 11:55 <DIR> . |
+| 03/09/2018 11:55 <DIR> .. |
+| 03/09/2018 11:55 146,296,819 apex-pdp-package-full-2.0.0-SNAPSHOT-tarball.tar.gz |
+| 03/09/2018 11:55 146,328,082 apex-pdp-package-full-2.0.0-SNAPSHOT.deb |
+| 03/09/2018 11:54 15,633 apex-pdp-package-full-2.0.0-SNAPSHOT.jar |
+| 03/09/2018 11:55 772 apex-pdp-package-full_2.0.0~SNAPSHOT_all.changes |
+| 03/09/2018 11:54 <DIR> archive-tmp |
+| 03/09/2018 11:54 89 checkstyle-cachefile |
+| 03/09/2018 11:54 10,621 checkstyle-checker.xml |
+| 03/09/2018 11:54 584 checkstyle-header.txt |
+| 03/09/2018 11:54 86 checkstyle-result.xml |
+| 03/09/2018 11:54 <DIR> classes |
+| 03/09/2018 11:54 <DIR> dependency-maven-plugin-markers |
+| 03/09/2018 11:54 <DIR> etc |
+| 03/09/2018 11:54 <DIR> examples |
+| 03/09/2018 11:55 <DIR> install_hierarchy |
+| 03/09/2018 11:54 <DIR> maven-archiver |
+| 8 File(s) 292,652,686 bytes |
+| 9 Dir(s) 14,138,720,256 bytes free |
++-----------------------------------------------------------------------------------------------------------------------------+
+
+.. container:: paragraph
+
+ Now, take the ``.deb`` or the ``.tar.gz`` file and install APEX.
+ Alternatively, copy the content of the folder ``install_hierarchy``
+ to your APEX directory.
+
+Installation Layout
+-------------------
+
+ .. container:: paragraph
+
+ A full installation of APEX comes with the following layout.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ ::
+
+ $APEX_HOME
+ ├───bin (1)
+ ├───etc (2)
+ │ ├───editor
+ │ ├───hazelcast
+ │ ├───infinispan
+ │ └───META-INF
+ ├───examples (3)
+ │ ├───config (4)
+ │ ├───docker (5)
+ │ ├───events (6)
+ │ ├───html (7)
+ │ ├───models (8)
+ │ └───scripts (9)
+ ├───lib (10)
+ │ └───applications (11)
+ └───war (12)
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | binaries, mainly scripts (bash |
+ | | and bat) to start the APEX engine |
+ | | and applications |
+ +-----------------------------------+-----------------------------------+
+ | **2** | configuration files, such as |
+ | | logback (logging) and third party |
+ | | library configurations |
+ +-----------------------------------+-----------------------------------+
+ | **3** | example policy models to get |
+ | | started |
+ +-----------------------------------+-----------------------------------+
+ | **4** | configurations for the examples |
+ | | (with sub directories for |
+ | | individual examples) |
+ +-----------------------------------+-----------------------------------+
+ | **5** | Docker files and additional |
+ | | Docker instructions for the |
+ | | exampples |
+ +-----------------------------------+-----------------------------------+
+ | **6** | example events for the examples |
+ | | (with sub directories for |
+ | | individual examples) |
+ +-----------------------------------+-----------------------------------+
+ | **7** | HTML files for some examples, |
+ | | e.g. the Decisionmaker example |
+ +-----------------------------------+-----------------------------------+
+ | **8** | the policy models, generated for |
+ | | each example (with sub |
+ | | directories for individual |
+ | | examples) |
+ +-----------------------------------+-----------------------------------+
+ | **9** | additional scripts for the |
+ | | examples (with sub directories |
+ | | for individual examples) |
+ +-----------------------------------+-----------------------------------+
+ | **10** | the library folder with all Java |
+ | | JAR files |
+ +-----------------------------------+-----------------------------------+
+ | **11** | applications, also known as jar |
+ | | with dependencies (or fat jars), |
+ | | individually deployable |
+ +-----------------------------------+-----------------------------------+
+ | **12** | WAR files for web applications |
+ +-----------------------------------+-----------------------------------+
+
+System Configuration
+--------------------
+
+ .. container:: paragraph
+
+ Once APEX is installed, a few configurations need to be done:
+
+ .. container:: ulist
+
+ - Create an APEX user and an APEX group (optional, if not
+ installed using RPM and DPKG)
+
+ - Create environment settings for ``APEX_HOME`` and
+ ``APEX_USER``, required by the start scripts
+
+ - Change settings of the logging framework (optional)
+
+ - Create directories for logging, required (execution might fail
+ if directories do not exist or cannot be created)
+
+APEX User and Group
+###################
+
+ .. container:: paragraph
+
+ On smaller installations and test systems, APEX can run as any
+ user or group.
+
+ .. container:: paragraph
+
+ However, if APEX is installed in production, we strongly
+ recommend you set up a dedicated user for running APEX. This
+ will isolate the execution of APEX to that user. We recommend
+ you use the userid ``apexuser`` but you may use any user you
+ choose.
+
+ .. container:: paragraph
+
+ The following example, for UNIX, creates a group called
+ ``apexuser``, an APEX user called ``apexuser``, adds the group
+ to the user, and changes ownership of the APEX installation to
+ the user. Substitute ``<apex-dir>`` with the directory where
+ APEX is installed.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ # sudo groupadd apexuser
+ # sudo useradd -g apexuser apexuser
+ # sudo chown -R apexuser:apexuser <apex-dir>
+
+.. container:: paragraph
+
+ For other operating systems please consult your manual or system
+ administrator.
+
+Environment Settings: APEX_HOME and APEX_USER
+#############################################
+
+ .. container:: paragraph
+
+ The provided start scripts for APEX require two environment
+ variables being set:
+
+ .. container:: ulist
+
+ - ``APEX_USER`` with the user under whos name and permission APEX
+ should be started (Unix only)
+
+ - ``APEX_HOME`` with the directory where APEX is installed (Unix,
+ Windows, Cygwin)
+
+ .. container:: paragraph
+
+ The first row in the following table shows how to set these
+ environment variables temporary (assuming the user is
+ ``apexuser``). The second row shows how to verify the settings.
+ The last row explains how to set those variables permanently.
+
+ +------------------------------------------------+---------------------------------------------------------+
+ | Unix, Cygwin (bash/tcsh) | Windows |
+ +================================================+=========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | :number-lines: | :number-lines: |
+ | | |
+ | # export APEX_USER=apexuser | >set APEX_HOME=C:\apex\apex-full-2.0.0-SNAPSHOT |
+ | # cd /opt/app/policy/apex-pdp | |
+ | # export APEX_HOME=`pwd` | |
+ | | |
+ +------------------------------------------------+ |
+ | .. container:: | |
+ | | |
+ | .. container:: content | |
+ | | |
+ | .. code:: tcsh | |
+ | :number-lines: | |
+ | | |
+ | # setenv APEX_USER apexuser | |
+ | # cd /opt/app/policy/apex-pdp | |
+ | # setenv APEX_HOME `pwd` | |
+ | | |
+ +------------------------------------------------+---------------------------------------------------------+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | :number-lines: | :number-lines: |
+ | | |
+ | # env | grep APEX | >set APEX_HOME |
+ | # APEX_USER=apexuser | APEX_HOME=\apex\apex-full-2.0.0-SNAPSHOT |
+ | # APEX_HOME=/opt/app/policy/apex-pdp | |
+ | | |
+ +------------------------------------------------+---------------------------------------------------------+
+
+Making Environment Settings Permanent (Unix, Cygwin)
+====================================================
+
+ .. container:: paragraph
+
+ For a per-user setting, edit the a user’s ``bash`` or ``tcsh``
+ settings in ``~/.bashrc`` or ``~/.tcshrc``. For system-wide
+ settings, edit ``/etc/profiles`` (requires permissions).
+
+Making Environment Settings Permanent (Windows)
+===============================================
+
+ .. container:: paragraph
+
+ On Windows 7 do
+
+ .. container:: ulist
+
+ - Click on the **Start** Menu
+
+ - Right click on **Computer**
+
+ - Select **Properties**
+
+ .. container:: paragraph
+
+ On Windows 8/10 do
+
+ .. container:: ulist
+
+ - Click on the **Start** Menu
+
+ - Select **System**
+
+ .. container:: paragraph
+
+ Then do the following
+
+ .. container:: ulist
+
+ - Select **Advanced System Settings**
+
+ - On the **Advanced** tab, click the **Environment Variables**
+ button
+
+ - Edit an existing variable, or create a new System variable:
+ 'Variable name'="APEX_HOME", 'Variable
+ value'="C:\apex\apex-full-2.0.0-SNAPSHOT"
+
+ .. container:: paragraph
+
+ For the settings to take effect, an application needs to be
+ restarted (e.g. any open ``cmd`` window).
+
+Edit the APEX Logging Settings
+##############################
+
+ .. container:: paragraph
+
+ Configure the APEX logging settings to your requirements, for
+ instance:
+
+ .. container:: ulist
+
+ - change the directory where logs are written to, or
+
+ - change the log levels
+
+ .. container:: paragraph
+
+ Edit the file ``$APEX_HOME/etc/logback.xml`` for any required
+ changes. To change the log directory change the line
+
+ .. container:: paragraph
+
+ ``<property name="VAR_LOG" value="/var/log/onap/policy/apex-pdp/" />``
+
+ .. container:: paragraph
+
+ to
+
+ .. container:: paragraph
+
+ ``<property name="VAR_LOG" value="/PATH/TO/LOG/DIRECTORY/" />``
+
+ .. container:: paragraph
+
+ On Windows, it is recommended to change the log directory to:
+
+ .. container:: paragraph
+
+ ``<property name="VAR_LOG" value="C:/apex/apex-full-2.0.0-SNAPSHOT/logs" />``
+
+ .. container:: paragraph
+
+ Note: Be careful about when to use ``\`` vs. ``/`` as the path
+ separator!
+
+Create Directories for Logging
+##############################
+
+ .. container:: paragraph
+
+ Make sure that the log directory exists. This is important when
+ APEX was installed manually or when the log directory was changed
+ in the settings (see above).
+
+ +------------------------------------------------------------------+-------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +==================================================================+=======================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | :number-lines: | :number-lines: |
+ | | |
+ | mkdir -p /var/log/onap/policy/apex-pdp | >mkdir C:\apex\apex-full-2.0.0-SNAPSHOT\logs |
+ | chown -R apexuser:apexuser /var/log/onap/policy/apex-pdp | |
+ +------------------------------------------------------------------+-------------------------------------------------------+
+
+Verify the APEX Installation
+----------------------------
+
+ .. container:: paragraph
+
+ When APEX is installed and all settings are realized, the
+ installation can be verified.
+
+Verify Installation - run Engine
+################################
+
+ .. container:: paragraph
+
+ A simple verification of an APEX installation can be done by
+ simply starting the APEX engine without any configuration. On
+ Unix (or Cygwin) start the engine using
+ ``$APEX_HOME/bin/apexEngine.sh``. On Windows start the engine
+ using ``%APEX_HOME%\bin\apexEngine.bat``. The engine will fail
+ to fully start. However, if the output looks similar to the
+ following line, the APEX installation is realized.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ Starting Apex service with parameters [] . . .
+ start of Apex service failed: Apex configuration file was not specified as an argument
+ 2018-09-03 13:11:33,914 Apex [main] ERROR o.o.p.a.service.engine.main.ApexMain - start of Apex service failed
+ org.onap.policy.apex.model.basicmodel.concepts.ApexException: Apex configuration file was not specified as an argument
+ at org.onap.policy.apex.service.engine.main.ApexCommandLineArguments.validateReadableFile(ApexCommandLineArguments.java:267)
+ at org.onap.policy.apex.service.engine.main.ApexCommandLineArguments.validate(ApexCommandLineArguments.java:161)
+ at org.onap.policy.apex.service.engine.main.ApexMain.<init>(ApexMain.java:68)
+ at org.onap.policy.apex.service.engine.main.ApexMain.main(ApexMain.java:165)
+ usage: org.onap.policy.apex.service.engine.main.ApexMain [options...]
+ options
+ -c,--config-file <CONFIG_FILE>the full path to the configuration file to use, the configuration file must be a Json file
+ containing the Apex configuration parameters
+ -h,--help outputs the usage of this command
+ -m,--model-file <MODEL_FILE> the full path to the model file to use, if set it overrides the model file set in the
+ configuration file
+ -v,--version outputs the version of Apex
+
+Verify Installation - run an Example
+####################################
+
+ .. container:: paragraph
+
+ A full APEX installation comes with several examples. Here, we can
+ fully verify the installation by running one of the examples.
+
+ .. container:: paragraph
+
+ We use the example called *SampleDomain* and configure the engine
+ to use standard in and standard out for events. Run the engine
+ with the provided configuration. Note: Cygwin executes scripts as
+ Unix scripts but runs Java as a Windows application, thus the
+ configuration file must be given as a Windows path.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ # $APEX_HOME/bin/apexEngine.sh -c $APEX_HOME/examples/config/SampleDomain/Stdin2StdoutJsonEventJava.json (1)
+ # $APEX_HOME/bin/apexEngine.sh -c C:/apex/apex-full-2.0.0-SNAPSHOT/examples/config/SampleDomain/Stdin2StdoutJsonEventJava.json (2)
+ >%APEX_HOME%\bin\apexEngine.bat -c %APEX_HOME%\examples\config\SampleDomain\Stdin2StdoutJsonEventJava.json :: (3)
+
+.. container:: colist arabic
+
+ +-------+---------+
+ | **1** | UNIX |
+ +-------+---------+
+ | **2** | Cygwin |
+ +-------+---------+
+ | **3** | Windows |
+ +-------+---------+
+
+.. container:: paragraph
+
+ The engine should start successfully. Assuming the logging levels are
+ not change (default level is ``info``), the output should look
+ similar to this (last few lines)
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ Starting Apex service with parameters [-c, v:/dev/ericsson/apex/onap/apex-pdp/packages/apex-pdp-package-full/target/install_hierarchy/examples/config/SampleDomain/Stdin2StdoutJsonEventJava.json] . . .
+ 2018-09-05 15:16:42,800 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-0:0.0.1 .
+ 2018-09-05 15:16:42,804 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-1:0.0.1 .
+ 2018-09-05 15:16:42,804 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-2:0.0.1 .
+ 2018-09-05 15:16:42,805 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Created apex engine MyApexEngine-3:0.0.1 .
+ 2018-09-05 15:16:42,805 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - APEX service created.
+ 2018-09-05 15:16:43,962 Apex [main] INFO o.o.p.a.s.e.e.EngDepMessagingService - engine<-->deployment messaging starting . . .
+ 2018-09-05 15:16:43,963 Apex [main] INFO o.o.p.a.s.e.e.EngDepMessagingService - engine<-->deployment messaging started
+ 2018-09-05 15:16:44,987 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-0:0.0.1
+ 2018-09-05 15:16:45,112 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-1:0.0.1
+ 2018-09-05 15:16:45,113 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-2:0.0.1
+ 2018-09-05 15:16:45,113 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Registering apex model on engine MyApexEngine-3:0.0.1
+ 2018-09-05 15:16:45,120 Apex [main] INFO o.o.p.a.s.e.r.impl.EngineServiceImpl - Added the action listener to the engine
+ Started Apex service
+
+.. container:: paragraph
+
+ Important are the last two line, stating that APEX has added the
+ final action listener to the engine and that the engine is started.
+
+.. container:: paragraph
+
+ The engine is configured to read events from standard input and write
+ produced events to standard output. The policy model is a very simple
+ policy.
+
+.. container:: paragraph
+
+ The following table shows an input event in the left column and an
+ output event in the right column. Past the input event into the
+ console where APEX is running, and the output event should appear in
+ the console. Pasting the input event multiple times will produce
+ output events with different values.
+
++-------------------------------------------------------------+-------------------------------------------------------------+
+| Input Event | Example Output Event |
++=============================================================+=============================================================+
+| .. container:: | .. container:: |
+| | |
+| .. container:: content | .. container:: content |
+| | |
+| .. code:: | .. code:: |
+| :number-lines: | :number-lines: |
+| | |
+| { | { |
+| "nameSpace": "org.onap.policy.apex.sample.events", | "name": "Event0004", |
+| "name": "Event0000", | "version": "0.0.1", |
+| "version": "0.0.1", | "nameSpace": "org.onap.policy.apex.sample.events", |
+| "source": "test", | "source": "Act", |
+| "target": "apex", | "target": "Outside", |
+| "TestSlogan": "Test slogan for External Event0", | "TestActCaseSelected": 2, |
+| "TestMatchCase": 0, | "TestActStateTime": 1536157104627, |
+| "TestTimestamp": 1469781869269, | "TestDecideCaseSelected": 0, |
+| "TestTemperature": 9080.866 | "TestDecideStateTime": 1536157104625, |
+| } | "TestEstablishCaseSelected": 0, |
+| | "TestEstablishStateTime": 1536157104623, |
+| | "TestMatchCase": 0, |
+| | "TestMatchCaseSelected": 1, |
+| | "TestMatchStateTime": 1536157104620, |
+| | "TestSlogan": "Test slogan for External Event0", |
+| | "TestTemperature": 9080.866, |
+| | "TestTimestamp": 1469781869269 |
+| | } |
++-------------------------------------------------------------+-------------------------------------------------------------+
+
+.. container:: paragraph
+
+ Terminate APEX by simply using ``CTRL+C`` in the console.
+
+Verify a Full Installation - REST Editor
+########################################
+
+ .. container:: paragraph
+
+ APEX has a REST application for viewing policy models. The
+ application can also be used to create new policy models close to
+ the engine native policy language. Start the REST editor as
+ follows.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ # $APEX_HOME/bin/apexApps.sh rest-editor
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ >%APEX_HOME%\bin\apexApps.bat rest-editor
+
+.. container:: paragraph
+
+ The script will start a simple web server
+ (`Grizzly <https://javaee.github.io/grizzly/>`__) and deploy a
+ ``war`` web archive in it. Once the editor is started, it will be
+ available on ``localhost:18989``. The last few line of the messages
+ should be:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ Apex Editor REST endpoint (ApexEditorMain: Config=[ApexEditorParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=READY) starting at http://localhost:18989/apexservices/ . . .
+ Sep 05, 2018 10:35:57 PM org.glassfish.grizzly.http.server.NetworkListener start
+ INFO: Started listener bound to [localhost:18989]
+ Sep 05, 2018 10:35:57 PM org.glassfish.grizzly.http.server.HttpServer start
+ INFO: [HttpServer] Started.
+ Apex Editor REST endpoint (ApexEditorMain: Config=[ApexEditorParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=RUNNING) started at http://localhost:18989/apexservices/
+
+.. container:: paragraph
+
+ Now open a browser (Firefox, Chrome, Opera, Internet Explorer) and
+ use the URL ``http://localhost:18989/``. This will connect the
+ browser to the started REST editor. The start screen should be as
+ follows.
+
+.. container:: imageblock
+
+ .. container:: content
+
+ |REST Editor Start Screen|
+
+ .. container:: title
+
+ Figure 1. REST Editor Start Screen
+
+.. container:: paragraph
+
+ Now load a policy model by clicking the menu ``File`` and then
+ ``Open``. In the opened dialog, go to the directory where APEX is
+ installed, then ``examples``, ``models``, ``SampleDomain``, and there
+ select the file ``SamplePolicyModelJAVA.json``. This will load the
+ policy model used to verify the policy engine (see above). Once
+ loaded, the screen should look as follows.
+
+.. container:: imageblock
+
+ .. container:: content
+
+ |REST Editor with loaded SampleDomain Policy Model|
+
+ .. container:: title
+
+ Figure 2. REST Editor with loaded SampleDomain Policy Model
+
+.. container:: paragraph
+
+ Now you can use the REST editor. To finish this verification, simply
+ terminate your browser (or the tab), and then use ``CTRL+C`` in the
+ console where you started the REST editor.
+
+Installing WAR Applications
+---------------------------
+
+ .. container:: paragraph
+
+ APEX comes with a set of WAR files. These are complete
+ applications that can be installed and run in an application
+ server. All of these applications are realized as servlets. You
+ can find the WAR applications in ``$APEX_HOME/war`` (UNIX, Cygwin)
+ or ``%APEX_HOME%\war`` (Windows).
+
+ .. container:: paragraph
+
+ Installing and using the WAR applications requires a web server
+ that can execute ``war`` web archives. We recommend to use `Apache
+ Tomcat <https://tomcat.apache.org/>`__, however other web servers
+ can be used as well.
+
+ .. container:: paragraph
+
+ Install Apache Tomcat including the ``Manager App``, see `V9.0
+ Docs <https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html#Configuring_Manager_Application_Access>`__
+ for details. Start the Tomcat service, or make sure that Tomcat is
+ running.
+
+ .. container:: paragraph
+
+ There are multiple ways to install the APEX WAR applications:
+
+ .. container:: ulist
+
+ - copy the ``.war`` file into the Tomcat ``webapps`` folder
+
+ - use the Tomcat ``Manager App`` to deploy via the web interface
+
+ - deploy using a REST call to Tomcat
+
+ .. container:: paragraph
+
+ For details on how to install ``war`` files please consult the
+ `Tomcat
+ Documentation <https://tomcat.apache.org/tomcat-9.0-doc/index.html>`__
+ or the `Manager App
+ HOW-TO <https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html>`__.
+ Once you installed an APEX WAR application (and wait for
+ sufficient time for Tomcat to finalize the installation), open the
+ ``Manager App`` in Tomcat. You should see the APEX WAR application
+ being installed and running.
+
+ .. container:: paragraph
+
+ In case of errors, examine the log files in the Tomcat log
+ directory. In a conventional install, those log files are in the
+ logs directory where Tomcat is installed.
+
+ .. container:: paragraph
+
+ The current APEX version provides the following WAR applications:
+
+ .. container:: ulist
+
+ - client-deployment-2.0.0-SNAPSHOT.war - a client to deploy new
+ policy models to a running engine
+
+ - client-editor-2.0.0-SNAPSHOT.war - the standard policy REST
+ editor GUI
+
+ - client-monitoring-2.0.0-SNAPSHOT.war - a client for monitoring
+ a running APEX engine
+
+ - client-full-2.0.0-SNAPSHOT.war - a full client with a
+ one-stop-access to deployment, monitoring, and REST editor
+
+ - examples-servlet-2.0.0-SNAPSHOT.war - an example APEX servlet
+
+Running APEX in Docker
+----------------------
+
+ .. container:: paragraph
+
+ Since APEX is in ONAP, we provide a full virtualization
+ environment for the engine.
+
+Run in ONAP
+###########
+
+ .. container:: paragraph
+
+ Running APEX from the ONAP docker repository only requires 2
+ commands:
+
+ .. container:: olist arabic
+
+ #. Log into the ONAP docker repo
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ ::
+
+ docker login -u docker -p docker nexus3.onap.org:10003
+
+ .. container:: olist arabic
+
+ #. Run the APEX docker image
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ ::
+
+ docker run -it --rm nexus3.onap.org:10003/onap/policy-apex-pdp:latest
+
+Build a Docker Image
+####################
+
+ .. container:: paragraph
+
+ Alternatively, one can use the Dockerfile defined in the Docker
+ package to build an image.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ APEX Dockerfile
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ #
+ # Docker file to build an image that runs APEX on Java 8 in Ubuntu
+ #
+ FROM ubuntu:16.04
+
+ RUN apt-get update && \
+ apt-get upgrade -y && \
+ apt-get install -y software-properties-common && \
+ add-apt-repository ppa:openjdk-r/ppa -y && \
+ apt-get update && \
+ apt-get install -y openjdk-8-jdk
+
+ # Create apex user and group
+ RUN groupadd apexuser
+ RUN useradd --create-home -g apexuser apexuser
+
+ # Add Apex-specific directories and set ownership as the Apex admin user
+ RUN mkdir -p /opt/app/policy/apex-pdp
+ RUN mkdir -p /var/log/onap/policy/apex-pdp
+ RUN chown -R apexuser:apexuser /var/log/onap/policy/apex-pdp
+
+ # Unpack the tarball
+ RUN mkdir /packages
+ COPY apex-pdp-package-full.tar.gz /packages
+ RUN tar xvfz /packages/apex-pdp-package-full.tar.gz --directory /opt/app/policy/apex-pdp
+ RUN rm /packages/apex-pdp-package-full.tar.gz
+
+ # Ensure everything has the correct permissions
+ RUN find /opt/app -type d -perm 755
+ RUN find /opt/app -type f -perm 644
+ RUN chmod a+x /opt/app/policy/apex-pdp/bin/*
+
+ # Copy examples to Apex user area
+ RUN cp -pr /opt/app/policy/apex-pdp/examples /home/apexuser
+
+ RUN apt-get clean
+
+ RUN chown -R apexuser:apexuser /home/apexuser/*
+
+ USER apexuser
+ ENV PATH /opt/app/policy/apex-pdp/bin:$PATH
+ WORKDIR /home/apexuser
+
+APEX Configurations Explained
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Introduction to APEX Configuration
+----------------------------------
+
+ .. container:: paragraph
+
+ An APEX engine can be configured to use various combinations
+ of event input handlers, event output handlers, event
+ protocols, context handlers, and logic executors. The system
+ is build using a plugin architecture. Each configuration
+ option is realized by a plugin, which can be loaded and
+ configured when the engine is started. New plugins can be
+ added to the system at any time, though to benefit from a
+ new plugin an engine will need to be restarted.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |APEX Configuration Matrix|
+
+ .. container:: title
+
+ Figure 3. APEX Configuration Matrix
+
+ .. container:: paragraph
+
+ The APEX distribution already comes with a number of
+ plugins. The figure above shows the provided plugins. Any
+ combination of input, output, event protocol, context
+ handlers, and executors is possible.
+
+General Configuration Format
+----------------------------
+
+ .. container:: paragraph
+
+ The APEX configuration file is a JSON file containing a few
+ main blocks for different parts of the configuration. Each
+ block then holds the configuration details. The following
+ code shows the main blocks:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ {
+ "engineServiceParameters":{
+ ... (1)
+ "engineParameters":{ (2)
+ "engineParameters":{...}, (3)
+ "contextParameters":{...} (4)
+ }
+ },
+ "eventInputParameters":{ (5)
+ "input1":{ (6)
+ "carrierTechnologyParameters":{...},
+ "eventProtocolParameters":{...}
+ },
+ "input2":{...}, (7)
+ "carrierTechnologyParameters":{...},
+ "eventProtocolParameters":{...}
+ },
+ ... (8)
+ },
+ "eventOutputParameters":{ (9)
+ "output1":{ (10)
+ "carrierTechnologyParameters":{...},
+ "eventProtocolParameters":{...}
+ },
+ "output2":{ (11)
+ "carrierTechnologyParameters":{...},
+ "eventProtocolParameters":{...}
+ },
+ ... (12)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | main engine configuration |
+ +-----------------------------------+-----------------------------------+
+ | **2** | engine parameters for plugin |
+ | | configurations (execution |
+ | | environments and context |
+ | | handling) |
+ +-----------------------------------+-----------------------------------+
+ | **3** | engine specific parameters, |
+ | | mainly for executor plugins |
+ +-----------------------------------+-----------------------------------+
+ | **4** | context specific parameters, e.g. |
+ | | for context schemas, persistence, |
+ | | etc. |
+ +-----------------------------------+-----------------------------------+
+ | **5** | configuration of the input |
+ | | interface |
+ +-----------------------------------+-----------------------------------+
+ | **6** | an example input called |
+ | | ``input1`` with carrier |
+ | | technology and event protocol |
+ +-----------------------------------+-----------------------------------+
+ | **7** | an example input called |
+ | | ``input2`` with carrier |
+ | | technology and event protocol |
+ +-----------------------------------+-----------------------------------+
+ | **8** | any further input configuration |
+ +-----------------------------------+-----------------------------------+
+ | **9** | configuration of the output |
+ | | interface |
+ +-----------------------------------+-----------------------------------+
+ | **10** | an example output called |
+ | | ``output1`` with carrier |
+ | | technology and event protocol |
+ +-----------------------------------+-----------------------------------+
+ | **11** | an example output called |
+ | | ``output2`` with carrier |
+ | | technology and event protocol |
+ +-----------------------------------+-----------------------------------+
+ | **12** | any further output configuration |
+ +-----------------------------------+-----------------------------------+
+
+Engine Service Parameters
+-------------------------
+
+ .. container:: paragraph
+
+ The configuration provides a number of parameters to
+ configure the engine. An example configuration with
+ explanations of all options is shown below.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "engineServiceParameters" : {
+ "name" : "AADMApexEngine", (1)
+ "version" : "0.0.1", (2)
+ "id" : 45, (3)
+ "instanceCount" : 4, (4)
+ "deploymentPort" : 12345, (5)
+ "policyModelFileName" : "examples/models/VPN/VPNPolicyModelJava.json", (6)
+ "periodicEventPeriod": 1000, (7)
+ "engineParameters":{ (8)
+ "engineParameters":{...}, (9)
+ "contextParameters":{...} (10)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | a name for the engine. The engine |
+ | | name is used to create a key in a |
+ | | runtime engine. An name matching |
+ | | the following regular expression |
+ | | can be used here: |
+ | | ``[A-Za-z0-9\\-_\\.]+`` |
+ +-----------------------------------+-----------------------------------+
+ | **2** | a version of the engine, use |
+ | | semantic versioning as explained |
+ | | here: `Semantic |
+ | | Versioning <http://semver.org/>`_ |
+ | | _. |
+ | | This version is used in a runtime |
+ | | engine to create a version of the |
+ | | engine. For that reason, the |
+ | | version must match the following |
+ | | regular expression ``[A-Z0-9.]+`` |
+ +-----------------------------------+-----------------------------------+
+ | **3** | a numeric identifier for the |
+ | | engine |
+ +-----------------------------------+-----------------------------------+
+ | **4** | the number of threads (policy |
+ | | instances executed in parallel) |
+ | | the engine should use, use ``1`` |
+ | | for single threaded engines |
+ +-----------------------------------+-----------------------------------+
+ | **5** | the port for the deployment |
+ | | Websocket connection to the |
+ | | engine |
+ +-----------------------------------+-----------------------------------+
+ | **6** | the model file to load into the |
+ | | engine on startup (optional) |
+ +-----------------------------------+-----------------------------------+
+ | **7** | an optional timer for periodic |
+ | | policies, in milliseconds (a |
+ | | defined periodic policy will be |
+ | | executed every ``X`` |
+ | | milliseconds), not used of not |
+ | | set or ``0`` |
+ +-----------------------------------+-----------------------------------+
+ | **8** | engine parameters for plugin |
+ | | configurations (execution |
+ | | environments and context |
+ | | handling) |
+ +-----------------------------------+-----------------------------------+
+ | **9** | engine specific parameters, |
+ | | mainly for executor plugins |
+ +-----------------------------------+-----------------------------------+
+ | **10** | context specific parameters, e.g. |
+ | | for context schemas, persistence, |
+ | | etc. |
+ +-----------------------------------+-----------------------------------+
+
+ .. container:: paragraph
+
+ The model file is optional, it can also be specified via
+ command line. In any case, make sure all execution and other
+ required plug-ins for the loaded model are loaded as
+ required.
+
+Input and Output Interfaces
+---------------------------
+
+ .. container:: paragraph
+
+ An APEX engine has two main interfaces:
+
+ .. container:: ulist
+
+ - An *input* interface to receive events: also known as
+ ingress interface or consumer, receiving (consuming)
+ events commonly named triggers, and
+
+ - An *output* interface to publish produced events: also
+ known as egress interface or producer, sending
+ (publishing) events commonly named actions or action
+ events.
+
+ .. container:: paragraph
+
+ The input and output interface is configured in terms of
+ inputs and outputs, respectively. Each input and output is a
+ combination of a carrier technology and an event protocol.
+ Carrier technologies and event protocols are provided by
+ plugins, each with its own specific configuration. Most
+ carrier technologies can be configured for input as well as
+ output. Most event protocols can be used for all carrier
+ technologies. One exception is the JMS object event
+ protocol, which can only be used for the JMS carrier
+ technology. Some further restrictions apply (for instance
+ for carrier technologies using bi- or uni-directional
+ modes).
+
+ .. container:: paragraph
+
+ Input and output interface can be configured separately, in
+ isolation, with any number of carrier technologies. The
+ resulting general configuration options are:
+
+ .. container:: ulist
+
+ - Input interface with one or more inputs
+
+ .. container:: ulist
+
+ - each input with a carrier technology and an event
+ protocol
+
+ - some inputs with optional synchronous mode
+
+ - some event protocols with additional parameters
+
+ - Output interface with one or more outputs
+
+ .. container:: ulist
+
+ - each output with a carrier technology and an event
+ encoding
+
+ - some outputs with optional synchronous mode
+
+ - some event protocols with additional parameters
+
+ .. container:: paragraph
+
+ The configuration for input and output is contained in
+ ``eventInputParameters`` and ``eventOutputParameters``,
+ respectively. Inside here, one can configure any number of
+ inputs and outputs. Each of them needs to have a unique
+ identifier (name), the content of the name is free form. The
+ example below shows a configuration for two inputs and two
+ outputs.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventInputParameters": { (1)
+ "FirstConsumer": { (2)
+ "carrierTechnologyParameters" : {...}, (3)
+ "eventProtocolParameters":{...}, (4)
+ ... (5)
+ },
+ "SecondConsumer": { (6)
+ "carrierTechnologyParameters" : {...}, (7)
+ "eventProtocolParameters":{...}, (8)
+ ... (9)
+ },
+ },
+ "eventOutputParameters": { (10)
+ "FirstProducer": { (11)
+ "carrierTechnologyParameters":{...}, (12)
+ "eventProtocolParameters":{...}, (13)
+ ... (14)
+ },
+ "SecondProducer": { (15)
+ "carrierTechnologyParameters":{...}, (16)
+ "eventProtocolParameters":{...}, (17)
+ ... (18)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +--------+--------------------------------------------------------------------+
+ | **1** | input interface configuration, APEX input plugins |
+ +--------+--------------------------------------------------------------------+
+ | **2** | first input called ``FirstConsumer`` |
+ +--------+--------------------------------------------------------------------+
+ | **3** | carrier technology for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **4** | event protocol for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **5** | any other input configuration (e.g. event name filter, see below) |
+ +--------+--------------------------------------------------------------------+
+ | **6** | second input called ``SecondConsumer`` |
+ +--------+--------------------------------------------------------------------+
+ | **7** | carrier technology for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **8** | event protocol for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **9** | any other plugin configuration |
+ +--------+--------------------------------------------------------------------+
+ | **10** | output interface configuration, APEX output plugins |
+ +--------+--------------------------------------------------------------------+
+ | **11** | first output called ``FirstProducer`` |
+ +--------+--------------------------------------------------------------------+
+ | **12** | carrier technology for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **13** | event protocol for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **14** | any other plugin configuration |
+ +--------+--------------------------------------------------------------------+
+ | **15** | second output called ``SecondProducer`` |
+ +--------+--------------------------------------------------------------------+
+ | **16** | carrier technology for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **17** | event protocol for plugin |
+ +--------+--------------------------------------------------------------------+
+ | **18** | any other output configuration (e.g. event name filter, see below) |
+ +--------+--------------------------------------------------------------------+
+
+Event Filters
+#############
+
+ .. container:: paragraph
+
+ APEX will always send an event after a policy execution
+ is finished. For a successful execution, the event sent
+ is the output event created by the policy. In case the
+ policy does not create an output event, APEX will create
+ a new event with all input event fields plus an
+ additional field ``exceptionMessage`` with an exception
+ message.
+
+ .. container:: paragraph
+
+ There are situations in which this auto-generated error
+ event might not be required or wanted:
+
+ .. container:: ulist
+
+ - when a policy failing should not result in an event
+ send out via an output interface
+
+ - when the auto-generated event goes back in an APEX
+ engine (or the same APEX engine), this can create
+ endless loops
+
+ - the auto-generated event should go to a special output
+ interface or channel
+
+ .. container:: paragraph
+
+ All of these situations are supported by a filter option
+ using a wildecard (regular expression) configuration on
+ APEX I/O interfaces. The parameter is called
+ ``eventNameFilter`` and the value are `Java regular
+ expressions <https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html>`__
+ (a
+ `tutorial <http://www.vogella.com/tutorials/JavaRegularExpressions/article.html>`__).
+ The following code shows some examples:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventInputParameters": {
+ "Input1": {
+ "carrierTechnologyParameters" : {...},
+ "eventProtocolParameters":{...},
+ "eventNameFilter" : "^E[Vv][Ee][Nn][Tt][0-9]004$" (1)
+ }
+ },
+ "eventOutputParameters": {
+ "Output1": {
+ "carrierTechnologyParameters":{...},
+ "eventProtocolParameters":{...},
+ "eventNameFilter" : "^E[Vv][Ee][Nn][Tt][0-9]104$" (2)
+ }
+ }
+
+Executors
+---------
+
+ .. container:: paragraph
+
+ Executors are plugins that realize the execution of logic
+ contained in a policy model. Logic can be in a task
+ selector, a task, and a state finalizer. Using plugins for
+ execution environments makes APEX very flexible to support
+ virtually any executable logic expressions.
+
+ .. container:: paragraph
+
+ APEX 2.0.0-SNAPSHOT supports the following executors:
+
+ .. container:: ulist
+
+ - Java, for Java implemented logic
+
+ .. container:: ulist
+
+ - This executor requires logic implemented using the
+ APEX Java interfaces.
+
+ - Generated JAR files must be in the classpath of the
+ APEX engine at start time.
+
+ - Javascript
+
+ - JRuby,
+
+ - Jython,
+
+ - MVEL
+
+ .. container:: ulist
+
+ - This executor uses the latest version of the MVEL
+ engine, which can be very hard to debug and can
+ produce unwanted side effects during execution
+
+Configure the Javascript Executor
+#################################
+
+ .. container:: paragraph
+
+ The Javascript executor is added to the configuration as
+ follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "engineServiceParameters":{
+ "engineParameters":{
+ "executorParameters":{
+ "JAVASCRIPT":{
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"
+ }
+ }
+ }
+ }
+
+Configure the Jython Executor
+#############################
+
+ .. container:: paragraph
+
+ The Jython executor is added to the configuration as
+ follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "engineServiceParameters":{
+ "engineParameters":{
+ "executorParameters":{
+ "JYTHON":{
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.jython.JythonExecutorParameters"
+ }
+ }
+ }
+ }
+
+Configure the JRuby Executor
+############################
+
+ .. container:: paragraph
+
+ The JRuby executor is added to the configuration as
+ follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "engineServiceParameters":{
+ "engineParameters":{
+ "executorParameters":{
+ "JRUBY":{
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.jruby.JrubyExecutorParameters"
+ }
+ }
+ }
+ }
+
+Configure the Java Executor
+###########################
+
+ .. container:: paragraph
+
+ The Java executor is added to the configuration as
+ follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "engineServiceParameters":{
+ "engineParameters":{
+ "executorParameters":{
+ "JAVA":{
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.java.JavaExecutorParameters"
+ }
+ }
+ }
+ }
+
+Configure the MVEL Executor
+###########################
+
+ .. container:: paragraph
+
+ The MVEL executor is added to the configuration as
+ follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "engineServiceParameters":{
+ "engineParameters":{
+ "executorParameters":{
+ "MVEL":{
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.mvel.MVELExecutorParameters"
+ }
+ }
+ }
+ }
+
+Context Handlers
+----------------
+
+ .. container:: paragraph
+
+ Context handlers are responsible for all context processing.
+ There are the following main areas:
+
+ .. container:: ulist
+
+ - Context schema: use schema handlers other than Java class
+ (supported by default without configuration)
+
+ - Context distribution: distribute context across multiple
+ APEX engines
+
+ - Context locking: mechanisms to lock context elements for
+ read/write
+
+ - Context persistence: mechanisms to persist context
+
+ .. container:: paragraph
+
+ APEX provides plugins for each of the main areas.
+
+Configure AVRO Schema Handler
+#############################
+
+ .. container:: paragraph
+
+ The AVRO schema handler is added to the configuration as
+ follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "engineServiceParameters":{
+ "engineParameters":{
+ "contextParameters":{
+ "parameterClassName" : "org.onap.policy.apex.context.parameters.ContextParameters",
+ "schemaParameters":{
+ "Avro":{
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters"
+ }
+ }
+ }
+ }
+ }
+
+ .. container:: paragraph
+
+ Using the AVRO schema handler has one limitation: AVRO
+ only supports field names that represent valid Java class
+ names. This means only letters and the character ``_``
+ are supported. Characters commonly used in field names,
+ such as ``.`` and ``-``, are not supported by AVRO. for
+ more information see `Avro Spec:
+ Names <https://avro.apache.org/docs/1.8.1/spec.html#names>`__.
+
+ .. container:: paragraph
+
+ To work with this limitation, the APEX Avro plugin will
+ parse a given AVRO definition and replace *all*
+ occurrences of ``.`` and ``-`` with a ``_``. This means
+ that
+
+ .. container:: ulist
+
+ - In a policy model, if the AVRO schema defined a field
+ as ``my-name`` the policy logic should access it as
+ ``my_name``
+
+ - In a policy model, if the AVRO schema defined a field
+ as ``my.name`` the policy logic should access it as
+ ``my_name``
+
+ - There should be no field names that convert to the
+ same internal name
+
+ .. container:: ulist
+
+ - For instance the simultaneous use of
+ ``my_name``, ``my.name``, and ``my-name`` should
+ be avoided
+
+ - If not avoided, the event processing might
+ create unwanted side effects
+
+ - If field names use any other not-supported character,
+ the AVRO plugin will reject it
+
+ .. container:: ulist
+
+ - Since AVRO uses lazy initialization, this
+ rejection might only become visible at runtime
+
+Carrier Technologies
+--------------------
+
+ .. container:: paragraph
+
+ Carrier technologies define how APEX receives (input) and
+ sends (output) events. They can be used in any combination,
+ using asynchronous or synchronous mode. There can also be
+ any number of carrier technologies for the input (consume)
+ and the output (produce) interface.
+
+ .. container:: paragraph
+
+ Supported *input* technologies are:
+
+ .. container:: ulist
+
+ - Standard input, read events from the standard input
+ (console), not suitable for APEX background servers
+
+ - File input, read events from a file
+
+ - Kafka, read events from a Kafka system
+
+ - Websockets, read events from a Websocket
+
+ - JMS,
+
+ - REST (synchronous and asynchronous), additionally as
+ client or server
+
+ - Event Requestor, allows reading of events that have been
+ looped back into APEX
+
+ .. container:: paragraph
+
+ Supported *output* technologies are:
+
+ .. container:: ulist
+
+ - Standard output, write events to the standard output
+ (console), not suitable for APEX background servers
+
+ - File output, write events to a file
+
+ - Kafka, write events to a Kafka system
+
+ - Websockets, write events to a Websocket
+
+ - JMS
+
+ - REST (synchronous and asynchronous), additionally as
+ client or server
+
+ - Event Requestor, allows events to be looped back into
+ APEX
+
+ .. container:: paragraph
+
+ New carrier technologies can be added as plugins to APEX or
+ developed outside APEX and added to an APEX deployment.
+
+Standard IO
+###########
+
+ .. container:: paragraph
+
+ Standard IO does not require a specific plugin, it is
+ supported be default.
+
+Standard Input
+==============
+ .. container:: paragraph
+
+ APEX will take events from its standard input. This
+ carrier is good for testing, but certainly not for a
+ use case where APEX runs as a server. The
+ configuration is as follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ ::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE", (1)
+ "parameters" : {
+ "standardIO" : true (2)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+---------------------------------------+
+ | **1** | standard input is considered a file |
+ +-------+---------------------------------------+
+ | **2** | file descriptor set to standard input |
+ +-------+---------------------------------------+
+
+Standard Output
+===============
+
+ .. container:: paragraph
+
+ APEX will send events to its standard output. This
+ carrier is good for testing, but certainly not for a
+ use case where APEX runs as a server. The
+ configuration is as follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE", (1)
+ "parameters" : {
+ "standardIO" : true (2)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+----------------------------------------+
+ | **1** | standard output is considered a file |
+ +-------+----------------------------------------+
+ | **2** | file descriptor set to standard output |
+ +-------+----------------------------------------+
+
+2.7.2. File IO
+##############
+
+ .. container:: paragraph
+
+ File IO does not require a specific plugin, it is
+ supported be default.
+
+File Input
+==========
+
+ .. container:: paragraph
+
+ APEX will take events from a file. The same file
+ should not be used as an output. The configuration is
+ as follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE", (1)
+ "parameters" : {
+ "fileName" : "examples/events/SampleDomain/EventsIn.xmlfile" (2)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+------------------------------------------+
+ | **1** | set file input |
+ +-------+------------------------------------------+
+ | **2** | the name of the file to read events from |
+ +-------+------------------------------------------+
+
+File Output
+===========
+ .. container:: paragraph
+
+ APEX will write events to a file. The same file should
+ not be used as an input. The configuration is as
+ follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE", (1)
+ "parameters" : {
+ "fileName" : "examples/events/SampleDomain/EventsOut.xmlfile" (2)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+-----------------------------------------+
+ | **1** | set file output |
+ +-------+-----------------------------------------+
+ | **2** | the name of the file to write events to |
+ +-------+-----------------------------------------+
+
+Event Requestor IO
+##################
+
+ .. container:: paragraph
+
+ Event Requestor IO does not require a specific plugin, it
+ is supported be default. It should only be used with the
+ APEX event protocol.
+
+Event Requestor Input
+=====================
+
+ .. container:: paragraph
+
+ APEX will take events from APEX.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology": "EVENT_REQUESTOR" (1)
+ }
+
+ .. container:: colist arabic
+
+ +-------+---------------------------+
+ | **1** | set event requestor input |
+ +-------+---------------------------+
+
+Event Requestor Output
+======================
+
+ .. container:: paragraph
+
+ APEX will write events to APEX.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology": "EVENT_REQUESTOR" (1)
+ }
+
+Peering Event Requestors
+========================
+
+ .. container:: paragraph
+
+ When using event requestors, they need to be peered.
+ This means an event requestor output needs to be
+ peered (associated) with an event requestor input. The
+ following example shows the use of an event requestor
+ with the APEX event protocol and the peering of output
+ and input.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventInputParameters": {
+ "EventRequestorConsumer": {
+ "carrierTechnologyParameters": {
+ "carrierTechnology": "EVENT_REQUESTOR" (1)
+ },
+ "eventProtocolParameters": {
+ "eventProtocol": "APEX" (2)
+ },
+ "eventNameFilter": "InputEvent", (3)
+ "requestorMode": true, (4)
+ "requestorPeer": "EventRequestorProducer", (5)
+ "requestorTimeout": 500 (6)
+ }
+ },
+ "eventOutputParameters": {
+ "EventRequestorProducer": {
+ "carrierTechnologyParameters": {
+ "carrierTechnology": "EVENT_REQUESTOR" (7)
+ },
+ "eventProtocolParameters": {
+ "eventProtocol": "APEX" (8)
+ },
+ "eventNameFilter": "EventListEvent", (9)
+ "requestorMode": true, (10)
+ "requestorPeer": "EventRequestorConsumer", (11)
+ "requestorTimeout": 500 (12)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | event requestor on a consumer |
+ +-----------------------------------+-----------------------------------+
+ | **2** | with APEX event protocol |
+ +-----------------------------------+-----------------------------------+
+ | **3** | optional filter (best to use a |
+ | | filter to prevent unwanted events |
+ | | on the consumer side) |
+ +-----------------------------------+-----------------------------------+
+ | **4** | activate requestor mode |
+ +-----------------------------------+-----------------------------------+
+ | **5** | the peer to the output (must |
+ | | match the output carrier) |
+ +-----------------------------------+-----------------------------------+
+ | **6** | an optional timeout in |
+ | | milliseconds |
+ +-----------------------------------+-----------------------------------+
+ | **7** | event requestor on a producer |
+ +-----------------------------------+-----------------------------------+
+ | **8** | with APEX event protocol |
+ +-----------------------------------+-----------------------------------+
+ | **9** | optional filter (best to use a |
+ | | filter to prevent unwanted events |
+ | | on the consumer side) |
+ +-----------------------------------+-----------------------------------+
+ | **10** | activate requestor mode |
+ +-----------------------------------+-----------------------------------+
+ | **11** | the peer to the output (must |
+ | | match the input carrier) |
+ +-----------------------------------+-----------------------------------+
+ | **12** | an optional timeout in |
+ | | milliseconds |
+ +-----------------------------------+-----------------------------------+
+
+Kafka IO
+########
+
+ .. container:: paragraph
+
+ Kafka IO is supported by the APEX Kafka plugin. The
+ configurations below are examples. APEX will take any
+ configuration inside the parameter object and forward it
+ to Kafka. More information on Kafka specific
+ configuration parameters can be found in the Kafka
+ documentation:
+
+ .. container:: ulist
+
+ - `Kafka Consumer
+ Class <https://kafka.apache.org/090/javadoc/org/apache/kafka/clients/consumer/KafkaConsumer.html>`__
+
+ - `Kafka Producer
+ Class <https://kafka.apache.org/090/javadoc/org/apache/kafka/clients/producer/KafkaProducer.html>`__
+
+Kafka Input
+===========
+ .. container:: paragraph
+
+ APEX will receive events from the Apache Kafka
+ messaging system. The input is uni-directional, an
+ engine will only receive events from the input but not
+ send any event to the input.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "KAFKA", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.kafka.KAFKACarrierTechnologyParameters",
+ "parameters" : {
+ "bootstrapServers" : "localhost:49092", (2)
+ "groupId" : "apex-group-id", (3)
+ "enableAutoCommit" : true, (4)
+ "autoCommitTime" : 1000, (5)
+ "sessionTimeout" : 30000, (6)
+ "consumerPollTime" : 100, (7)
+ "consumerTopicList" : ["apex-in-0", "apex-in-1"], (8)
+ "keyDeserializer" :
+ "org.apache.kafka.common.serialization.StringDeserializer", (9)
+ "valueDeserializer" :
+ "org.apache.kafka.common.serialization.StringDeserializer" (10)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +--------+-------------------------------------+
+ | **1** | set Kafka as carrier technology |
+ +--------+-------------------------------------+
+ | **2** | bootstrap server and port |
+ +--------+-------------------------------------+
+ | **3** | a group identifier |
+ +--------+-------------------------------------+
+ | **4** | flag for auto-commit |
+ +--------+-------------------------------------+
+ | **5** | auto-commit timeout in milliseconds |
+ +--------+-------------------------------------+
+ | **6** | session timeout in milliseconds |
+ +--------+-------------------------------------+
+ | **7** | consumer poll time in milliseconds |
+ +--------+-------------------------------------+
+ | **8** | consumer topic list |
+ +--------+-------------------------------------+
+ | **9** | key for the Kafka de-serializer |
+ +--------+-------------------------------------+
+ | **10** | value for the Kafka de-serializer |
+ +--------+-------------------------------------+
+
+Kafka Output
+============
+ .. container:: paragraph
+
+ APEX will send events to the Apache Kafka messaging
+ system. The output is uni-directional, an engine will
+ send events to the output but not receive any event
+ from the output.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "KAFKA", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.kafka.KAFKACarrierTechnologyParameters",
+ "parameters" : {
+ "bootstrapServers" : "localhost:49092", (2)
+ "acks" : "all", (3)
+ "retries" : 0, (4)
+ "batchSize" : 16384, (5)
+ "lingerTime" : 1, (6)
+ "bufferMemory" : 33554432, (7)
+ "producerTopic" : "apex-out", (8)
+ "keySerializer" :
+ "org.apache.kafka.common.serialization.StringSerializer", (9)
+ "valueSerializer" :
+ "org.apache.kafka.common.serialization.StringSerializer" (10)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +--------+---------------------------------+
+ | **1** | set Kafka as carrier technology |
+ +--------+---------------------------------+
+ | **2** | bootstrap server and port |
+ +--------+---------------------------------+
+ | **3** | acknowledgement strategy |
+ +--------+---------------------------------+
+ | **4** | number of retries |
+ +--------+---------------------------------+
+ | **5** | batch size |
+ +--------+---------------------------------+
+ | **6** | time to linger in milliseconds |
+ +--------+---------------------------------+
+ | **7** | buffer memory in byte |
+ +--------+---------------------------------+
+ | **8** | producer topic |
+ +--------+---------------------------------+
+ | **9** | key for the Kafka serializer |
+ +--------+---------------------------------+
+ | **10** | value for the Kafka serializer |
+ +--------+---------------------------------+
+
+JMS IO
+#######
+
+ .. container:: paragraph
+
+ APEX supports the Java Messaging Service (JMS) as input
+ as well as output. JMS IO is supported by the APEX JMS
+ plugin. Input and output support an event encoding as
+ text (JSON string) or object (serialized object). The
+ input configuration is the same for both encodings, the
+ output configuration differs.
+
+JMS Input
+=========
+ .. container:: paragraph
+
+ APEX will receive events from a JMS messaging system.
+ The input is uni-directional, an engine will only
+ receive events from the input but not send any event
+ to the input.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "JMS", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.jms.JMSCarrierTechnologyParameters",
+ "parameters" : { (2)
+ "initialContextFactory" :
+ "org.jboss.naming.remote.client.InitialContextFactory", (3)
+ "connectionFactory" : "ConnectionFactory", (4)
+ "providerURL" : "remote://localhost:5445", (5)
+ "securityPrincipal" : "guest", (6)
+ "securityCredentials" : "IAmAGuest", (7)
+ "consumerTopic" : "jms/topic/apexIn" (8)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | set JMS as carrier technology |
+ +-----------------------------------+-----------------------------------+
+ | **2** | set all JMS specific parameters |
+ +-----------------------------------+-----------------------------------+
+ | **3** | the context factory, in this case |
+ | | from JBOSS (it requires the |
+ | | dependency |
+ | | org.jboss:jboss-remote-naming:2.0 |
+ | | .4.Final |
+ | | or a different version to be in |
+ | | the directory ``$APEX_HOME/lib`` |
+ | | or ``%APEX_HOME%\lib`` |
+ +-----------------------------------+-----------------------------------+
+ | **4** | a connection factory for the JMS |
+ | | connection |
+ +-----------------------------------+-----------------------------------+
+ | **5** | URL with host and port of the JMS |
+ | | provider |
+ +-----------------------------------+-----------------------------------+
+ | **6** | access credentials, user name |
+ +-----------------------------------+-----------------------------------+
+ | **7** | access credentials, user password |
+ +-----------------------------------+-----------------------------------+
+ | **8** | the JMS topic to listen to |
+ +-----------------------------------+-----------------------------------+
+
+JMS Output with Text
+====================
+
+ .. container:: paragraph
+
+ APEX engine send events to a JMS messaging system. The
+ output is uni-directional, an engine will send events
+ to the output but not receive any event from output.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "JMS", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.jms.JMSCarrierTechnologyParameters",
+ "parameters" : { (2)
+ "initialContextFactory" :
+ "org.jboss.naming.remote.client.InitialContextFactory", (3)
+ "connectionFactory" : "ConnectionFactory", (4)
+ "providerURL" : "remote://localhost:5445", (5)
+ "securityPrincipal" : "guest", (6)
+ "securityCredentials" : "IAmAGuest", (7)
+ "producerTopic" : "jms/topic/apexOut", (8)
+ "objectMessageSending": "false" (9)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | set JMS as carrier technology |
+ +-----------------------------------+-----------------------------------+
+ | **2** | set all JMS specific parameters |
+ +-----------------------------------+-----------------------------------+
+ | **3** | the context factory, in this case |
+ | | from JBOSS (it requires the |
+ | | dependency |
+ | | org.jboss:jboss-remote-naming:2.0 |
+ | | .4.Final |
+ | | or a different version to be in |
+ | | the directory ``$APEX_HOME/lib`` |
+ | | or ``%APEX_HOME%\lib`` |
+ +-----------------------------------+-----------------------------------+
+ | **4** | a connection factory for the JMS |
+ | | connection |
+ +-----------------------------------+-----------------------------------+
+ | **5** | URL with host and port of the JMS |
+ | | provider |
+ +-----------------------------------+-----------------------------------+
+ | **6** | access credentials, user name |
+ +-----------------------------------+-----------------------------------+
+ | **7** | access credentials, user password |
+ +-----------------------------------+-----------------------------------+
+ | **8** | the JMS topic to write to |
+ +-----------------------------------+-----------------------------------+
+ | **9** | set object messaging to ``false`` |
+ | | means it sends JSON text |
+ +-----------------------------------+-----------------------------------+
+
+JMS Output with Object
+======================
+
+ .. container:: paragraph
+
+ To configure APEX for JMS objects on the output
+ interface use the same configuration as above (for
+ output). Simply change the ``objectMessageSending``
+ parameter to ``true``.
+
+Websocket (WS) IO
+########################
+
+ .. container:: paragraph
+
+ APEX supports the Websockets as input as well as output.
+ WS IO is supported by the APEX Websocket plugin. This
+ carrier technology does only support uni-directional
+ communication. APEX will not send events to a Websocket
+ input and any event sent to a Websocket output will
+ result in an error log.
+
+ .. container:: paragraph
+
+ The input can be configured as client (APEX connects to
+ an existing Websocket server) or server (APEX starts a
+ Websocket server). The same applies to the output. Input
+ and output can both use a client or a server
+ configuration, or separate configurations (input as
+ client and output as server, input as server and output
+ as client). Each configuration should use its own
+ dedicated port to avoid any communication loops. The
+ configuration of a Websocket client is the same for input
+ and output. The configuration of a Websocket server is
+ the same for input and output.
+
+Websocket Client
+================
+
+ .. container:: paragraph
+
+ APEX will connect to a given Websocket server. As
+ input, it will receive events from the server but not
+ send any events. As output, it will send events to the
+ server and any event received from the server will
+ result in an error log.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "WEBSOCKET", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.websocket.WEBSOCKETCarrierTechnologyParameters",
+ "parameters" : {
+ "host" : "localhost", (2)
+ "port" : 42451 (3)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+------------------------------------------------------+
+ | **1** | set Websocket as carrier technology |
+ +-------+------------------------------------------------------+
+ | **2** | the host name on which a Websocket server is running |
+ +-------+------------------------------------------------------+
+ | **3** | the port of that Websocket server |
+ +-------+------------------------------------------------------+
+
+Websocket Server
+================
+
+ .. container:: paragraph
+
+ APEX will start a Websocket server, which will accept
+ any Websocket clients to connect. As input, it will
+ receive events from the server but not send any
+ events. As output, it will send events to the server
+ and any event received from the server will result in
+ an error log.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "WEBSOCKET", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.websocket.WEBSOCKETCarrierTechnologyParameters",
+ "parameters" : {
+ "wsClient" : false, (2)
+ "port" : 42450 (3)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+------------------------------------------------------------+
+ | **1** | set Websocket as carrier technology |
+ +-------+------------------------------------------------------------+
+ | **2** | disable client, so that APEX will start a Websocket server |
+ +-------+------------------------------------------------------------+
+ | **3** | the port for the Websocket server APEX will start |
+ +-------+------------------------------------------------------------+
+
+REST Client IO
+##############
+
+ .. container:: paragraph
+
+ APEX can act as REST client on the input as well as on
+ the output interface. The media type is
+ ``application/json``, so this plugin does only work with
+ the JSON Event protocol.
+
+REST Client Input
+=================
+
+ .. container:: paragraph
+
+ APEX will connect to a given URL to receive events,
+ but not send any events. The server is polled, i.e.
+ APEX will do an HTTP GET, take the result, and then do
+ the next GET. Any required timing needs to be handled
+ by the server configured via the URL. For instance,
+ the server could support a wait timeout via the URL as
+ ``?timeout=100ms``.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "RESTCLIENT", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.restclient.RESTClientCarrierTechnologyParameters",
+ "parameters" : {
+ "url" : "http://example.org:8080/triggers/events", (2)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+---------------------------------------+
+ | **1** | set REST client as carrier technology |
+ +-------+---------------------------------------+
+ | **2** | the URL of the HTTP server for events |
+ +-------+---------------------------------------+
+
+REST Client Output
+==================
+
+ .. container:: paragraph
+
+ APEX will connect to a given URL to send events, but
+ not receive any events. The default HTTP operation is
+ POST (no configuration required). To change it to PUT
+ simply add the configuration parameter (as shown in
+ the example below).
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "RESTCLIENT", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.restclient.RESTClientCarrierTechnologyParameters",
+ "parameters" : {
+ "url" : "http://example.com:8888/actions/events", (2)
+ "httpMethod" : "PUT" (3)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+--------------------------------------------------+
+ | **1** | set REST client as carrier technology |
+ +-------+--------------------------------------------------+
+ | **2** | the URL of the HTTP server for events |
+ +-------+--------------------------------------------------+
+ | **3** | use HTTP PUT (remove this line to use HTTP POST) |
+ +-------+--------------------------------------------------+
+
+REST Server IO
+##############
+
+ .. container:: paragraph
+
+ APEX supports a REST server for input and output.
+
+ .. container:: paragraph
+
+ The REST server plugin always uses a synchronous mode. A
+ client does a HTTP GET on the APEX REST server with the
+ input event and receives the generated output event in
+ the server reply. This means that for the REST server
+ there has to always to be an input with an associated
+ output. Input or output only are not permitted.
+
+ .. container:: paragraph
+
+ The plugin will start a Grizzly server as REST server for
+ a normal APEX engine. If the APEX engine is executed as a
+ servlet, for instance inside Tomcat, then Tomcat will be
+ used as REST server (this case requires configuration on
+ Tomcat as well).
+
+ .. container:: paragraph
+
+ Some configuration restrictions apply for all scenarios:
+
+ .. container:: ulist
+
+ - Minimum port: 1024
+
+ - Maximum port: 65535
+
+ - The media type is ``application/json``, so this plugin
+ does only work with the JSON Event protocol.
+
+ .. container:: paragraph
+
+ The URL the client calls is created using
+
+ .. container:: ulist
+
+ - the configured host and port, e.g.
+ ``http://localhost:12345``
+
+ - the standard path, e.g. ``/apex/``
+
+ - the name of the input/output, e.g. ``FirstConsumer/``
+
+ - the input or output name, e.g. ``EventIn``.
+
+ .. container:: paragraph
+
+ The examples above lead to the URL
+ ``http://localhost:12345/apex/FirstConsumer/EventIn``.
+
+ .. container:: paragraph
+
+ A client can also get status information of the REST
+ server using ``/Status``, e.g.
+ ``http://localhost:12345/apex/FirstConsumer/Status``.
+
+REST Server Stand-alone
+=======================
+
+ .. container:: paragraph
+
+ We need to configure a REST server input and a REST
+ server output. Input and output are associated with
+ each other via there name.
+
+ .. container:: paragraph
+
+ Timeouts for REST calls need to be set carefully. If
+ they are too short, the call might timeout before a
+ policy finished creating an event.
+
+ .. container:: paragraph
+
+ The following example configures the input named as
+ ``MyConsumer`` and associates an output named
+ ``MyProducer`` with it.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventInputParameters": {
+ "MyConsumer": {
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "RESTSERVER", (1)
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.restserver.RESTServerCarrierTechnologyParameters",
+ "parameters" : {
+ "standalone" : true, (2)
+ "host" : "localhost", (3)
+ "port" : 12345 (4)
+ }
+ },
+ "eventProtocolParameters":{
+ "eventProtocol" : "JSON" (5)
+ },
+ "synchronousMode" : true, (6)
+ "synchronousPeer" : "MyProducer", (7)
+ "synchronousTimeout" : 500 (8)
+ }
+ }
+
+ .. container:: colist arabic
+
+ +-------+---------------------------------------+
+ | **1** | set REST server as carrier technology |
+ +-------+---------------------------------------+
+ | **2** | set the server as stand-alone |
+ +-------+---------------------------------------+
+ | **3** | set the server host |
+ +-------+---------------------------------------+
+ | **4** | set the server listen port |
+ +-------+---------------------------------------+
+ | **5** | use JSON event protocol |
+ +-------+---------------------------------------+
+ | **6** | activate synchronous mode |
+ +-------+---------------------------------------+
+ | **7** | associate an output ``MyProducer`` |
+ +-------+---------------------------------------+
+ | **8** | set a timeout of 500 milliseconds |
+ +-------+---------------------------------------+
+
+ .. container:: paragraph
+
+ The following example configures the output named as
+ ``MyProducer`` and associates the input ``MyConsumer``
+ with it. Note that for the output there are no more
+ paramters (such as host or port), since they are
+ already configured in the associated input
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventOutputParameters": {
+ "MyProducer": {
+ "carrierTechnologyParameters":{
+ "carrierTechnology" : "RESTSERVER",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.restserver.RESTServerCarrierTechnologyParameters"
+ },
+ "eventProtocolParameters":{
+ "eventProtocol" : "JSON"
+ },
+ "synchronousMode" : true,
+ "synchronousPeer" : "MyConsumer",
+ "synchronousTimeout" : 500
+ }
+ }
+
+REST Server Stand-alone, multi input
+====================================
+
+ .. container:: paragraph
+
+ Any number of input/output pairs for REST servers can
+ be configured. For instance, we can configure an input
+ ``FirstConsumer`` with output ``FirstProducer`` and an
+ input ``SecondConsumer`` with output
+ ``SecondProducer``. Important is that there is always
+ one pair of input/output.
+
+REST Server Stand-alone in Servlet
+==================================
+
+ .. container:: paragraph
+
+ If APEX is executed as a servlet, e.g. inside Tomcat,
+ the configuration becomes easier since the plugin can
+ now use Tomcat as the REST server. In this scenario,
+ there are not parameters (port, host, etc.) and the
+ key ``standalone`` must not be used (or set to false).
+
+ .. container:: paragraph
+
+ For the Tomcat configuration, we need to add the REST
+ server plugin, e.g.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <servlet>
+ ...
+ <init-param>
+ ...
+ <param-value>org.onap.policy.apex.plugins.event.carrier.restserver</param-value>
+ </init-param>
+ ...
+ </servlet>
+
+REST Requestor IO
+##################
+
+ .. container:: paragraph
+
+ APEX can act as REST requestor on the input as well as on
+ the output interface. The media type is
+ ``application/json``, so this plugin does only work with
+ the JSON Event protocol.
+
+REST Requestor Input
+====================
+
+ .. container:: paragraph
+
+ APEX will connect to a given URL to request an input.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters": {
+ "carrierTechnology": "RESTREQUESTOR", (1)
+ "parameterClassName": "org.onap.policy.apex.plugins.event.carrier.restrequestor.RESTRequestorCarrierTechnologyParameters",
+ "parameters": {
+ "url": "http://localhost:54321/some/path/to/rest/resource", (2)
+ "httpMethod": "POST", (3)
+ "restRequestTimeout": 2000 (4)
+ }
+ },
+
+ .. container:: colist arabic
+
+ +-------+--------------------------------------------------+
+ | **1** | set REST requestor as carrier technology |
+ +-------+--------------------------------------------------+
+ | **2** | the URL of the HTTP server for events |
+ +-------+--------------------------------------------------+
+ | **3** | use HTTP PUT (remove this line to use HTTP POST) |
+ +-------+--------------------------------------------------+
+ | **4** | request timeout in milliseconds |
+ +-------+--------------------------------------------------+
+
+ .. container:: paragraph
+
+ Further settings are required on the consumer to
+ define the event that is requested, for example:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventName": "GuardResponseEvent", (1)
+ "eventNameFilter": "GuardResponseEvent", (2)
+ "requestorMode": true, (3)
+ "requestorPeer": "GuardRequestorProducer", (4)
+ "requestorTimeout": 500 (5)
+
+ .. container:: colist arabic
+
+ +-------+---------------------------+
+ | **1** | the event name |
+ +-------+---------------------------+
+ | **2** | a filter on the event |
+ +-------+---------------------------+
+ | **3** | the mode of the requestor |
+ +-------+---------------------------+
+ | **4** | a peer for the requestor |
+ +-------+---------------------------+
+ | **5** | a general request timeout |
+ +-------+---------------------------+
+
+REST Requestor Output
+=====================
+
+ .. container:: paragraph
+
+ APEX will connect to a given URL to send events, but
+ not receive any events.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "carrierTechnologyParameters": {
+ "carrierTechnology": "RESTREQUESTOR", (1)
+ "parameterClassName": "org.onap.policy.apex.plugins.event.carrier.restrequestor.RESTRequestorCarrierTechnologyParameters"
+ },
+
+ .. container:: colist arabic
+
+ +-------+------------------------------------------+
+ | **1** | set REST requestor as carrier technology |
+ +-------+------------------------------------------+
+
+ .. container:: paragraph
+
+ Further settings are required on the consumer to
+ define the event that is requested, for example:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventNameFilter": "GuardRequestEvent", (1)
+ "requestorMode": true, (2)
+ "requestorPeer": "GuardRequestorConsumer", (3)
+ "requestorTimeout": 500 (4)
+
+ .. container:: colist arabic
+
+ +-------+---------------------------+
+ | **1** | a filter on the event |
+ +-------+---------------------------+
+ | **2** | the mode of the requestor |
+ +-------+---------------------------+
+ | **3** | a peer for the requestor |
+ +-------+---------------------------+
+ | **4** | a general request timeout |
+ +-------+---------------------------+
+
+Event Protocols, Format and Encoding
+------------------------------------
+
+ .. container:: paragraph
+
+ Event protocols define what event formats APEX can receive
+ (input) and should send (output). They can be used in any
+ combination for input and output, unless further restricted
+ by a carrier technology plugin (for instance for JMS
+ output). There can only be 1 event protocol per event
+ plugin.
+
+ .. container:: paragraph
+
+ Supported *input* event protocols are:
+
+ .. container:: ulist
+
+ - JSON, the event as a JSON string
+
+ - APEX, an APEX event
+
+ - JMS object, the event as a JMS object,
+
+ - JMS text, the event as a JMS text,
+
+ - XML, the event as an XML string,
+
+ - YAML, the event as YAML text
+
+ .. container:: paragraph
+
+ Supported *output* event protocols are:
+
+ .. container:: ulist
+
+ - JSON, the event as a JSON string
+
+ - APEX, an APEX event
+
+ - JMS object, the event as a JMS object,
+
+ - JMS text, the event as a JMS text,
+
+ - XML, the event as an XML string,
+
+ - YAML, the event as YAML text
+
+ .. container:: paragraph
+
+ New event protocols can be added as plugins to APEX or
+ developed outside APEX and added to an APEX deployment.
+
+JSON Event
+##########
+
+ .. container:: paragraph
+
+ The event protocol for JSON encoding does not require a
+ specific plugin, it is supported by default. Furthermore,
+ there is no difference in the configuration for the input
+ and output interface.
+
+ .. container:: paragraph
+
+ For an input, APEX requires a well-formed JSON string.
+ Well-formed here means according to the definitions of a
+ policy. Any JSON string that is not defined as a trigger
+ event (consume) will not be consumed (errors will be
+ thrown). For output JSON events, APEX will always produce
+ valid JSON strings according to the definition in the
+ policy model.
+
+ .. container:: paragraph
+
+ The following JSON shows the configuration.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventProtocolParameters":{
+ "eventProtocol" : "JSON"
+ }
+
+ .. container:: paragraph
+
+ For JSON events, there are a few more optional
+ parameters, which allow to define a mapping for standard
+ event fields. An APEX event must have the fields
+ ``name``, ``version``, ``source``, and ``target``
+ defined. Sometimes it is not possible to configure a
+ trigger or actioning system to use those fields. However,
+ they might be in an event generated outside APEX (or used
+ outside APEX) just with different names. To configure
+ APEX to map between the different event names, simply add
+ the following parameters to a JSON event:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventProtocolParameters":{
+ "eventProtocol" : "JSON",
+ "nameAlias" : "policyName", (1)
+ "versionAlias" : "policyVersion", (2)
+ "sourceAlias" : "from", (3)
+ "targetAlias" : "to", (4)
+ "nameSpaceAlias": "my.name.space" (5)
+ }
+
+ .. container:: colist arabic
+
+ +-----------------------------------+-----------------------------------+
+ | **1** | mapping for the ``name`` field, |
+ | | here from a field called |
+ | | ``policyName`` |
+ +-----------------------------------+-----------------------------------+
+ | **2** | mapping for the ``version`` |
+ | | field, here from a field called |
+ | | ``policyVersion`` |
+ +-----------------------------------+-----------------------------------+
+ | **3** | mapping for the ``source`` field, |
+ | | here from a field called ``from`` |
+ | | (only for an input event) |
+ +-----------------------------------+-----------------------------------+
+ | **4** | mapping for the ``target`` field, |
+ | | here from a field called ``to`` |
+ | | (only for an output event) |
+ +-----------------------------------+-----------------------------------+
+ | **5** | mapping for the ``nameSpace`` |
+ | | field, here from a field called |
+ | | ``my.name.space`` |
+ +-----------------------------------+-----------------------------------+
+
+APEX Event
+##########
+ .. container:: paragraph
+
+ The event protocol for APEX events does not require a
+ specific plugin, it is supported by default. Furthermore,
+ there is no difference in the configuration for the input
+ and output interface.
+
+ .. container:: paragraph
+
+ For input and output APEX uses APEX events.
+
+ .. container:: paragraph
+
+ The following JSON shows the configuration.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventProtocolParameters":{
+ "eventProtocol" : "APEX"
+ }
+
+JMS Event
+#########
+
+ .. container:: paragraph
+
+ The event protocol for JMS is provided by the APEX JMS
+ plugin. The plugin supports encoding as JSON text or as
+ object. There is no difference in the configuration for
+ the input and output interface.
+
+JMS Text
+========
+ .. container:: paragraph
+
+ If used as input, APEX will take a JMS message and
+ extract a JSON string, then proceed as if a JSON event
+ was received. If used as output, APEX will take the
+ event produced by a policy, create a JSON string, and
+ then wrap it into a JMS message.
+
+ .. container:: paragraph
+
+ The configuration for JMS text is as follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventProtocolParameters":{
+ "eventProtocol" : "JMSTEXT",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.protocol.jms.JMSTextEventProtocolParameters"
+ }
+
+JMS Object
+==========
+ .. container:: paragraph
+
+ If used as input, APEX will will take a JMS message,
+ extract a Java Bean from the ``ObjectMessage``
+ message, construct an APEX event and put the bean on
+ the APEX event as a parameter. If used as output, APEX
+ will take the event produced by a policy, create a
+ Java Bean and send it as a JMS message.
+
+ .. container:: paragraph
+
+ The configuration for JMS object is as follows:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventProtocolParameters":{
+ "eventProtocol" : "JMSOBJECT",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.protocol.jms.JMSObjectEventProtocolParameters"
+ }
+
+YAML Event
+##########
+
+ .. container:: paragraph
+
+ The event protocol for YAML is provided by the APEX YAML
+ plugin. There is no difference in the configuration for
+ the input and output interface.
+
+ .. container:: paragraph
+
+ If used as input, APEX will consume events as YAML and
+ map them to policy trigger events. Not well-formed YAML
+ and not understood trigger events will be rejected. If
+ used as output, APEX produce YAML encoded events from the
+ event a policy produces. Those events will always be
+ well-formed according to the definition in the policy
+ model.
+
+ .. container:: paragraph
+
+ The following code shows the configuration.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventProtocolParameters":{
+ "eventProtocol" : "XML",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.protocol.yaml.YamlEventProtocolParameters"
+ }
+
+XML Event
+#########
+ .. container:: paragraph
+
+ The event protocol for XML is provided by the APEX XML
+ plugin. There is no difference in the configuration for
+ the input and output interface.
+
+ .. container:: paragraph
+
+ If used as input, APEX will consume events as XML and map
+ them to policy trigger events. Not well-formed XML and
+ not understood trigger events will be rejected. If used
+ as output, APEX produce XML encoded events from the event
+ a policy produces. Those events will always be
+ well-formed according to the definition in the policy
+ model.
+
+ .. container:: paragraph
+
+ The following code shows the configuration.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ "eventProtocolParameters":{
+ "eventProtocol" : "XML",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.protocol.xml.XMLEventProtocolParameters"
+ }
+
+A configuration example
+-----------------------
+
+ .. container:: paragraph
+
+ The following example loads all available plug-ins.
+
+ .. container:: paragraph
+
+ Events are consumed from a Websocket, APEX as client.
+ Consumed event format is JSON.
+
+ .. container:: paragraph
+
+ Events are produced to Kafka. Produced event format is XML.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ {
+ "engineServiceParameters" : {
+ "name" : "MyApexEngine",
+ "version" : "0.0.1",
+ "id" : 45,
+ "instanceCount" : 4,
+ "deploymentPort" : 12345,
+ "policyModelFileName" : "examples/models/some-model.json",
+ "engineParameters" : {
+ "executorParameters" : {
+ "JAVASCRIPT" : {
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"
+ },
+ "JYTHON" : {
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.jython.JythonExecutorParameters"
+ },
+ "JRUBY" : {
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.jruby.JrubyExecutorParameters"
+ },
+ "JAVA" : {
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.java.JavaExecutorParameters"
+ },
+ "MVEL" : {
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.executor.mvel.MVELExecutorParameters"
+ }
+ },
+ "contextParameters" : {
+ "parameterClassName" :
+ "org.onap.policy.apex.context.parameters.ContextParameters",
+ "schemaParameters" : {
+ "Avro":{
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters"
+ }
+ }
+ }
+ }
+ },
+ "producerCarrierTechnologyParameters" : {
+ "carrierTechnology" : "KAFKA",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.kafka.KAFKACarrierTechnologyParameters",
+ "parameters" : {
+ "bootstrapServers" : "localhost:49092",
+ "acks" : "all",
+ "retries" : 0,
+ "batchSize" : 16384,
+ "lingerTime" : 1,
+ "bufferMemory" : 33554432,
+ "producerTopic" : "apex-out",
+ "keySerializer" : "org.apache.kafka.common.serialization.StringSerializer",
+ "valueSerializer" : "org.apache.kafka.common.serialization.StringSerializer"
+ }
+ },
+ "producerEventProtocolParameters" : {
+ "eventProtocol" : "XML",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.protocol.xml.XMLEventProtocolParameters"
+ },
+ "consumerCarrierTechnologyParameters" : {
+ "carrierTechnology" : "WEBSOCKET",
+ "parameterClassName" :
+ "org.onap.policy.apex.plugins.event.carrier.websocket.WEBSOCKETCarrierTechnologyParameters",
+ "parameters" : {
+ "host" : "localhost",
+ "port" : 88888
+ }
+ },
+ "consumerEventProtocolParameters" : {
+ "eventProtocol" : "JSON"
+ }
+ }
+
+Engine and Applications of the APEX System
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Introduction to APEX Engine and Applications
+--------------------------------------------
+
+ .. container:: paragraph
+
+ The core of APEX is the APEX Engine, also known as the APEX
+ Policy Engine or the APEX PDP (since it is in fact a Policy
+ Decision Point). Beside this engine, an APEX system comes
+ with a few applications intended to help with policy
+ authoring, deployment, and execution.
+
+ .. container:: paragraph
+
+ The engine itself and most applications are started from the
+ command line with command line arguments. This is called a
+ Command Line Interface (CLI). Some applications require an
+ installation on a webserver, as for instance the REST
+ Editor. Those applications can be accessed via a web
+ browser.
+
+ .. container:: paragraph
+
+ You can also use the available APEX APIs and applications to
+ develop other applications as required. This includes policy
+ languages (and associated parsers and compilers /
+ interpreters), GUIs to access APEX or to define policies,
+ clients to connect to APEX, etc.
+
+ .. container:: paragraph
+
+ For this documentation, we assume an installation of APEX as
+ a full system based on a current ONAP release.
+
+CLI on Unix, Windows, and Cygwin
+--------------------------------
+
+ .. container:: paragraph
+
+ A note on APEX CLI applications: all applications and the
+ engine itself have been deployed and tested on different
+ operating systems: Red Hat, Ubuntu, Debian, Mac OSX,
+ Windows, Cygwin. Each operating system comes with its own
+ way of configuring and executing Java. The main items here
+ are:
+
+ .. container:: ulist
+
+ - For UNIX systems (RHL, Ubuntu, Debian, Mac OSX), the
+ provided bash scripts work as expected with absolute
+ paths (e.g.
+ ``/opt/app/policy/apex-pdp/apex-pdp-2.0.0-SNAPSHOT/examples``),
+ indirect and linked paths (e.g. ``../apex/apex``), and
+ path substitutions using environment settings (e.g.
+ ``$APEX_HOME/bin/``)
+
+ - For Windows systems, the provided batch files (``.bat``)
+ work as expected with with absolute paths (e.g.
+ ``C:\apex\apex-2.0.0-SNAPSHOT\examples``), and path
+ substitutions using environment settings (e.g.
+ ``%APEX_HOME%\bin\``)
+
+ - For Cygwin system we assume a standard Cygwin
+ installation with standard tools (mainly bash) using a
+ Windows Java installation. This means that the bash
+ scripts can be used as in UNIX, however any argument
+ pointing to files and directories need to use either a
+ DOS path (e.g.
+ ``C:\apex\apex-2.0.0-SNAPSHOT\examples\config...``) or
+ the command ``cygpath`` with a mixed option. The reason
+ for that is: Cygwin executes Java using UNIX paths but
+ then runs Java as a DOS/WINDOWS process, which requires
+ DOS paths for file access.
+
+The APEX Engine
+---------------
+
+ .. container:: paragraph
+
+ The APEX engine can be started in different ways, depending
+ your requirements. All scripts are located in the APEX *bin*
+ directory
+
+ .. container:: paragraph
+
+ On UNIX and Cygwin systems use:
+
+ .. container:: ulist
+
+ - ``apexEngine.sh`` - this script will
+
+ .. container:: ulist
+
+ - Test if ``$APEX_USER`` is set and if the user
+ exists, terminate with an error otherwise
+
+ - Test if ``$APEX_HOME`` is set. If not set, it will
+ use the default setting as
+ ``/opt/app/policy/apex-pdp/apex-pdp``. Then the set
+ directory is tested to exist, the script will
+ terminate if not.
+
+ - When all tests are passed successfully, the script
+ will call ``apexApps.sh`` with arguments to start
+ the APEX engine.
+
+ - ``apexApps.sh engine`` - this is the general APEX
+ application launcher, which will
+
+ .. container:: ulist
+
+ - Start the engine with the argument ``engine``
+
+ - Test if ``$APEX_HOME`` is set and points to an
+ existing directory. If not set or directory does
+ not exist, script terminates.
+
+ - Not test for any settings of ``$APEX_USER``.
+
+ .. container:: paragraph
+
+ On Windows systems use ``apexEngine.bat`` and
+ ``apexApps.bat engine`` respectively. Note: none of the
+ windows batch files will test for ``%APEX_USER%``.
+
+ .. container:: paragraph
+
+ Summary of alternatives to start the APEX Engine:
+
+ +--------------------------------------------------------+----------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +========================================================+==========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexEngine.sh [args] | > %APEX_HOME%\bin\apexEngine.bat [args] |
+ | # $APEX_HOME/bin/apexApps.sh engine [args] | > %APEX_HOME%\bin\apexApps.bat engine [args] |
+ +--------------------------------------------------------+----------------------------------------------------------+
+
+ .. container:: paragraph
+
+ The APEX engine comes with a few CLI arguments for setting
+ configuration and policy model. The configuration file is
+ always required. The policy model file is only required if
+ no model file is specified in the configuration, or if the
+ specified model file should be over written. The option
+ ``-h`` prints a help screen.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ usage: org.onap.policy.apex.service.engine.main.ApexMain [options...]
+ options
+ -c,--config-file <CONFIG_FILE> the full path to the configuration file to use, the configuration file must be a Json file
+ containing the Apex configuration parameters
+ -h,--help outputs the usage of this command
+ -m,--model-file <MODEL_FILE> the full path to the model file to use, if set it overrides the model file set in the
+ configuration file
+ -v,--version outputs the version of Apex
+
+The APEX CLI Editor
+-------------------
+
+ .. container:: paragraph
+
+ The CLI Editor allows to define policies from the command
+ line. The application uses a simple language and supports
+ all elements of an APEX policy. It can be used in to
+ different ways:
+
+ .. container:: ulist
+
+ - non-interactive, specifying a file with the commands to
+ create a policy
+
+ - interactive, using the editors CLI to create a policy
+
+ .. container:: paragraph
+
+ When a policy is fully specified, the editor will generate
+ the APEX core policy specification in JSON. This core
+ specification is called the policy model in the APEX engine
+ and can be used directly with the APEX engine.
+
+ .. container:: paragraph
+
+ On UNIX and Cygwin systems use:
+
+ .. container:: ulist
+
+ - ``apexCLIEditor.sh`` - simply starts the CLI editor,
+ arguments to the script determine the mode of the editor
+
+ - ``apexApps.sh cli-editor`` - simply starts the CLI
+ editor, arguments to the script determine the mode of the
+ editor
+
+ .. container:: paragraph
+
+ On Windows systems use:
+
+ .. container:: ulist
+
+ - ``apexCLIEditor.bat`` - simply starts the CLI editor,
+ arguments to the script determine the mode of the editor
+
+ - ``apexApps.bat cli-editor`` - simply starts the CLI
+ editor, arguments to the script determine the mode of the
+ editor
+
+ .. container:: paragraph
+
+ Summary of alternatives to start the APEX CLI Editor:
+
+ +------------------------------------------------------------+--------------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +============================================================+==============================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexCLIEditor.sh.sh [args] | > %APEX_HOME%\bin\apexCLIEditor.bat [args] |
+ | # $APEX_HOME/bin/apexApps.sh cli-editor [args] | > %APEX_HOME%\bin\apexApps.bat cli-editor [args] |
+ +------------------------------------------------------------+--------------------------------------------------------------+
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen with all command
+ line arguments.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ usage: org.onap.policy.apex.auth.clieditor.ApexCLIEditorMain [options...]
+ options
+ -a,--model-props-file <MODEL_PROPS_FILE> name of the apex model properties file to use
+ -c,--command-file <COMMAND_FILE> name of a file containing editor commands to run into the editor
+ -h,--help outputs the usage of this command
+ -i,--input-model-file <INPUT_MODEL_FILE> name of a file that contains an input model for the editor
+ -if,--ignore-failures <IGNORE_FAILURES_FLAG> true or false, ignore failures of commands in command files and continue
+ executing the command file
+ -l,--log-file <LOG_FILE> name of a file that will contain command logs from the editor, will log
+ to standard output if not specified or suppressed with "-nl" flag
+ -m,--metadata-file <CMD_METADATA_FILE> name of the command metadata file to use
+ -nl,--no-log if specified, no logging or output of commands to standard output or log
+ file is carried out
+ -nm,--no-model-output if specified, no output of a model to standard output or model output
+ file is carried out, the user can use the "save" command in a script to
+ save a model
+ -o,--output-model-file <OUTPUT_MODEL_FILE> name of a file that will contain the output model for the editor, will
+ output model to standard output if not specified or suppressed with
+ "-nm" flag
+ -wd,--working-directory <WORKING_DIRECTORY> the working directory that is the root for the CLI editor and is the
+ root from which to look for included macro files
+
+The APEX REST Editor
+--------------------
+
+ .. container:: paragraph
+
+ The standard way to use the APEX REST Editor is via an
+ installation of the *war* file on a webserver. However, the
+ REST editor can also be started via command line. This will
+ start a Grizzly webserver with the *war* deployed. Access to
+ the REST Editor is then via the provided URL
+
+ .. container:: paragraph
+
+ On UNIX and Cygwin systems use:
+
+ .. container:: ulist
+
+ - ``apexRESTEditor.sh`` - simply starts the webserver with
+ the REST editor
+
+ - ``apexApps.sh rest-editor`` - simply starts the webserver
+ with the REST editor
+
+ .. container:: paragraph
+
+ On Windows systems use:
+
+ .. container:: ulist
+
+ - ``apexRESTEditor.bat`` - simply starts the webserver with
+ the REST editor
+
+ - ``apexApps.bat rest-editor`` - simply starts the
+ webserver with the REST editor
+
+ .. container:: paragraph
+
+ Summary of alternatives to start the APEX REST Editor:
+
+ +-------------------------------------------------------------+---------------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=============================================================+===============================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexRESTEditor.sh.sh [args] | > %APEX_HOME%\bin\apexRESTEditor.bat [args] |
+ | # $APEX_HOME/bin/apexApps.sh rest-editor [args] | > %APEX_HOME%\bin\apexApps.bat rest-editor [args] |
+ +-------------------------------------------------------------+---------------------------------------------------------------+
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen with all command
+ line arguments.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ usage: org.onap.policy.apex.client.editor.rest.ApexEditorMain [options...]
+ -h,--help outputs the usage of this command
+ -l,--listen <ADDRESS> the IP address to listen on. Default value is localhost to restrict access to the
+ local machine only.
+ -p,--port <PORT> port to use for the Apex RESTful editor REST calls.
+ -t,--time-to-live <TIME_TO_LIVE> the amount of time in seconds that the server will run for before terminating. Default
+ value is -1 to run indefinitely.
+
+ .. container:: paragraph
+
+ If the REST Editor is started without any arguments the
+ final messages will look similar to this:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ Apex Editor REST endpoint (ApexEditorMain: Config=[ApexEditorParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=READY) starting at http://localhost:18989/apexservices/ . . .
+ Sep 05, 2018 11:24:30 PM org.glassfish.grizzly.http.server.NetworkListener start
+ INFO: Started listener bound to [localhost:18989]
+ Sep 05, 2018 11:24:30 PM org.glassfish.grizzly.http.server.HttpServer start
+ INFO: [HttpServer] Started.
+ Apex Editor REST endpoint (ApexEditorMain: Config=[ApexEditorParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=RUNNING) started at http://localhost:18989/apexservices/
+
+ .. container:: paragraph
+
+ The last line states the URL on which the REST Editor can be
+ accessed. The example above stated
+ ``http://0.0.0.0:18989/apex/``. In a web browser use the URL
+ ``http://localhost:18989`` and the REST Editor will start.
+
+The APEX Monitoring Client
+--------------------------
+
+ .. container:: paragraph
+
+ The standard way to use the APEX Monitoring Client is via an
+ installation of the *war* file on a webserver. However, the
+ Monitoring Client can also be started via command line. This
+ will start a Grizzly webserver with the *war* deployed.
+ Access to the Monitoring Client is then via the provided URL
+
+ .. container:: paragraph
+
+ On UNIX and Cygwin systems use:
+
+ .. container:: ulist
+
+ - ``apexApps.sh eng-monitoring`` - simply starts the
+ webserver with the Monitoring Client
+
+ .. container:: paragraph
+
+ On Windows systems use:
+
+ .. container:: ulist
+
+ - ``apexApps.bat eng-monitoring`` - simply starts the
+ webserver with the Monitoring Client
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen with all command
+ line arguments.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ usage: org.onap.policy.apex.client.monitoring.rest.ApexMonitoringRestMain [options...]
+ -h,--help outputs the usage of this command
+ -p,--port <PORT> port to use for the Apex Services REST calls
+ -t,--time-to-live <TIME_TO_LIVE> the amount of time in seconds that the server will run for before terminating
+
+ .. container:: paragraph
+
+ If the Monitoring Client is started without any arguments
+ the final messages will look similar to this:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ Apex Services REST endpoint (ApexMonitoringRestMain: Config=[ApexMonitoringRestParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=READY) starting at http://localhost:18989/apexservices/ . . .
+ Sep 05, 2018 11:26:20 PM org.glassfish.grizzly.http.server.NetworkListener start
+ INFO: Started listener bound to [localhost:18989]
+ Sep 05, 2018 11:26:20 PM org.glassfish.grizzly.http.server.HttpServer start
+ INFO: [HttpServer] Started.
+ Apex Services REST endpoint (ApexMonitoringRestMain: Config=[ApexMonitoringRestParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=RUNNING) started at http://localhost:18989/apexservices/
+
+ .. container:: paragraph
+
+ The last line states the URL on which the Monitoring Client
+ can be accessed. The example above stated
+ ``http://localhost:18989/apexservices``. In a web browser
+ use the URL ``http://localhost:18989``.
+
+The APEX Deployment Client
+--------------------------
+
+ .. container:: paragraph
+
+ The standard way to use the APEX Deployment Client is via an
+ installation of the *war* file on a webserver. However, the
+ Deployment Client can also be started via command line. This
+ will start a Grizzly webserver with the *war* deployed.
+ Access to the Deployment Client is then via the provided URL
+
+ .. container:: paragraph
+
+ On UNIX and Cygwin systems use:
+
+ .. container:: ulist
+
+ - ``apexApps.sh eng-deployment`` - simply starts the
+ webserver with the Deployment Client
+
+ .. container:: paragraph
+
+ On Windows systems use:
+
+ .. container:: ulist
+
+ - ``apexApps.bat eng-deployment`` - simply starts the
+ webserver with the Deployment Client
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen with all command
+ line arguments.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ usage: org.onap.policy.apex.client.deployment.rest.ApexDeploymentRestMain [options...]
+ -h,--help outputs the usage of this command
+ -p,--port <PORT> port to use for the Apex Services REST calls
+ -t,--time-to-live <TIME_TO_LIVE> the amount of time in seconds that the server will run for before terminating
+
+ .. container:: paragraph
+
+ If the Deployment Client is started without any arguments
+ the final messages will look similar to this:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ Apex Services REST endpoint (ApexDeploymentRestMain: Config=[ApexDeploymentRestParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=READY) starting at http://localhost:18989/apexservices/ . . .
+ Sep 05, 2018 11:27:09 PM org.glassfish.grizzly.http.server.NetworkListener start
+ INFO: Started listener bound to [localhost:18989]
+ Sep 05, 2018 11:27:09 PM org.glassfish.grizzly.http.server.HttpServer start
+ INFO: [HttpServer] Started.
+ Apex Services REST endpoint (ApexDeploymentRestMain: Config=[ApexDeploymentRestParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=RUNNING) started at http://localhost:18989/apexservices/
+
+ .. container:: paragraph
+
+ The last line states the URL on which the Deployment Client
+ can be accessed. The example above stated
+ ``http://localhost:18989/apexservices``. In a web browser
+ use the URL ``http://localhost:18989``.
+
+The APEX Full Client
+--------------------
+
+ .. container:: paragraph
+
+ The APEX Full Client combines the REST Editor, the
+ Monitoring Client, and the Deployment Client into a single
+ application. The standard way to use the APEX Full Client is
+ via an installation of the *war* file on a webserver.
+ However, the Full Client can also be started via command
+ line. This will start a Grizzly webserver with the *war*
+ deployed. Access to the Full Client is then via the provided
+ URL
+
+ .. container:: paragraph
+
+ On UNIX and Cygwin systems use:
+
+ .. container:: ulist
+
+ - ``apexApps.sh full-client`` - simply starts the webserver
+ with the Full Client
+
+ .. container:: paragraph
+
+ On Windows systems use:
+
+ .. container:: ulist
+
+ - ``apexApps.bat full-client`` - simply starts the
+ webserver with the Full Client
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen with all command
+ line arguments.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ usage: org.onap.policy.apex.client.full.rest.ApexServicesRestMain [options...]
+ -h,--help outputs the usage of this command
+ -p,--port <PORT> port to use for the Apex Services REST calls
+ -t,--time-to-live <TIME_TO_LIVE> the amount of time in seconds that the server will run for before terminating
+
+ .. container:: paragraph
+
+ If the Full Client is started without any arguments the
+ final messages will look similar to this:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ Apex Editor REST endpoint (ApexServicesRestMain: Config=[ApexServicesRestParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=READY) starting at http://localhost:18989/apexservices/ . . .
+ Sep 05, 2018 11:28:28 PM org.glassfish.grizzly.http.server.NetworkListener start
+ INFO: Started listener bound to [localhost:18989]
+ Sep 05, 2018 11:28:28 PM org.glassfish.grizzly.http.server.HttpServer start
+ INFO: [HttpServer] Started.
+ Apex Editor REST endpoint (ApexServicesRestMain: Config=[ApexServicesRestParameters: URI=http://localhost:18989/apexservices/, TTL=-1sec], State=RUNNING) started at http://localhost:18989/apexservices/
+
+ .. container:: paragraph
+
+ The last line states the URL on which the Monitoring Client
+ can be accessed. The example above stated
+ ``http://localhost:18989/apexservices``. In a web browser
+ use the URL ``http://localhost:18989``.
+
+ The APEX Application Launcher
+------------------------------
+
+ .. container:: paragraph
+
+ The standard applications (Engine, CLI Editor, REST Editor)
+ come with dedicated start scripts. For all other APEX
+ applications, we provide an application launcher.
+
+ .. container:: paragraph
+
+ On UNIX and Cygwin systems use:
+
+ .. container:: ulist
+
+ - apexApps.sh\` - simply starts the application launcher
+
+ .. container:: paragraph
+
+ On Windows systems use:
+
+ .. container:: ulist
+
+ - ``apexApps.bat`` - simply starts the application launcher
+
+ .. container:: paragraph
+
+ Summary of alternatives to start the APEX application
+ launcher:
+
+ +-------------------------------------------------+---------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=================================================+===================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexApps.sh [args] | > %APEX_HOME%\bin\apexApps.bat [args] |
+ +-------------------------------------------------+---------------------------------------------------+
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen with all launcher
+ command line arguments.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ apexApps.sh - runs APEX applications
+
+ Usage: apexApps.sh [options] | [<application> [<application options>]]
+
+ Options
+ -d <app> - describes an application
+ -l - lists all applications supported by this script
+ -h - this help screen
+
+ .. container:: paragraph
+
+ Using ``-l`` lists all known application the launcher can
+ start.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ apexApps.sh: supported applications:
+ --> ws-echo engine eng-monitoring full-client eng-deployment tpl-event-json model-2-cli rest-editor cli-editor ws-console
+
+ .. container:: paragraph
+
+ Using the ``-d <name>`` option describes the named
+ application, for instance for the ``ws-console``:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ apexApps.sh: application 'ws-console'
+ --> a simple console sending events to APEX, connect to APEX consumer port
+
+ .. container:: paragraph
+
+ Launching an application is done by calling the script with
+ only the application name and any CLI arguments for the
+ application. For instance, starting the ``ws-echo``
+ application with port ``8888``:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ apexApps.sh ws-echo -p 8888
+
+Application: Create Event Templates
+-----------------------------------
+
+ .. container:: paragraph
+
+ **Status: Experimental**
+
+ .. container:: paragraph
+
+ This application takes a policy model (JSON or XML encoded)
+ and generates templates for events in JSON format. This can
+ help when a policy defines rather complex trigger or action
+ events or complex events between states. The application can
+ produce events for the types: stimuli (policy trigger
+ events), internal (events between policy states), and
+ response (action events).
+
+ +----------------------------------------------------------------+------------------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +================================================================+==================================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexApps.sh tpl-event-json [args] | > %APEX_HOME%\bin\apexApps.bat tpl-event-json [args] |
+ +----------------------------------------------------------------+------------------------------------------------------------------+
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ gen-model2event v{release-version} - generates JSON templates for events generated from a policy model
+ usage: gen-model2event
+ -h,--help prints this help and usage screen
+ -m,--model <MODEL-FILE> set the input policy model file
+ -t,--type <TYPE> set the event type for generation, one of:
+ stimuli (trigger events), response (action
+ events), internal (events between states)
+ -v,--version prints the application version
+
+ .. container:: paragraph
+
+ The created templates are not valid events, instead they use
+ some markup for values one will need to change to actual
+ values. For instance, running the tool with the *Sample
+ Domain* policy model as:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ apexApps.sh tpl-event-json -m $APEX_HOME/examples/models/SampleDomain/SamplePolicyModelJAVA.json -t stimuli
+
+ .. container:: paragraph
+
+ will produce the following status messages:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ gen-model2event: starting Event generator
+ --> model file: examples/models/SampleDomain/SamplePolicyModelJAVA.json
+ --> type: stimuli
+
+ .. container:: paragraph
+
+ and then run the generator application producing two event
+ templates. The first template is called ``Event0000``.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ {
+ "name" : "Event0000",
+ "nameSpace" : "org.onap.policy.apex.sample.events",
+ "version" : "0.0.1",
+ "source" : "Outside",
+ "target" : "Match",
+ "TestTemperature" : ###double: 0.0###,
+ "TestTimestamp" : ###long: 0###,
+ "TestMatchCase" : ###integer: 0###,
+ "TestSlogan" : "###string###"
+ }
+
+ .. container:: paragraph
+
+ The values for the keys are marked with ``#`` and the
+ expected type of the value. To create an actual stimuli
+ event, all these markers need to be change to actual values,
+ for instance:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ {
+ "name" : "Event0000",
+ "nameSpace" : "org.onap.policy.apex.sample.events",
+ "version" : "0.0.1",
+ "source" : "Outside",
+ "target" : "Match",
+ "TestTemperature" : 25,
+ "TestTimestamp" : 123456789123456789,
+ "TestMatchCase" : 1,
+ "TestSlogan" : "Testing the Match Case with Temperature 25"
+ }
+
+Application: Convert a Policy Model to CLI Editor Commands
+----------------------------------------------------------
+
+ .. container:: paragraph
+
+ **Status: Experimental**
+
+ .. container:: paragraph
+
+ This application takes a policy model (JSON or XML encoded)
+ and generates commands for the APEX CLI Editor. This
+ effectively reverses a policy specification realized with
+ the CLI Editor.
+
+ +-------------------------------------------------------------+---------------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=============================================================+===============================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexApps.sh model-2-cli [args] | > %APEX_HOME%\bin\apexApps.bat model-2-cli [args] |
+ +-------------------------------------------------------------+---------------------------------------------------------------+
+
+ .. container:: paragraph
+
+ The option ``-h`` provides a help screen.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ usage: gen-model2cli
+ -h,--help prints this help and usage screen
+ -m,--model <MODEL-FILE> set the input policy model file
+ -sv,--skip-validation switch of validation of the input file
+ -v,--version prints the application version
+
+ .. container:: paragraph
+
+ For instance, running the tool with the *Sample Domain*
+ policy model as:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ apexApps.sh model-2-cli -m $APEX_HOME/examples/models/SampleDomain/SamplePolicyModelJAVA.json
+
+ .. container:: paragraph
+
+ will produce the following status messages:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ gen-model2cli: starting CLI generator
+ --> model file: examples/models/SampleDomain/SamplePolicyModelJAVA.json
+
+ .. container:: paragraph
+
+ and then run the generator application producing all CLI
+ Editor commands and printing them to standard out.
+
+Application: Websocket Clients (Echo and Console)
+-------------------------------------------------
+
+ .. container:: paragraph
+
+ **Status: Production**
+
+ .. container:: paragraph
+
+ The application launcher also provides a Websocket echo
+ client and a Websocket console client. The echo client
+ connects to APEX and prints all events it receives from
+ APEX. The console client connects to APEX, reads input from
+ the command line, and sends this input as events to APEX.
+
+ +------------------------------------------------------------+--------------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +============================================================+==============================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexApps.sh ws-echo [args] | > %APEX_HOME%\bin\apexApps.bat ws-echo [args] |
+ | # $APEX_HOME/bin/apexApps.sh ws-console [args] | > %APEX_HOME%\bin\apexApps.bat ws-console [args] |
+ +------------------------------------------------------------+--------------------------------------------------------------+
+
+ .. container:: paragraph
+
+ The arguments are the same for both applications:
+
+ .. container:: ulist
+
+ - ``-p`` defines the Websocket port to connect to (defaults
+ to ``8887``)
+
+ - ``-s`` defines the host on which a Websocket server is
+ running (defaults to ``localhost``)
+
+ .. container:: paragraph
+
+ A discussion on how to use these two applications to build
+ an APEX system is detailed HowTo-Websockets.
+
+My First Policy
+^^^^^^^^^^^^^^^
+
+Introduction
+------------
+ .. container:: paragraph
+
+ Consider a scenario where a supermarket chain called
+ *HyperM* controls how it sells items in a policy-based
+ manner. Each time an item is processed by *HyperM*'s
+ point-of-sale (PoS) system an event is generated and
+ published about that item of stock being sold. This event
+ can then be used to update stock levels, etc..
+
+ .. container:: paragraph
+
+ *HyperM* want to extend this approach to allow some checks
+ to be performed before the sale can be completed. This can
+ be achieved by requesting a policy-controlled decision as
+ each item is processed by for sale by each PoS system. The
+ decision process is integrated with *HyperM*'s other IT
+ systems that manage stock control, sourcing and purchasing,
+ personnel systems, etc.
+
+ .. container:: paragraph
+
+ In this document we will show how APEX and APEX Policies can
+ be used to achieve this, starting with a simple policy,
+ building up to more complicated policy that demonstrates the
+ features of APEX.
+
+Data Models
+-----------
+
+Sales Input Event
+#################
+
+ .. container:: paragraph
+
+ Each time a PoS system processes a sales item an event
+ with the following format is emitted:
+
+ .. table:: Table 1. Sale Input Event
+
+ +----------------------+----------------------+-----------------------+
+ | Event | Fields | Description |
+ +======================+======================+=======================+
+ | SALE_INPUT | time, sale_ID, | Event indicating a |
+ | | amount, item_ID, | sale of an item is |
+ | | quantity, | occurring |
+ | | assistant_ID, | |
+ | | branch_ID, notes, …​ | |
+ +----------------------+----------------------+-----------------------+
+
+ .. container:: paragraph
+
+ In each ``SALE_INPUT`` event the ``sale_ID`` field is a
+ unique ID generated by the PoS system. A timestamp for
+ the event is stored in the ``time`` field. The ``amount``
+ field refers to the value of the item(s) to be sold (in
+ cents). The ``item_ID`` field is a unique identifier for
+ each item type, and can be used to retrieve more
+ information about the item from *HyperM*'s stock control
+ system. The ``quantity`` field refers to the quantity of
+ the item to be sold. The ``assistant_ID`` field is a
+ unique identifier for the PoS operator, and can be used
+ to retrieve more information about the operator from the
+ *HyperM*'s personnel system. Since *HyperM* has many
+ branches the ``branch_ID`` identifies the shop. The
+ ``notes`` field contains arbitrary notes about the sale.
+
+Sales Decision Event
+####################
+
+ .. container:: paragraph
+
+ After a ``SALE_INPUT`` event is emitted by the PoS system
+ *HyperM*'s policy-based controlled sales checking system
+ emits a Sale Authorization Event indicating whether the
+ sale is authorized or denied. The PoS system can then
+ listen for this event before continuing with the sale.
+
+ .. table:: Table 2. Sale Authorisation Event
+
+ +----------------------+----------------------+-----------------------+
+ | Event | Fields | Description |
+ +======================+======================+=======================+
+ | SALE_AUTH | sale_ID, time, | Event indicating a |
+ | | authorized, amount, | sale of an item is |
+ | | item_ID, quantity, | authorized or denied |
+ | | assistant_ID, | |
+ | | branch_ID, notes, | |
+ | | message…​ | |
+ +----------------------+----------------------+-----------------------+
+
+ .. container:: paragraph
+
+ In each ``SALE_AUTH`` event the ``sale_ID`` field is
+ copied from the ``SALE_INPUT`` event that trigger the
+ decision request. The ``SALE_AUTH`` event is also
+ timestamped using the ``time`` field, and a field called
+ ``authorised`` is set to ``true`` or ``false`` depending
+ on whether the sale is authorized or denied. The
+ ``message`` field carries an optional message about why a
+ sale was not authorized. The other fields from the
+ ``SALE_INPUT`` event are also included for completeness.
+
+Stock Control: Items
+####################
+
+ .. container:: paragraph
+
+ *HyperM* maintains information about each item for sale
+ in a database table called ``ITEMS``.
+
+ .. table:: Table 3. Items Database
+
+ +----------------------+----------------------+-----------------------+
+ | Table | Fields | Description |
+ +======================+======================+=======================+
+ | ITEMS | item_ID, | Database table |
+ | | description, | describing each item |
+ | | cost_price, barcode, | for sale |
+ | | supplier_ID, | |
+ | | category, …​ | |
+ +----------------------+----------------------+-----------------------+
+
+ .. container:: paragraph
+
+ The database table ``ITEMS`` has a row for each items
+ that *HyperM* sells. Each item is identified by an
+ ``item_ID`` value. The ``description`` field stores a
+ description of the item. The cost price of the item is
+ given in ``cost_price``. The barcode of the item is
+ encoded in ``barcode``, while the item supplier is
+ identified by ``supplier_ID``. Items may also be
+ classified into categories using the ``category`` field.
+ Useful categories might include: ``soft drinks``,
+ ``alcoholic drinks``, ``cigarettes``, ``knives``,
+ ``confectionery``, ``bakery``, ``fruit&vegetables``,
+ ``meat``, etc..
+
+Personnel System: Assistants
+############################
+
+ .. table:: Table 4. Assistants Database
+
+ +----------------------+----------------------+-----------------------+
+ | Table | Fields | Description |
+ +======================+======================+=======================+
+ | ASSISTANTS | assistant_ID, | Database table |
+ | | surname, firstname, | describing each |
+ | | middlename, age, | *HyperM* sales |
+ | | grade, phone_number, | assistant |
+ | | …​ | |
+ +----------------------+----------------------+-----------------------+
+
+ .. container:: paragraph
+
+ The database table ``ASSISTANTS`` has a row for each
+ sales assistant employed by *HyperM*. Each assistant is
+ identified by an ``assistant_ID`` value, with their name
+ given in the ``firstname``, ``middlename`` and
+ ``surname`` fields. The assistant’s age in years is given
+ in ``age``, while their phone number is contained in the
+ ``phone_number`` field. The assistant’s grade is encoded
+ in ``grade``. Useful values for ``grade`` might include:
+ ``trainee``, ``operator``, ``supervisor``, etc..
+
+Locations: Branches
+####################
+
+ .. table:: Table 5. Branches Database
+
+ +----------------------+----------------------+-----------------------+
+ | Table | Fields | Description |
+ +======================+======================+=======================+
+ | BRANCHES | branch_ID, | Database table |
+ | | branch_Name, | describing each |
+ | | category, street, | *HyperM* branch |
+ | | city, country, | |
+ | | postcode, …​ | |
+ +----------------------+----------------------+-----------------------+
+
+ .. container:: paragraph
+
+ *HyperM* operates a number of branches. Each branch is
+ described in the ``BRANCHES`` database table. Each branch
+ is identified by a ``branch_ID``, with a branch name
+ given in ``branch_Name``. The address for the branch is
+ encoded in ``street``, ``city``, ``country`` and
+ ``postcode``. The branch category is given in the
+ ``category`` field. Useful values for ``category`` might
+ include: ``Small``, ``Large``, ``Super``, ``Hyper``,
+ etc..
+
+Policy Step 1
+-------------
+
+Scenario
+#########
+ .. container:: paragraph
+
+ For the first version of our policy, let’s start with
+ something simple. Let us assume that there exists some
+ restriction that alcohol products cannot be sold before
+ 11:30am. In this section we will go through the necessary
+ steps to define a policy that can enforce this for
+ *HyperM*.
+
+ .. container:: ulist
+
+ - Alcohol cannot be sold before 11:30am.
+
+Create the an new empty Policy Model ``MyFirstPolicyModel``
+###########################################################
+
+ .. container:: paragraph
+
+ Since an organisation like *HyperM* may have many
+ policies covering many different domains, policies should
+ be grouped into policy sets. In order to edit or deploy a
+ policy, or policy set, the definition of the policy(ies)
+ and all required events, tasks, states, etc., are grouped
+ together into a 'Policy Model'. An organization might
+ define many Policy Models, each containing a different
+ set of policies.
+
+ .. container:: paragraph
+
+ So the first step is to create a new empty Policy Model
+ called ``MyFirstPolicyModel``. Using the APEX Policy
+ Editor, click on the 'File' menus and select 'New'. Then
+ define our new policy model called
+ ``MyFirstPolicyModel``. Use the 'Generate UUID' button to
+ create a new unique ID for the policy model, and fill in
+ a description for the policy model. Press the ``Submit``
+ button to save your changes.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |File > New to create a new Policy Model|
+
+ .. container:: title
+
+ Figure 4. Create a new Policy Model 1/2
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Create a new Policy Model|
+
+ .. container:: title
+
+ Figure 5. Create a new Policy Model 2/2
+
+Create the input event ``SALE_INPUT`` and the output event ``SALE_AUTH``
+########################################################################
+
+ .. container:: paragraph
+
+ Using the APEX Policy Editor, click on the 'Events' tab.
+ In the 'Events' pane, right click and select 'New':
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Right click to create a new event|
+
+ .. container:: title
+
+ Figure 6. Create a new Event type
+
+ .. container:: paragraph
+
+ Create a new event type called ``SALE_INPUT``. Use the
+ 'Generate UUID' button to create a new unique ID for the
+ event type, and fill in a description for the event. Add
+ a namespace, e.g. ``com.hyperm``. We can add hard-coded
+ strings for the ``Source`` and ``Target``, e.g. ``POS``
+ and ``APEX``. At this stage we will not add any parameter
+ fields, we will leave this until later. Use the
+ ``Submit`` button to create the event.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Fill in the necessary information for the
+ 'SALE_INPUT' event and click 'Submit'|
+
+ .. container:: title
+
+ Figure 7. Populate the ``SALE_INPUT`` event
+
+ .. container:: paragraph
+
+ Repeat the same steps for a new event type called
+ ``SALE_AUTH``. Just use ``APEX`` as source and ``POS`` as
+ target, since this is the output event coming from APEX
+ going to the sales point.
+
+ .. container:: paragraph
+
+ Before we can add parameter fields to an event we must
+ first define APEX Context Item Schemas that can be used
+ by those fields.
+
+ .. container:: paragraph
+
+ To create new item schemas, click on the 'Context Item
+ Schemas' tab. In that 'Context Item Schemas' pane, right
+ click and select 'Create new ContextSchema'.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Right click to create a new Item Schema|
+
+ .. container:: title
+
+ Figure 8. Create new Data Types
+
+ .. container:: paragraph
+
+ Create item schemas with the following characteristics,
+ each with its own unique UUID:
+
+ .. table:: Table 6. Item Schemas
+
+ +-------------------+-----------------+-----------------+----------------------+
+ | Name | Schema Flavour | Schema | Description |
+ | | | Definition | |
+ +===================+=================+=================+======================+
+ | timestamp_type | Java | java.lang.Long | A type for |
+ | | | | ``time`` values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | sale_ID_type | Java | java.lang.Long | A type for |
+ | | | | ``sale_ID`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | price_type | Java | java.lang.Long | A type for |
+ | | | | ``amount``/``price`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | item_ID_type | Java | java.lang.Long | A type for |
+ | | | | ``item_ID`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | assistant_ID_type | Java | java.lang.Long | A type for |
+ | | | | ``assistant_ID`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | quantity_type | Java | java.lang.Integ | A type for |
+ | | | er | ``quantity`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | branch_ID_type | Java | java.lang.Long | A type for |
+ | | | | ``branch_ID`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | notes_type | Java | java.lang.Strin | A type for |
+ | | | g | ``notes`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | authorised_type | Java | java.lang.Boole | A type for |
+ | | | an | ``authorised`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+ | message_type | Java | java.lang.Strin | A type for |
+ | | | g | ``message`` |
+ | | | | values |
+ +-------------------+-----------------+-----------------+----------------------+
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Create a new Item Schema|
+
+ .. container:: title
+
+ Figure 9. Create new Item Schemas
+
+ .. container:: paragraph
+
+ The item schemas can now be seen on the 'Context Item
+ Schemas' tab, and can be updated at any time by
+ right-clicking on the item schemas on the 'Context Item
+ Schemas' tab. Now we can go back to the event definitions
+ for ``SALE_INPUT`` and ``SALE_AUTH`` and add some
+ parameter fields.
+
+ .. tip
+
+ .. container:: title
+
+ Field Schema types
+
+ .. container:: paragraph
+
+ APEX natively supports schema definitions in ``Java`` and ``Avro``.
+
+ .. container:: paragraph
+
+ ``Java`` schema definitions are simply the name of a Java Class. There are some restrictions:
+
+ .. container:: ulist
+
+ - the class must be instantiatable, i.e. not an Java interface or abstract class
+
+ - primitive types are not supported, i.e. use ``java.lang.Integer`` instead of ``int``, etc.
+
+ - it must be possible to find the class, i.e. the class must be contained in the Java classpath.
+
+ .. container:: paragraph
+
+ ``Avro`` schema definitions can be any valid `Avro <https://avro.apache.org/docs/current/spec.html>`__
+ schema. For events using fields defined with ``Avro`` schemas, any incoming event containing that field must
+ contain a value that conforms to the Avro schema.
+
+ .. container:: paragraph
+
+ Click on the 'Events' tab, then right click the
+ ``SALE_INPUT`` row and select 'Edit Event
+ :literal:`SALE_INPUT’. To add a new event parameter use the 'Add Event Parameter' button at the bottom of the screen. For the `SALE_INPUT`
+ event add the following event parameters:
+
+ .. table:: Table 7. Event Parameter Fields for the ``SALE_INPUT`` Event
+
+ +----------------------+----------------------+-----------------------+
+ | Parameter Name | Parameter Type | Optional |
+ +======================+======================+=======================+
+ | time | timestamp_type | no |
+ +----------------------+----------------------+-----------------------+
+ | sale_ID | sale_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | amount | price_type | no |
+ +----------------------+----------------------+-----------------------+
+ | item_ID | item_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | quantity | quantity_type | no |
+ +----------------------+----------------------+-----------------------+
+ | assistant_ID | assistant_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | branch_ID | branch_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | notes | notes_type | *yes* |
+ +----------------------+----------------------+-----------------------+
+
+ .. container:: paragraph
+
+ Remember to click the 'Submit' button at the bottom of
+ the event definition pane.
+
+ .. tip::
+ Optional Fields in APEX Events
+ Parameter fields can be *optional* in events. If a parameter is not marked as *optional* then by default it
+ is *mandatory*, so it must appear in any input event passed to APEX. If an *optional* field is not set
+ for an output event then value will be set to ``null``.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Add new event parameters to an event|
+
+ .. container:: title
+
+ Figure 10. Add typed parameter fields to an event
+
+ .. container:: paragraph
+
+ Select the ``SALE_AUTH`` event and add the following
+ event parameters:
+
+ .. table:: Table 8. Event Parameter Fields for the ``SALE_AUTH`` Event
+
+ +----------------------+----------------------+-----------------------+
+ | Parameter Name | Parameter Type | no |
+ +======================+======================+=======================+
+ | sale_ID | sale_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | time | timestamp_type | no |
+ +----------------------+----------------------+-----------------------+
+ | authorised | authorised_type | no |
+ +----------------------+----------------------+-----------------------+
+ | message | message_type | *yes* |
+ +----------------------+----------------------+-----------------------+
+ | amount | price_type | no |
+ +----------------------+----------------------+-----------------------+
+ | item_ID | item_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | assistant_ID | assistant_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | quantity | quantity_type | no |
+ +----------------------+----------------------+-----------------------+
+ | branch_ID | branch_ID_type | no |
+ +----------------------+----------------------+-----------------------+
+ | notes | notes_type | *yes* |
+ +----------------------+----------------------+-----------------------+
+
+ .. container:: paragraph
+
+ Remember to click the 'Submit' button at the bottom of
+ the event definition pane.
+
+ .. container:: paragraph
+
+ The events for our policy are now defined.
+
+Create a new Policy and add the *"No Booze before 11:30"* check
+###############################################################
+
+ .. container:: paragraph
+
+ APEX policies are defined using a state-machine model.
+ Each policy comprises one or more *states* that can be
+ individually executed. Where there is more than one
+ *state* the states are chained together to form a
+ `Directed Acyclic Graph
+ (DAG) <https://en.wikipedia.org/wiki/Directed_acyclic_graph>`__
+ of states. A *state* is triggered by passing it a single
+ input (or 'trigger') event and once executed each state
+ then emits an output event. For each *state* the logic
+ for the *state* is embedded in one or more *tasks*. Each
+ *task* contains specific *task logic* that is executed by
+ the APEX execution environment each time the *task* is
+ invoked. Where there is more than one *task* in a *state*
+ then the *state* also defines some *task selection logic*
+ to select an appropriate task each time the *state* is
+ executed.
+
+ .. container:: paragraph
+
+ Therefore, to create a new policy we must first define
+ one or more tasks.
+
+ .. container:: paragraph
+
+ To create a new Task click on the 'Tasks' tab. In the
+ 'Tasks' pane, right click and select 'Create new Task'.
+ Create a new Task called ``MorningBoozeCheck``. Use the
+ 'Generate UUID' button to create a new unique ID for the
+ task, and fill in a description for the task.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Right click to create a new task|
+
+ .. container:: title
+
+ Figure 11. Create a new Task
+
+ .. container:: paragraph
+
+ Tasks are configured with a set of *input fields* and a
+ set of *output fields*. To add new input/output fields
+ for a task use the 'Add Task Input Field' and 'Add Task
+ Output Field' button. The list of input and out fields to
+ add for the ``MorningBoozeCheck`` task are given below.
+ The input fields are drawn from the parameters in the
+ state’s input event, and the task’s output fields are
+ used to populate the state’s output event. The task’s
+ input and output fields must be a subset of the event
+ parameters defined for the input and output events for
+ any state that uses that task. (You may have noticed that
+ the input and output fields for the ``MorningBoozeCheck``
+ task have the exact same names and reuse the item schemas
+ that we used for the parameters in the ``SALE_INPUT`` and
+ ``SALE_AUTH`` events respectively).
+
+ .. table:: Table 9. Input fields for ``MorningBoozeCheck`` task
+
+ +-----------------------------------+-----------------------------------+
+ | Parameter Name | Parameter Type |
+ +===================================+===================================+
+ | time | timestamp_type |
+ +-----------------------------------+-----------------------------------+
+ | sale_ID | sale_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | amount | price_type |
+ +-----------------------------------+-----------------------------------+
+ | item_ID | item_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | quantity | quantity_type |
+ +-----------------------------------+-----------------------------------+
+ | assistant_ID | assistant_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | branch_ID | branch_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | notes | notes_type |
+ +-----------------------------------+-----------------------------------+
+
+ .. table:: Table 10. Output fields for ``MorningBoozeCheck`` task
+
+ +-----------------------------------+-----------------------------------+
+ | Parameter Name | Parameter Type |
+ +===================================+===================================+
+ | sale_ID | sale_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | time | timestamp_type |
+ +-----------------------------------+-----------------------------------+
+ | authorised | authorised_type |
+ +-----------------------------------+-----------------------------------+
+ | message | message_type |
+ +-----------------------------------+-----------------------------------+
+ | amount | price_type |
+ +-----------------------------------+-----------------------------------+
+ | item_ID | item_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | assistant_ID | assistant_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | quantity | quantity_type |
+ +-----------------------------------+-----------------------------------+
+ | branch_ID | branch_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | notes | notes_type |
+ +-----------------------------------+-----------------------------------+
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Add input and out fields for the task|
+
+ .. container:: title
+
+ Figure 12. Add input and out fields for the Task
+
+ .. container:: paragraph
+
+ Each task must include some 'Task Logic' that implements
+ the behaviour for the task. Task logic can be defined in
+ a number of different ways using a choice of languages.
+ For this task we will author the logic using the
+ Java-like scripting language called
+ ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__.
+
+ .. container:: paragraph
+
+ For simplicity use the following code for the task logic.
+ Paste the script text into the 'Task Logic' box, and use
+ "MVEL" as the 'Task Logic Type / Flavour'.
+
+ .. container:: paragraph
+
+ This logic assumes that all items with ``item_ID``
+ between 1000 and 2000 contain alcohol, which is not very
+ realistic, but we will see a better approach for this
+ later. It also uses the standard ``Java`` time utilities
+ to check if the current time is between ``00:00:00 GMT``
+ and ``11:30:00 GMT``. For a detailed guide to how to
+ write your own logic in
+ ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__,
+ ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__ or one
+ of the other supported languages please refer to APEX
+ Programmers Guide.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ MVEL code for the ``MorningBoozeCheck`` task
+
+ .. container:: content
+
+ .. code::
+
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+ import java.util.Date;
+ import java.util.Calendar;
+ import java.util.TimeZone;
+ import java.text.SimpleDateFormat;
+
+ logger.info("Task Execution: '"+subject.id+"'. Input Fields: '"+inFields+"'");
+
+ outFields.put("amount" , inFields.get("amount"));
+ outFields.put("assistant_ID", inFields.get("assistant_ID"));
+ outFields.put("notes" , inFields.get("notes"));
+ outFields.put("quantity" , inFields.get("quantity"));
+ outFields.put("branch_ID" , inFields.get("branch_ID"));
+ outFields.put("item_ID" , inFields.get("item_ID"));
+ outFields.put("time" , inFields.get("time"));
+ outFields.put("sale_ID" , inFields.get("sale_ID"));
+
+ item_id = inFields.get("item_ID");
+
+ //The events used later to test this task use GMT timezone!
+ gmt = TimeZone.getTimeZone("GMT");
+ timenow = Calendar.getInstance(gmt);
+ df = new SimpleDateFormat("HH:mm:ss z");
+ df.setTimeZone(gmt);
+ timenow.setTimeInMillis(inFields.get("time"));
+
+ midnight = timenow.clone();
+ midnight.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),0,0,0);
+ eleven30 = timenow.clone();
+ eleven30.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),11,30,0);
+
+ itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol
+ && timenow.after(midnight) && timenow.before(eleven30)){
+ outFields.put("authorised", false);
+ outFields.put("message", "Sale not authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime())+
+ ". Alcohol can not be sold between "+df.format(midnight.getTime())+
+ " and "+df.format(eleven30.getTime()));
+ return true;
+ }
+ else{
+ outFields.put("authorised", true);
+ outFields.put("message", "Sale authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime()));
+ return true;
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
+ authorised. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID value between 1000 and
+ 2000 are all alcoholic drinks :-)
+ */
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Add task logic the task|
+
+ .. container:: title
+
+ Figure 13. Add Task Logic the Task
+
+ .. container:: paragraph
+
+ An alternative version of the same logic is available in
+ JavaScript. Just use "JAVASCRIPT" as the 'Task Logic Type
+ / Flavour' instead.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ Javascript alternative for the ``MorningBoozeCheck``
+ task
+
+ .. container:: content
+
+ .. code::
+
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+ var returnValueType = Java.type("java.lang.Boolean");
+ var returnValue = new returnValueType(true);
+
+ // Load compatibility script for imports etc
+ load("nashorn:mozilla_compat.js");
+ importPackage(java.text);
+ importClass(java.text.SimpleDateFormat);
+
+ executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+ executor.outFields.put("amount" , executor.inFields.get("amount"));
+ executor.outFields.put("assistant_ID", executor.inFields.get("assistant_ID"));
+ executor.outFields.put("notes" , executor.inFields.get("notes"));
+ executor.outFields.put("quantity" , executor.inFields.get("quantity"));
+ executor.outFields.put("branch_ID" , executor.inFields.get("branch_ID"));
+ executor.outFields.put("item_ID" , executor.inFields.get("item_ID"));
+ executor.outFields.put("time" , executor.inFields.get("time"));
+ executor.outFields.put("sale_ID" , executor.inFields.get("sale_ID"));
+
+ item_id = executor.inFields.get("item_ID");
+
+ //All times in this script are in GMT/UTC since the policy and events assume time is in GMT.
+ var timenow_gmt = new Date(Number(executor.inFields.get("time")));
+
+ var midnight_gmt = new Date(Number(executor.inFields.get("time")));
+ midnight_gmt.setUTCHours(0,0,0,0);
+
+ var eleven30_gmt = new Date(Number(executor.inFields.get("time")));
+ eleven30_gmt.setUTCHours(11,30,0,0);
+
+ var timeformatter = new java.text.SimpleDateFormat("HH:mm:ss z");
+
+ var itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol
+ && timenow_gmt.getTime() >= midnight_gmt.getTime()
+ && timenow_gmt.getTime() < eleven30_gmt.getTime()) {
+
+ executor.outFields.put("authorised", false);
+ executor.outFields.put("message", "Sale not authorised by policy task " +
+ executor.subject.taskName+ " for time " + timeformatter.format(timenow_gmt.getTime()) +
+ ". Alcohol can not be sold between " + timeformatter.format(midnight_gmt.getTime()) +
+ " and " + timeformatter.format(eleven30_gmt.getTime()));
+ }
+ else{
+ executor.outFields.put("authorised", true);
+ executor.outFields.put("message", "Sale authorised by policy task " +
+ executor.subject.taskName + " for time "+timeformatter.format(timenow_gmt.getTime()));
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
+ authorised. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID value between 1000 and
+ 2000 are all alcoholic drinks :-)
+ */
+
+ .. container:: paragraph
+
+ The task definition is now complete so click the 'Submit'
+ button to save the task. The task can now be seen on the
+ 'Tasks' tab, and can be updated at any time by
+ right-clicking on the task on the 'Task' tab. Now that we
+ have created our task, we can can create a policy that
+ uses that task.
+
+ .. container:: paragraph
+
+ To create a new Policy click on the 'Policies' tab. In
+ the 'Policies' pane, right click and select 'Create new
+ Policy':
+
+ .. container:: paragraph
+
+ Create a new Policy called ``MyFirstPolicy``. Use the
+ 'Generate UUID' button to create a new unique ID for the
+ policy, and fill in a description for the policy. Use
+ 'FREEFORM' as the 'Policy Flavour'.
+
+ .. container:: paragraph
+
+ Each policy must have at least one state. Since this is
+ 'freeform' policy we can add as many states as we wish.
+ Let’s start with one state. Add a new state called
+ ``BoozeAuthDecide`` to this ``MyFirstPolicy`` policy
+ using the 'Add new State' button after filling in the
+ name of our new state.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Create a new policy|
+
+ .. container:: title
+
+ Figure 14. Create a new Policy
+
+ .. container:: paragraph
+
+ Each state must uses one input event type. For this new
+ state select the ``SALE_INPUT`` event as the input event.
+
+ .. container:: paragraph
+
+ Each policy must define a 'First State' and a 'Policy
+ Trigger Event'. The 'Policy Trigger Event' is the input
+ event for the policy as a whole. This event is then
+ passed to the first state in the chain of states in the
+ policy, therefore the 'Policy Trigger Event' will be the
+ input event for the first state. Each policy can only
+ have one 'First State'. For our ``MyFirstPolicy`` policy,
+ select ``BoozeAuthDecide`` as the 'First State'. This
+ will automatically select ``SALE_INPUT`` as the 'Policy
+ Trigger Event' for our policy.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Create a state|
+
+ .. container:: title
+
+ Figure 15. Create a new State
+
+ .. container:: paragraph
+
+ In this case we will create a reference the pre-existing
+ ``MorningBoozeCheck`` task that we defined above using
+ the 'Add New Task' button. Select the
+ ``MorningBoozeCheck`` task, and use the name of the task
+ as the 'Local Name' for the task.
+
+ .. container:: paragraph
+
+ in the case where a state references more than one task,
+ a 'Default Task' must be selected for the state and some
+ logic ('Task Selection Logic') must be specified to
+ select the appropriate task at execution time. Since our
+ new state ``BoozeAuthDecide`` only has one task the
+ default task is automatically selected and no 'Task
+ Selection Logic' is required.
+
+ .. note::
+ .. container:: title
+
+ State Output Mappings
+
+ .. container:: paragraph
+
+ In a 'Policy' 'State' a 'State Output Mapping' has 3 roles:
+ 1) Select which 'State' should be executed next, 2) Select
+ the type of the state’s 'Outgoing Event', and 3)
+ Populate the state’s 'Outgoing Event'. This is how states are
+ chained together to form a (`Directed Acyclic Graph
+ (DAG) <https://en.wikipedia.org/wiki/Directed_acyclic_graph>`__ )
+ of states. The final state(s) of a policy are those that do
+ not select any 'next' state. Since a 'State' can only
+ accept a single type of event, the type of the event emitted
+ by a previous 'State' must be match the incoming event type
+ of the next 'State'. This is also how the last state(s) in
+ a policy can emit events of different types. The 'State
+ Output Mapping' is also responsible for taking the
+ fields that are output by the task executed in the state and
+ populating the state’s output event before it is emitted.
+
+ .. container:: paragraph
+
+ Each 'Task' referenced in 'State' must have a defined
+ 'Output Mapping' to take the output of the task, select an
+ 'Outgoing Event' type for the state, populate the state’s
+ outgoing event, and then select the next state to be
+ executed (if any).
+
+ .. container:: paragraph
+
+ There are 2 basic types of output mappings:
+
+ .. container:: olist arabic
+
+ #. **Direct Output Mappings** have a single value for
+ 'Next State' and a single value for 'State Output
+ Event'. The outgoing event for the state is
+ automatically created, any outgoing event parameters
+ that were present in the incoming event are copied
+ into the outgoing event, then any task output fields
+ that have the same name and type as parameters in the
+ outgoing event are automatically copied into
+ the outgoing event.
+
+ #. **Logic-based State Output Mappings / Finalizers**
+ have some logic defined that dynamically selects
+ and creates the 'State Outgoing Event', manages
+ the population of the outgoing event parameters
+ (perhaps changing or adding to the outputs from the
+ task), and then dynamically selects the next state to
+ be executed (if any).
+
+ .. container:: paragraph
+
+ Each task reference must also have an associated 'Output
+ State Mapping' so we need an 'Output State Mapping' for
+ the ``BoozeAuthDecide`` state to use when the
+ ``MorningBoozeCheck`` task is executed. The simplest type
+ of output mapping is a 'Direct Output Mapping'.
+
+ .. container:: paragraph
+
+ Create a new 'Direct Output Mapping' for the state called
+ ``MorningBoozeCheck_Output_Direct`` using the 'Add New
+ Direct State Output Mapping' button. Select ``SALE_AUTH``
+ as the output event and select ``None`` for the next
+ state value. We can then select this output mapping for
+ use when the the ``MorningBoozeCheck`` task is executed.
+ Since there is only state, and only one task for that
+ state, this output mapping ensures that the
+ ``BoozeAuthDecide`` state is the only state executed and
+ the state (and the policy) can only emit events of type
+ ``SALE_AUTH``. (You may remember that the output fields
+ for the ``MorningBoozeCheck`` task have the exact same
+ names and reuse the item schemas that we used for the
+ parameters in ``SALE_AUTH`` event. The
+ ``MorningBoozeCheck_Output_Direct`` direct output mapping
+ can now automatically copy the values from the
+ ``MorningBoozeCheck`` task directly into outgoing
+ ``SALE_AUTH`` events.)
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Add a Task and Output Mapping|
+
+ .. container:: title
+
+ Figure 16. Add a Task and Output Mapping
+
+ .. container:: paragraph
+
+ Click the 'Submit' button to complete the definition of
+ our ``MyFirstPolicy`` policy. The policy
+ ``MyFirstPolicy`` can now be seen in the list of policies
+ on the 'Policies' tab, and can be updated at any time by
+ right-clicking on the policy on the 'Policies' tab.
+
+ .. container:: paragraph
+
+ The ``MyFirstPolicyModel``, including our
+ ``MyFirstPolicy`` policy can now be checked for errors.
+ Click on the 'Model' menu and select 'Validate'. The
+ model should validate without any 'Warning' or 'Error'
+ messages. If you see any 'Error' or 'Warning' messages,
+ carefully read the message as a hint to find where you
+ might have made a mistake when defining some aspect of
+ your policy model.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Validate the policy model for error using the 'Model'
+ > 'Validate' menu item|
+
+ .. container:: title
+
+ Figure 17. Validate a Policy Model
+
+ .. container:: paragraph
+
+ Congratulations, you have now completed your first APEX
+ policy. The policy model containing our new policy can
+ now be exported from the editor and saved. Click on the
+ 'File' menu and select 'Download' to save the policy
+ model in JSON format. The exported policy model is then
+ available in the directory you selected, for instance
+ ``$APEX_HOME/examples/models/MyFirstPolicy/1/MyFirstPolicyModel_0.0.1.json``.
+ The exported policy can now be loaded into the APEX
+ Policy Engine, or can be re-loaded and edited by the APEX
+ Policy Editor.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Download the completed policy model using the 'File'
+ > 'Download' menu item|
+
+ .. container:: title
+
+ Figure 18. Export a Policy Model
+
+Test Policy Step 1
+##################
+
+ .. container:: paragraph
+
+ To start a new APEX Engine you can use the following
+ configuration. In a full APEX installation you can find
+ this configuration in
+ ``$APEX_HOME/examples/config/MyFirstPolicy/1/MyFirstPolicyConfigStdin2StdoutJsonEvent.json``.
+ This configuration expects incoming events to be in
+ ``JSON`` format and to be passed into the APEX Engine
+ from ``stdin``, and result events will be printed in
+ ``JSON`` format to ``stdout``. This configuration loads
+ the policy model stored in the file
+ 'MyFirstPolicyModel_0.0.1.json' as exported from the APEX
+ Editor. Note, you may need to edit this file to provide
+ the full path to wherever you stored the exported policy
+ model file.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JSON to load and execute *My First Policy*, read input
+ JSON events from ``stdin``, and emit output events to
+ ``stdout``
+
+ .. container:: content
+
+ .. code::
+
+ {
+ "engineServiceParameters" : {
+ "name" : "MyFirstPolicyApexEngine",
+ "version" : "0.0.1",
+ "id" : 101,
+ "instanceCount" : 4,
+ "deploymentPort" : 12345,
+ "policyModelFileName" : "examples/models/MyFirstPolicy/1/MyFirstPolicyModel_0.0.1.json",
+ "engineParameters" : {
+ "executorParameters" : {
+ "MVEL" : {
+ "parameterClassName" : "org.onap.policy.apex.plugins.executor.mvel.MVELExecutorParameters"
+ },
+ "JAVASCRIPT" : {
+ "parameterClassName" : "org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"
+ }
+ }
+ }
+ },
+ "eventOutputParameters": {
+ "FirstProducer": {
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE",
+ "parameters" : {
+ "standardIO" : true
+ }
+ },
+ "eventProtocolParameters" : {
+ "eventProtocol" : "JSON"
+ }
+ }
+ },
+ "eventInputParameters": {
+ "FirstConsumer": {
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE",
+ "parameters" : {
+ "standardIO" : true
+ }
+ },
+ "eventProtocolParameters" : {
+ "eventProtocol" : "JSON"
+ }
+ }
+ }
+ }
+
+ .. container:: paragraph
+
+ To test the policy try paste the following events into
+ the console as the APEX engine executes:
+
+ .. table:: Table 11. Inputs and Outputs when testing *My First Policy*
+
+ +------------------------------------------+-------------------------------------------+-----------+
+ | Input Event (JSON) | Output Event (JSON) | comment |
+ +==========================================+===========================================+===========+
+ | .. container:: | .. container:: | Request |
+ | | | to buy a |
+ | .. container:: listingblock | .. container:: listingblock | non-alcoh |
+ | | | olic |
+ | | .. container:: content | item |
+ | .. container:: content | | (``item_I |
+ | | .. code:: | D=5123``) |
+ | | | at |
+ | .. code:: | { | *10:13:09 |
+ | | "name": "SALE_AUTH", | * |
+ | | | on |
+ | { | "version": "0.0.1", | *Tuesday, |
+ | "nameSpace": "com.hyperm", | "nameSpace": "com.hyperm", | 10 |
+ | "name" : "SALE_INPUT", | "source": "", | January |
+ | "version": "0.0.1", | "target": "", | 2017*. |
+ | "time" : 1483351989000, | "amount": 299, | Sale is |
+ | "sale_ID": 99999991, | "assistant_ID": 23, | authorize |
+ | "amount": 299, | "authorised": true, | d. |
+ | "item_ID": 5123, | "branch_ID": 1, | |
+ | "quantity": 1, | "item_ID": 5123, | |
+ | "assistant_ID": 23, | "message": "Sale authorised | |
+ | "branch_ID": 1, | by policy task MorningBo | |
+ | "notes": "Special Offer!!" | ozeCheck for time 10:13:09 | |
+ | } | GMT", | |
+ | | "notes": "Special Offer!!", | |
+ | | "quantity": 1, | |
+ | | "sale_ID": 99999991, | |
+ | | "time": 1483351989000 | |
+ | | } | |
+ | | | |
+ | | | |
+ | | | |
+ +------------------------------------------+-------------------------------------------+-----------+
+ | .. container:: | .. container:: | Request |
+ | | | to buy |
+ | .. container:: listingblock | .. container:: listingblock | alcohol |
+ | | | item |
+ | .. container:: content | .. container:: content | (``item_I |
+ | | | D=1249``) |
+ | .. code:: | .. code:: | at |
+ | | | *08:41:06 |
+ | { | { | * |
+ | "nameSpace": "com.hyperm", | "nameSpace": "com.hyperm", | on |
+ | "name": "SALE_INPUT", | "name": "SALE_AUTH", | *Monday, |
+ | "version": "0.0.1", | "source": "", | 02 |
+ | "time": 1483346466000, | "target": "", | January |
+ | "sale_ID": 99999992, | "amount": 1249, | 2017*. |
+ | "version": "0.0.1", | "assistant_ID": 12, | |
+ | "amount": 1249, | "authorised": false, | Sale is |
+ | "item_ID": 1012, | "branch_ID": 2, | not |
+ | "quantity": 1, | "item_ID": 1012, | authorize |
+ | "assistant_ID": 12, | "message": "Sale not | d. |
+ | "branch_ID": 2 | authorised by policy task | |
+ | } | MorningBoozeCheck for time | |
+ | | 08:41:06 GMT. Alcohol can | |
+ | | not be sold between | |
+ | | 00:00:00 GMT and 11:30:00 | |
+ | | GMT", | |
+ | | "notes": null, | |
+ | | "quantity": 1, | |
+ | | "sale_ID": 99999992, | |
+ | | "time": 1483346466000 | |
+ | | } | |
+ +------------------------------------------+-------------------------------------------+-----------+
+ | .. container:: | .. container:: | Request |
+ | | | to buy |
+ | .. container:: listingblock | .. container:: listingblock | alcohol |
+ | | | (``item_I |
+ | | .. container:: content | D=1943``) |
+ | .. container:: content | | at |
+ | | .. code:: | *20:17:13 |
+ | | | * |
+ | .. code:: | { | on |
+ | | "name": "SALE_AUTH", | *Tuesday, |
+ | { | "version": "0.0.1", | 20 |
+ | "nameSpace": "com.hyperm", | "nameSpace": "com.hyperm", | December |
+ | "name" : "SALE_INPUT", | "source": "", | 2016*. |
+ | "version": "0.0.1", | "target": "", | |
+ | "time" : 1482265033000, | "amount": 4799, | Sale is |
+ | "sale_ID": 99999993, | "assistant_ID": 9, | authorize |
+ | "amount": 4799, | "authorised": true, | d. |
+ | "item_ID": 1943, | "branch_ID": 3, | |
+ | "quantity": 2, | "item_ID": 1943, | |
+ | "assistant_ID": 9, | "message": "Sale authorised | |
+ | "branch_ID": 3 | by policy task MorningBo | |
+ | } | ozeCheck for time 20:17:13 | |
+ | | GMT", | |
+ | | "notes": null, | |
+ | | "quantity": 2, | |
+ | | "sale_ID": 99999993, | |
+ | | "time": 1482265033000 | |
+ | | } | |
+ +------------------------------------------+-------------------------------------------+-----------+
+
+4.3.6. Policy 1 in CLI Editor
+#############################
+
+ .. container:: paragraph
+
+ An equivalent version of the ``MyFirstPolicyModel``
+ policy model can again be generated using the APEX CLI
+ editor. A sample APEX CLI script is shown below:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ APEX CLI Editor code for Policy 1
+
+ .. container:: content
+
+ .. code::
+
+ #-------------------------------------------------------------------------------
+ # ============LICENSE_START=======================================================
+ # Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ # ================================================================================
+ # Licensed 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.
+ #
+ # SPDX-License-Identifier: Apache-2.0
+ # ============LICENSE_END=========================================================
+ #-------------------------------------------------------------------------------
+
+ model create name=MyFirstPolicyModel version=0.0.1 uuid=540226fb-55ee-4f0e-a444-983a0494818e description="This is my first Apex Policy Model."
+
+ schema create name=assistant_ID_type version=0.0.1 uuid=36df4c71-9616-4206-8b53-976a5cd4bd87 description="A type for 'assistant_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=authorised_type version=0.0.1 uuid=d48b619e-d00d-4008-b884-02d76ea4350b description="A type for 'authorised' values" flavour=Java schema=java.lang.Boolean
+
+ schema create name=branch_ID_type version=0.0.1 uuid=6468845f-4122-4128-8e49-0f52c26078b5 description="A type for 'branch_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=item_ID_type version=0.0.1 uuid=4f227ff1-aee0-453a-b6b6-9a4b2e0da932 description="A type for 'item_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=message_type version=0.0.1 uuid=ad1431bb-3155-4e73-b5a3-b89bee498749 description="A type for 'message' values" flavour=Java schema=java.lang.String
+
+ schema create name=notes_type version=0.0.1 uuid=eecfde90-896c-4343-8f9c-2603ced94e2d description="A type for 'notes' values" flavour=Java schema=java.lang.String
+
+ schema create name=price_type version=0.0.1 uuid=52c2fc45-fd8c-463c-bd6f-d91b0554aea7 description="A type for 'amount'/'price' values" flavour=Java schema=java.lang.Long
+
+ schema create name=quantity_type version=0.0.1 uuid=ac3d9842-80af-4a98-951c-bd79a431c613 description="A type for 'quantity' values" flavour=Java schema=java.lang.Integer
+
+ schema create name=sale_ID_type version=0.0.1 uuid=cca47d74-7754-4a61-b163-ca31f66b157b description="A type for 'sale_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=timestamp_type version=0.0.1 uuid=fd594e88-411d-4a94-b2be-697b3a0d7adf description="A type for 'time' values" flavour=Java schema=java.lang.Long
+
+ task create name=MorningBoozeCheck version=0.0.1 uuid=3351b0f4-cf06-4fa2-8823-edf67bd30223 description=LS
+ This task checks if the sales request is for an item that contains alcohol.
+ If the local time is between 00:00:00 and 11:30:00 then the sale is not authorised. Otherwise the sale is authorised.
+ In this implementation we assume that all items with item_ID values between 1000 and 2000 contain alcohol :-)
+ LE
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=amount schemaName=price_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=time schemaName=timestamp_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=amount schemaName=price_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=authorised schemaName=authorised_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=time schemaName=timestamp_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=message schemaName=message_type schemaVersion=0.0.1 optional=true
+ task logic create name=MorningBoozeCheck version=0.0.1 logicFlavour=MVEL logic=LS
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+ import java.util.Date;
+ import java.util.Calendar;
+ import java.util.TimeZone;
+ import java.text.SimpleDateFormat;
+
+ logger.info("Task Execution: '"+subject.id+"'. Input Fields: '"+inFields+"'");
+
+ outFields.put("amount" , inFields.get("amount"));
+ outFields.put("assistant_ID", inFields.get("assistant_ID"));
+ outFields.put("notes" , inFields.get("notes"));
+ outFields.put("quantity" , inFields.get("quantity"));
+ outFields.put("branch_ID" , inFields.get("branch_ID"));
+ outFields.put("item_ID" , inFields.get("item_ID"));
+ outFields.put("time" , inFields.get("time"));
+ outFields.put("sale_ID" , inFields.get("sale_ID"));
+
+ item_id = inFields.get("item_ID");
+
+ //The events used later to test this task use GMT timezone!
+ gmt = TimeZone.getTimeZone("GMT");
+ timenow = Calendar.getInstance(gmt);
+ df = new SimpleDateFormat("HH:mm:ss z");
+ df.setTimeZone(gmt);
+ timenow.setTimeInMillis(inFields.get("time"));
+
+ midnight = timenow.clone();
+ midnight.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),0,0,0);
+ eleven30 = timenow.clone();
+ eleven30.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),11,30,0);
+
+ itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol
+ && timenow.after(midnight) && timenow.before(eleven30)){
+ outFields.put("authorised", false);
+ outFields.put("message", "Sale not authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime())+
+ ". Alcohol can not be sold between "+df.format(midnight.getTime())+
+ " and "+df.format(eleven30.getTime()));
+ return true;
+ }
+ else{
+ outFields.put("authorised", true);
+ outFields.put("message", "Sale authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime()));
+ return true;
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
+ authorised. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID value between 1000 and
+ 2000 are all alcoholic drinks :-)
+ */
+ LE
+
+ event create name=SALE_AUTH version=0.0.1 uuid=c4500941-3f98-4080-a9cc-5b9753ed050b description="An event emitted by the Policy to indicate whether the sale of an item has been authorised" nameSpace=com.hyperm source="APEX" target="POS"
+ event parameter create name=SALE_AUTH version=0.0.1 parName=amount schemaName=price_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=authorised schemaName=authorised_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=message schemaName=message_type schemaVersion=0.0.1 optional=true
+ event parameter create name=SALE_AUTH version=0.0.1 parName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ event parameter create name=SALE_AUTH version=0.0.1 parName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=time schemaName=timestamp_type schemaVersion=0.0.1
+
+ event create name=SALE_INPUT version=0.0.1 uuid=4f04aa98-e917-4f4a-882a-c75ba5a99374 description="An event raised by the PoS system each time an item is scanned for purchase" nameSpace=com.hyperm source="POS" target="APEX"
+ event parameter create name=SALE_INPUT version=0.0.1 parName=amount schemaName=price_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ event parameter create name=SALE_INPUT version=0.0.1 parName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=time schemaName=timestamp_type schemaVersion=0.0.1
+
+
+ policy create name=MyFirstPolicy version=0.0.1 uuid=6c5e410f-489a-46ff-964e-982ce6e8b6d0 description="This is my first Apex policy. It checks if a sale should be authorised or not." template=FREEFORM firstState=BoozeAuthDecide
+ policy state create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide triggerName=SALE_INPUT triggerVersion=0.0.1 defaultTaskName=MorningBoozeCheck defaultTaskVersion=0.0.1
+ policy state output create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide outputName=MorningBoozeCheck_Output_Direct eventName=SALE_AUTH eventVersion=0.0.1 nextState=NULL
+ policy state taskref create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide taskLocalName=MorningBoozeCheck taskName=MorningBoozeCheck taskVersion=0.0.1 outputType=DIRECT outputName=MorningBoozeCheck_Output_Direct
+
+Policy Step 2
+-------------
+
+Scenario
+#########
+ .. container:: paragraph
+
+ *HyperM* have just opened a new branch in a different
+ country, but that country has different rules about when
+ alcohol can be sold! In this section we will go through
+ the necessary steps to extend our policy to enforce this
+ for *HyperM*.
+
+ .. container:: ulist
+
+ - In some branches alcohol cannot be sold before 1pm,
+ and not at all on Sundays.
+
+ .. container:: paragraph
+
+ Although there are a number of ways to accomplish this
+ the easiest approach for us is to define another task and
+ then select which task is appropriate at runtime
+ depending on the branch identifier in the incoming event.
+
+Extend the Policy with the new Scenario
+#######################################
+
+ .. container:: paragraph
+
+ To create a new Task click on the 'Tasks' tab. In the
+ 'Tasks' pane, right click and select 'Create new Task':
+
+ .. container:: paragraph
+
+ Create a new Task called ``MorningBoozeCheckAlt1``. Use
+ the 'Generate UUID' button to create a new unique ID for
+ the task, and fill in a description for the task. Select
+ the same input and output fields that we used earlier
+ when we defined the ``MorningBoozeCheck`` task earlier.
+
+ .. table:: Table 12. Input fields for ``MorningBoozeCheckAlt1`` task
+
+ +-----------------------------------+-----------------------------------+
+ | Parameter Name | Parameter Type |
+ +===================================+===================================+
+ | time | timestamp_type |
+ +-----------------------------------+-----------------------------------+
+ | sale_ID | sale_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | amount | price_type |
+ +-----------------------------------+-----------------------------------+
+ | item_ID | item_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | quantity | quantity_type |
+ +-----------------------------------+-----------------------------------+
+ | assistant_ID | assistant_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | branch_ID | branch_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | notes | notes_type |
+ +-----------------------------------+-----------------------------------+
+
+ .. table:: Table 13. Output fields for ``MorningBoozeCheckAlt1`` task
+
+ +-----------------------------------+-----------------------------------+
+ | Parameter Name | Parameter Type |
+ +===================================+===================================+
+ | sale_ID | sale_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | time | timestamp_type |
+ +-----------------------------------+-----------------------------------+
+ | authorised | authorised_type |
+ +-----------------------------------+-----------------------------------+
+ | message | message_type |
+ +-----------------------------------+-----------------------------------+
+ | amount | price_type |
+ +-----------------------------------+-----------------------------------+
+ | item_ID | item_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | assistant_ID | assistant_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | quantity | quantity_type |
+ +-----------------------------------+-----------------------------------+
+ | branch_ID | branch_ID_type |
+ +-----------------------------------+-----------------------------------+
+ | notes | notes_type |
+ +-----------------------------------+-----------------------------------+
+
+ .. container:: paragraph
+
+ This task also requires some 'Task Logic' to implement
+ the new behaviour for this task.
+
+ .. container:: paragraph
+
+ For simplicity use the following code for the task logic.
+ It again assumes that all items with ``item_ID`` between
+ 1000 and 2000 contain alcohol. We again use the standard
+ ``Java`` time utilities to check if the current time is
+ between ``00:00:00 CET`` and ``13:00:00 CET`` or if it is
+ ``Sunday``.
+
+ .. container:: paragraph
+
+ For this task we will again author the logic using the
+ ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__
+ scripting language. Sample task logic code (specified in
+ ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__) is
+ given below. For a detailed guide to how to write your
+ own logic in
+ ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__,
+ ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__ or one
+ of the other supported languages please refer to APEX
+ Programmers Guide.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ MVEL code for the ``MorningBoozeCheckAlt1`` task
+
+ .. container:: content
+
+ .. code::
+
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+ import java.util.Date;
+ import java.util.Calendar;
+ import java.util.TimeZone;
+ import java.text.SimpleDateFormat;
+
+ logger.info("Task Execution: '"+subject.id+"'. Input Event: '"+inFields+"'");
+
+ outFields.put("amount" , inFields.get("amount"));
+ outFields.put("assistant_ID", inFields.get("assistant_ID"));
+ outFields.put("notes" , inFields.get("notes"));
+ outFields.put("quantity" , inFields.get("quantity"));
+ outFields.put("branch_ID" , inFields.get("branch_ID"));
+ outFields.put("item_ID" , inFields.get("item_ID"));
+ outFields.put("time" , inFields.get("time"));
+ outFields.put("sale_ID" , inFields.get("sale_ID"));
+
+ item_id = inFields.get("item_ID");
+
+ //The events used later to test this task use CET timezone!
+ cet = TimeZone.getTimeZone("CET");
+ timenow = Calendar.getInstance(cet);
+ df = new SimpleDateFormat("HH:mm:ss z");
+ df.setTimeZone(cet);
+ timenow.setTimeInMillis(inFields.get("time"));
+
+ midnight = timenow.clone();
+ midnight.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),0,0,0);
+ onepm = timenow.clone();
+ onepm.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),13,0,0);
+
+ itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol &&
+ ( (timenow.after(midnight) && timenow.before(onepm))
+ ||
+ (timenow.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
+ )){
+ outFields.put("authorised", false);
+ outFields.put("message", "Sale not authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime())+
+ ". Alcohol can not be sold between "+df.format(midnight.getTime())+
+ " and "+df.format(onepm.getTime()) +" or on Sunday");
+ return true;
+ }
+ else{
+ outFields.put("authorised", true);
+ outFields.put("message", "Sale authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime()));
+ return true;
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 CET and 13:00:00 CET then the sale is not authorised.
+ Also alcohol sales are not allowed on Sundays. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID between 1000 and 2000 are all alcoholic drinks :-)
+ */
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Create a new alternative task MorningBoozeCheckAlt1|
+
+ .. container:: title
+
+ Figure 19. Create a new Task
+
+ .. container:: paragraph
+
+ The task definition is now complete so click the 'Submit'
+ button to save the task. Now that we have created our
+ task, we can can add this task to the single pre-existing
+ state (``BoozeAuthDecide``) in our policy.
+
+ .. container:: paragraph
+
+ To edit the ``BoozeAuthDecide`` state in our policy click
+ on the 'Policies' tab. In the 'Policies' pane, right
+ click on our ``MyFirstPolicy`` policy and select 'Edit'.
+ Navigate to the ``BoozeAuthDecide`` state in the 'states'
+ section at the bottom of the policy definition pane.
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |Right click to edit a policy|
+
+ .. container:: title
+
+ Figure 20. Edit a Policy
+
+ .. container:: paragraph
+
+ To add our new task ``MorningBoozeCheckAlt1``, scroll
+ down to the ``BoozeAuthDecide`` state in the 'States'
+ section. In the 'State Tasks' section for
+ ``BoozeAuthDecide`` use the 'Add new task' button. Select
+ our new ``MorningBoozeCheckAlt1`` task, and use the name
+ of the task as the 'Local Name' for the task. The
+ ``MorningBoozeCheckAlt1`` task can reuse the same
+ ``MorningBoozeCheck_Output_Direct`` 'Direct State Output
+ Mapping' that we used for the ``MorningBoozeCheck`` task.
+ (Recall that the role of the 'State Output Mapping' is to
+ select the output event for the state, and select the
+ next state to be executed. These both remain the same as
+ before.)
+
+ .. container:: paragraph
+
+ Since our state has more than one task we must define
+ some logic to determine which task should be used each
+ time the state is executed. This *task selection logic*
+ is defined in the state definition. For our
+ ``BoozeAuthDecide`` state we want the choice of which
+ task to use to be based on the ``branch_ID`` from which
+ the ``SALE_INPUT`` event originated. For simplicity sake
+ let us assume that branches with ``branch_ID`` between
+ ``0`` and ``999`` should use the ``MorningBoozeCheck``
+ task, and the branches with with ``branch_ID`` between
+ ``1000`` and ``1999`` should use the
+ ``MorningBoozeCheckAlt1`` task.
+
+ .. container:: paragraph
+
+ This time, for variety, we will author the task selection
+ logic using the
+ ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__
+ scripting language. Sample task selection logic code
+ (specified in
+ ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__)
+ is given below. Paste the script text into the 'Task
+ Selection Logic' box, and use "JAVASCRIPT" as the 'Task
+ Selection Logic Type / Flavour'. It is necessary to mark
+ one of the tasks as the 'Default Task' so that the task
+ selection logic always has a fallback default option in
+ cases where a particular task cannot be selected. In this
+ case the ``MorningBoozeCheck`` task can be the default
+ task.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JavaScript code for the ``BoozeAuthDecide`` task
+ selection logic
+
+ .. container:: content
+
+ .. code::
+
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+
+ var returnValueType = Java.type("java.lang.Boolean");
+ var returnValue = new returnValueType(true);
+
+ executor.logger.info("Task Selection Execution: '"+executor.subject.id+
+ "'. Input Event: '"+executor.inFields+"'");
+
+ branchid = executor.inFields.get("branch_ID");
+ taskorig = executor.subject.getTaskKey("MorningBoozeCheck");
+ taskalt = executor.subject.getTaskKey("MorningBoozeCheckAlt1");
+ taskdef = executor.subject.getDefaultTaskKey();
+
+ if(branchid >=0 && branchid <1000){
+ taskorig.copyTo(executor.selectedTask);
+ }
+ else if (branchid >=1000 && branchid <2000){
+ taskalt.copyTo(executor.selectedTask);
+ }
+ else{
+ taskdef.copyTo(executor.selectedTask);
+ }
+
+ /*
+ This task selection logic selects task "MorningBoozeCheck" for branches with
+ 0<=branch_ID<1000 and selects task "MorningBoozeCheckAlt1" for branches with
+ 1000<=branch_ID<2000. Otherwise the default task is selected.
+ In this case the default task is also "MorningBoozeCheck"
+ */
+
+ .. container:: imageblock
+
+ .. container:: content
+
+ |State definition with 2 Tasks and Task Selection
+ Logic|
+
+ .. container:: title
+
+ Figure 21. State definition with 2 Tasks and Task
+ Selection Logic
+
+ .. container:: paragraph
+
+ When complete don’t forget to click the 'Submit' button
+ at the bottom of 'Policies' pane for our
+ ``MyFirstPolicy`` policy after updating the
+ ``BoozeAuthDecide`` state.
+
+ .. container:: paragraph
+
+ Congratulations, you have now completed the second step
+ towards your first APEX policy. The policy model
+ containing our new policy can again be validated and
+ exported from the editor and saved as shown in Step 1.
+
+ .. container:: paragraph
+
+ The exported policy model is then available in the
+ directory you selected, as
+ `MyFirstPolicyModel_0.0.1.json <files/mfp-files/2/MyFirstPolicyModel_0.0.1.json>`__.
+ The exported policy can now be loaded into the APEX
+ Policy Engine, or can be re-loaded and edited by the APEX
+ Policy Editor.
+
+Test Policy Step 2
+##################
+
+ .. container:: paragraph
+
+ To start a new APEX Engine you can use the following
+ configuration. In a full APEX installation you can find
+ this configuration in
+ ``$APEX_HOME/examples/config/MyFirstPolicy/2/MyFirstPolicyConfigStdin2StdoutJsonEvent.json``.
+ Note, this has changed from the configuration file in
+ Step 1 to enable the ``JAVASCRIPT`` executor for our new
+ 'Task Selection Logic'.
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ JSON to load and execute *My First Policy*, read input
+ JSON events from ``stdin``, and emit output events to
+ ``stdout``
+
+ .. container:: content
+
+ .. code::
+
+ {
+ "engineServiceParameters" : {
+ "name" : "MyFirstPolicyApexEngine",
+ "version" : "0.0.1",
+ "id" : 102,
+ "instanceCount" : 4,
+ "deploymentPort" : 12345,
+ "policyModelFileName" : "examples/models/MyFirstPolicy/2/MyFirstPolicyModel_0.0.1.json",
+ "engineParameters" : {
+ "executorParameters" : {
+ "MVEL" : {
+ "parameterClassName" : "org.onap.policy.apex.plugins.executor.mvel.MVELExecutorParameters"
+ },
+ "JAVASCRIPT" : {
+ "parameterClassName" : "org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"
+ }
+ }
+ }
+ },
+ "eventOutputParameters": {
+ "FirstProducer": {
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE",
+ "parameters" : {
+ "standardIO" : true
+ }
+ },
+ "eventProtocolParameters" : {
+ "eventProtocol" : "JSON"
+ }
+ }
+ },
+ "eventInputParameters": {
+ "FirstConsumer": {
+ "carrierTechnologyParameters" : {
+ "carrierTechnology" : "FILE",
+ "parameters" : {
+ "standardIO" : true
+ }
+ },
+ "eventProtocolParameters" : {
+ "eventProtocol" : "JSON"
+ }
+ }
+ }
+ }
+
+ .. container:: paragraph
+
+ To test the policy try paste the following events into
+ the console as the APEX engine executes. Note, all tests
+ from Step 1 will still work perfectly since none of those
+ events originate from a branch with ``branch_ID`` between
+ ``1000`` and ``2000``. The 'Task Selection Logic' will
+ therefore pick the ``MorningBoozeCheck`` task as
+ expected, and will therefore give the same results.
+
+ .. table:: Table 14. Inputs and Outputs when testing *My First Policy*
+
+ +----------------------------------------------+------------------------------------------------------------+---------------------------+
+ | Input Event (JSON) | Output Event (JSON) | comment |
+ +==============================================+============================================================+===========================+
+ | .. container:: | .. container:: | Request to buy |
+ | | | alcohol item |
+ | .. container:: listingblock | .. container:: listingblock | (``item_ID=1249``) |
+ | | | |
+ | | | at *08:41:06 |
+ | | .. container:: content | GMT* on *Monday, |
+ | .. container:: content | | 02 January |
+ | | .. code:: | 2017*. |
+ | | | |
+ | | { | Sale is not |
+ | .. code:: | "nameSpace": "com.hyperm", | authorized. Uses |
+ | | "name": "SALE_AUTH", | the |
+ | | "version": "0.0.1", | ``MorningBoozeCheck`` |
+ | { | "source": "", | |
+ | "nameSpace": "com.hyperm", | "target": "", | task. |
+ | "name": "SALE_INPUT", | "amount": 1249, | |
+ | "version": "0.0.1", | "assistant_ID":12, | Note this test |
+ | "time": 1483346466000, | "authorised": false, | is copied from |
+ | "sale_ID": 99999992, | "branch_ID": 2, | Step 1 above, |
+ | "amount": 1249, | "item_ID": 1012, | and demonstrates |
+ | "item_ID": 1012, | "message": "Sale not authorised by policy ta | that the |
+ | "quantity": 1, | sk MorningBoozeCheck for time 08:41:06 GMT.| original |
+ | "assistant_ID": 12, | Alcohol can not be sold between 00:00:00 | ``MorningBoozeCheck`` |
+ | "branch_ID": 2 | GMT and 11:30:00 GMT", | |
+ | } | "notes": null, | task is |
+ | | "quantity": 1, | executed. |
+ | | "sale_ID": 99999992, | |
+ | | "time": 1483346466000 | |
+ | | } | |
+ +----------------------------------------------+------------------------------------------------------------+---------------------------+
+ | .. container:: | .. container:: | Request to buy |
+ | | | alcohol |
+ | .. container:: listingblock | .. container:: listingblock | (``item_ID=1047``) |
+ | | | |
+ | | | at *10:14:33* on |
+ | | .. container:: content | *Thursday, 22 |
+ | .. container:: content | | December 2016*. |
+ | | .. code:: | |
+ | | | Sale is not |
+ | | { | authorized. Uses |
+ | .. code:: | "nameSpace" : "com.hyperm", | the |
+ | | "name" : "SALE_AUTH", | ``MorningBoozeCheckAlt1`` |
+ | | "version" : "0.0.1", | task. |
+ | { | "source" : "", | |
+ | | "target" : "", | |
+ | "nameSpace": "com.hyperm", | "sale_ID" : 99999981, | |
+ | "name": "SALE_INPUT", | "amount" : 299, | |
+ | "version": "0.0.1", | "assistant_ID": 1212, | |
+ | "time": 1482398073000, | "notes" : null, | |
+ | "sale_ID": 99999981, | "quantity" : 1, | |
+ | "amount": 299, | "branch_ID" : 1002, | |
+ | "item_ID": 1047, | "item_ID" : 1047, | |
+ | "quantity": 1, | "authorised" : false, | |
+ | "assistant_ID": 1212, | "time" : 1482398073000, | |
+ | "branch_ID": 1002 | "message" : "Sale not authorised by policy t | |
+ | } | ask MorningBoozeCheckAlt1 fortime | |
+ | | 10:14:33 CET. Alcohol can not be sold | |
+ | | between 00:00:00 CET and 13:00:00 CET or on | |
+ | | Sunday" | |
+ | | } | |
+ +----------------------------------------------+------------------------------------------------------------+---------------------------+
+ | .. container:: | .. container:: | Request to buy |
+ | | | alcohol |
+ | .. container:: listingblock | .. container:: listingblock | (``item_ID=1443``) |
+ | | | |
+ | | | at *17:19:37* on |
+ | | .. container:: content | *Sunday, 18 |
+ | .. container:: content | | December 2016*. |
+ | | .. code:: | |
+ | | | Sale is not |
+ | | { | authorized. Uses |
+ | .. code:: | "nameSpace" : "com.hyperm", | the |
+ | | | ``MorningBoozeCheckAlt1`` |
+ | | "name" : "SALE_AUTH", | task. |
+ | { | | |
+ | "nameSpace": "com.hyperm", | "version" : "0.0.1", | |
+ | "name": "SALE_INPUT", | "source" : "", | |
+ | "version": "0.0.1", | "target" : "", | |
+ | "time": 1482077977000, | "sale_ID" : 99999982, | |
+ | "sale_ID": 99999982, | "amount" : 2199, | |
+ | "amount": 2199, | "assistant_ID" : 94, | |
+ | "item_ID": 1443, | "notes" : "Buy 3, get 1 free!!", | |
+ | "quantity": 12, | "quantity" : 12, | |
+ | "assistant_ID": 94, | "branch_ID" : 1003, | |
+ | "branch_ID": 1003, | "item_ID" : 1443, | |
+ | "notes": "Buy 3, get 1 free!!" | "authorised" : false, | |
+ | } | "time" : 1482077977000, | |
+ | | "message" : "Sale not authorised by policy t | |
+ | | ask MorningBoozeCheckAlt1 for | |
+ | | time 17:19:37 CET. Alcohol c | |
+ | | an not be sold between 00:00: | |
+ | | 00 CET and 13:00:00 CET or on | |
+ | | Sunday" | |
+ +----------------------------------------------+------------------------------------------------------------+---------------------------+
+ | .. container:: | .. container:: | Request to buy |
+ | | | non-alcoholic |
+ | .. container:: listingblock | .. container:: listingblock | item |
+ | | | (``item_ID=5321``) |
+ | | | |
+ | | .. container:: content | at *11:13:09* on |
+ | .. container:: content | | *Monday, 2 |
+ | | .. code:: | January 2017*. |
+ | | | |
+ | | { | Sale is |
+ | .. code:: | "nameSpace" : "com.hyperm", | authorized. Uses |
+ | | "name" : "SALE_AUTH", | the |
+ | { | "version" : "0.0.1", | ``MorningBoozeCheckAlt1`` |
+ | "nameSpace": "com.hyperm", | "source" : "", | task. |
+ | "name": "SALE_INPUT", | "target" : "", | |
+ | "version": "0.0.1", | "sale_ID" : 99999983, | |
+ | "time": 1483351989000, | "amount" : 699, | |
+ | "sale_ID": 99999983, | "assistant_ID" : 2323, | |
+ | "amount": 699, | "notes" : "", | |
+ | tem_ID": 5321, | "quantity" : 1, | |
+ | "quantity": 1, | "branch_ID" : 1001, | |
+ | "assistant_ID": 2323, | "item_ID" : 5321, | |
+ | "branch_ID": 1001, | "authorised" : true, | |
+ | "notes": "" | "time" : 1483351989000, | |
+ | } | "message" : "Sale authorised by policy task | |
+ | | MorningBoozeCheckAlt1 for time 11:13:09 CET"| |
+ | | } | |
+ +----------------------------------------------+------------------------------------------------------------+---------------------------+
+
+Policy 2 in CLI Editor
+######################
+
+ .. container:: paragraph
+
+ An equivalent version of the ``MyFirstPolicyModel``
+ policy model can again be generated using the APEX CLI
+ editor. A sample APEX CLI script is shown below:
+
+ .. container:: listingblock
+
+ .. container:: title
+
+ APEX CLI Editor code for Policy 2
+
+ .. container:: content
+
+ .. code::
+
+ #-------------------------------------------------------------------------------
+ # ============LICENSE_START=======================================================
+ # Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ # ================================================================================
+ # Licensed 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.
+ #
+ # SPDX-License-Identifier: Apache-2.0
+ # ============LICENSE_END=========================================================
+ #-------------------------------------------------------------------------------
+
+ model create name=MyFirstPolicyModel version=0.0.1 uuid=540226fb-55ee-4f0e-a444-983a0494818e description="This is my first Apex Policy Model."
+
+ schema create name=assistant_ID_type version=0.0.1 uuid=36df4c71-9616-4206-8b53-976a5cd4bd87 description="A type for 'assistant_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=authorised_type version=0.0.1 uuid=d48b619e-d00d-4008-b884-02d76ea4350b description="A type for 'authorised' values" flavour=Java schema=java.lang.Boolean
+
+ schema create name=branch_ID_type version=0.0.1 uuid=6468845f-4122-4128-8e49-0f52c26078b5 description="A type for 'branch_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=item_ID_type version=0.0.1 uuid=4f227ff1-aee0-453a-b6b6-9a4b2e0da932 description="A type for 'item_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=message_type version=0.0.1 uuid=ad1431bb-3155-4e73-b5a3-b89bee498749 description="A type for 'message' values" flavour=Java schema=java.lang.String
+
+ schema create name=notes_type version=0.0.1 uuid=eecfde90-896c-4343-8f9c-2603ced94e2d description="A type for 'notes' values" flavour=Java schema=java.lang.String
+
+ schema create name=price_type version=0.0.1 uuid=52c2fc45-fd8c-463c-bd6f-d91b0554aea7 description="A type for 'amount'/'price' values" flavour=Java schema=java.lang.Long
+
+ schema create name=quantity_type version=0.0.1 uuid=ac3d9842-80af-4a98-951c-bd79a431c613 description="A type for 'quantity' values" flavour=Java schema=java.lang.Integer
+
+ schema create name=sale_ID_type version=0.0.1 uuid=cca47d74-7754-4a61-b163-ca31f66b157b description="A type for 'sale_ID' values" flavour=Java schema=java.lang.Long
+
+ schema create name=timestamp_type version=0.0.1 uuid=fd594e88-411d-4a94-b2be-697b3a0d7adf description="A type for 'time' values" flavour=Java schema=java.lang.Long
+
+ task create name=MorningBoozeCheck version=0.0.1 uuid=3351b0f4-cf06-4fa2-8823-edf67bd30223 description=LS
+ This task checks if the sales request is for an item that contains alcohol.
+ If the local time is between 00:00:00 and 11:30:00 then the sale is not authorised. Otherwise the sale is authorised.
+ In this implementation we assume that all items with item_ID values between 1000 and 2000 contain alcohol :-)
+ LE
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=amount schemaName=price_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheck version=0.0.1 fieldName=time schemaName=timestamp_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=amount schemaName=price_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=authorised schemaName=authorised_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=time schemaName=timestamp_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheck version=0.0.1 fieldName=message schemaName=message_type schemaVersion=0.0.1 optional=true
+ task logic create name=MorningBoozeCheck version=0.0.1 logicFlavour=MVEL logic=LS
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+ import java.util.Date;
+ import java.util.Calendar;
+ import java.util.TimeZone;
+ import java.text.SimpleDateFormat;
+
+ logger.info("Task Execution: '"+subject.id+"'. Input Fields: '"+inFields+"'");
+
+ outFields.put("amount" , inFields.get("amount"));
+ outFields.put("assistant_ID", inFields.get("assistant_ID"));
+ outFields.put("notes" , inFields.get("notes"));
+ outFields.put("quantity" , inFields.get("quantity"));
+ outFields.put("branch_ID" , inFields.get("branch_ID"));
+ outFields.put("item_ID" , inFields.get("item_ID"));
+ outFields.put("time" , inFields.get("time"));
+ outFields.put("sale_ID" , inFields.get("sale_ID"));
+
+ item_id = inFields.get("item_ID");
+
+ //The events used later to test this task use GMT timezone!
+ gmt = TimeZone.getTimeZone("GMT");
+ timenow = Calendar.getInstance(gmt);
+ df = new SimpleDateFormat("HH:mm:ss z");
+ df.setTimeZone(gmt);
+ timenow.setTimeInMillis(inFields.get("time"));
+
+ midnight = timenow.clone();
+ midnight.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),0,0,0);
+ eleven30 = timenow.clone();
+ eleven30.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),11,30,0);
+
+ itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol
+ && timenow.after(midnight) && timenow.before(eleven30)){
+ outFields.put("authorised", false);
+ outFields.put("message", "Sale not authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime())+
+ ". Alcohol can not be sold between "+df.format(midnight.getTime())+
+ " and "+df.format(eleven30.getTime()));
+ return true;
+ }
+ else{
+ outFields.put("authorised", true);
+ outFields.put("message", "Sale authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime()));
+ return true;
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
+ authorised. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID value between 1000 and
+ 2000 are all alcoholic drinks :-)
+ */
+ LE
+
+ task create name=MorningBoozeCheckAlt1 version=0.0.1 uuid=bc6d90c9-c902-4686-afd3-925b30e39990 description=LS
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 CET and 13:00:00 CET then the sale is not authorised.
+ Also alcohol sales are not allowed on Sundays. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID between 1000 and 2000 are all alcoholic drinks
+ LE
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=amount schemaName=price_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ task inputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=time schemaName=timestamp_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=amount schemaName=price_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=authorised schemaName=authorised_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=time schemaName=timestamp_type schemaVersion=0.0.1
+ task outputfield create name=MorningBoozeCheckAlt1 version=0.0.1 fieldName=message schemaName=message_type schemaVersion=0.0.1 optional=true
+ task logic create name=MorningBoozeCheckAlt1 version=0.0.1 logicFlavour=MVEL logic=LS
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+ import java.util.Date;
+ import java.util.Calendar;
+ import java.util.TimeZone;
+ import java.text.SimpleDateFormat;
+
+ logger.info("Task Execution: '"+subject.id+"'. Input Event: '"+inFields+"'");
+
+ outFields.put("amount" , inFields.get("amount"));
+ outFields.put("assistant_ID", inFields.get("assistant_ID"));
+ outFields.put("notes" , inFields.get("notes"));
+ outFields.put("quantity" , inFields.get("quantity"));
+ outFields.put("branch_ID" , inFields.get("branch_ID"));
+ outFields.put("item_ID" , inFields.get("item_ID"));
+ outFields.put("time" , inFields.get("time"));
+ outFields.put("sale_ID" , inFields.get("sale_ID"));
+
+ item_id = inFields.get("item_ID");
+
+ //The events used later to test this task use CET timezone!
+ cet = TimeZone.getTimeZone("CET");
+ timenow = Calendar.getInstance(cet);
+ df = new SimpleDateFormat("HH:mm:ss z");
+ df.setTimeZone(cet);
+ timenow.setTimeInMillis(inFields.get("time"));
+
+ midnight = timenow.clone();
+ midnight.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),0,0,0);
+ onepm = timenow.clone();
+ onepm.set(
+ timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
+ timenow.get(Calendar.DATE),13,0,0);
+
+ itemisalcohol = false;
+ if(item_id != null && item_id >=1000 && item_id < 2000)
+ itemisalcohol = true;
+
+ if( itemisalcohol &&
+ ( (timenow.after(midnight) && timenow.before(onepm))
+ ||
+ (timenow.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
+ )){
+ outFields.put("authorised", false);
+ outFields.put("message", "Sale not authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime())+
+ ". Alcohol can not be sold between "+df.format(midnight.getTime())+
+ " and "+df.format(onepm.getTime()) +" or on Sunday");
+ return true;
+ }
+ else{
+ outFields.put("authorised", true);
+ outFields.put("message", "Sale authorised by policy task "+subject.taskName+
+ " for time "+df.format(timenow.getTime()));
+ return true;
+ }
+
+ /*
+ This task checks if a sale request is for an item that is an alcoholic drink.
+ If the local time is between 00:00:00 CET and 13:00:00 CET then the sale is not authorised.
+ Also alcohol sales are not allowed on Sundays. Otherwise the sale is authorised.
+ In this implementation we assume that items with item_ID between 1000 and 2000 are all alcoholic drinks :-)
+ */
+ LE
+
+ event create name=SALE_AUTH version=0.0.1 uuid=c4500941-3f98-4080-a9cc-5b9753ed050b description="An event emitted by the Policy to indicate whether the sale of an item has been authorised" nameSpace=com.hyperm source="APEX" target="POS"
+ event parameter create name=SALE_AUTH version=0.0.1 parName=amount schemaName=price_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=authorised schemaName=authorised_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=message schemaName=message_type schemaVersion=0.0.1 optional=true
+ event parameter create name=SALE_AUTH version=0.0.1 parName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ event parameter create name=SALE_AUTH version=0.0.1 parName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_AUTH version=0.0.1 parName=time schemaName=timestamp_type schemaVersion=0.0.1
+
+ event create name=SALE_INPUT version=0.0.1 uuid=4f04aa98-e917-4f4a-882a-c75ba5a99374 description="An event raised by the PoS system each time an item is scanned for purchase" nameSpace=com.hyperm source="POS" target="APEX"
+ event parameter create name=SALE_INPUT version=0.0.1 parName=amount schemaName=price_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=assistant_ID schemaName=assistant_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=branch_ID schemaName=branch_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=item_ID schemaName=item_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=notes schemaName=notes_type schemaVersion=0.0.1 optional=true
+ event parameter create name=SALE_INPUT version=0.0.1 parName=quantity schemaName=quantity_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=sale_ID schemaName=sale_ID_type schemaVersion=0.0.1
+ event parameter create name=SALE_INPUT version=0.0.1 parName=time schemaName=timestamp_type schemaVersion=0.0.1
+
+
+ policy create name=MyFirstPolicy version=0.0.1 uuid=6c5e410f-489a-46ff-964e-982ce6e8b6d0 description="This is my first Apex policy. It checks if a sale should be authorised or not." template=FREEFORM firstState=BoozeAuthDecide
+ policy state create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide triggerName=SALE_INPUT triggerVersion=0.0.1 defaultTaskName=MorningBoozeCheck defaultTaskVersion=0.0.1
+ policy state output create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide outputName=MorningBoozeCheck_Output_Direct eventName=SALE_AUTH eventVersion=0.0.1 nextState=NULL
+ policy state taskref create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide taskLocalName=MorningBoozeCheckAlt1 taskName=MorningBoozeCheckAlt1 taskVersion=0.0.1 outputType=DIRECT outputName=MorningBoozeCheck_Output_Direct
+ policy state taskref create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide taskLocalName=MorningBoozeCheck taskName=MorningBoozeCheck taskVersion=0.0.1 outputType=DIRECT outputName=MorningBoozeCheck_Output_Direct
+ policy state selecttasklogic create name=MyFirstPolicy version=0.0.1 stateName=BoozeAuthDecide logicFlavour=JAVASCRIPT logic=LS
+ /*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+ var returnValueType = Java.type("java.lang.Boolean");
+ var returnValue = new returnValueType(true);
+
+ executor.logger.info("Task Selection Execution: '"+executor.subject.id+"'. Input Event: '"+executor.inFields+"'");
+
+ branchid = executor.inFields.get("branch_ID");
+ taskorig = executor.subject.getTaskKey("MorningBoozeCheck");
+ taskalt = executor.subject.getTaskKey("MorningBoozeCheckAlt1");
+ taskdef = executor.subject.getDefaultTaskKey();
+
+ if(branchid >=0 && branchid <1000){
+ taskorig.copyTo(executor.selectedTask);
+ }
+ else if (branchid >=1000 && branchid <2000){
+ taskalt.copyTo(executor.selectedTask);
+ }
+ else{
+ taskdef.copyTo(executor.selectedTask);
+ }
+
+ /*
+ This task selection logic selects task "MorningBoozeCheck" for branches with 0<=branch_ID<1000 and selects task "MorningBoozeCheckAlt1" for branches with 1000<=branch_ID<2000. Otherwise the default task is selected. In this case the default task is also "MorningBoozeCheck"
+ */
+ LE
+
+APEX Logging
+^^^^^^^^^^^^
+
+Introduction to APEX Logging
+----------------------------
+
+ .. container:: paragraph
+
+ All APEX components make extensive use of logging using the
+ logging façade `SLF4J <https://www.slf4j.org/>`__ with the
+ backend `Logback <https://logback.qos.ch/>`__. Both are used
+ off-the-shelve, so the standard documentation and
+ configuration apply to APEX logging. For details on how to
+ work with logback please see the `logback
+ manual <https://logback.qos.ch/manual/index.html>`__.
+
+ .. container:: paragraph
+
+ The APEX applications is the logback configuration file
+ ``$APEX_HOME/etc/logback.xml`` (Windows:
+ ``%APEX_HOME%\etc\logback.xml``). The logging backend is set
+ to no debug, i.e. logs from the logging framework should be
+ hidden at runtime.
+
+ .. container:: paragraph
+
+ The configurable log levels work as expected:
+
+ .. container:: ulist
+
+ - *error* (or *ERROR*) is used for serious errors in the
+ APEX runtime engine
+
+ - *warn* (or *WARN*) is used for warnings, which in general
+ can be ignored but might indicate some deeper problems
+
+ - *info* (or *INFO*) is used to provide generally
+ interesting messages for startup and policy execution
+
+ - *debug* (or *DEBUG*) provides more details on startup and
+ policy execution
+
+ - *trace* (or *TRACE*) gives full details on every aspect
+ of the APEX engine from start to end
+
+ .. container:: paragraph
+
+ The loggers can also be configured as expected. The standard
+ configuration (after installing APEX) uses log level *info*
+ on all APEX classes (components).
+
+ .. container:: paragraph
+
+ The applications and scripts in ``$APEX_HOME/bin`` (Windows:
+ ``%APEX_HOME\bin``) are configured to use the logback
+ configuration ``$APEX_HOME/etc/logback.xml`` (Windows:
+ ``%APEX_HOME\etc\logback.xml``). There are multiple ways to
+ use different logback configurations, for instance:
+
+ .. container:: ulist
+
+ - Maintain multiple configurations in ``etc``, for instance
+ a ``logback-debug.xml`` for deep debugging and a
+ ``logback-production.xml`` for APEX in production mode,
+ then copy the required configuration file to the used
+ ``logback.xml`` prior starting APEX
+
+ - Edit the scripts in ``bin`` to use a different logback
+ configuration file (only recommended if you are familiar
+ with editing bash scripts or windows batch files)
+
+Standard Logging Configuration
+------------------------------
+
+ .. container:: paragraph
+
+ The standard logging configuration defines a context *APEX*,
+ which is used in the standard output pattern. The location
+ for log files is defined in the property ``VAR_LOG`` and set
+ to ``/var/log/onap/policy/apex-pdp``. The standard status
+ listener is set to *NOP* and the overall logback
+ configuration is set to no debug.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ <configuration debug="false">
+ <statusListener class="ch.qos.logback.core.status.NopStatusListener" />
+
+ <contextName>Apex</contextName>
+ <property name="VAR_LOG" value="/var/log/onap/policy/apex-pdp/" />
+
+ ...appenders
+ ...loggers
+ </configuration>
+
+.. container:: paragraph
+
+ The first appender defined is called ``STDOUT`` for logs to standard
+ out.
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <Pattern>%d %contextName [%t] %level %logger{36} - %msg%n</Pattern>
+ </encoder>
+ </appender>
+
+.. container:: paragraph
+
+ The root level logger then is set to the level *info* using the
+ standard out appender.
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ <root level="info">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+.. container:: paragraph
+
+ The second appender is called ``FILE``. It writes logs to a file
+ ``apex.log``.
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>${VAR_LOG}/apex.log</file>
+ <encoder>
+ <pattern>%d %-5relative [procId=${processId}] [%thread] %-5level %logger{26} - %msg %n %ex{full}</pattern>
+ </encoder>
+ </appender>
+
+.. container:: paragraph
+
+ The third appender is called ``CTXT_FILE``. It writes logs to a file
+ ``apex_ctxt.log``.
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ <appender name="CTXT_FILE" class="ch.qos.logback.core.FileAppender">
+ <file>${VAR_LOG}/apex_ctxt.log</file>
+ <encoder>
+ <pattern>%d %-5relative [procId=${processId}] [%thread] %-5level %logger{26} - %msg %n %ex{full}</pattern>
+ </encoder>
+ </appender>
+
+.. container:: paragraph
+
+ The last definitions are for specific loggers. The first logger
+ captures all standard APEX classes. It is configured for log level
+ *info* and uses the standard output and file appenders. The second
+ logger captures APEX context classes responsible for context
+ monitoring. It is configured for log level *trace* and uses the
+ context file appender.
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+
+ <logger name="org.onap.policy.apex" level="info" additivity="false">
+ <appender-ref ref="STDOUT" />
+ <appender-ref ref="FILE" />
+ </logger>
+
+ <logger name="org.onap.policy.apex.core.context.monitoring" level="TRACE" additivity="false">
+ <appender-ref ref="CTXT_FILE" />
+ </logger>
+
+Adding Logback Status and Debug
+-------------------------------
+
+ .. container:: paragraph
+
+ To activate logback status messages change the status listener
+ from 'NOP' to for instance console.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
+
+ .. container:: paragraph
+
+ To activate all logback debugging, for instance to debug a new
+ logback configuration, activate the debug attribute in the
+ configuration.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <configuration debug="true">
+ ...
+ </configuration>
+
+Logging External Components
+---------------------------
+
+ .. container:: paragraph
+
+ Logback can also be configured to log any other, external
+ components APEX is using, if they are using the common logging
+ framework.
+
+ .. container:: paragraph
+
+ For instance, the context component of APEX is using *Infinispan*
+ and one can add a logger for this external component. The
+ following example adds a logger for *Infinispan* using the
+ standard output appender.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <logger name="org.infinispan" level="INFO" additivity="false">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ .. container:: paragraph
+
+ Another example is Apache Zookeeper. The following example adds a
+ logger for Zookeeper using the standard outout appender.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <logger name="org.apache.zookeeper.ClientCnxn" level="INFO" additivity="false">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+Configuring loggers for Policy Logic
+------------------------------------
+
+ .. container:: paragraph
+
+ The logging for the logic inside a policy (task logic, task
+ selection logic, state finalizer logic) can be configured separate
+ from standard logging. The logger for policy logic is
+ ``org.onap.policy.apex.executionlogging``. The following example
+ defines
+
+ .. container:: ulist
+
+ - a new appender for standard out using a very simple pattern
+ (simply the actual message)
+
+ - a logger for policy logic to standard out using the new
+ appender and the already described file appender.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <appender name="POLICY_APPENDER_STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>policy: %msg\n</pattern>
+ </encoder>
+ </appender>
+
+ <logger name="org.onap.policy.apex.executionlogging" level="info" additivity="false">
+ <appender-ref ref="POLICY_APPENDER_STDOUT" />
+ <appender-ref ref="FILE" />
+ </logger>
+
+ .. container:: paragraph
+
+ It is also possible to use specific logging for parts of policy
+ logic. The following example defines a logger for task logic.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <logger name="org.onap.policy.apex.executionlogging.TaskExecutionLogging" level="TRACE" additivity="false">
+ <appender-ref ref="POLICY_APPENDER_STDOUT" />
+ </logger>
+
+Rolling File Appenders
+----------------------
+
+ .. container:: paragraph
+
+ Rolling file appenders are a good option for more complex logging
+ of a production or complex testing APEX installation. The standard
+ logback configuration can be used for these use cases. This
+ section gives two examples for the standard logging and for
+ context logging.
+
+ .. container:: paragraph
+
+ First the standard logging. The following example defines a
+ rolling file appender. The appender rolls over on a daily basis.
+ It allows for a file size of 100 MB.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${VAR_LOG}/apex.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- rollover daily -->
+ <!-- <fileNamePattern>xstream-%d{yyyy-MM-dd}.%i.txt</fileNamePattern> -->
+ <fileNamePattern>${VAR_LOG}/apex_%d{yyyy-MM-dd}.%i.log.gz
+ </fileNamePattern>
+ <maxHistory>4</maxHistory>
+ <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+ <!-- or whenever the file size reaches 100MB -->
+ <maxFileSize>100MB</maxFileSize>
+ </timeBasedFileNamingAndTriggeringPolicy>
+ </rollingPolicy>
+ <encoder>
+ <pattern>
+ %d %-5relative [procId=${processId}] [%thread] %-5level %logger{26} - %msg %ex{full} %n
+ </pattern>
+ </encoder>
+ </appender>
+
+ .. container:: paragraph
+
+ A very similar configuration can be used for a rolling file
+ appender logging APEX context.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <appender name="CTXT-FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${VAR_LOG}/apex_ctxt.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <fileNamePattern>${VAR_LOG}/apex_ctxt_%d{yyyy-MM-dd}.%i.log.gz
+ </fileNamePattern>
+ <maxHistory>4</maxHistory>
+ <timeBasedFileNamingAndTriggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+ <maxFileSize>100MB</maxFileSize>
+ </timeBasedFileNamingAndTriggeringPolicy>
+ </rollingPolicy>
+ <encoder>
+ <pattern>
+ %d %-5relative [procId=${processId}] [%thread] %-5level %logger{26} - %msg %ex{full} %n
+ </pattern>
+ </encoder>
+ </appender>
+
+Example Configuration for Logging Logic
+---------------------------------------
+
+ .. container:: paragraph
+
+ The following example shows a configuration that logs policy logic
+ to standard out and a file (*info*). All other APEX components are
+ logging to a file (*debug*).. This configuration an be used in a
+ pre-production phase with the APEX engine still running in a
+ separate terminal to monitor policy execution. This logback
+ configuration is in the APEX installation as
+ ``etc/logback-logic.xml``.
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <configuration debug="false">
+ <statusListener class="ch.qos.logback.core.status.NopStatusListener" />
+
+ <contextName>Apex</contextName>
+ <property name="VAR_LOG" value="/var/log/onap/policy/apex-pdp/" />
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <Pattern>%d %contextName [%t] %level %logger{36} - %msg%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>${VAR_LOG}/apex.log</file>
+ <encoder>
+ <pattern>
+ %d %-5relative [procId=${processId}] [%thread] %-5level%logger{26} - %msg %n %ex{full}
+ </pattern>
+ </encoder>
+ </appender>
+
+ <appender name="POLICY_APPENDER_STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>policy: %msg\n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="error">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+ <logger name="org.onap.policy.apex" level="debug" additivity="false">
+ <appender-ref ref="FILE" />
+ </logger>
+
+ <logger name="org.onap.policy.apex.executionlogging" level="info" additivity="false">
+ <appender-ref ref="POLICY_APPENDER_STDOUT" />
+ <appender-ref ref="FILE" />
+ </logger>
+ </configuration>
+
+Example Configuration for a Production Server
+---------------------------------------------
+
+ .. container:: paragraph
+
+ The following example shows a configuration that logs all APEX
+ components, including policy logic, to a file (*debug*). This
+ configuration an be used in a production phase with the APEX
+ engine being executed as a service on a system without console
+ output. This logback configuration is in the APEX installation as
+ ``logback-server.xml``
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ <configuration debug="false">
+ <statusListener class="ch.qos.logback.core.status.NopStatusListener" />
+
+ <contextName>Apex</contextName>
+ <property name="VAR_LOG" value="/var/log/onap/policy/apex-pdp/" />
+
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>${VAR_LOG}/apex.log</file>
+ <encoder>
+ <pattern>
+ %d %-5relative [procId=${processId}] [%thread] %-5level%logger{26} - %msg %n %ex{full}
+ </pattern>
+ </encoder>
+ </appender>
+
+ <root level="debug">
+ <appender-ref ref="FILE" />
+ </root>
+
+ <logger name="org.onap.policy.apex.executionlogging" level="debug" additivity="false">
+ <appender-ref ref="FILE" />
+ </logger>
+ </configuration>
+
+Building a System with Websocket Backend
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Websockets
+----------
+
+ .. container:: paragraph
+
+ Websocket is a protocol to run sockets of HTTP. Since it in
+ essence a socket, the connection is realized between a
+ server (waiting for connections) and a client (connecting to
+ a server). Server/client separation is only important for
+ connection establishment, once connected, everyone can
+ send/receive on the same socket (as any standard socket
+ would allow).
+
+ .. container:: paragraph
+
+ Standard Websocket implementations are simple, no
+ publish/subscribe and no special event handling. Most
+ servers simply send all incoming messages to all
+ connections. There is a PubSub definition on top of
+ Websocket called `WAMP <http://wamp-proto.org/>`__. APEX
+ does not support WAMP at the moment.
+
+Websocket in Java
+-----------------
+
+ .. container:: paragraph
+
+ In Java, `JSR
+ 356 <http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html>`__
+ defines the standard Websocket API. This JSR is part of Jave
+ EE 7 standard. For Java SE, several implementations exist in
+ open source. Since Websockets are a stable standard and
+ simple, most implementations are stable and ready to use. A
+ lot of products support Websockets, like Spring, JBoss,
+ Netty, … there are also Kafka extensions for Websockets.
+
+Websocket Example Code for Websocket clients (FOSS)
+---------------------------------------------------
+
+ .. container:: paragraph
+
+ There are a lot of implementations and examples available on
+ Github for Websocket clients. If one is using Java EE 7,
+ then one can also use the native Websocket implementation.
+ Good examples for clients using simply Java SE are here:
+
+ .. container:: ulist
+
+ - `Websocket
+ implementation <https://github.com/TooTallNate/Java-WebSocket>`__
+
+ - `Websocket sending client example, using
+ AWT <https://github.com/TooTallNate/Java-WebSocket/blob/master/src/main/example/ChatClient.java>`__
+
+ - `Websocket receiving client example (simple echo
+ client) <https://github.com/TooTallNate/Java-WebSocket/blob/master/src/main/example/ExampleClient.java>`__
+
+ .. container:: paragraph
+
+ For Java EE, the native Websocket API is explained here:
+
+ .. container:: ulist
+
+ - `Oracle
+ docs <http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html>`__
+
+ - link: `An
+ example <http://www.programmingforliving.com/2013/08/jsr-356-java-api-for-websocket-client-api.html>`__
+
+BCP: Websocket Configuration
+----------------------------
+
+ .. container:: paragraph
+
+ The probably best is to configure APEX for Websocket servers
+ for input (ingress, consume) and output (egress, produce)
+ interfaces. This means that APEX will start Websocket
+ servers on named ports and wait for clients to connect.
+ Advantage: once APEX is running all connectivity
+ infrastructure is running as well. Consequence: if APEX is
+ not running, everyone else is in the dark, too.
+
+ .. container:: paragraph
+
+ The best protocol to be used is JSON string. Each event on
+ any interface is then a string with a JSON encoding. JSON
+ string is a little bit slower than byte code, but we doubt
+ that this will be noticeable. A further advantage of JSON
+ strings over Websockets with APEX starting the servers: it
+ is very easy to connect web browsers to such a system.
+ Simple connect the web browser to the APEX sockets and
+ send/read JSON strings.
+
+ .. container:: paragraph
+
+ Once APEX is started you simply connect Websocket clients to
+ it, and send/receive event. When APEX is terminated, the
+ Websocket servers go down, and the clients will be
+ disconnected. APEX does not (yet) support auto-client
+ reconnect nor WAMP, so clients might need to be restarted or
+ reconnected manually after an APEX boot.
+
+Demo with VPN Policy Model
+--------------------------
+
+ .. container:: paragraph
+
+ We assume that you have an APEX installation using the full
+ package, i.e. APEX with all examples, of version ``0.5.6``
+ or higher. We will use the VPN policy from the APEX examples
+ here.
+
+ .. container:: paragraph
+
+ Now, have the following ready to start the demo:
+
+ .. container:: ulist
+
+ - 3 terminals on the host where APEX is running (we need 1
+ for APEX and 1 for each client)
+
+ - the events in the file
+ ``$APEX_HOME/examples/events/VPN/SetupEvents.json`` open
+ in an editor (we need to send those events to APEX)
+
+ - the events in the file
+ ``$APEX_HOME/examples/events/VPN/Link09Events.json`` open
+ in an editor (we need to send those events to APEX)
+
+A Websocket Configuration for the VPN Domain
+############################################
+
+ .. container:: paragraph
+
+ Create a new APEX configuration using the VPN policy
+ model and configuring APEX as discussed above for
+ Websockets. Copy the following configuration into
+ ``$APEX_HOME/examples/config/VPN/Ws2WsServerAvroContextJsonEvent.json``
+ (for Windows use
+ ``%APEX_HOME%\examples\config\VPN\Ws2WsServerAvroContextJsonEvent.json``):
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ {
+ "engineServiceParameters" : {
+ "name" : "VPNApexEngine",
+ "version" : "0.0.1",
+ "id" : 45,
+ "instanceCount" : 1,
+ "deploymentPort" : 12345,
+ "policyModelFileName" : "examples/models/VPN/VPNPolicyModelAvro.json",
+ "engineParameters" : {
+ "executorParameters" : {
+ "MVEL" : {
+ "parameterClassName" : "org.onap.policy.apex.plugins.executor.mvel.MVELExecutorParameters"
+ }
+ },
+ "contextParameters" : {
+ "parameterClassName" : "org.onap.policy.apex.context.parameters.ContextParameters",
+ "schemaParameters":{
+ "Avro":{
+ "parameterClassName" : "org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters"
+ }
+ }
+ }
+ }
+ },
+ "producerCarrierTechnologyParameters" : {
+ "carrierTechnology" : "WEBSOCKET",
+ "parameterClassName" : "org.onap.policy.apex.plugins.event.carrier.websocket.WEBSOCKETCarrierTechnologyParameters",
+ "parameters" : {
+ "wsClient" : false,
+ "port" : 42452
+ }
+ },
+ "producerEventProtocolParameters" : {
+ "eventProtocol" : "JSON"
+ },
+ "consumerCarrierTechnologyParameters" : {
+ "carrierTechnology" : "WEBSOCKET",
+ "parameterClassName" : "org.onap.policy.apex.plugins.event.carrier.websocket.WEBSOCKETCarrierTechnologyParameters",
+ "parameters" : {
+ "wsClient" : false,
+ "port" : 42450
+ }
+ },
+ "consumerEventProtocolParameters" : {
+ "eventProtocol" : "JSON"
+ }
+ }
+
+Start APEX Engine
+#################
+
+ .. container:: paragraph
+
+ In a new terminal, start APEX with the new configuration for
+ Websocket-Server ingress/egress:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ #: $APEX_HOME/bin/apexEngine.sh -c $APEX_HOME/examples/config/VPN/Ws2WsServerAvroContextJsonEvent.json
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ #: %APEX_HOME%\bin\apexEngine.bat -c %APEX_HOME%\examples\config\VPN\Ws2WsServerAvroContextJsonEvent.json
+
+.. container:: paragraph
+
+ Wait for APEX to start, it takes a while to create all Websocket
+ servers (about 8 seconds on a standard laptop without cached
+ binaries). depending on your log messages, you will see no (some, a
+ lot) log messages. If APEX starts correctly, the last few messages
+ you should see are:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ 2017-07-28 13:17:20,834 Apex [main] INFO c.e.a.s.engine.runtime.EngineService - engine model VPNPolicyModelAvro:0.0.1 added to the engine-AxArtifactKey:(name=VPNApexEngine-0,version=0.0.1)
+ 2017-07-28 13:17:21,057 Apex [Apex-apex-engine-service-0:0] INFO c.e.a.s.engine.runtime.EngineService - Engine AxArtifactKey:(name=VPNApexEngine-0,version=0.0.1) processing ...
+ 2017-07-28 13:17:21,296 Apex [main] INFO c.e.a.s.e.r.impl.EngineServiceImpl - Added the action listener to the engine
+ Started Apex service
+
+.. container:: paragraph
+
+ APEX is running in the new terminal and will produce output when the
+ policy is triggered/executed.
+
+Run the Websocket Echo Client
+#############################
+
+ .. container:: paragraph
+
+ The echo client is included in an APEX full installation. To run
+ the client, open a new shell (Unix, Cygwin) or command prompt
+ (``cmd`` on Windows). Then use the APEX application launcher to
+ start the client.
+
+ .. important::
+ APEX engine needs to run first
+ The example assumes that an APEX engine configured for *produce* carrier technology Websocket and *JSON* event protocol is executed first.
+
+ +---------------------------------------------------------+-----------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +=========================================================+===========================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexApps.sh ws-echo [args] | > %APEX_HOME%\bin\apexApps.bat ws-echo [args] |
+ +---------------------------------------------------------+-----------------------------------------------------------+
+
+ .. container:: paragraph
+
+ Use the following command line arguments for server and port of
+ the Websocket server. The port should be the same as configured in
+ the APEX engine. The server host should be the host on which the
+ APEX engine is running
+
+ .. container:: ulist
+
+ - ``-p`` defines the Websocket port to connect to (defaults to
+ ``8887``)
+
+ - ``-s`` defines the host on which a Websocket server is running
+ (defaults to ``localhost``)
+
+ .. container:: paragraph
+
+ Let’s assume that there is an APEX engine running, configured for
+ produce Websocket carrier technology, as server, for port 42452,
+ with produce event protocol JSON,. If we start the console client
+ on the same host, we can omit the ``-s`` options. We start the
+ console client as:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ # $APEX_HOME/bin/apexApps.sh ws-echo -p 42452 (1)
+ > %APEX_HOME%\bin\apexApps.bat ws-echo -p 42452 (2)
+
+ .. container:: colist arabic
+
+ +-------+--------------------------------+
+ | **1** | Start client on Unix or Cygwin |
+ +-------+--------------------------------+
+ | **2** | Start client on Windows |
+ +-------+--------------------------------+
+
+ .. container:: paragraph
+
+ Once started successfully, the client will produce the following
+ messages (assuming we used ``-p 42452`` and an APEX engine is
+ running on ``localhost`` with the same port:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ ws-simple-echo: starting simple event echo
+ --> server: localhost
+ --> port: 42452
+
+ Once started, the application will simply print out all received events to standard out.
+ Each received event will be prefixed by '---' and suffixed by '===='
+
+
+ ws-simple-echo: opened connection to APEX (Web Socket Protocol Handshake)
+
+Run the Websocket Console Client
+################################
+
+ .. container:: paragraph
+
+ The console client is included in an APEX full installation. To
+ run the client, open a new shell (Unix, Cygwin) or command prompt
+ (``cmd`` on Windows). Then use the APEX application launcher to
+ start the client.
+
+ .. important::
+ APEX engine needs to run first
+ The example assumes that an APEX engine configured for *consume* carrier technology Websocket and *JSON* event
+ protocol is executed first.
+
+ +------------------------------------------------------------+--------------------------------------------------------------+
+ | Unix, Cygwin | Windows |
+ +============================================================+==============================================================+
+ | .. container:: | .. container:: |
+ | | |
+ | .. container:: listingblock | .. container:: listingblock |
+ | | |
+ | .. container:: content | .. container:: content |
+ | | |
+ | .. code:: | .. code:: |
+ | | |
+ | # $APEX_HOME/bin/apexApps.sh ws-console [args] | > %APEX_HOME%\bin\apexApps.bat ws-console [args] |
+ +------------------------------------------------------------+--------------------------------------------------------------+
+
+ .. container:: paragraph
+
+ Use the following command line arguments for server and port of
+ the Websocket server. The port should be the same as configured in
+ the APEX engine. The server host should be the host on which the
+ APEX engine is running
+
+ .. container:: ulist
+
+ - ``-p`` defines the Websocket port to connect to (defaults to
+ ``8887``)
+
+ - ``-s`` defines the host on which a Websocket server is running
+ (defaults to ``localhost``)
+
+ .. container:: paragraph
+
+ Let’s assume that there is an APEX engine running, configured for
+ consume Websocket carrier technology, as server, for port 42450,
+ with consume event protocol JSON,. If we start the console client
+ on the same host, we can omit the ``-s`` options. We start the
+ console client as:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ # $APEX_HOME/bin/apexApps.sh ws-console -p 42450 (1)
+ > %APEX_HOME%\bin\apexApps.sh ws-console -p 42450 (2)
+
+ .. container:: colist arabic
+
+ +-------+--------------------------------+
+ | **1** | Start client on Unix or Cygwin |
+ +-------+--------------------------------+
+ | **2** | Start client on Windows |
+ +-------+--------------------------------+
+
+ .. container:: paragraph
+
+ Once started successfully, the client will produce the following
+ messages (assuming we used ``-p 42450`` and an APEX engine is
+ running on ``localhost`` with the same port:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+
+ ws-simple-console: starting simple event console
+ --> server: localhost
+ --> port: 42450
+
+ - terminate the application typing 'exit<enter>' or using 'CTRL+C'
+ - events are created by a non-blank starting line and terminated by a blank line
+
+
+ ws-simple-console: opened connection to APEX (Web Socket Protocol Handshake)
+
+Send Events
+###########
+
+ .. container:: paragraph
+
+ Now you have the full system up and running:
+
+ .. container:: ulist
+
+ - Terminal 1: APEX ready and loaded
+
+ - Terminal 2: an echo client, printing received messages produced
+ by the VPN policy
+
+ - Terminal 2: a console client, waiting for input on the console
+ (standard in) and sending text to APEX
+
+ .. container:: paragraph
+
+ We started the engine with the VPN policy example. So all the
+ events we are using now are located in files in the following
+ example directory:
+
+ .. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ #: $APEX_HOME/examples/events/VPN
+ > %APEX_HOME%\examples\events\VPN
+
+.. container:: paragraph
+
+ To sends events, simply copy the content of the event files into
+ Terminal 3 (the console client). It will read multi-line JSON text
+ and send the events. So copy the content of ``SetupEvents.json`` into
+ the client. APEX will trigger a policy and produce some output, the
+ echo client will also print some events created in the policy. In
+ Terminal 1 (APEX) you’ll see some status messages from the policy as:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ {Link=L09, LinkUp=true}
+ L09 true
+ outFields: {Link=L09, LinkUp=true}
+ {Link=L10, LinkUp=true}
+ L09 true
+ L10 true
+ outFields: {Link=L10, LinkUp=true}
+ {CustomerName=C, LinkList=L09 L10, SlaDT=300, YtdDT=300}
+ *** Customers ***
+ C 300 300 [L09, L10]
+ outFields: {CustomerName=C, LinkList=L09 L10, SlaDT=300, YtdDT=300}
+ {CustomerName=A, LinkList=L09 L10, SlaDT=300, YtdDT=50}
+ *** Customers ***
+ A 300 50 [L09, L10]
+ C 300 300 [L09, L10]
+ outFields: {CustomerName=A, LinkList=L09 L10, SlaDT=300, YtdDT=50}
+ {CustomerName=D, LinkList=L09 L10, SlaDT=300, YtdDT=400}
+ *** Customers ***
+ A 300 50 [L09, L10]
+ C 300 300 [L09, L10]
+ D 300 400 [L09, L10]
+ outFields: {CustomerName=D, LinkList=L09 L10, SlaDT=300, YtdDT=400}
+ {CustomerName=B, LinkList=L09 L10, SlaDT=300, YtdDT=299}
+ *** Customers ***
+ A 300 50 [L09, L10]
+ B 300 299 [L09, L10]
+ C 300 300 [L09, L10]
+ D 300 400 [L09, L10]
+ outFields: {CustomerName=B, LinkList=L09 L10, SlaDT=300, YtdDT=299}
+
+.. container:: paragraph
+
+ In Terminal 2 (echo-client) you see the received events, the last two
+ should look like:
+
+.. container:: listingblock
+
+ .. container:: content
+
+ .. code::
+ :number-lines:
+
+ ws-simple-echo: received
+ ---------------------------------
+ {
+ "name": "VPNCustomerCtxtActEvent",
+ "version": "0.0.1",
+ "nameSpace": "org.onap.policy.apex.domains.vpn.events",
+ "source": "Source",
+ "target": "Target",
+ "CustomerName": "C",
+ "LinkList": "L09 L10",
+ "SlaDT": 300,
+ "YtdDT": 300
+ }
+ =================================
+
+ ws-simple-echo: received
+ ---------------------------------
+ {
+ "name": "VPNCustomerCtxtActEvent",
+ "version": "0.0.1",
+ "nameSpace": "org.onap.policy.apex.domains.vpn.events",
+ "source": "Source",
+ "target": "Target",
+ "CustomerName": "D",
+ "LinkList": "L09 L10",
+ "SlaDT": 300,
+ "YtdDT": 400
+ }
+ =================================
+
+.. container:: paragraph
+
+ Congratulations, you have triggered a policy in APEX using
+ Websockets, the policy did run through, created events, picked up by
+ the echo-client.
+
+.. container:: paragraph
+
+ Now you can send the Link 09 and Link 10 events, they will trigger
+ the actual VPN policy and some calculations are made. Let’s take the
+ Link 09 events from ``Link09Events.json``, copy them all into
+ Terminal 3 (the console). APEX will run the policy (with some status
+ output), and the echo client will receive and print events.
+
+.. container:: paragraph
+
+ To terminate the applications, simply press ``CTRL+C`` in Terminal 1
+ (APEX). This will also terminate the echo-client in Terminal 2. Then
+ type ``exit<enter>`` in Terminal 3 (or ``CTRL+C``) to terminate the
+ console-client.
+
+.. container::
+ :name: footer
+
+ .. container::
+ :name: footer-text
+
+ 2.0.0-SNAPSHOT
+ Last updated 2018-09-10 15:38:16 IST
+
+.. |Extract the TAR archive| image:: images/install-guide/win-extract-tar-gz.png
+.. |Extract the APEX distribution| image:: images/install-guide/win-extract-tar.png
+.. |REST Editor Start Screen| image:: images/install-guide/rest-start.png
+.. |REST Editor with loaded SampleDomain Policy Model| image:: images/install-guide/rest-loaded.png
+.. |APEX Configuration Matrix| image:: images/apex-intro/ApexEngineConfig.png
+.. |File > New to create a new Policy Model| image:: images/mfp/MyFirstPolicy_P1_newPolicyModel1.png
+.. |Create a new Policy Model| image:: images/mfp/MyFirstPolicy_P1_newPolicyModel2.png
+.. |Right click to create a new event| image:: images/mfp/MyFirstPolicy_P1_newEvent1.png
+.. |Fill in the necessary information for the 'SALE_INPUT' event and click 'Submit'| image:: images/mfp/MyFirstPolicy_P1_newEvent2.png
+.. |Right click to create a new Item Schema| image:: images/mfp/MyFirstPolicy_P1_newItemSchema1.png
+.. |Create a new Item Schema| image:: images/mfp/MyFirstPolicy_P1_newItemSchema2.png
+.. |Add new event parameters to an event| image:: images/mfp/MyFirstPolicy_P1_newEvent3.png
+.. |Right click to create a new task| image:: images/mfp/MyFirstPolicy_P1_newTask1.png
+.. |Add input and out fields for the task| image:: images/mfp/MyFirstPolicy_P1_newTask2.png
+.. |Add task logic the task| image:: images/mfp/MyFirstPolicy_P1_newTask3.png
+.. |Create a new policy| image:: images/mfp/MyFirstPolicy_P1_newPolicy1.png
+.. |Create a state| image:: images/mfp/MyFirstPolicy_P1_newState1.png
+.. |Add a Task and Output Mapping| image:: images/mfp/MyFirstPolicy_P1_newState2.png
+.. |Validate the policy model for error using the 'Model' > 'Validate' menu item| image:: images/mfp/MyFirstPolicy_P1_validatePolicyModel.png
+.. |Download the completed policy model using the 'File' > 'Download' menu item| image:: images/mfp/MyFirstPolicy_P1_exportPolicyModel1.png
+.. |Create a new alternative task MorningBoozeCheckAlt1| image:: images/mfp/MyFirstPolicy_P2_newTask1.png
+.. |Right click to edit a policy| image:: images/mfp/MyFirstPolicy_P2_editPolicy1.png
+.. |State definition with 2 Tasks and Task Selection Logic| image:: images/mfp/MyFirstPolicy_P2_editState1.png
+
diff --git a/docs/images/apex-intro/ApexEcosystem.png b/docs/images/apex-intro/ApexEcosystem.png
new file mode 100644
index 000000000..dec2b4a89
--- /dev/null
+++ b/docs/images/apex-intro/ApexEcosystem.png
Binary files differ
diff --git a/docs/images/apex-intro/ApexEngineConfig.png b/docs/images/apex-intro/ApexEngineConfig.png
new file mode 100644
index 000000000..93ebf6312
--- /dev/null
+++ b/docs/images/apex-intro/ApexEngineConfig.png
Binary files differ
diff --git a/docs/images/apex-intro/ApexPolicyMatrix.png b/docs/images/apex-intro/ApexPolicyMatrix.png
new file mode 100644
index 000000000..28e238d3b
--- /dev/null
+++ b/docs/images/apex-intro/ApexPolicyMatrix.png
Binary files differ
diff --git a/docs/images/apex-intro/ApexSimple.png b/docs/images/apex-intro/ApexSimple.png
new file mode 100644
index 000000000..4fb49ece4
--- /dev/null
+++ b/docs/images/apex-intro/ApexSimple.png
Binary files differ
diff --git a/docs/images/apex-intro/ApexStatesAndContext.png b/docs/images/apex-intro/ApexStatesAndContext.png
new file mode 100644
index 000000000..2fb394b35
--- /dev/null
+++ b/docs/images/apex-intro/ApexStatesAndContext.png
Binary files differ
diff --git a/docs/images/apex-intro/UpeeClusterOptions.png b/docs/images/apex-intro/UpeeClusterOptions.png
new file mode 100644
index 000000000..1298bee53
--- /dev/null
+++ b/docs/images/apex-intro/UpeeClusterOptions.png
Binary files differ
diff --git a/docs/images/apex-intro/UpeeDeploymentOptions.png b/docs/images/apex-intro/UpeeDeploymentOptions.png
new file mode 100644
index 000000000..35f97467e
--- /dev/null
+++ b/docs/images/apex-intro/UpeeDeploymentOptions.png
Binary files differ
diff --git a/docs/images/apex-policy-model/ConceptsKeys.png b/docs/images/apex-policy-model/ConceptsKeys.png
new file mode 100644
index 000000000..4de34b57d
--- /dev/null
+++ b/docs/images/apex-policy-model/ConceptsKeys.png
Binary files differ
diff --git a/docs/images/apex-policy-model/UmlPolicyModels.png b/docs/images/apex-policy-model/UmlPolicyModels.png
new file mode 100644
index 000000000..f559dc133
--- /dev/null
+++ b/docs/images/apex-policy-model/UmlPolicyModels.png
Binary files differ
diff --git a/docs/images/howto-config/ApexEngineConfig.png b/docs/images/howto-config/ApexEngineConfig.png
new file mode 100644
index 000000000..93ebf6312
--- /dev/null
+++ b/docs/images/howto-config/ApexEngineConfig.png
Binary files differ
diff --git a/docs/images/install-guide/rest-loaded.png b/docs/images/install-guide/rest-loaded.png
new file mode 100644
index 000000000..3d0056618
--- /dev/null
+++ b/docs/images/install-guide/rest-loaded.png
Binary files differ
diff --git a/docs/images/install-guide/rest-start.png b/docs/images/install-guide/rest-start.png
new file mode 100644
index 000000000..dd515c6a8
--- /dev/null
+++ b/docs/images/install-guide/rest-start.png
Binary files differ
diff --git a/docs/images/install-guide/win-extract-tar-gz.png b/docs/images/install-guide/win-extract-tar-gz.png
new file mode 100644
index 000000000..55d7e7dd5
--- /dev/null
+++ b/docs/images/install-guide/win-extract-tar-gz.png
Binary files differ
diff --git a/docs/images/install-guide/win-extract-tar.png b/docs/images/install-guide/win-extract-tar.png
new file mode 100644
index 000000000..ba76fa338
--- /dev/null
+++ b/docs/images/install-guide/win-extract-tar.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_exportPolicyModel1.png b/docs/images/mfp/MyFirstPolicy_P1_exportPolicyModel1.png
new file mode 100644
index 000000000..fb646f40f
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_exportPolicyModel1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newEvent1.png b/docs/images/mfp/MyFirstPolicy_P1_newEvent1.png
new file mode 100644
index 000000000..d67ac82df
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newEvent1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newEvent2.png b/docs/images/mfp/MyFirstPolicy_P1_newEvent2.png
new file mode 100644
index 000000000..0cc4a4215
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newEvent2.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newEvent3.png b/docs/images/mfp/MyFirstPolicy_P1_newEvent3.png
new file mode 100644
index 000000000..7a75049ef
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newEvent3.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newItemSchema1.png b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema1.png
new file mode 100644
index 000000000..0a6b5b06a
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newItemSchema2.png b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema2.png
new file mode 100644
index 000000000..dbeba702a
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema2.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newPolicy1.png b/docs/images/mfp/MyFirstPolicy_P1_newPolicy1.png
new file mode 100644
index 000000000..0a1b34fa1
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newPolicy1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel1.png b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel1.png
new file mode 100644
index 000000000..168e82deb
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel2.png b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel2.png
new file mode 100644
index 000000000..858911d6f
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel2.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newState1.png b/docs/images/mfp/MyFirstPolicy_P1_newState1.png
new file mode 100644
index 000000000..559a7cc37
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newState1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newState2.png b/docs/images/mfp/MyFirstPolicy_P1_newState2.png
new file mode 100644
index 000000000..806bc0eb8
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newState2.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newTask1.png b/docs/images/mfp/MyFirstPolicy_P1_newTask1.png
new file mode 100644
index 000000000..911ae02b7
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newTask1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newTask2.png b/docs/images/mfp/MyFirstPolicy_P1_newTask2.png
new file mode 100644
index 000000000..46dc6c781
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newTask2.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_newTask3.png b/docs/images/mfp/MyFirstPolicy_P1_newTask3.png
new file mode 100644
index 000000000..1805c14e9
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_newTask3.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P1_validatePolicyModel.png b/docs/images/mfp/MyFirstPolicy_P1_validatePolicyModel.png
new file mode 100644
index 000000000..2029b1856
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P1_validatePolicyModel.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P2_editPolicy1.png b/docs/images/mfp/MyFirstPolicy_P2_editPolicy1.png
new file mode 100644
index 000000000..be16f5a4d
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P2_editPolicy1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P2_editState1.png b/docs/images/mfp/MyFirstPolicy_P2_editState1.png
new file mode 100644
index 000000000..83c28b0e4
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P2_editState1.png
Binary files differ
diff --git a/docs/images/mfp/MyFirstPolicy_P2_newTask1.png b/docs/images/mfp/MyFirstPolicy_P2_newTask1.png
new file mode 100644
index 000000000..036a4ad96
--- /dev/null
+++ b/docs/images/mfp/MyFirstPolicy_P2_newTask1.png
Binary files differ
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 000000000..7e321263b
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,12 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+
+APEX PDP
+------------------------------------------------
+.. toctree::
+ :maxdepth: 1
+
+ APEX-Introduction.rst
+ APEX-User-Manual.rst
+ APEX-Policy-Guide.rst
+ APEX-Developer-Guide.rst
+ APEX-Install-Guide.rst