aboutsummaryrefslogtreecommitdiffstats
path: root/docs/APEX-Policy-Guide.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/APEX-Policy-Guide.rst')
-rw-r--r--docs/APEX-Policy-Guide.rst2133
1 files changed, 0 insertions, 2133 deletions
diff --git a/docs/APEX-Policy-Guide.rst b/docs/APEX-Policy-Guide.rst
deleted file mode 100644
index 392f31c7b..000000000
--- a/docs/APEX-Policy-Guide.rst
+++ /dev/null
@@ -1,2133 +0,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
-
-APEX Policy Matrix
-^^^^^^^^^^^^^^^^^^
-
-APEX Policy Matrix
-------------------
-
- .. container:: paragraph
-
- APEX offers a lot of flexibility for defining, deploying,
- and executing policies. Based on a theoretic model, it
- supports virtually any policy model and allows to
- translate legacy policies into the APEX execution format.
- However, the most important aspect for using APEX is to
- decide what policy is needed, what underlying policy
- concepts should be used, and how the decision logic
- should be realized. Once these aspects are decided, APEX
- can be used to execute the policies. If the policy
- evolves, say from a simple decision table to a fully
- adaptable policy, only the policy definition requires
- change. APEX supports all of that.
-
- .. container:: paragraph
-
- The figure below shows a (non-exhaustive) matrix, which
- will help to decide what policy is required to solve your
- problem. Read the matrix from left to right choosing one
- cell in each column.
-
- .. container:: imageblock
-
- .. container:: content
-
- |APEX Policy Matrix|
-
- .. container:: title
-
- Figure 1. APEX Policy Matrix
-
- .. container:: paragraph
-
- The policy can support one of a number of stimuli with an
- associated purpose/model of the policy, for instance:
-
- .. container:: ulist
-
- - Configuration, i.e. what should happen. An example is
- an event that states an intended network configuration
- and the policy should provide the detailed actions for
- it. The policy can be realized for instance as an
- obligation policy, a promise or an intent.
-
- - Report, i.e. something did happen. An example is an
- event about an error or fault and the policy needs to
- repair that problem. The policy would usually be an
- obligation, utility function, or goal policy.
-
- - Monitoring, i.e. something does happen. An example is
- a notification about certain network conditions, to
- which the policy might (or might not) react. The
- policy will mitigate the monitored events or permit
- (deny) related actions as an obligation or
- authorization.
-
- - Analysis, i.e. why did something happen. An example is
- an analytic component sends insights of a situation
- requiring a policy to act on it. The policy can solve
- the problem, escalate it, or delegate it as a refrain
- or delegation policy.
-
- - Prediction, i.e. what will happen next. An example are
- events that a policy uses to predict a future network
- condition. The policy can prevent or enforce the
- prediction as an adaptive policy, a utility function,
- or a goal.
-
- - Feedback, i.e. why did something happen or not happen.
- Similar to analysis, but here the feedback will be in
- the input event and the policy needs to something with
- that information. Feedback can be related to history
- or experience, for instance a previous policy
- execution. The policy needs to be context-aware or be
- a meta-policy.
-
- .. container:: paragraph
-
- Once the purpose of the policy is decided, the next step
- is to look into what context information the policy will
- require to do its job. This can range from very simple to
- a lot of different information, for instance:
-
- .. container:: ulist
-
- - No context, nothing but a trigger event, e.g. a string
- or a number, is required
-
- - Event context, the incoming event provides all
- information (more than a string or number) for the
- policy
-
- - Policy context (read only), the policy has access to
- additional information related to its class but cannot
- change/alter them
-
- - Policy context (read and write), the policy has access
- to additional information related to its class and can
- alter this information (for instance to record
- historic information)
-
- - Global context (read only), the policy has access to
- additional information of any kind but cannot
- change/alter them
-
- - Global context (read and write), the policy the policy
- has access to additional information of any kind and
- can alter this information (for instance to record
- historic information)
-
- .. container:: paragraph
-
- The next step is to decide how the policy should do its
- job, i.e. what flavor it has, how many states are needed,
- and how many tasks. There are many possible combinations,
- for instance:
-
- .. container:: ulist
-
- - Simple / God: a simple policy with 1 state and 1 task,
- which is doing everything for the decision-making.
- This is the ideal policy for simple situation, e.g.
- deciding on configuration parameters or simple access
- control.
-
- - Simple sequence: a simple policy with a number of
- states each having a single task. This is a very good
- policy for simple decision-making with different
- steps. For instance, a classic action policy (ECA)
- would have 3 states (E, C, and A) with some logic (1
- task) in each state.
-
- - Simple selective: a policy with 1 state but more than
- one task. Here, the appropriate task (and it’s logic)
- will be selected at execution time. This policy is
- very good for dealing with similar (or the same)
- situation in different contexts. For instance, the
- tasks can be related to available external software,
- or to current work load on the compute node, or to
- time of day.
-
- - Selective: any number of states having any number of
- tasks (usually more than 1 task). This is a
- combination of the two policies above, for instance an
- ECA policy with more than one task in E, C, and A.
-
- - Classic directed: a policy with more than one state,
- each having one task, but a non-sequential execution.
- This means that the sequence of the states is not
- pre-defined in the policy (as would be for all cases
- above) but calculated at runtime. This can be good to
- realize decision trees based on contextual
- information.
-
- - Super Adaptive: using the full potential of the APEX
- policy model, states and tasks and state execution are
- fully flexible and calculated at runtime (per policy
- execution). This policy is very close to a general
- programming system (with only a few limitations), but
- can solve very hard problems.
-
- .. container:: paragraph
-
- The final step is to select a response that the policy
- creates. Possible responses have been discussed in the
- literature for a very long time. A few examples are:
-
- .. container:: ulist
-
- - Obligation (deontic for what should happen)
-
- - Authorization (e.g. for rule-based or other access
- control or security systems)
-
- - Intent (instead of providing detailed actions the
- response is an intent statement and a further system
- processes that)
-
- - Delegation (hand the problem over to someone else,
- possibly with some information or instructions)
-
- - Fail / Error (the policy has encountered a problem,
- and reports it)
-
- - Feedback (why did the policy make a certain decision)
-
-APEX Policy Model
-^^^^^^^^^^^^^^^^^
-
-Introduction
-------------
-
- .. container:: paragraph
-
- The APEX policy model is shown in UML notation in the
- figure below. A policy model can be stored in JSON or XML
- format in a file or can be held in a database. The APEX
- editor creates and modifies APEX policy models. APEX
- deployment deploys policy models, and a policy model is
- loaded into APEX engines so that the engines can run the
- policies in the policy model.
-
- .. container:: paragraph
-
- The figure shows four different views of the policy
- model:
-
- .. container:: ulist
-
- - The general model view shows the main parts of a
- policy: state, state output, event, and task. A task
- can also have parameters. Data types can be defined on
- a per-model basis using either standard atomic types
- (such as character, string, numbers) or complex types
- from a policy domain.
-
- - The logic model view emphasizes how decision-making
- logic is injected into a policy. There are essentially
- three different types of logic: task logic (for
- decision making in a task), task selection logic (to
- select a task if more than one is defined in a state),
- and state finalizer logic (to compute the final output
- event of a state and select an appropriate next state
- from the policy model).
-
- - The context model view shows how context is injected
- into a policy. States collect all context from their
- tasks. A task can define what context it requires for
- the decision making, i.e. what context the task logic
- will process. Context itself is a collection of items
- (individual context information) with data types.
- Context can be templated.
-
- - The event and field model view shows the events in the
- policy model. Tasks define what information they
- consume (input) and produce (output). This information
- is modeled as fields, essentially a key/type tuple in
- the model and a key/type/value triple at execution.
- Events then are collection of fields.
-
- .. container:: imageblock
-
- .. container:: content
-
- |APEX Policy Model for Execution|
-
- .. container:: title
-
- Figure 2. APEX Policy Model for Execution
-
-Concepts and Keys
-#################
-
- .. container:: paragraph
-
- Each element of the policy model is called a
- *concept*. Each *concept* is a subclass of the
- abstract *Concept* class, as shown in the next figure.
- Every concept implements the following abstract
- methods:
-
- .. container:: imageblock
-
- .. container:: content
-
- |Concepts and Keys|
-
- .. container:: title
-
- Figure 3. Concepts and Keys
-
- .. container:: ulist
-
- - ``getKey()`` - gets the unique key for this concept
- instance in the system
-
- - ``validate()`` - validates the structure of this
- concept, its sub-concepts and its relationships
-
- - ``clean()`` - carries out housekeeping on the
- concept such as trimming strings, remove any
- hanging references
-
- - ``clone()`` - creates a deep copy of an instance of
- this concept
-
- - ``equals()`` - checks if two instances of this
- concept are equal
-
- - ``toString()`` - returns a string representation of
- the concept
-
- - ``hashCode()`` - returns a hash code for the
- concept
-
- - ``copyTo()`` - carries out a deep copy of one
- instance of the concept to another instance,
- overwriting the target fields.
-
- .. container:: paragraph
-
- All concepts must have a *key*, which uniquely
- identifies a concept instance. The *key* of a subclass
- of an *Concept* must either be an ``ArtifactKey`` or
- an ``ReferenceKey``. Concepts that have a stand-alone
- independent existence such as *Policy*, *Task*, and
- *Event* must have an ``ArtifctKey`` key. Concepts that
- are contained in other concepts, that do not exist as
- stand-alone concepts must have an ``ReferenceKey``
- key. Examples of such concepts are *State* and
- *EventParameter*.
-
- .. container:: paragraph
-
- An ``ArticactKey`` has two fields; the *Name* of the
- concept it is the key for and the concept’s *Version*.
- A concept’s name must be unique in a given
- PolicyModel. A concept version is represented using
- the well known *major.minor.path* scheme as used in
- semantic versioning.
-
- .. container:: paragraph
-
- A ``ReferenceKey`` has three fields. The *UserKeyName*
- and *UserKeyVersion* fields identify the
- ``ArtifactKey`` of the concept in which the concept
- keyed by the ``ReferenceKey`` is contained. The
- *LocalName* field identifies the contained concept
- instance. The *LocalName* must be unique in the
- concepts of a given type contained by a parent.
-
- .. container:: paragraph
-
- For example, a policy called ``SalesPolicy`` with a
- Version of ``1.12.4`` has a state called ``Decide``.
- The ``Decide`` state is linked to the ``SalesPolicy``
- with a ``ReferenceKey`` with fields *UserKeyName* of
- ``SalesPolicy``, *UserKeyVersion* of ``1.12.4``, and
- *LocalName* of ``Decide``. There must not be another
- state called ``Decide`` in the policy ``SalesPolicy``.
- However, there may well be a state called ``Decide``
- in some other policy called ``PurchasingPolicy``.
-
- .. container:: paragraph
-
- Each concept in the model is also a JPA (`Java
- Persistence
- API <https://en.wikipedia.org/wiki/Java_Persistence_API>`__)
- Entity. This means that every concept can be
- individually persisted or the entire model can be
- persisted en-bloc to any persistence mechanism using
- an JPA framework such as
- `Hibernate <http://hibernate.org/>`__ or
- `EclipseLink <http://www.eclipse.org/eclipselink/>`__.
-
-Concept: PolicyModel
-####################
-
- .. container:: paragraph
-
- The *PolicyModel* concept is a container that holds
- the definition of a set of policies and their
- associated events, context maps, and tasks. A
- *PolicyModel* is implemented as four maps for
- policies, events, context maps, and tasks. Each map is
- indexed by the key of the policy, event, context map,
- or task. Any non-empty policy model must have at least
- one entry in its policy, event, and task map because
- all policies must have at least one input and output
- event and must execute at least one task.
-
- .. container:: paragraph
-
- A *PolicyModel* concept is keyed with an
- ``ArtifactKey key``. Because a *PolicyModel* is an
- ``AxConcept``, calling the ``validate()`` method on a
- policy model validates the concepts, structure, and
- relationships of the entire policy model.
-
-Concept: DataType
-#################
-
- .. container:: paragraph
-
- Data types are tightly controlled in APEX in order to
- provide a very high degree of consistency in policies
- and to facilitate tracking of changes to context as
- policies execute. All context is modeled as a
- *DataType* concept. Each DataType concept instance is
- keyed with an ``ArtifactKey`` key. The DataType field
- identifies the Java class of objects that is used to
- represent concept instances that use this data type.
- All context has a *DataType*; incoming and outgoing
- context is represented by *EventField* concepts and
- all other context is represented by *ContextItem*
- concepts.
-
-Concept: Event
-##############
-
- .. container:: paragraph
-
- An *Event* defines the structure of a message that
- passes into or out of an APEX engine or that passes
- between two states in an APEX engine. APEX supports
- message reception and sending in many formats and all
- messages are translated into an *Event* prior to
- processing by an APEX engine. Event concepts are keyed
- with an ``ArtifactKey`` key. The parameters of an
- event are held as a map of *EventField* concept
- instances with each parameter indexed by the
- *LocalName* of its ``ReferenceKey``. An *Event* has
- three fields:
-
- .. container:: ulist
-
- - The *NameSpace* identifies the domain of
- application of the event
-
- - The *Source* of the event identifies the system
- that emitted the event
-
- - The *Target* of the event identifies the system
- that the event was sent to
-
- .. container:: paragraph
-
- A *PolicyModel* contains a map of all the events known
- to a given policy model. Although an empty model may
- have no events in its event map, any sane policy model
- must have at least one *Event* defined.
-
-Concept: EventField
-###################
-
- .. container:: paragraph
-
- The incoming context and outgoing context of an event
- are the fields of the event. Each field representing a
- single piece of incoming or outgoing context. Each
- field of an *Event* is represented by an instance of
- the *EventField* concept. Each *EventField* concept
- instance in an event is keyed with a ``ReferenceKey``
- key, which references the event. The *LocalName* field
- of the ``ReferenceKey`` holds the name of the field A
- reference to a *DataType* concept defines the data
- type that values of this parameter have at run time.
-
-Concept: ContextMap
-###################
-
- .. container:: paragraph
-
- The set of context that is available for use by the
- policies of a *PolicyModel* is defined as *ContextMap*
- concept instances. The *PolicyModel* holds a map of
- all the *ContextMap* definitions. A *ContextMap* is
- itself a container for a group of related context
- items, each of which is represented by a *ContextItem*
- concept instance. *ContextMap* concepts are keyed with
- an ``ArtifactKey`` key. A developer can use the APEX
- Policy Editor to create context maps for their
- application domain.
-
- .. container:: paragraph
-
- A *ContextMap* uses a map to hold the context items.
- The ContextItem concept instances in the map are
- indexed by the *LocalName* of their ``ReferenceKey``.
-
- .. container:: paragraph
-
- The *ContextMapType* field of a *ContextMap* defines
- the type of a context map. The type can have either of
- two values:
-
- .. container:: ulist
-
- - A *BAG* context map is a context map with fixed
- content. Each possible context item in the context
- map is defined at design time and is held in the
- *ContextMap* context instance as *ContextItem*
- concept definitions and only the values of the
- context items in the context map can be changed at
- run time. The context items in a *BAG* context map
- have mixed types and distinct *ContextItem* concept
- instances of the same type can be defined. A *BAG*
- context map is convenient for defining a group of
- context items that are diverse but are related by
- domain, such as the characteristics of a device. A
- fully defined *BAG* context map has a fully
- populated *ContextItem* map but its
- *ContextItemTemplate* reference is not defined.
-
- - A *SAMETYPE* context map is used to represent a
- group of *ContextItem* instances of the same type.
- Unlike a *BAG* context map, the *ContextItem*
- concept instances of a *SAMETYPE* context map can
- be added, modified, and deleted at runtime. All
- *ContextItem* concept instances in a *SAMETYPE*
- context map must be of the same type, and that
- context item is defined as a single
- *ContextItemTemplate* concept instances at design
- time. At run time, the *ContextItemTemplate*
- definition is used to create new *ContextItem*
- concept instances for the context map on demand. A
- fully defined *SAMETYPE context map has an empty
- ContextItem map and its ContextItemTemplate\_*
- reference is defined.
-
- .. container:: paragraph
-
- The *Scope* of a *ContextMap* defines the range of
- applicability of a context map in APEX. The following
- scopes of applicability are defined:
-
- .. container:: ulist
-
- - *EPHEMERAL* scope means that the context map is
- owned, used, and modified by a single application,
- but the context map only exists while that
- application is running
-
- - *APPLICATION* scope specifies that the context map
- is owned, used, and modified by a single
- application, the context map is persistent
-
- - *GLOBAL* scope specifies that the context map is
- globally owned and is used and modified by any
- application, the context map is persistent
-
- - *EXTERNAL* scope specifies that the context map is
- owned by an external system and may be used in a
- read-only manner by any application, the context
- map is persistent
-
- .. container:: paragraph
-
- A much more sophisticated scoping mechanism for
- context maps is envisaged for Apex in future work. In
- such a mechanism, the scope of a context map would
- work somewhat like the way roles work in security
- authentication systems.
-
-Concept: ContextItem
-####################
-
- .. container:: paragraph
-
- Each piece of context in a *ContextMap* is represented
- by an instance of the *ContextItem* concept. Each
- *ContextItem* concept instance in a context map keyed
- with a ``ReferenceKey`` key, which references the
- context map of the context item. The *LocalName* field
- of the ``ReferenceKey`` holds the name of the context
- item in the context map A reference to a *DataType*
- concept defines the data type that values of this
- context item have at run time. The *WritableFlag*
- indicates if the context item is read only or
- read-write at run time.
-
-Concept: ContextItemTemplate
-############################
-
- .. container:: paragraph
-
- In a *SAMETYPE* *ContextMap*, the
- *ContextItemTemplate* definition provides a template
- for the *ContextItem* instances that will be created
- on the context map at run time. Each *ContextItem*
- concept instance in the context map is created using
- the *ContextItemTemplate* template. It is keyed with a
- ``ReferenceKey`` key, which references the context map
- of the context item. The *LocalName* field of the
- ``ReferenceKey``, supplied by the creator of the
- context item at run time, holds the name of the
- context item in the context map. A reference to a
- *DataType* concept defines the data type that values
- of this context item have at run time. The
- *WritableFlag* indicates if the context item is read
- only or read-write at run time.
-
-Concept: Task
-#############
-
- .. container:: paragraph
-
- The smallest unit of logic in a policy is a *Task*. A
- task encapsulates a single atomic unit of logic, and
- is designed to be a single indivisible unit of
- execution. A task may be invoked by a single policy or
- by many policies. A task has a single trigger event,
- which is sent to the task when it is invoked. Tasks
- emit one or more outgoing events, which carry the
- result of the task execution. Tasks may use or modify
- context as they execute.
-
- .. container:: paragraph
-
- The Task concept definition captures the definition of
- an APEX task. Task concepts are keyed with an
- ``ArtifactKey`` key. The Trigger of the task is a
- reference to the *Event* concept that triggers the
- task. The *OutgoingEvents* of a task are a set of
- references to *Event* concepts that may be emitted by
- the task.
-
- .. container:: paragraph
-
- All tasks have logic, some code that is programmed to
- execute the work of the task. The *Logic* concept of
- the task holds the definition of that logic.
-
- .. container:: paragraph
-
- The *Task* definition holds a set of *ContextItem* and
- *ContextItemTemplate* context items that the task is
- allow to access, as defined by the task developer at
- design time. The type of access (read-only or read
- write) that a task has is determined by the
- *WritableFlag* flag on the individual context item
- definitions. At run time, a task may only access the
- context items specified in its context item set, the
- APEX engine makes only the context items in the task
- context item set is available to the task.
-
- .. container:: paragraph
-
- A task can be configured with startup parameters. The
- set of parameters that can be configured on a task are
- defined as a set of *TaskParameter* concept
- definitions.
-
-Concept: TaskParameter
-######################
-
- .. container:: paragraph
-
- Each configuration parameter of a task are represented
- as a *Taskparameter* concept keyed with a
- ``ReferenceKey`` key, which references the task. The
- *LocalName* field of the ``ReferenceKey`` holds the
- name of the parameter. The *DefaultValue* field
- defines the default value that the task parameter is
- set to. The value of *TaskParameter* instances can be
- overridden at deployment time by specifying their
- values in the configuration information passed to APEX
- engines.
-
-Concept: Logic
-##############
-
- .. container:: paragraph
-
- The *Logic* concept instance holds the actual
- programmed task logic for a task defined in a *Task*
- concept or the programmed task selection logic for a
- state defined in a *State* concept. It is keyed with a
- ``ReferenceKey`` key, which references the task or
- state that owns the logic. The *LocalName* field of
- the Logic concept is the name of the logic.
-
- .. container:: paragraph
-
- The *LogicCode* field of a Logic concept definition is
- a string that holds the program code that is to be
- executed at run time. The *LogicType* field defines
- the language of the code. The standard values are the
- logic languages supported by APEX:
- `JAVASCRIPT <https://en.wikipedia.org/wiki/JavaScript>`__,
- `JAVA <https://java.com/en/>`__,
- `JYTHON <http://www.jython.org/>`__,
- `JRUBY <http://jruby.org/>`__, or
- `MVEL <https://en.wikibooks.org/wiki/Transwiki:MVEL_Language_Guide>`__.
-
- .. container:: paragraph
-
- The APEX engine uses the *LogicType* field value to
- decide which language interpreter to use for a task
- and then sends the logic defined in the *LogicCode*
- field to that interpreter.
-
-Concept: Policy
-###############
-
- .. container:: paragraph
-
- The *Policy* concept defines a policy in APEX. The
- definition is rather straightforward. A policy is made
- up of a set of states with the flavor of the policy
- determining the structure of the policy states and the
- first state defining what state in the policy executes
- first. *Policy* concepts are keyed with an
- ``ArtifactKey`` key.
-
- .. container:: paragraph
-
- The *PolicyFlavour* of a *Policy* concept specifies
- the structure that will be used for the states in the
- policy. A number of commonly used policy patterns are
- supported as APEX policy flavors. The standard policy
- flavors are:
-
- .. container:: ulist
-
- - The *MEDA* flavor supports policies written to the
- `MEDA policy
- pattern <https://www.researchgate.net/publication/282576518_Dynamically_Adaptive_Policies_for_Dynamically_Adaptive_Telecommunications_Networks>`__
- and require a sequence of four states: namely
- *Match*, *Establish*, *Decide* and *Act*.
-
- - The *OODA* flavor supports policies written to the
- `OODA loop
- pattern <https://en.wikipedia.org/wiki/OODA_loop>`__
- and require a sequence of four states: namely
- *Observe*, *Orient*, *Decide* and *Act*.
-
- - The *ECA* flavor supports policies written to the
- `ECA active rule
- pattern <https://en.wikipedia.org/wiki/Event_condition_action>`__
- and require a sequence of three states: namely
- *Event*, *Condition* and *Action*
-
- - The *XACML* flavor supports policies written in
- `XACML <https://en.wikipedia.org/wiki/XACML>`__ and
- require a single state: namely *XACML*
-
- - The *FREEFORM* flavor supports policies written in
- an arbitrary style. A user can define a *FREEFORM*
- policy as an arbitrarily long chain of states.
-
- .. container:: paragraph
-
- The *FirstState* field of a *Policy* definition is the
- starting point for execution of a policy. Therefore,
- the trigger event of the state referenced in the
- *FirstState* field is also the trigger event for the
- entire policy.
-
-Concept: State
-##############
-
- .. container:: paragraph
-
- The *State* concept represents a phase or a stage in a
- policy, with a policy being composed of a series of
- states. Each state has at least one but may have many
- tasks and, on each run of execution, a state executes
- one and only one of its tasks. If a state has more
- than one task, then its task selection logic is used
- to select which task to execute. Task selection logic
- is programmable logic provided by the state designer.
- That logic can use incoming, policy, global, and
- external context to select which task best
- accomplishes the purpose of the state in a give
- situation if more than one task has been specified on
- a state. A state calls one and only one task when it
- is executed.
-
- .. container:: paragraph
-
- Each state is triggered by an event, which means that
- all tasks of a state must also be triggered by that
- same event. The set of output events for a state is
- the union of all output events from all tasks for that
- task. In practice at the moment, because a state can
- only have a single input event, a state that is not
- the final state of a policy may only output a single
- event and all tasks of that state may also only output
- that single event. In future work, the concept of
- having a less restrictive trigger pattern will be
- examined.
-
- .. container:: paragraph
-
- A *State* concept is keyed with a ``ReferenceKey``
- key, which references the *Policy* concept that owns
- the state. The *LocalName* field of the
- ``ReferenceKey`` holds the name of the state. As a
- state is part of a chain of states, the *NextState*
- field of a state holds the ``ReferenceKey`` key of the
- state in the policy to execute after this state.
-
- .. container:: paragraph
-
- The *Trigger* field of a state holds the
- ``ArtifactKey`` of the event that triggers this state.
- The *OutgoingEvents* field holds the ``ArtifactKey``
- references of all possible events that may be output
- from the state. This is a set that is the union of all
- output events of all tasks of the state.
-
- .. container:: paragraph
-
- The *Task* concepts that hold the definitions of the
- task for the state are held as a set of
- ``ArtifactKey`` references in the state. The
- *DefaultTask* field holds a reference to the default
- task for the state, a task that is executed if no task
- selection logic is specified. If the state has only
- one task, that task is the default task.
-
- .. container:: paragraph
-
- The *Logic* concept referenced by a state holds the
- task selection logic for a state. The task selection
- logic uses the incoming context (parameters of the
- incoming event) and other context to determine the
- best task to use to execute its goals. The state holds
- a set of references to *ContextItem* and
- *ContextItemTemplate* definitions for the context used
- by its task selection logic.
-
-Writing Logic
-^^^^^^^^^^^^^
-
-Writing APEX Task Logic
------------------------
-
- .. container:: paragraph
-
- Task logic specifies the behavior of an Apex Task. This
- logic can be specified in a number of ways, exploiting
- Apex’s plug-in architecture to support a range of logic
- executors. In Apex scripted Task Logic can be written in
- any of these languages:
-
- .. container:: ulist
-
- - ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__,
-
- - ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__,
-
- - ```JRuby`` <https://en.wikipedia.org/wiki/JRuby>`__ or
-
- - ```Jython`` <https://en.wikipedia.org/wiki/Jython>`__.
-
- .. container:: paragraph
-
- These languages were chosen because the scripts can be
- compiled into Java bytecode at runtime and then
- efficiently executed natively in the JVM. Task Logic an
- also be written directly in Java but needs to be
- compiled, with the resulting classes added to the
- classpath. There are also a number of other Task Logic
- types (e.g. Fuzzy Logic), but these are not supported as
- yet. This guide will focus on the scripted Task Logic
- approaches, with MVEL and JavaScript being our favorite
- languages. In particular this guide will focus on the
- Apex aspects of the scripts. However, this guide does not
- attempt to teach you about the scripting languages
- themselves …​ that is up to you!
-
- .. tip::
- JVM-based scripting languages
- For more more information on scripting for the Java platform see: https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/index.html
-
- .. note::
- What do Tasks do?
- The function of an Apex Task is to provide the logic that can be executed for an Apex State as one of the steps in
- an Apex Policy. Each task receives some *incoming fields*, executes some logic (e.g: make a decision based on
- *shared state* or *context*, *incoming fields*, *external context*, etc.), perhaps set some *shared state* or
- *context* and then emits *outgoing fields*. The state that uses the task is responsible for extracting the
- *incoming fields* from the state input event. The state also has an *output mapper* associated with the task, and
- this *output mapper* is responsible for mapping the *outgoing fields* from the task into an appropriate
- output event for the state.
-
- .. container:: paragraph
-
- First lets start with a sample task, drawn from the "My
- First Apex Policy" example: The task "MorningBoozeCheck"
- from the "My First Apex Policy" example is available in
- both MVEL and JavaScript:
-
- .. container:: listingblock
-
- .. container:: title
-
- Javascript code for the ``MorningBoozeCheck`` task
-
- .. container:: content
-
- .. code:: javascript
- :number-lines:
-
- /*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2016-2018 Ericsson. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
- var returnValueType = Java.type("java.lang.Boolean");
- var returnValue = new returnValueType(true);
-
- // Load compatibility script for imports etc
- load("nashorn:mozilla_compat.js");
- importPackage(java.text);
- importClass(java.text.SimpleDateFormat);
-
- executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
-
- executor.outFields.put("amount" , executor.inFields.get("amount"));
- executor.outFields.put("assistant_ID", executor.inFields.get("assistant_ID"));
- executor.outFields.put("notes" , executor.inFields.get("notes"));
- executor.outFields.put("quantity" , executor.inFields.get("quantity"));
- executor.outFields.put("branch_ID" , executor.inFields.get("branch_ID"));
- executor.outFields.put("item_ID" , executor.inFields.get("item_ID"));
- executor.outFields.put("time" , executor.inFields.get("time"));
- executor.outFields.put("sale_ID" , executor.inFields.get("sale_ID"));
-
- item_id = executor.inFields.get("item_ID");
-
- //All times in this script are in GMT/UTC since the policy and events assume time is in GMT.
- var timenow_gmt = new Date(Number(executor.inFields.get("time")));
-
- var midnight_gmt = new Date(Number(executor.inFields.get("time")));
- midnight_gmt.setUTCHours(0,0,0,0);
-
- var eleven30_gmt = new Date(Number(executor.inFields.get("time")));
- eleven30_gmt.setUTCHours(11,30,0,0);
-
- var timeformatter = new java.text.SimpleDateFormat("HH:mm:ss z");
-
- var itemisalcohol = false;
- if(item_id != null && item_id >=1000 && item_id < 2000)
- itemisalcohol = true;
-
- if( itemisalcohol
- && timenow_gmt.getTime() >= midnight_gmt.getTime()
- && timenow_gmt.getTime() < eleven30_gmt.getTime()) {
-
- executor.outFields.put("authorised", false);
- executor.outFields.put("message", "Sale not authorised by policy task " +
- executor.subject.taskName+ " for time " + timeformatter.format(timenow_gmt.getTime()) +
- ". Alcohol can not be sold between " + timeformatter.format(midnight_gmt.getTime()) +
- " and " + timeformatter.format(eleven30_gmt.getTime()));
- }
- else{
- executor.outFields.put("authorised", true);
- executor.outFields.put("message", "Sale authorised by policy task " +
- executor.subject.taskName + " for time "+timeformatter.format(timenow_gmt.getTime()));
- }
-
- /*
- This task checks if a sale request is for an item that is an alcoholic drink.
- If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
- authorised. Otherwise the sale is authorised.
- In this implementation we assume that items with item_ID value between 1000 and
- 2000 are all alcoholic drinks :-)
- */
-
- .. container:: listingblock
-
- .. container:: title
-
- MVEL code for the ``MorningBoozeCheck`` task
-
- .. container:: content
-
- .. code:: javascript
- :number-lines:
-
- /*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2016-2018 Ericsson. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
- import java.util.Date;
- import java.util.Calendar;
- import java.util.TimeZone;
- import java.text.SimpleDateFormat;
-
- logger.info("Task Execution: '"+subject.id+"'. Input Fields: '"+inFields+"'");
-
- outFields.put("amount" , inFields.get("amount"));
- outFields.put("assistant_ID", inFields.get("assistant_ID"));
- outFields.put("notes" , inFields.get("notes"));
- outFields.put("quantity" , inFields.get("quantity"));
- outFields.put("branch_ID" , inFields.get("branch_ID"));
- outFields.put("item_ID" , inFields.get("item_ID"));
- outFields.put("time" , inFields.get("time"));
- outFields.put("sale_ID" , inFields.get("sale_ID"));
-
- item_id = inFields.get("item_ID");
-
- //The events used later to test this task use GMT timezone!
- gmt = TimeZone.getTimeZone("GMT");
- timenow = Calendar.getInstance(gmt);
- df = new SimpleDateFormat("HH:mm:ss z");
- df.setTimeZone(gmt);
- timenow.setTimeInMillis(inFields.get("time"));
-
- midnight = timenow.clone();
- midnight.set(
- timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
- timenow.get(Calendar.DATE),0,0,0);
- eleven30 = timenow.clone();
- eleven30.set(
- timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),
- timenow.get(Calendar.DATE),11,30,0);
-
- itemisalcohol = false;
- if(item_id != null && item_id >=1000 && item_id < 2000)
- itemisalcohol = true;
-
- if( itemisalcohol
- && timenow.after(midnight) && timenow.before(eleven30)){
- outFields.put("authorised", false);
- outFields.put("message", "Sale not authorised by policy task "+subject.taskName+
- " for time "+df.format(timenow.getTime())+
- ". Alcohol can not be sold between "+df.format(midnight.getTime())+
- " and "+df.format(eleven30.getTime()));
- return true;
- }
- else{
- outFields.put("authorised", true);
- outFields.put("message", "Sale authorised by policy task "+subject.taskName+
- " for time "+df.format(timenow.getTime()));
- return true;
- }
-
- /*
- This task checks if a sale request is for an item that is an alcoholic drink.
- If the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not
- authorised. Otherwise the sale is authorised.
- In this implementation we assume that items with item_ID value between 1000 and
- 2000 are all alcoholic drinks :-)
- */
-
- .. container:: paragraph
-
- The role of the task in this simple example is to copy
- the values in the incoming fields into the outgoing
- fields, then examine the values in some incoming fields
- (``item_id`` and ``time``), then set the values in some
- other outgoing fields (``authorised`` and ``message``).
-
- .. container:: paragraph
-
- Both MVEL and JavaScript like most JVM-based scripting
- languages can use standard Java libraries to perform
- complex tasks. Towards the top of the scripts you will
- see how to import Java classes and packages to be used
- directly in the logic. Another thing to notice is that
- Task Logic should return a ``java.lang.Boolean`` value
- ``true`` if the logic executed correctly. If the logic
- fails for some reason then ``false`` can be returned, but
- this will cause the policy invoking this task will fail
- and exit.
-
- .. note::
- How to return a value from task logic
- Some languages explicitly support returning values from the script (e.g. MVEL and JRuby) using an explicit
- return statement (e.g. ``return true``), other languages do not (e.g. JavaScript and Jython). For
- languages that do not support the ``return`` statement, a special field called ``returnValue`` must be
- created to hold the result of the task logic operation (i.e. assign a ``java.lang.Boolean``
- value to the ``returnValue`` field before completing the task).
- Also, in MVEL if there is no explicit return statement then the return value of the last executed statement will return
- (e.g. the statement a=(1+2) will return the value 3).
-
- .. container:: paragraph
-
- Besides these imported classes and normal language
- features Apex provides some natively available parameters
- and functions that can be used directly. At run-time
- these parameters are populated by the Apex execution
- environment and made natively available to logic scripts
- each time the logic script is invoked. (These can be
- accessed using the ``executor`` keyword for most
- languages, or can be accessed directly without the
- ``executor`` keyword in MVEL):
-
- Table 1. The ``executor`` Fields / Methods
-
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| Name | Type | Java type | Description |
-+============+=============+================================+=====================================================================================+
-| inFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
-| | | | |
-| | | | The incoming task fields. This is implemented as a standard Java |
-| | | | Java (unmodifiable) Map |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.logger.debug("Incoming fields: " |
-| | | | +executor.inFields.entrySet()); |
-| | | | var item_id = executor.incomingFields["item_ID"]; |
-| | | | if (item_id >=1000) { ... } |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| outFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
-| | | | |
-| | | | The outgoing task fields. This is implemented as a standard initially empty Java |
-| | | | (modifiable) Map. To create a new schema-compliant instance of a field object |
-| | | | see the utility method subject.getOutFieldSchemaHelper() below |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.outFields["authorised"] = false; |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| logger | Logger | org.slf4j.ext.XLogger | .. container:: paragraph |
-| | | | |
-| | | | A helpful logger |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.logger.info("Executing task: " |
-| | | | +executor.subject.id); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| TRUE/FALSE | boolean | java.lang.Boolean | .. container:: paragraph |
-| | | | |
-| | | | 2 helpful constants. These are useful to retrieve correct return values for the |
-| | | | task logic |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | var returnValue = executor.isTrue; |
-| | | | var returnValueType = Java.type("java.lang.Boolean"); |
-| | | | var returnValue = new returnValueType(true); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| subject | Task | TaskFacade | .. container:: paragraph |
-| | | | |
-| | | | This provides some useful information about the task that contains this task |
-| | | | logic. This object has some useful fields and methods : |
-| | | | |
-| | | | .. container:: ulist |
-| | | | |
-| | | | - **AxTask task** to get access to the full task definition of |
-| | | | the host task |
-| | | | |
-| | | | - **String getTaskName()** to get the name of the host task |
-| | | | |
-| | | | - **String getId()** to get the ID of the host task |
-| | | | |
-| | | | - **SchemaHelper getInFieldSchemaHelper( String fieldName )** to |
-| | | | get a ``SchemaHelper`` helper object to manipulate incoming |
-| | | | task fields in a schema-aware manner |
-| | | | |
-| | | | - **SchemaHelper getOutFieldSchemaHelper( String fieldName )** to |
-| | | | get a ``SchemaHelper`` helper object to manipulate outgoing |
-| | | | task fields in a schema-aware manner, e.g. to instantiate new |
-| | | | schema-compliant field objects to populate the |
-| | | | ``executor.outFields`` outgoing fields map |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.logger.info("Task name: " |
-| | | | +executor.subject.getTaskName()); |
-| | | | executor.logger.info("Task id: " |
-| | | | +executor.subject.getId()); |
-| | | | executor.logger.info("Task inputs definitions: " |
-| | | | +"executor.subject.task.getInputFieldSet()); |
-| | | | executor.logger.info("Task outputs definitions: " |
-| | | | +"executor.subject.task.getOutputFieldSet()); |
-| | | | executor.outFields["authorised"] = executor.subject |
-| | | | .getOutFieldSchemaHelper("authorised") |
-| | | | .createNewInstance("false"); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| ContextAlbum getContextAlbum(String ctxtAlbumName ) | .. container:: paragraph |
-| | |
-| | A utility method to retrieve a ``ContextAlbum`` for use in the task. |
-| | This is how you access the context used by the task. The returned |
-| | ``ContextAlbum`` implements the ``java.util.Map <String,Object>`` |
-| | interface to get and set context as appropriate. The returned |
-| | ``ContextAlbum`` also has methods to lock context albums, get |
-| | information about the schema of the items to be stored in a context |
-| | album, and get a ``SchemaHelper`` to manipulate context album items. How |
-| | to define and use context in a task is described in the Apex |
-| | Programmer’s Guide and in the My First Apex Policy guide. |
-| | |
-| | .. container:: |
-| | |
-| | .. container:: content |
-| | |
-| | .. container:: paragraph |
-| | |
-| | **Example:** |
-| | |
-| | .. code:: javascript |
-| | |
-| | var bkey = executor.inFields.get("branch_ID"); |
-| | var cnts = executor.getContextMap("BranchCounts"); |
-| | cnts.lockForWriting(bkey); |
-| | cnts.put(bkey, cnts.get(bkey) + 1); |
-| | cnts.unlockForWriting(bkey); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-
-Writing APEX Task Selection Logic
----------------------------------
-
- .. container:: paragraph
-
- The function of Task Selection Logic is to choose which task
- should be executed for an Apex State as one of the steps in an
- Apex Policy. Since each state must define a default task there is
- no need for Task Selection Logic unless the state uses more than
- one task. This logic can be specified in a number of ways,
- exploiting Apex’s plug-in architecture to support a range of logic
- executors. In Apex scripted Task Selection Logic can be written in
- any of these languages:
-
- .. container:: ulist
-
- - ```MVEL`` <https://en.wikipedia.org/wiki/MVEL>`__,
-
- - ```JavaScript`` <https://en.wikipedia.org/wiki/JavaScript>`__,
-
- - ```JRuby`` <https://en.wikipedia.org/wiki/JRuby>`__ or
-
- - ```Jython`` <https://en.wikipedia.org/wiki/Jython>`__.
-
- .. container:: paragraph
-
- These languages were chosen because the scripts can be compiled
- into Java bytecode at runtime and then efficiently executed
- natively in the JVM. Task Selection Logic an also be written
- directly in Java but needs to be compiled, with the resulting
- classes added to the classpath. There are also a number of other
- Task Selection Logic types but these are not supported as yet.
- This guide will focus on the scripted Task Selection Logic
- approaches, with MVEL and JavaScript being our favorite languages.
- In particular this guide will focus on the Apex aspects of the
- scripts. However, this guide does not attempt to teach you about
- the scripting languages themselves …​ that is up to you!
-
- .. tip::
- JVM-based scripting languages
- For more more information on Scripting for the Java platform see:
- https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/index.html
-
- .. note::
- What does Task Selection Logic do?
- When an Apex state references multiple tasks, there must be a way to dynamically decide
- which task should be chosen and executed. This can depend on the many factors, e.g. the
- *incoming event for the state*, *shared state* or *context*, *external context*,
- etc.. This is the function of a state’s Task Selection Logic. Obviously, if there is
- only one task then Task only one task then Task Selection Logic is not needed.
- Each state must also select one of the tasks a the *default state*. If the Task
- Selection Logic is unable to select an appropriate task, then it should select the
- *default task*. Once the task has been selected the Apex Engine will then execute that
- task.
-
- .. container:: paragraph
-
- First lets start with some simple Task Selection Logic, drawn from
- the "My First Apex Policy" example: The Task Selection Logic from
- the "My First Apex Policy" example is specified in JavaScript
- here:
-
- .. container:: listingblock
-
- .. container:: title
-
- Javascript code for the "My First Policy" Task Selection Logic
-
- .. container:: content
-
- .. code:: javascript
-
- /*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2016-2018 Ericsson. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-
- var returnValueType = Java.type("java.lang.Boolean");
- var returnValue = new returnValueType(true);
-
- executor.logger.info("Task Selection Execution: '"+executor.subject.id+
- "'. Input Event: '"+executor.inFields+"'");
-
- branchid = executor.inFields.get("branch_ID");
- taskorig = executor.subject.getTaskKey("MorningBoozeCheck");
- taskalt = executor.subject.getTaskKey("MorningBoozeCheckAlt1");
- taskdef = executor.subject.getDefaultTaskKey();
-
- if(branchid >=0 && branchid <1000){
- taskorig.copyTo(executor.selectedTask);
- }
- else if (branchid >=1000 && branchid <2000){
- taskalt.copyTo(executor.selectedTask);
- }
- else{
- taskdef.copyTo(executor.selectedTask);
- }
-
- /*
- This task selection logic selects task "MorningBoozeCheck" for branches with
- 0<=branch_ID<1000 and selects task "MorningBoozeCheckAlt1" for branches with
- 1000<=branch_ID<2000. Otherwise the default task is selected.
- In this case the default task is also "MorningBoozeCheck"
- */
-
- .. container:: paragraph
-
- The role of the Task Selection Logic in this simple example is to
- examine the value in one incoming field (``branchid``), then
- depending on that field’s value set the value for the selected
- task to the appropriate task (``MorningBoozeCheck``,
- ``MorningBoozeCheckAlt1``, or the default task).
-
- .. container:: paragraph
-
- Another thing to notice is that Task Selection Logic should return
- a ``java.lang.Boolean`` value ``true`` if the logic executed
- correctly. If the logic fails for some reason then ``false`` can
- be returned, but this will cause the policy invoking this task
- will fail and exit.
-
- .. note::
- How to return a value from Task Selection Logic
- Some languages explicitly support returning values from the script (e.g. MVEL and
- JRuby) using an explicit return statement (e.g. ``return true``), other languages do not (e.g.
- JavaScript and Jython). For languages that do not support the ``return`` statement, a special field called
- ``returnValue`` must be created to hold the result of the task logic operation (i.e. assign a ``java.lang.Boolean``
- value to the ``returnValue`` field before completing the task).
- Also, in MVEL if there is not explicit return statement then the return value of the last executed statement will
- return (e.g. the statement a=(1+2) will return the value 3).
-
- .. container:: paragraph
-
- Each of the scripting languages used in Apex can import and use
- standard Java libraries to perform complex tasks. Besides imported
- classes and normal language features Apex provides some natively
- available parameters and functions that can be used directly. At
- run-time these parameters are populated by the Apex execution
- environment and made natively available to logic scripts each time
- the logic script is invoked. (These can be accessed using the
- ``executor`` keyword for most languages, or can be accessed
- directly without the ``executor`` keyword in MVEL):
-
- Table 2. The ``executor`` Fields / Methods
- +-------------------------------------------------------+--------------------------------------------------------+
- | Unix, Cygwin | Windows |
- +=======================================================+========================================================+
- | .. container:: | .. container:: |
- | | |
- | .. container:: content | .. container:: content |
- | | |
- | .. code:: bash | .. code:: bash |
- | :number-lines: | :number-lines: |
- | | |
- | >c: | # cd /usr/local/src/apex-pdp |
- | >cd \dev\apex | # mvn clean install -DskipTest |
- | >mvn clean install -DskipTests | |
- +-------------------------------------------------------+--------------------------------------------------------+
-
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| Name | Type | Java type | Description |
-+============+=============+================================+=====================================================================================+
-| inFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
-| | | | |
-| | | | All fields in the state’s incoming event. This is implemented as a standard Java |
-| | | | Java (unmodifiable) Map |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.logger.debug("Incoming fields: " |
-| | | | +executor.inFields.entrySet()); |
-| | | | var item_id = executor.incomingFields["item_ID"]; |
-| | | | if (item_id >=1000) { ... } |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| outFields | Fields | java.util.Map <String,Object> | .. container:: paragraph |
-| | | | |
-| | | | The outgoing task fields. This is implemented as a standard initially empty Java |
-| | | | (modifiable) Map. To create a new schema-compliant instance of a field object |
-| | | | see the utility method subject.getOutFieldSchemaHelper() below |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.outFields["authorised"] = false; |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| logger | Logger | org.slf4j.ext.XLogger | .. container:: paragraph |
-| | | | |
-| | | | A helpful logger |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.logger.info("Executing task: " |
-| | | | +executor.subject.id); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| TRUE/FALSE | boolean | java.lang.Boolean | .. container:: paragraph |
-| | | | |
-| | | | 2 helpful constants. These are useful to retrieve correct return values for the |
-| | | | task logic |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | var returnValue = executor.isTrue; |
-| | | | var returnValueType = Java.type("java.lang.Boolean"); |
-| | | | var returnValue = new returnValueType(true); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| subject | Task | TaskFacade | .. container:: paragraph |
-| | | | |
-| | | | This provides some useful information about the task that contains this task |
-| | | | logic. This object has some useful fields and methods : |
-| | | | |
-| | | | .. container:: ulist |
-| | | | |
-| | | | - **AxTask task** to get access to the full task definition of |
-| | | | the host task |
-| | | | |
-| | | | - **String getTaskName()** to get the name of the host task |
-| | | | |
-| | | | - **String getId()** to get the ID of the host task |
-| | | | |
-| | | | - **SchemaHelper getInFieldSchemaHelper( String fieldName )** to |
-| | | | get a ``SchemaHelper`` helper object to manipulate incoming |
-| | | | task fields in a schema-aware manner |
-| | | | |
-| | | | - **SchemaHelper getOutFieldSchemaHelper( String fieldName )** to |
-| | | | get a ``SchemaHelper`` helper object to manipulate outgoing |
-| | | | task fields in a schema-aware manner, e.g. to instantiate new |
-| | | | schema-compliant field objects to populate the |
-| | | | ``executor.outFields`` outgoing fields map |
-| | | | |
-| | | | .. container:: |
-| | | | |
-| | | | .. container:: content |
-| | | | |
-| | | | .. container:: paragraph |
-| | | | |
-| | | | **Example:** |
-| | | | |
-| | | | .. code:: javascript |
-| | | | |
-| | | | executor.logger.info("Task name: " |
-| | | | +executor.subject.getTaskName()); |
-| | | | executor.logger.info("Task id: " |
-| | | | +executor.subject.getId()); |
-| | | | executor.logger.info("Task inputs definitions: " |
-| | | | +"executor.subject.task.getInputFieldSet()); |
-| | | | executor.logger.info("Task outputs definitions: " |
-| | | | +"executor.subject.task.getOutputFieldSet()); |
-| | | | executor.outFields["authorised"] = executor.subject |
-| | | | .getOutFieldSchemaHelper("authorised") |
-| | | | .createNewInstance("false"); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-| ContextAlbum getContextAlbum(String ctxtAlbumName ) | .. container:: paragraph |
-| | |
-| | A utility method to retrieve a ``ContextAlbum`` for use in the task. |
-| | This is how you access the context used by the task. The returned |
-| | ``ContextAlbum`` implements the ``java.util.Map <String,Object>`` |
-| | interface to get and set context as appropriate. The returned |
-| | ``ContextAlbum`` also has methods to lock context albums, get |
-| | information about the schema of the items to be stored in a context |
-| | album, and get a ``SchemaHelper`` to manipulate context album items. How |
-| | to define and use context in a task is described in the Apex |
-| | Programmer’s Guide and in the My First Apex Policy guide. |
-| | |
-| | .. container:: |
-| | |
-| | .. container:: content |
-| | |
-| | .. container:: paragraph |
-| | |
-| | **Example:** |
-| | |
-| | .. code:: javascript |
-| | |
-| | var bkey = executor.inFields.get("branch_ID"); |
-| | var cnts = executor.getContextMap("BranchCounts"); |
-| | cnts.lockForWriting(bkey); |
-| | cnts.put(bkey, cnts.get(bkey) + 1); |
-| | cnts.unlockForWriting(bkey); |
-+------------+-------------+--------------------------------+-------------------------------------------------------------------------------------+
-
-Logic Cheatsheet
-----------------
-
- .. container:: paragraph
-
- Examples given here use Javascript (if not stated otherwise),
- other execution environments will be similar.
-
-Add Nashorn
-###########
-
- .. container:: paragraph
-
- First line in the logic use this import.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Nashorn
-
- .. container:: content
-
- .. code:: javascript
-
- load("nashorn:mozilla_compat.js");
-
-Finish Logic with Success or Error
-##################################
-
- .. container:: paragraph
-
- To finish logic, i.e. return to APEX, with success use the
- following lines close to the end of the logic.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Success
-
- .. container:: content
-
- .. code:: javascript
-
- var returnValueType = Java.type("java.lang.Boolean");
- var returnValue = new returnValueType(true);
-
- .. container:: paragraph
-
- To notify a problem, finish with an error.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Fail
-
- .. container:: content
-
- .. code:: javascript
-
- var returnValueType = Java.type("java.lang.Boolean");
- var returnValue = new returnValueType(false);
-
-Logic Logging
-#############
-
- .. container:: paragraph
-
- Logging can be made easy using a local variable for the logger.
- Line 1 below does that. Then we start with a trace log with the
- task (or task logic) identifier followed by the infields.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Logging
-
- .. container:: content
-
- .. code:: javascript
-
- var logger = executor.logger;
- logger.trace("start: " + executor.subject.id);
- logger.trace("-- infields: " + executor.inFields);
-
- .. container:: paragraph
-
- For larger logging blocks you can use the standard logging API
- to detect log levels, for instance:
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Logging Blocks
-
- .. container:: content
-
- .. code:: javascript
-
- if(logger.isTraceEnabled()){
- // trace logging block here
- }
-
- .. container:: paragraph
-
- Note: the shown logger here logs to
- ``org.onap.policy.apex.executionlogging``. The behavior of the
- actual logging can be specified in the
- ``$APEX_HOME/etc/logback.xml``.
-
- .. container:: paragraph
-
- If you want to log into the APEX root logger (which is
- sometimes necessary to report serious logic errors to the top),
- then import the required class and use this logger.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Root Logger
-
- .. container:: content
-
- .. code:: javascript
-
- importClass(org.slf4j.LoggerFactory);
- var rootLogger = LoggerFactory.getLogger(logger.ROOT_LOGGER_NAME);
-
- rootLogger.error("Serious error in logic detected: " + executor.subject.id);
-
-Local Variable for Infields
-###########################
-
- .. container:: paragraph
-
- It is a good idea to use local variables for ``infields``. This
- avoids long code lines and policy evolution. The following
- example assumes infields named ``nodeName`` and ``nodeAlias``.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Infields Local Var
-
- .. container:: content
-
- .. code:: javascript
-
- var ifNodeName = executor.inFields["nodeName"];
- var ifNodeAlias = executor.inFields["nodeAlias"];
-
-Local Variable for Context Albums
-#################################
-
- .. container:: paragraph
-
- Similar to the ``infields`` it is good practice to use local
- variables for context albums as well. The following example
- assumes that a task can access a context album
- ``albumTopoNodes``. The second line gets a particular node from
- this context album.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Infields Local Var
-
- .. container:: content
-
- .. code:: javascript
-
- var albumTopoNodes = executor.getContextAlbum("albumTopoNodes");
- var ctxtNode = albumTopoNodes.get(ifNodeName);
-
-Set Outfields in Logic
-######################
-
- .. container:: paragraph
-
- The task logic needs to set outfields with content generated.
- The exception are outfields that are a direct copy from an
- infield of the same name, APEX does that autmatically.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Set Outfields
-
- .. container:: content
-
- .. code:: javascript
-
- executor.outFields["report"] = "node ctxt :: added node " + ifNodeName;
-
-Create a instance of an Outfield using Schemas
-##############################################
-
- .. container:: paragraph
-
- If an outfield is not an atomic type (string, integer, etc.)
- but uses a complex schema (with a Java or Avro backend), APEX
- can help to create new instances. The ``executor`` provides a
- field called ``subject``, which provides a schem helper with an
- API for this. The complete API of the schema helper is
- documented here: `API Doc:
- SchemaHelper <https://ericsson.github.io/apex-docs/javadocs/index.html>`__.
-
- .. container:: paragraph
-
- If the backend is Avro, then an import of the Avro schema
- library is required:
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Import Avro
-
- .. container:: content
-
- .. code:: javascript
-
- importClass(org.apache.avro.generic.GenericData.Array);
- importClass(org.apache.avro.generic.GenericRecord);
- importClass(org.apache.avro.Schema);
-
- .. container:: paragraph
-
- If the backend is Java, then the Java class implementing the
- schema needs to be imported.
-
- .. container:: paragraph
-
- The following example assumes an outfield ``situation``. The
- ``subject`` method ``getOutFieldSchemaHelper()`` is used to
- create a new instance.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Outfield Instance with Schema
-
- .. container:: content
-
- .. code:: javascript
-
- var situation = executor.subject.getOutFieldSchemaHelper("situation").createNewInstance();
-
- .. container:: paragraph
-
- If the schema backend is Java, the new instance will be as
- implemented in the Java class. If the schema backend is Avro,
- the new instance will have all fields from the Avro schema
- specification, but set to ``null``. So any entry here needs to
- be done separately. For instance, the ``situation`` schema has
- a field ``problemID`` which we set.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Outfield Instance with Schema, set
-
- .. container:: content
-
- .. code:: javascript
-
- situation.put("problemID", "my-problem");
-
-Create a instance of an Context Album entry using Schemas
-#########################################################
-
- .. container:: paragraph
-
- Context album instances can be created using very similar to
- the outfields. Here, the schema helper comes from the context
- album directly. The API of the schema helper is the same as for
- outfields, see `API Doc:
- SchemaHelper <https://ericsson.github.io/apex-docs/javadocs/index.html>`__.
-
- .. container:: paragraph
-
- If the backend is Avro, then an import of the Avro schema
- library is required:
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Import Avro
-
- .. container:: content
-
- .. code:: javascript
-
- importClass(org.apache.avro.generic.GenericData.Array);
- importClass(org.apache.avro.generic.GenericRecord);
- importClass(org.apache.avro.Schema);
-
- .. container:: paragraph
-
- If the backend is Java, then the Java class implementing the
- schema needs to be imported.
-
- .. container:: paragraph
-
- The following example creates a new instance of a context album
- instance named ``albumProblemMap``.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Outfield Instance with Schema
-
- .. container:: content
-
- .. code:: javascript
-
- var albumProblemMap = executor.getContextAlbum("albumProblemMap");
- var linkProblem = albumProblemMap.getSchemaHelper().createNewInstance();
-
- .. container:: paragraph
-
- This can of course be also done in a single call without the
- local variable for the context album.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Outfield Instance with Schema, one line
-
- .. container:: content
-
- .. code:: javascript
-
- var linkProblem = executor.getContextAlbum("albumProblemMap").getSchemaHelper().createNewInstance();
-
- .. container:: paragraph
-
- If the schema backend is Java, the new instance will be as
- implemented in the Java class. If the schema backend is Avro,
- the new instance will have all fields from the Avro schema
- specification, but set to ``null``. So any entry here needs to
- be done separately (see above in outfields for an example).
-
-Enumerates
-##########
-
- .. container:: paragraph
-
- When dealing with enumerates (Avro or Java defined), it is
- sometimes and in some execution environments necessary to
- convert them to a string. For example, assume an Avro enumerate
- schema as:
-
- .. container:: listingblock
-
- .. container:: title
-
- Avro Enumerate Schema
-
- .. container:: content
-
- .. code:: javascript
-
- {
- "type": "enum",
- "name": "Status",
- "symbols" : [
- "UP",
- "DOWN"
- ]
- }
-
- .. container:: paragraph
-
- Using a switch over a field initialized with this enumerate in
- Javascript will fail. Instead, use the ``toString`` method, for
- example:
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Outfield Instance with Schema, one line
-
- .. container:: content
-
- .. code:: javascript
-
- var switchTest = executor.inFields["status"];
- switch(switchTest.toString()){
- case "UP": ...; break;
- case "DOWN": ...; break;
- default: ...;
- }
-
-MVEL Initialize Outfields First!
-################################
-
- .. container:: paragraph
-
- In MVEL, we observed a problem when accessing (setting)
- outfields without a prior access to them. So in any MVEL task
- logic, before setting any outfield, simply do a get (with any
- string), to load the outfields into the MVEL cache.
-
- .. container:: listingblock
-
- .. container:: title
-
- MVEL Outfield Initialization
-
- .. container:: content
-
- .. code:: javascript
-
- outFields.get("initialize outfields");
-
-Using Java in Scripting Logic
-#############################
-
- .. container:: paragraph
-
- Since APEX executes the logic inside a JVM, most scripting
- languages provide access to all standard Java classes. Simply
- add an import for the required class and then use it as in
- actual Java.
-
- .. container:: paragraph
-
- The following example imports ``java.util.arraylist`` into a
- Javascript logic, and then creates a new list.
-
- .. container:: listingblock
-
- .. container:: title
-
- JS Import ArrayList
-
- .. container:: content
-
- .. code:: javascript
-
- importClass(java.util.ArrayList);
- var myList = new ArrayList();
-
-Policy Examples
-^^^^^^^^^^^^^^^
-
-My First Policy
----------------
-
- .. container:: paragraph
-
- A good starting point is the ``My First Policy`` example. It
- describes a sales problem, to which policy can be applied.
- The example details the policy background, shows how to use
- the REST Editor to create a policy, and provides details for
- running the policies. The documentation can be found:
-
- .. container:: ulist
-
- - `My-First-Policy on the APEX
- site <https://ericsson.github.io/apex-docs/modules/examples/examples-myfirstpolicy/MyFirstPolicyHowto.html>`__
-
- - `Stand-alone
- HTML <https://ericsson.github.io/apex-docs/docs-apex/html/HowTo-MyFirstPolicy.html>`__
-
- - `Stand-alone
- PDF <https://ericsson.github.io/apex-docs/docs-apex/pdf/HowTo-MyFirstPolicy.pdf>`__
-
-VPN SLA
--------
-
- .. container:: paragraph
-
- The domain Policy-controlled Video Streaming (PCVS) contains
- a policy for controlling video streams with different
- strategies. It also provides details for installing an
- actual testbed with off-the-shelve software (Mininet,
- Floodlight, Kafka, Zookeeper). The policy model here
- demonstrates virtually all APEX features: local context and
- policies controlling it, task selection logic and multiple
- tasks in a single state, AVRO schemas for context, AVOR
- schemas for events (trigger and local), and a CLI editor
- specification of the policy. The documentation can be found:
-
- .. container:: ulist
-
- - `VPN SLA Policy on the APEX
- site <https://ericsson.github.io/apex-docs/modules/examples/examples-pcvs/vpnsla/policy.html>`__
-
-Decision Maker
---------------
-
- .. container:: paragraph
-
- The domain Decision Maker shows a very simple policy for
- decisions. Interesting here is that the it creates a Docker
- image to run the policy and that it uses the APEX REST
- applications to update the policy on the-fly. It also has
- local context to remember past decisions, and shows how to
- use that to no make the same decision twice in a row. The
- documentation can be found:
-
- .. container:: ulist
-
- - `Decision Maker on APEX
- site <https://ericsson.github.io/apex-docs/modules/examples/examples-decisionmaker/index.html>`__
-
-.. container::
- :name: footer
-
- .. container::
- :name: footer-text
-
- 2.0.0-SNAPSHOT
- Last updated 2018-09-04 16:04:24 IST
-
-.. |APEX Policy Matrix| image:: images/apex-intro/ApexPolicyMatrix.png
-.. |APEX Policy Model for Execution| image:: images/apex-policy-model/UmlPolicyModels.png
-.. |Concepts and Keys| image:: images/apex-policy-model/ConceptsKeys.png
-