diff options
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 Binary files differnew file mode 100644 index 000000000..dec2b4a89 --- /dev/null +++ b/docs/images/apex-intro/ApexEcosystem.png diff --git a/docs/images/apex-intro/ApexEngineConfig.png b/docs/images/apex-intro/ApexEngineConfig.png Binary files differnew file mode 100644 index 000000000..93ebf6312 --- /dev/null +++ b/docs/images/apex-intro/ApexEngineConfig.png diff --git a/docs/images/apex-intro/ApexPolicyMatrix.png b/docs/images/apex-intro/ApexPolicyMatrix.png Binary files differnew file mode 100644 index 000000000..28e238d3b --- /dev/null +++ b/docs/images/apex-intro/ApexPolicyMatrix.png diff --git a/docs/images/apex-intro/ApexSimple.png b/docs/images/apex-intro/ApexSimple.png Binary files differnew file mode 100644 index 000000000..4fb49ece4 --- /dev/null +++ b/docs/images/apex-intro/ApexSimple.png diff --git a/docs/images/apex-intro/ApexStatesAndContext.png b/docs/images/apex-intro/ApexStatesAndContext.png Binary files differnew file mode 100644 index 000000000..2fb394b35 --- /dev/null +++ b/docs/images/apex-intro/ApexStatesAndContext.png diff --git a/docs/images/apex-intro/UpeeClusterOptions.png b/docs/images/apex-intro/UpeeClusterOptions.png Binary files differnew file mode 100644 index 000000000..1298bee53 --- /dev/null +++ b/docs/images/apex-intro/UpeeClusterOptions.png diff --git a/docs/images/apex-intro/UpeeDeploymentOptions.png b/docs/images/apex-intro/UpeeDeploymentOptions.png Binary files differnew file mode 100644 index 000000000..35f97467e --- /dev/null +++ b/docs/images/apex-intro/UpeeDeploymentOptions.png diff --git a/docs/images/apex-policy-model/ConceptsKeys.png b/docs/images/apex-policy-model/ConceptsKeys.png Binary files differnew file mode 100644 index 000000000..4de34b57d --- /dev/null +++ b/docs/images/apex-policy-model/ConceptsKeys.png diff --git a/docs/images/apex-policy-model/UmlPolicyModels.png b/docs/images/apex-policy-model/UmlPolicyModels.png Binary files differnew file mode 100644 index 000000000..f559dc133 --- /dev/null +++ b/docs/images/apex-policy-model/UmlPolicyModels.png diff --git a/docs/images/howto-config/ApexEngineConfig.png b/docs/images/howto-config/ApexEngineConfig.png Binary files differnew file mode 100644 index 000000000..93ebf6312 --- /dev/null +++ b/docs/images/howto-config/ApexEngineConfig.png diff --git a/docs/images/install-guide/rest-loaded.png b/docs/images/install-guide/rest-loaded.png Binary files differnew file mode 100644 index 000000000..3d0056618 --- /dev/null +++ b/docs/images/install-guide/rest-loaded.png diff --git a/docs/images/install-guide/rest-start.png b/docs/images/install-guide/rest-start.png Binary files differnew file mode 100644 index 000000000..dd515c6a8 --- /dev/null +++ b/docs/images/install-guide/rest-start.png diff --git a/docs/images/install-guide/win-extract-tar-gz.png b/docs/images/install-guide/win-extract-tar-gz.png Binary files differnew file mode 100644 index 000000000..55d7e7dd5 --- /dev/null +++ b/docs/images/install-guide/win-extract-tar-gz.png diff --git a/docs/images/install-guide/win-extract-tar.png b/docs/images/install-guide/win-extract-tar.png Binary files differnew file mode 100644 index 000000000..ba76fa338 --- /dev/null +++ b/docs/images/install-guide/win-extract-tar.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_exportPolicyModel1.png b/docs/images/mfp/MyFirstPolicy_P1_exportPolicyModel1.png Binary files differnew file mode 100644 index 000000000..fb646f40f --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_exportPolicyModel1.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newEvent1.png b/docs/images/mfp/MyFirstPolicy_P1_newEvent1.png Binary files differnew file mode 100644 index 000000000..d67ac82df --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newEvent1.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newEvent2.png b/docs/images/mfp/MyFirstPolicy_P1_newEvent2.png Binary files differnew file mode 100644 index 000000000..0cc4a4215 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newEvent2.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newEvent3.png b/docs/images/mfp/MyFirstPolicy_P1_newEvent3.png Binary files differnew file mode 100644 index 000000000..7a75049ef --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newEvent3.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newItemSchema1.png b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema1.png Binary files differnew file mode 100644 index 000000000..0a6b5b06a --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema1.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newItemSchema2.png b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema2.png Binary files differnew file mode 100644 index 000000000..dbeba702a --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newItemSchema2.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newPolicy1.png b/docs/images/mfp/MyFirstPolicy_P1_newPolicy1.png Binary files differnew file mode 100644 index 000000000..0a1b34fa1 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newPolicy1.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel1.png b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel1.png Binary files differnew file mode 100644 index 000000000..168e82deb --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel1.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel2.png b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel2.png Binary files differnew file mode 100644 index 000000000..858911d6f --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newPolicyModel2.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newState1.png b/docs/images/mfp/MyFirstPolicy_P1_newState1.png Binary files differnew file mode 100644 index 000000000..559a7cc37 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newState1.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newState2.png b/docs/images/mfp/MyFirstPolicy_P1_newState2.png Binary files differnew file mode 100644 index 000000000..806bc0eb8 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newState2.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newTask1.png b/docs/images/mfp/MyFirstPolicy_P1_newTask1.png Binary files differnew file mode 100644 index 000000000..911ae02b7 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newTask1.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newTask2.png b/docs/images/mfp/MyFirstPolicy_P1_newTask2.png Binary files differnew file mode 100644 index 000000000..46dc6c781 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newTask2.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_newTask3.png b/docs/images/mfp/MyFirstPolicy_P1_newTask3.png Binary files differnew file mode 100644 index 000000000..1805c14e9 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_newTask3.png diff --git a/docs/images/mfp/MyFirstPolicy_P1_validatePolicyModel.png b/docs/images/mfp/MyFirstPolicy_P1_validatePolicyModel.png Binary files differnew file mode 100644 index 000000000..2029b1856 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P1_validatePolicyModel.png diff --git a/docs/images/mfp/MyFirstPolicy_P2_editPolicy1.png b/docs/images/mfp/MyFirstPolicy_P2_editPolicy1.png Binary files differnew file mode 100644 index 000000000..be16f5a4d --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P2_editPolicy1.png diff --git a/docs/images/mfp/MyFirstPolicy_P2_editState1.png b/docs/images/mfp/MyFirstPolicy_P2_editState1.png Binary files differnew file mode 100644 index 000000000..83c28b0e4 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P2_editState1.png diff --git a/docs/images/mfp/MyFirstPolicy_P2_newTask1.png b/docs/images/mfp/MyFirstPolicy_P2_newTask1.png Binary files differnew file mode 100644 index 000000000..036a4ad96 --- /dev/null +++ b/docs/images/mfp/MyFirstPolicy_P2_newTask1.png 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 |