diff options
Diffstat (limited to 'docs/apex')
-rw-r--r-- | docs/apex/APEX-Developer-Guide.rst | 1471 | ||||
-rw-r--r-- | docs/apex/APEX-Install-Guide.rst | 1418 | ||||
-rw-r--r-- | docs/apex/APEX-Policy-Guide.rst | 3267 | ||||
-rw-r--r-- | docs/apex/apex.rst | 4 |
4 files changed, 1477 insertions, 4683 deletions
diff --git a/docs/apex/APEX-Developer-Guide.rst b/docs/apex/APEX-Developer-Guide.rst deleted file mode 100644 index b247ab83..00000000 --- a/docs/apex/APEX-Developer-Guide.rst +++ /dev/null @@ -1,1471 +0,0 @@ -.. 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 - - Once 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 built 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 built 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. - -+-----------------------------------------------------------------------------------------------------------------------------+ -| 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 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 built 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 - successfully. - -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 for a standard - build with *all* components. - - .. important:: - Might require specific software. - When building all components, some modules require specific software to be 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 documentation, - such as the HowTo documents, the Installation Guide, and the User - Manual. Use Maven to build the APEX Documentation. The Maven - option ``-N`` prevents Maven from going 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 built, 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 projects 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 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 - - Now 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 a means to version an - application automatically towards the APEX version for which it is - written. 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 method 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/APEX-Install-Guide.rst b/docs/apex/APEX-Install-Guide.rst deleted file mode 100644 index 0cff1317..00000000 --- a/docs/apex/APEX-Install-Guide.rst +++ /dev/null @@ -1,1418 +0,0 @@ -.. 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 built if the ``rpm`` package is installed (Unix). To install ``rpm`` run ``sudo apt-get install rpm``, - then build APEX. - - .. container:: paragraph - - Use Maven 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 -Pdocker -DskipTests | - | >mvn clean install -Pdocker -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. - -+----------------------------------------------------------------------------------------------------------------------------+ -| 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 copy 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 save some time. It - assumes that the APEX 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 -Pdocker -DskipTests | - | >mvn clean install -Pdocker -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 - built 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 successfully. - -.. 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 whose 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 temporarily (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 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 is installed manually or when the log directory is 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 changed (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 lines, 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. Paste 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 using - `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 have 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/APEX-Policy-Guide.rst b/docs/apex/APEX-Policy-Guide.rst index cb2388e0..4b11413f 100644 --- a/docs/apex/APEX-Policy-Guide.rst +++ b/docs/apex/APEX-Policy-Guide.rst @@ -1,2107 +1,1792 @@ -.. This work is licensed under a Creative Commons Attribution 4.0 International License. -.. http://creativecommons.org/licenses/by/4.0 - + .. 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 + :depth: 5 +****************** APEX Policy Matrix -^^^^^^^^^^^^^^^^^^ +****************** -APEX Policy Matrix ------------------- +.. container:: paragraph - .. 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 supports translation of 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. - APEX offers a lot of flexibility for defining, deploying, - and executing policies. Based on a theoretic model, it - supports virtually any policy model and supports - translation of 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 - .. 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. - 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:: imageblock + .. container:: content - .. container:: content + |APEX Policy Matrix| - |APEX Policy Matrix| + .. container:: title - .. 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) + Figure 1. APEX Policy Matrix - .. container:: paragraph +.. 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: + The policy can support one of a number of stimuli with an associated purpose/model of the policy, for instance: - .. container:: ulist +.. 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. + - 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. - - 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) + - 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. - - Intent (instead of providing detailed actions the - response is an intent statement and a further system - processes that) + - 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. - - Delegation (hand the problem over to someone else, - possibly with some information or instructions) + - 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. - - Fail / Error (the policy has encountered a problem, - and reports it) + - 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 (why did the policy make a certain decision) + - 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. -APEX Policy Model -^^^^^^^^^^^^^^^^^ +.. 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 -Introduction ------------- + 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:: paragraph +.. container:: ulist - 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. + - Obligation (deontic for what should happen) - .. container:: paragraph + - Authorization (e.g. for rule-based or other access control or security systems) - The figure shows four different views of the policy - model: + - Intent (instead of providing detailed actions the response is an intent statement and a further system + processes that) - .. container:: ulist + - Delegation (hand the problem over to someone else, possibly with some information or instructions) - - 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. + - Fail / Error (the policy has encountered a problem, and reports it) - - 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). + - Feedback (why did the policy make a certain decision) - - 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. +***************** +APEX Policy Model +***************** + +.. 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 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. + - 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. - .. container:: imageblock + - 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). - .. container:: content + - 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. - |APEX Policy Model for Execution| + - 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:: title +.. container:: imageblock - Figure 2. APEX Policy Model for Execution + .. container:: content + + |APEX Policy Model for Execution| + + .. container:: title + + Figure 2. APEX Policy Model for Execution Concepts and Keys -################# +================= - .. container:: paragraph +.. 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: + 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:: imageblock - .. container:: content + .. container:: content - |Concepts and Keys| + |Concepts and Keys| - .. container:: title + .. container:: title - Figure 3. Concepts and Keys + Figure 3. Concepts and Keys - .. container:: ulist +.. container:: ulist - - ``getKey()`` - gets the unique key for this concept - instance in the system + - ``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 + - ``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 + - ``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 + - ``clone()`` - creates a deep copy of an instance of this concept - - ``equals()`` - checks if two instances of this - concept are equal + - ``equals()`` - checks if two instances of this concept are equal - - ``toString()`` - returns a string representation of - the concept + - ``toString()`` - returns a string representation of the concept - - ``hashCode()`` - returns a hash code for 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. + - ``copyTo()`` - carries out a deep copy of one instance of the concept to another instance, overwriting the + target fields. - .. container:: paragraph +.. 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*. + 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 +.. 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. + 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 +.. 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. + 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 +.. 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``. + 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 +.. 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/>`__. + 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 +.. 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. + 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 +.. 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. + 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 - .. 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. + 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 +.. 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: + 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 +.. container:: ulist - - The *NameSpace* identifies the domain of - application of the event + - The *NameSpace* identifies the domain of application of the event - - The *Source* of the event identifies the system - that emitted 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 + - The *Target* of the event identifies the system that the event was sent to - .. container:: paragraph +.. 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. + 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 +.. 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. + 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. +=================== + +.. 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. +==================== + +.. 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. +============================ + +.. 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. +============= + +.. 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 +.. 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. + 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. - .. container:: paragraph +.. container:: paragraph - The *taskParameters* field is specified under *engineParameters* - in the ApexConfig. It can contain one or more task parameters, where each - item can contain the parameter key, value as well as the taskId to which it is associated. - If the taskId is not specified, then the parameters are added to all tasks. + The *taskParameters* field is specified under *engineParameters* in the ApexConfig. It can contain one or more task + parameters, where each item can contain the parameter key, value as well as the taskId to which it is associated. If + the taskId is not specified, then the parameters are added to all tasks. 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. +============== + +.. 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. +=============== + +.. 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. +============== + +.. 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 + + 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 - - 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 -DskipTests | - | >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"); | -+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+ -| parameters | Fields | java.util.Map <String,String> | .. container:: paragraph | -| | | | | -| | | | All parameters in the current task. This is implemented as a standard Java Map. | -| | | | | -| | | | .. container:: | -| | | | | -| | | | .. container:: content | -| | | | | -| | | | .. container:: paragraph | -| | | | | -| | | | **Example:** | -| | | | | -| | | | .. code:: javascript | -| | | | | -| | | | executor.parameters.get("ParameterKey1")) | -+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+ -| 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. +.. 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. + * Modifications Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * 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========================================================= + */ + + 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 :-) + */ + + true; + +.. 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. + * Modifications Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * 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. 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). + + For Javascript, the last statement of a script must be a statement that evaluates to *true* or *false*, indicating + whether the script executed correctly or not. In the case where the script always executes to compeletion + sucessfully, simply add a last line with the statement *true'*. In cases where success or failure is assessed in the + script, create a boolean + local variable with a name such as ``returnvalue``. In the execution of the script, set ``returnValue`` to be ``true`` + or ``false`` as appropriate. The last line of the scritp tehn should simply be ``returnValue;``, which returns the + value of ``returnValue``. + +.. 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> |The incoming task fields, implemented as a standard Java (unmodifiable) Map | + | | | | | + | | | |**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> |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 | + | | | | | + | | | |**Example:** | + | | | | | + | | | |.. code:: javascript | + | | | | | + | | | | executor.outFields["authorised"] = false; | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | logger | Logger | org.slf4j.ext.XLogger |A helpful logger | + | | | | | + | | | |**Example:** | + | | | | | + | | | |.. code:: javascript | + | | | | | + | | | | executor.logger.info("Executing task: " +executor.subject.id); | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | TRUE/FALSE | boolean | java.lang.Boolean |2 helpful constants. These are useful to retrieve correct return values for the | + | | | |task logic | + | | | | | + | | | |**Example:** | + | | | | | + | | | |.. code:: javascript | + | | | | | + | | | | var returnValue = executor.isTrue; | + | | | | var returnValueType = Java.type("java.lang.Boolean"); | + | | | | var returnValue = new returnValueType(true); | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | subject | Task | TaskFacade |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 | + | | | | | + | | | |**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 ) |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. | | | + | | | | | + | |**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. + * Modifications Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * 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========================================================= + */ + + 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" + */ + + true; + +.. 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:: content |.. container:: content | + | | | + | .. code:: bash | .. code:: bash | + | :number-lines: | :number-lines: | + | | | + | >c: | # cd /usr/local/src/apex-pdp | + | >cd \dev\apex | # mvn clean install -DskipTests | + | >mvn clean install -DskipTests | | + +-----------------------------------+------------------------------------+ + + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | Name | Type | Java type | Description | + +=====================================================+==========================================================================+===============================+==================================================================================+ + | inFields | Fields | java.util.Map <String,Object> | All fields in the state’s incoming event. This is implemented as a standard Java | + | | | | Java (unmodifiable) Map | + | | | | | + | | | | **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> | 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 | + | | | | | + | | | | **Example:** | + | | | | | + | | | | .. code:: javascript | + | | | | | + | | | | executor.outFields["authorised"] = false; | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | logger | Logger | org.slf4j.ext.XLogger | A helpful logger | + | | | | | + | | | | **Example:** | + | | | | | + | | | | .. code:: javascript | + | | | | | + | | | | executor.logger.info("Executing task: " | + | | | | +executor.subject.id); | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | TRUE/FALSE | boolean | java.lang.Boolean | 2 helpful constants. These are useful to retrieve correct return values for the | + | | | | task logic | + | | | | | + | | | | **Example:** | + | | | | | + | | | | .. code:: javascript | + | | | | | + | | | | var returnValue = executor.isTrue; | + | | | | var returnValueType = Java.type("java.lang.Boolean"); | + | | | | var returnValue = new returnValueType(true); | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | subject | Task | TaskFacade | 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 | + | | | | | + | | | | **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"); | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | parameters | Fields | java.util.Map <String,String> | All parameters in the current task. This is implemented as a standard Java Map. | + | | | | | + | | | | **Example:** | + | | | | | + | | | | .. code:: javascript | + | | | | | + | | | | executor.parameters.get("ParameterKey1")) | + +-----------------------------------------------------+--------------------------------------------------------------------------+-------------------------------+----------------------------------------------------------------------------------+ + | ContextAlbum getContextAlbum(String ctxtAlbumName ) | 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. | | | + | | | | | + | | **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 Cheat Sheet +================= + +.. container:: paragraph + + Examples given here use Javascript (if not stated otherwise), other execution environments will be similar. Finish Logic with Success or Error -################################## +---------------------------------- - .. container:: paragraph +.. container:: paragraph - To finish logic, i.e. return to APEX, with success use the - following line close to the end of the logic. + To finish logic, i.e. return to APEX, with success use the following line close to the end of the logic. - .. container:: listingblock +.. container:: listingblock - .. container:: title + .. container:: title - JS Success + JS Success - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - true; + true; - .. container:: paragraph +.. container:: paragraph - To notify a problem, finish with an error. + To notify a problem, finish with an error. - .. container:: listingblock + .. container:: listingblock - .. container:: title + .. container:: title - JS Fail + JS Fail - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - false; + false; Logic Logging -############# +------------- - .. container:: paragraph +.. 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. + 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:: listingblock - .. container:: title + .. container:: title - JS Logging + JS Logging - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - var logger = executor.logger; - logger.trace("start: " + executor.subject.id); - logger.trace("-- infields: " + executor.inFields); + var logger = executor.logger; + logger.trace("start: " + executor.subject.id); + logger.trace("-- infields: " + executor.inFields); - .. container:: paragraph +.. container:: paragraph - For larger logging blocks you can use the standard logging API - to detect log levels, for instance: + For larger logging blocks you can use the standard logging API to detect log levels, for instance: - .. container:: listingblock + .. container:: listingblock - .. container:: title + .. container:: title - JS Logging Blocks + JS Logging Blocks - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - if(logger.isTraceEnabled()){ - // trace logging block here - } + if(logger.isTraceEnabled()){ + // trace logging block here + } - .. container:: paragraph +.. 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``. + 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 +.. 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. + 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:: listingblock - .. container:: title + .. container:: title - JS Root Logger + JS Root Logger - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - importClass(org.slf4j.LoggerFactory); - var rootLogger = LoggerFactory.getLogger(logger.ROOT_LOGGER_NAME); - - rootLogger.error("Serious error in logic detected: " + executor.subject.id); + var rootLogger = LoggerFactory.getLogger(logger.ROOT_LOGGER_NAME); + rootLogger.error("Serious error in logic detected: " + executor.subject.id); Accessing TaskParameters -######################## +------------------------ - .. container:: paragraph +.. container:: paragraph - TaskParameters available in a Task can be accessed in the logic. - The parameters in each task are made available at the executor level. - This example assumes a parameter with key ``ParameterKey1``. + TaskParameters available in a Task can be accessed in the logic. The parameters in each task are made + available at the executor level. This example assumes a parameter with key ``ParameterKey1``. - .. container:: listingblock + .. container:: listingblock - .. container:: title + .. container:: title - JS TaskParameter value + JS TaskParameter value - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - executor.parameters.get("ParameterKey1")) + executor.parameters.get("ParameterKey1")) - .. container:: paragraph +.. container:: paragraph - Alternatively, the task parameters can also be accessed from the task object. + Alternatively, the task parameters can also be accessed from the task object. - .. container:: listingblock + .. container:: listingblock - .. container:: title + .. container:: title - JS TaskParameter value using task object + JS TaskParameter value using task object - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - executor.subject.task.getTaskParameters.get("ParameterKey1").getTaskParameterValue() + executor.subject.task.getTaskParameters.get("ParameterKey1").getTaskParameterValue() Local Variable for Infields -########################### +--------------------------- - .. container:: paragraph +.. 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``. + 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:: listingblock - .. container:: title + .. container:: title - JS Infields Local Var + JS Infields Local Var - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - var ifNodeName = executor.inFields["nodeName"]; - var ifNodeAlias = executor.inFields["nodeAlias"]; + var ifNodeName = executor.inFields["nodeName"]; + var ifNodeAlias = executor.inFields["nodeAlias"]; Local Variable for Context Albums -################################# +--------------------------------- - .. container:: paragraph +.. 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. + 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:: listingblock - .. container:: title + .. container:: title - JS Infields Local Var + JS Infields Local Var - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - var albumTopoNodes = executor.getContextAlbum("albumTopoNodes"); - var ctxtNode = albumTopoNodes.get(ifNodeName); + var albumTopoNodes = executor.getContextAlbum("albumTopoNodes"); + var ctxtNode = albumTopoNodes.get(ifNodeName); Set Outfields in Logic -###################### +---------------------- - .. container:: paragraph +.. 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. + 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:: listingblock - .. container:: title + .. container:: title - JS Set Outfields + JS Set Outfields - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - executor.outFields["report"] = "node ctxt :: added node " + ifNodeName; + executor.outFields["report"] = "node ctxt :: added node " + ifNodeName; Create a instance of an Outfield using Schemas -############################################## +---------------------------------------------- + +.. container:: paragraph - .. 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>`__. - 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 - .. container:: paragraph + If the backend is Java, then the Java class implementing the schema needs to be imported. - If the backend is Avro, then an import of the Avro schema - library is required: +.. container:: paragraph - .. container:: listingblock + The following example assumes an outfield ``situation``. The ``subject`` method ``getOutFieldSchemaHelper()`` is used + to create a new instance. - .. container:: title +.. container:: listingblock - JS Import Avro + .. container:: title - .. container:: content + JS Outfield Instance with Schema - .. code:: javascript + .. container:: content - importClass(org.apache.avro.generic.GenericData.Array); - importClass(org.apache.avro.generic.GenericRecord); - importClass(org.apache.avro.Schema); + .. code:: javascript - .. container:: paragraph + var situation = executor.subject.getOutFieldSchemaHelper("situation").createNewInstance(); - If the backend is Java, then the Java class implementing the - schema needs to be imported. +.. container:: paragraph - .. 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. - The following example assumes an outfield ``situation``. The - ``subject`` method ``getOutFieldSchemaHelper()`` is used to - create a new instance. +.. container:: listingblock - .. container:: listingblock + .. container:: title - .. container:: title + JS Outfield Instance with Schema, set - JS Outfield Instance with Schema + .. container:: content - .. container:: content + .. code:: javascript - .. code:: javascript + situation.put("problemID", "my-problem"); - var situation = executor.subject.getOutFieldSchemaHelper("situation").createNewInstance(); +Create a instance of an Context Album entry using Schemas +--------------------------------------------------------- - .. container:: paragraph +.. 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. + 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:: listingblock +.. container:: paragraph - .. container:: title + If the backend is Java, then the Java class implementing the schema needs to be imported. - JS Outfield Instance with Schema, set +.. container:: paragraph - .. container:: content + The following example creates a new instance of a context album instance named ``albumProblemMap``. - .. code:: javascript +.. container:: listingblock - situation.put("problemID", "my-problem"); + .. container:: title -Create a instance of an Context Album entry using Schemas -######################################################### + JS Outfield Instance with Schema + + .. container:: content - .. container:: paragraph + .. code:: javascript - 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>`__. + var albumProblemMap = executor.getContextAlbum("albumProblemMap"); + var linkProblem = albumProblemMap.getSchemaHelper().createNewInstance(); - .. container:: paragraph +.. container:: paragraph - If the backend is Avro, then an import of the Avro schema - library is required: + This can of course be also done in a single call without the local variable for the context album. - .. container:: listingblock +.. container:: listingblock - .. container:: title + .. container:: title - JS Import Avro + JS Outfield Instance with Schema, one line - .. container:: content + .. container:: content - .. code:: javascript + .. code:: javascript - importClass(org.apache.avro.generic.GenericData.Array); - importClass(org.apache.avro.generic.GenericRecord); - importClass(org.apache.avro.Schema); + var linkProblem = executor.getContextAlbum("albumProblemMap").getSchemaHelper().createNewInstance(); - .. container:: paragraph +.. container:: paragraph - If the backend is Java, then the Java class implementing the - schema needs to be imported. + 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). - .. container:: paragraph +Enumerates +---------- - The following example creates a new instance of a context album - instance named ``albumProblemMap``. +.. container:: paragraph - .. container:: listingblock + 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:: title +.. container:: listingblock - JS Outfield Instance with Schema + .. container:: title - .. container:: content + Avro Enumerate Schema - .. code:: javascript + .. container:: content - var albumProblemMap = executor.getContextAlbum("albumProblemMap"); - var linkProblem = albumProblemMap.getSchemaHelper().createNewInstance(); + .. code:: javascript - .. container:: paragraph + { + "type": "enum", "name": "Status", "symbols" : [ + "UP", "DOWN" + ] + } - This can of course be also done in a single call without the - local variable for the context album. +.. container:: paragraph - .. container:: listingblock + Using a switch over a field initialized with this enumerate in Javascript will fail. Instead, use the ``toString`` method, for example: - .. container:: title +.. container:: listingblock - JS Outfield Instance with Schema, one line + .. container:: title - .. container:: content + JS Outfield Instance with Schema, one line - .. code:: javascript + .. container:: content - var linkProblem = executor.getContextAlbum("albumProblemMap").getSchemaHelper().createNewInstance(); + .. code:: javascript - .. container:: paragraph + var switchTest = executor.inFields["status"]; switch(switchTest.toString()){ + case "UP": ...; break; case "DOWN": ...; break; default: ...; + } - 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). +MVEL Initialize Outfields First! +-------------------------------- -Enumerates -########## +.. container:: paragraph - .. 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. - 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:: listingblock + .. container:: title - .. container:: title + MVEL Outfield Initialization - Avro Enumerate Schema + .. container:: content - .. container:: content + .. code:: javascript - .. code:: javascript + outFields.get("initialize outfields"); - { - "type": "enum", - "name": "Status", - "symbols" : [ - "UP", - "DOWN" - ] - } +Using Java in Scripting Logic +----------------------------- - .. container:: paragraph +.. container:: paragraph - Using a switch over a field initialized with this enumerate in - Javascript will fail. Instead, use the ``toString`` method, for - example: + 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:: listingblock +.. container:: paragraph - .. container:: title + The following example imports ``java.util.arraylist`` into a Javascript logic, and then creates a new + list. - JS Outfield Instance with Schema, one line +.. container:: listingblock - .. container:: content + .. container:: title - .. code:: javascript + JS Import ArrayList - var switchTest = executor.inFields["status"]; - switch(switchTest.toString()){ - case "UP": ...; break; - case "DOWN": ...; break; - default: ...; - } + .. container:: content -MVEL Initialize Outfields First! -################################ + .. code:: javascript + + var myList = new ArrayList(); - .. container:: paragraph +Converting Javascript scripts from Nashorn to Rhino dialects +------------------------------------------------------------ - 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. +The Nashorn Javascript engine was removed from Java in the Java 11 release. Java 11 was introduced into +the Policy Framework in the Frankfurt release, so from Frankfurt on, APEX Javascript scripts use the Rhino +Javascript engine and scripts must be in the Rhino dialect. - .. container:: listingblock +There are some minor but important differences between the dialects that users should be aware of so +that they can convert their scripts into the Rhino dialect. - .. container:: title +Return Values +^^^^^^^^^^^^^ - MVEL Outfield Initialization +APEX scripts must always return a value of ``true`` indicating that the script executed correctly or ``false`` +indicating that there was an error in script execution. - .. container:: content +*Pre Frankfurt* - .. code:: javascript +In Nashorn dialect scripts, the user had to create a special variable called ``returnValue`` and set the value of +that variable to be the return value for the script. - outFields.get("initialize outfields"); +*Frankfurt and Later* -Using Java in Scripting Logic -############################# +In Rhino dialect scripts, the return value of the script is the logical result of the last statement. Therefore the +last line of the script must evaluate to either ``true`` or ``false``. + +.. container:: listingblock + + .. container:: title + + JS Rhino script last executed line examples + + .. container:: content + + .. code:: javascript + + true; + + returnValue; // Where returnValue is assigned earlier in the script + + someValue == 1; // Where the value of someValue is assigned earlier in the script + +return statement +^^^^^^^^^^^^^^^^ + +The ``return`` statement is not supported from the main script called in the Rhino interpreter. + +*Pre Frankfurt* + +In Nashorn dialect scripts, the user could return a value of ``true`` or ``false`` at any point in their script. + +.. container:: listingblock + + .. container:: title + + JS Nashorn main script returning ``true`` and ``false`` + + .. container:: content + + .. code:: javascript + + var n; + + // some code assigns n a value + + if (n < 2) { + return false; + } else { + return true; + } + +*Frankfurt and Later* + +In Rhino dialect scripts, the ``return`` statement cannot be used in the main method, but it can still be used in +functions. If you want to have a ``return`` statement in your code prior to the last statement, encapsulate your code +in a function. + +.. container:: listingblock + + .. container:: title + + JS Rhino script with ``return`` statements in a function + + .. container:: content + + .. code:: javascript + + someFunction(); + + function someFunction() { + var n; + + // some code assigns n a value + + if (n < 2) { + return false; + } else { + return true; + } + } + +Compatibility Script +^^^^^^^^^^^^^^^^^^^^ + +For Nashorn, the user had to call a compatibility script at the beginning of their Javascript script. This is not +required in Rhino. + +*Pre Frankfurt* + +In Nashorn dialect scripts, the compatibility script must be loaded. + +.. container:: listingblock + + .. container:: title + + Nashorn compatability script loading + + .. container:: content + + .. code:: javascript + + load("nashorn:mozilla_compat.js"); + +*Frankfurt and Later* + +Not required. + +Import of Java classes +^^^^^^^^^^^^^^^^^^^^^^ + +For Nashorn, the user had explicitly import all the Java packages and classes they wished to use in their Javascript +script. In Rhino, all Java classes on the classpath are available for use. + +*Pre Frankfurt* + +In Nashorn dialect scripts, Java classes must be imported. + +.. container:: listingblock + + .. container:: title + + Importation of Java packages and classes + + .. container:: content + + .. code:: javascript + + importPackage(java.text); + importClass(java.text.SimpleDateFormat); + +*Frankfurt and Later* + +Not required. + +Using Java Classes and Objects as Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Setting a Javascript variable to hold a Java class or a Java object is more straightforward in Rhino than it is in +Nashorn. The examples below show how to instantiate a Javascript variable as a Java class and how to use that variable +to create an instance of the Java class in another Javascript variable in both dialects. + + +*Pre Frankfurt* + +.. container:: listingblock - .. container:: paragraph + .. container:: title - 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. + Create Javascript variables to hold a Java class and instance - .. container:: paragraph + .. container:: content - The following example imports ``java.util.arraylist`` into a - Javascript logic, and then creates a new list. + .. code:: javascript - .. container:: listingblock + var webClientClass = Java.type("org.onap.policy.apex.examples.bbs.WebClient"); + var webClientObject = new webClientClass(); - .. container:: title +*Frankfurt and Later* - JS Import ArrayList +.. container:: listingblock - .. container:: content + .. container:: title - .. code:: javascript + Create Javascript variables to hold a Java class and instance - importClass(java.util.ArrayList); - var myList = new ArrayList(); + .. container:: content + .. code:: javascript -.. container:: - :name: footer + var webClientClass = org.onap.policy.apex.examples.bbs.WebClient; + var webClientObject = new webClientClass(); - .. container:: - :name: footer-text +Equal Value and Equal Type operator ``===`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 2.3.0-SNAPSHOT - Last updated 2020-03-16 16:04:24 GMT +The *Equal Value and Equal Type* operator ``===`` is not supported in Rhino. Developers must use the Equal To +operator ``==`` instead. To check types, they may need to explicitly find and check the type of the variables +they are using. .. |APEX Policy Matrix| image:: images/apex-intro/ApexPolicyMatrix.png .. |APEX Policy Model for Execution| image:: images/apex-policy-model/UmlPolicyModels.png diff --git a/docs/apex/apex.rst b/docs/apex/apex.rst index 8023e6d7..862bcfaf 100644 --- a/docs/apex/apex.rst +++ b/docs/apex/apex.rst @@ -3,14 +3,12 @@ .. _apex-doc: Policy APEX PDP Engine ------------------------------------------------- +---------------------- .. toctree:: :maxdepth: 1 APEX-Introduction.rst APEX-User-Manual.rst APEX-Policy-Guide.rst - APEX-Developer-Guide.rst - APEX-Install-Guide.rst APEX-OnapPf-Guide.rst APEX-Policy-Examples.rst |