Author: shuber
Date: Wed Feb  9 08:27:10 2022
New Revision: 1897886

URL: http://svn.apache.org/viewvc?rev=1897886&view=rev
Log:
Site checkin for project Apache Unomi :: Root Project

Modified:
    unomi/website/manual/1_1_x/index.html
    unomi/website/manual/1_2_x/index.html
    unomi/website/manual/1_3_x/index.html
    unomi/website/manual/1_4_x/index.html
    unomi/website/manual/1_5_x/index.html
    unomi/website/manual/latest/index.html

Modified: unomi/website/manual/1_1_x/index.html
URL: 
http://svn.apache.org/viewvc/unomi/website/manual/1_1_x/index.html?rev=1897886&r1=1897885&r2=1897886&view=diff
==============================================================================
--- unomi/website/manual/1_1_x/index.html (original)
+++ unomi/website/manual/1_1_x/index.html Wed Feb  9 08:27:10 2022
@@ -921,7 +921,7 @@ information about the context for the cu
 <p>We need to either retrieve (from the initial context we retrieved 
previously using <code>cxs.sessionId</code>) or generate a session identifier 
for our request since Unomi currently requires one.</p>
 </li>
 <li>
-<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=&#39"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=&#39</a>; + 
sessionId</code>. This URI requests context from Unomi, resulting in an updated 
<code>cxs</code> object in the javascript global scope. The context server can 
reply to this request either by returning a JSON-only object containing solely 
the context information as is the case when the requested URI is 
<code>context.json</code>. However, if the client requests 
<code>context.js</code> then useful functions to interact with Unomi are added 
to the <code>cxs</code> object in addition to the context information as 
depicted above.</p>
+<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=sessionId"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=sessionId</a></code>.
 This URI requests context from Unomi, resulting in an updated <code>cxs</code> 
object in the javascript global scope. The context server can reply to this 
request either by returning a JSON-only object containing solely the context 
information as is the case when the requested URI is <code>context.json</code>. 
However, if the client requests <code>context.js</code> then useful functions 
to interact with Unomi are added to the <code>cxs</code> object in addition to 
the context information as depicted above.</p>
 </li>
 <li>
 <p>We don&#8217;t need to provide any authentication at all to interact with 
this part of Unomi since we only have access to read-only data (as well as 
providing events as we shall see later on). If we had been using the REST API, 
we would have needed to provide authentication information as well.</p>

Modified: unomi/website/manual/1_2_x/index.html
URL: 
http://svn.apache.org/viewvc/unomi/website/manual/1_2_x/index.html?rev=1897886&r1=1897885&r2=1897886&view=diff
==============================================================================
--- unomi/website/manual/1_2_x/index.html (original)
+++ unomi/website/manual/1_2_x/index.html Wed Feb  9 08:27:10 2022
@@ -1657,7 +1657,7 @@ information about the context for the cu
 <p>We need to either retrieve (from the initial context we retrieved 
previously using <code>cxs.sessionId</code>) or generate a session identifier 
for our request since Unomi currently requires one.</p>
 </li>
 <li>
-<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=&#39"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=&#39</a>; + 
sessionId</code>. This URI requests context from Unomi, resulting in an updated 
<code>cxs</code> object in the javascript global scope. The context server can 
reply to this request either by returning a JSON-only object containing solely 
the context information as is the case when the requested URI is 
<code>context.json</code>. However, if the client requests 
<code>context.js</code> then useful functions to interact with Unomi are added 
to the <code>cxs</code> object in addition to the context information as 
depicted above.</p>
+<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=sessionId"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=sessionId</a></code>.
 This URI requests context from Unomi, resulting in an updated <code>cxs</code> 
object in the javascript global scope. The context server can reply to this 
request either by returning a JSON-only object containing solely the context 
information as is the case when the requested URI is <code>context.json</code>. 
However, if the client requests <code>context.js</code> then useful functions 
to interact with Unomi are added to the <code>cxs</code> object in addition to 
the context information as depicted above.</p>
 </li>
 <li>
 <p>We don&#8217;t need to provide any authentication at all to interact with 
this part of Unomi since we only have access to read-only data (as well as 
providing events as we shall see later on). If we had been using the REST API, 
we would have needed to provide authentication information as well.</p>

Modified: unomi/website/manual/1_3_x/index.html
URL: 
http://svn.apache.org/viewvc/unomi/website/manual/1_3_x/index.html?rev=1897886&r1=1897885&r2=1897886&view=diff
==============================================================================
--- unomi/website/manual/1_3_x/index.html (original)
+++ unomi/website/manual/1_3_x/index.html Wed Feb  9 08:27:10 2022
@@ -1300,7 +1300,7 @@ information about the context for the cu
 <p>We need to either retrieve (from the initial context we retrieved 
previously using <code>cxs.sessionId</code>) or generate a session identifier 
for our request since Unomi currently requires one.</p>
 </li>
 <li>
-<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=&#39"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=&#39</a>; + 
sessionId</code>. This URI requests context from Unomi, resulting in an updated 
<code>cxs</code> object in the javascript global scope. The context server can 
reply to this request either by returning a JSON-only object containing solely 
the context information as is the case when the requested URI is 
<code>context.json</code>. However, if the client requests 
<code>context.js</code> then useful functions to interact with Unomi are added 
to the <code>cxs</code> object in addition to the context information as 
depicted above.</p>
+<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=sessionId"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=sessionId</a></code>.
 This URI requests context from Unomi, resulting in an updated <code>cxs</code> 
object in the javascript global scope. The context server can reply to this 
request either by returning a JSON-only object containing solely the context 
information as is the case when the requested URI is <code>context.json</code>. 
However, if the client requests <code>context.js</code> then useful functions 
to interact with Unomi are added to the <code>cxs</code> object in addition to 
the context information as depicted above.</p>
 </li>
 <li>
 <p>We don&#8217;t need to provide any authentication at all to interact with 
this part of Unomi since we only have access to read-only data (as well as 
providing events as we shall see later on). If we had been using the REST API, 
we would have needed to provide authentication information as well.</p>

Modified: unomi/website/manual/1_4_x/index.html
URL: 
http://svn.apache.org/viewvc/unomi/website/manual/1_4_x/index.html?rev=1897886&r1=1897885&r2=1897886&view=diff
==============================================================================
--- unomi/website/manual/1_4_x/index.html (original)
+++ unomi/website/manual/1_4_x/index.html Wed Feb  9 08:27:10 2022
@@ -4033,7 +4033,7 @@ information about the context for the cu
 <p>We need to either retrieve (from the initial context we retrieved 
previously using <code>cxs.sessionId</code>) or generate a session identifier 
for our request since Unomi currently requires one.</p>
 </li>
 <li>
-<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=&#39"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=&#39</a>; + 
sessionId</code>. This URI requests context from Unomi, resulting in an updated 
<code>cxs</code> object in the javascript global scope. The context server can 
reply to this request either by returning a JSON-only object containing solely 
the context information as is the case when the requested URI is 
<code>context.json</code>. However, if the client requests 
<code>context.js</code> then useful functions to interact with Unomi are added 
to the <code>cxs</code> object in addition to the context information as 
depicted above.</p>
+<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=sessionId"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=sessionId</a></code>.
 This URI requests context from Unomi, resulting in an updated <code>cxs</code> 
object in the javascript global scope. The context server can reply to this 
request either by returning a JSON-only object containing solely the context 
information as is the case when the requested URI is <code>context.json</code>. 
However, if the client requests <code>context.js</code> then useful functions 
to interact with Unomi are added to the <code>cxs</code> object in addition to 
the context information as depicted above.</p>
 </li>
 <li>
 <p>We don&#8217;t need to provide any authentication at all to interact with 
this part of Unomi since we only have access to read-only data (as well as 
providing events as we shall see later on). If we had been using the REST API, 
we would have needed to provide authentication information as well.</p>

Modified: unomi/website/manual/1_5_x/index.html
URL: 
http://svn.apache.org/viewvc/unomi/website/manual/1_5_x/index.html?rev=1897886&r1=1897885&r2=1897886&view=diff
==============================================================================
--- unomi/website/manual/1_5_x/index.html (original)
+++ unomi/website/manual/1_5_x/index.html Wed Feb  9 08:27:10 2022
@@ -6844,7 +6844,7 @@ information about the context for the cu
 <p>We need to either retrieve (from the initial context we retrieved 
previously using <code>cxs.sessionId</code>) or generate a session identifier 
for our request since Unomi currently requires one.</p>
 </li>
 <li>
-<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=&#39"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=&#39</a>; + 
sessionId</code>. This URI requests context from Unomi, resulting in an updated 
<code>cxs</code> object in the javascript global scope. The context server can 
reply to this request either by returning a JSON-only object containing solely 
the context information as is the case when the requested URI is 
<code>context.json</code>. However, if the client requests 
<code>context.js</code> then useful functions to interact with Unomi are added 
to the <code>cxs</code> object in addition to the context information as 
depicted above.</p>
+<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=sessionId"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=sessionId</a></code>.
 This URI requests context from Unomi, resulting in an updated <code>cxs</code> 
object in the javascript global scope. The context server can reply to this 
request either by returning a JSON-only object containing solely the context 
information as is the case when the requested URI is <code>context.json</code>. 
However, if the client requests <code>context.js</code> then useful functions 
to interact with Unomi are added to the <code>cxs</code> object in addition to 
the context information as depicted above.</p>
 </li>
 <li>
 <p>We don&#8217;t need to provide any authentication at all to interact with 
this part of Unomi since we only have access to read-only data (as well as 
providing events as we shall see later on). If we had been using the REST API, 
we would have needed to provide authentication information as well.</p>

Modified: unomi/website/manual/latest/index.html
URL: 
http://svn.apache.org/viewvc/unomi/website/manual/latest/index.html?rev=1897886&r1=1897885&r2=1897886&view=diff
==============================================================================
--- unomi/website/manual/latest/index.html (original)
+++ unomi/website/manual/latest/index.html Wed Feb  9 08:27:10 2022
@@ -77,7 +77,8 @@
 <li><a href="#_multi_layer_scripting_filtering_system">3.8.1. Multi-layer 
scripting filtering system</a></li>
 <li><a href="#_scripts_and_expressions">3.8.2. Scripts and expressions</a></li>
 <li><a href="#_scripting_expression_filtering_configuration_parameters">3.8.3. 
Scripting expression filtering configuration parameters</a></li>
-<li><a href="#_scripting_roadmap">3.8.4. Scripting roadmap</a></li>
+<li><a href="#_groovy_actions">3.8.4. Groovy Actions</a></li>
+<li><a href="#_scripting_roadmap">3.8.5. Scripting roadmap</a></li>
 </ul>
 </li>
 <li><a href="#_automatic_profile_merging">3.9. Automatic profile 
merging</a></li>
@@ -359,8 +360,7 @@
 <li><a href="#_deploying_into_an_existing_karaf_server">13.1.5. Deploying into 
an existing Karaf server</a></li>
 <li><a href="#_jdk_selection_on_mac_os_x">13.1.6. JDK Selection on Mac OS 
X</a></li>
 <li><a href="#_running_the_integration_tests">13.1.7. Running the integration 
tests</a></li>
-<li><a href="#_running_the_performance_tests">13.1.8. Running the performance 
tests</a></li>
-<li><a href="#_testing_with_an_example_page">13.1.9. Testing with an example 
page</a></li>
+<li><a href="#_testing_with_an_example_page">13.1.8. Testing with an example 
page</a></li>
 </ul>
 </li>
 <li><a href="#_ssh_shell_commands">13.2. SSH Shell Commands</a>
@@ -567,7 +567,7 @@ Apache Unomi.</p>
 endpoint. However you will need to send a body along with that request. 
Here&#8217;s an example:</p>
 </div>
 <div class="paragraph">
-<p>Here is an example that will retrieve all the session and profile 
properties.</p>
+<p>Here is an example that will retrieve all the session and profile 
properties, as well as the profile&#8217;s segments and scores</p>
 </div>
 <div class="listingblock">
 <div class="content">
@@ -582,7 +582,8 @@ endpoint. However you will need to send
     },
     "requiredProfileProperties":["*"],
     "requiredSessionProperties":["*"],
-    "requireSegments":true
+    "requireSegments":true,
+    "requireScores":true
 }
 EOF</code></pre>
 </div>
@@ -997,7 +998,8 @@ the profile or session properties. If yo
 of the context.js(on) servlet.</p>
 </div>
 <div class="paragraph">
-<p>Here is an example that will retrieve all the session and profile 
properties.</p>
+<p>Here is an example that will retrieve all the session and profile 
properties, as well as the profile&#8217;s segments and
+scores</p>
 </div>
 <div class="listingblock">
 <div class="content">
@@ -1012,7 +1014,8 @@ of the context.js(on) servlet.</p>
     },
     "requiredProfileProperties":["*"],
     "requiredSessionProperties":["*"],
-    "requireSegments":true
+    "requireSegments":true,
+    "requireScores":true
 }
 EOF</code></pre>
 </div>
@@ -2056,15 +2059,221 @@ org.apache.unomi.security.personalizatio
 </div>
 </div>
 <div class="sect3">
-<h4 id="_scripting_roadmap">3.8.4. Scripting roadmap</h4>
+<h4 id="_groovy_actions">3.8.4. Groovy Actions</h4>
 <div class="paragraph">
-<p>Scripting will probably undergo major changes in future versions of Apache 
Unomi, possibly replacing MVEL with a
-more secure implementation of a scripting language, or possibly even removed 
completely (see Groovy actions below).</p>
+<p>Groovy actions offer the ability to define a set of actions and action 
types (aka action descriptors) purely from Groovy scripts defined at 
runtime.</p>
 </div>
 <div class="paragraph">
-<p>It is recommended that scripting be avoided as in most cases it could be 
replaced by custom action implementations,
-which are also possible using the Groovy Scripting language. The main 
difference is in the deployment mechanism,
-Groovy actions or Java actions must be deployed as plugins, which require 
system administrator access and permissions.</p>
+<p>Initially submitted to Unomi through a purpose-built REST API endpoint, 
Groovy actions are then stored in Elasticsearch. When an event matches a rule 
configured to execute an action, the corresponding action is fetched from 
Elasticsearch and executed.</p>
+</div>
+<div class="sect4">
+<h5 id="_anatomy_of_a_groovy_action">Anatomy of a Groovy Action</h5>
+<div class="paragraph">
+<p>To be valid, a Groovy action must follow a particular convention which is 
divided in two parts:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>An annotation used to define the associated action type</p>
+</li>
+<li>
+<p>The function to be executed</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Placed right before the function, the “@Action” annotation contains a 
set of parameter detailing how the action should be triggered.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<caption class="title">Table 2. @Action annotation</caption>
+<colgroup>
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Field name</th>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Required</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">id</p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">String</p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">YES</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Id of the 
action</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">actionExecutor</p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">String</p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">YES</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Action 
executor contains the name of the script to call for the action type and must 
be prefixed with “<strong>groovy:</strong>”. The prefix indicates to Unomi 
which dispatcher to use when processing the action.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">name</p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">String</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Action 
name</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">hidden</p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">Boolean</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Define if 
the action is hidden or not. It is usually used to hide objects in a 
UI.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">parameters</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">List&lt;<a 
href="https://github.com/apache/unomi/blob/master/extensions/groovy-actions/services/src/main/java/org/apache/unomi/groovy/actions/annotations/Parameter.java";>Parameter</a>&gt;</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The 
parameters of the actions, also defined by annotations</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">systemTags</p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">List&lt;String&gt;</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">A 
(reserved) list of tags for the associated object. This is usually populated 
through JSON descriptors and is not meant to be modified by end users. These 
tags may include values that help classify associated objects.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The function contained within the Groovy Action must be called 
<code>execute()</code> and its last instruction must be an integer.</p>
+</div>
+<div class="paragraph">
+<p>This integer serves as an indication whether the values of the session and 
profile should be persisted. In general, the codes used are defined in the <a 
href="https://github.com/apache/unomi/blob/master/api/src/main/java/org/apache/unomi/api/services/EventService.java";>EventService
 interface</a>.</p>
+</div>
+<div class="paragraph">
+<p>Each groovy actions extends by default a Base script
+<a 
href="https://github.com/apache/unomi/blob/master/extensions/groovy-actions/services/src/main/resources/META-INF/base/BaseScript.groovy";>defined
 here</a></p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_rest_api">REST API</h5>
+<div class="paragraph">
+<p>Actions can be deployed/updated/deleted via the dedicated 
<code>/cxs/groovyActions</code> rest endpoint.</p>
+</div>
+<div class="paragraph">
+<p>Deploy/update an Action:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-bash" data-lang="bash">curl -X 
POST 'http://localhost:8181/cxs/groovyActions' \
+--user karaf:karaf \
+--form 'file=@"&lt;file location&gt;"'</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A Groovy Action can be updated by submitting another Action with the same 
id.</p>
+</div>
+<div class="paragraph">
+<p>Delete an Action:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-bash" data-lang="bash">curl -X 
DELETE 'http://localhost:8181/cxs/groovyActions/&lt;Action id&gt;' \
+--user karaf:karaf</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Note that when a groovy action is deleted by the API, the action type 
associated with this action will also be deleted.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_hello_world">Hello World!</h5>
+<div class="paragraph">
+<p>In this short example, we’re going to create a Groovy Action that will be 
adding “Hello world!” to the logs whenever a new view event is 
triggered.</p>
+</div>
+<div class="paragraph">
+<p>The first step consists in creating the groovy script on your filesystem, 
start by creating the file <code>hello-world.groovy</code>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-groovy" 
data-lang="groovy">@Action(id = "helloWorldGroovyAction",
+        actionExecutor = "groovy:helloWorldAction")
+        parameters = [@Parameter(id = "location", type = "string", multivalued 
= false)])
+def execute() {
+    logger.info("Hello {}", action.getParameterValues().get("location"))
+    EventService.NO_CHANGE
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>As the last instruction of the script is 
<code>EventService.NO_CHANGE</code>, data will not be persisted.</p>
+</div>
+<div class="paragraph">
+<p>Once the action has been created you need to submit it to Unomi (from the 
same folder as <code>hello-world.groovy</code>).</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-bash" data-lang="bash">curl -X 
POST 'http://localhost:8181/cxs/groovyActions' \
+--user karaf:karaf \
+--form '[email protected]'</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Finally, register a rule to trigger execution of the groovy action:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-bash" data-lang="bash">curl -X 
POST 'http://localhost:8181/cxs/rules' \
+--user karaf:karaf \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "metadata": {
+   "id": "scriptGroovyActionRule",
+   "name": "Test Groovy Action Rule",
+   "description": "A sample rule to test Groovy actions"
+ },
+ "condition": {
+     "type": "eventTypeCondition",
+     "parameterValues": {
+       "eventTypeId": "view"
+     }
+ },
+ "actions": [
+   {
+     "parameterValues": {
+       "location": "world!"
+     },
+     "type": "helloWorldAction"
+   }
+ ]
+}'</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Note that this rule contains a “location” parameter, with the value 
“world!”, which is then used in the log message triggered by the action.</p>
+</div>
+<div class="paragraph">
+<p>You can now use unomi to trigger a “view” event and see the 
corresponding message in the Unomi logs.</p>
+</div>
+<div class="paragraph">
+<p>Once you’re done with the Hello World! action, it can be deleted using 
the following command:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-bash" data-lang="bash">curl -X 
DELETE 'http://localhost:8181/cxs/groovyActions/helloWorldGroovyAction' \
+--user karaf:karaf</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>And the corresponding rule can be deleted using the following command:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-bash" data-lang="bash">curl -X 
DELETE 'http://localhost:8181/cxs/rules/scriptGroovyActionRule' \
+--user karaf:karaf</code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_scripting_roadmap">3.8.5. Scripting roadmap</h4>
+<div class="paragraph">
+<p>Scripting will probably undergo major changes in future versions of Apache 
Unomi, with the likely retirement of MVEL in favor of Groovy Actions detailed 
above.</p>
 </div>
 <div class="paragraph">
 <p>These changes will not happen on maintenance versions of Apache Unomi, only 
in the next major version. Maintenance
@@ -3735,7 +3944,7 @@ results as the returned JSON is not beau
 <p>Important : all URLs are relative to the private Apache Unomi URL, by 
default: <a href="https://localhost:9443"; 
class="bare">https://localhost:9443</a></p>
 </div>
 <table class="tableblock frame-all grid-all stretch">
-<caption class="title">Table 2. Useful URLs</caption>
+<caption class="title">Table 3. Useful URLs</caption>
 <colgroup>
 <col style="width: 33.3333%;">
 <col style="width: 33.3333%;">
@@ -6886,7 +7095,7 @@ information about the context for the cu
 <p>We need to either retrieve (from the initial context we retrieved 
previously using <code>cxs.sessionId</code>) or generate a session identifier 
for our request since Unomi currently requires one.</p>
 </li>
 <li>
-<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=&#39"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=&#39</a>; + 
sessionId</code>. This URI requests context from Unomi, resulting in an updated 
<code>cxs</code> object in the javascript global scope. The context server can 
reply to this request either by returning a JSON-only object containing solely 
the context information as is the case when the requested URI is 
<code>context.json</code>. However, if the client requests 
<code>context.js</code> then useful functions to interact with Unomi are added 
to the <code>cxs</code> object in addition to the context information as 
depicted above.</p>
+<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/cxs/context.json?sessionId=sessionId"; 
class="bare">http://localhost:8181/cxs/context.json?sessionId=sessionId</a></code>.
 This URI requests context from Unomi, resulting in an updated <code>cxs</code> 
object in the javascript global scope. The context server can reply to this 
request either by returning a JSON-only object containing solely the context 
information as is the case when the requested URI is <code>context.json</code>. 
However, if the client requests <code>context.js</code> then useful functions 
to interact with Unomi are added to the <code>cxs</code> object in addition to 
the context information as depicted above.</p>
 </li>
 <li>
 <p>We don&#8217;t need to provide any authentication at all to interact with 
this part of Unomi since we only have access to read-only data (as well as 
providing events as we shall see later on). If we had been using the REST API, 
we would have needed to provide authentication information as well.</p>
@@ -7024,7 +7233,7 @@ conditions and we want to know which is
     "source": null,
     "requireSegments": false,
     "requiredProfileProperties": null,
-    "requiredSessionProperties": null,
+    "requiredSessionProperties": [ "unomiControlGroups" ],
     "events": null,
     "filters": null,
     "personalizations": [
@@ -7032,7 +7241,13 @@ conditions and we want to know which is
             "id": "gender-test",
             "strategy": "matching-first",
             "strategyOptions": {
-                "fallback": "var2"
+                "fallback": "var2",
+                "controlGroup" : {
+                  "percentage" : 10.0,
+                  "displayName" : "Gender test control group",
+                  "path" : "/gender-test",
+                  "storeInSession" : true
+                }
             },
             "contents": [
                 {
@@ -7070,8 +7285,7 @@ conditions and we want to know which is
 <div class="paragraph">
 <p>In the above example, we basically setup two variants : <code>var1</code> 
and <code>var2</code> and setup the <code>var2</code> to be the fallback variant
 in case no variant is matched. We could of course specify more than a variant. 
The <code>strategy</code> indicates to the
-personalization service how to calculate the "winning" variant. In this case 
the strategy <code>matching-first</code> will return
-the first variant that matches the current profile.</p>
+personalization service how to calculate the "winning" variant. In this case 
the strategy <code>matching-first</code> will return variants that match the 
current profile. We also use the <code>controlGroups</code> option to specify 
that we want to have a control group for this personalization. The 
<code>10.0</code> percentage value represents 10% (0.0 to 100.0) of traffic 
that will be assigned randomly to the control group. The control group will be 
stored in the profile and the session of the visitors if they were assigned to 
it. We also specify that we store the control group in the session (by default 
it is stored in the profile)</p>
 </div>
 <div class="paragraph">
 <p>Currently the following strategies are available:</p>
@@ -7079,10 +7293,10 @@ the first variant that matches the curre
 <div class="ulist">
 <ul>
 <li>
-<p><code>matching-first</code>: will return the first matching variant.</p>
+<p><code>matching-first</code>: will return the variant IDs that match the 
current profile (using the initial content order)</p>
 </li>
 <li>
-<p><code>random</code>: will return a random variant</p>
+<p><code>random</code>: will return a shuffled list of variant IDs (ignoring 
any conditions)</p>
 </li>
 <li>
 <p><code>score-sorted</code>: allows to sort the variants based on scores 
associated with the filtering conditions, effectively
@@ -7099,7 +7313,16 @@ sorting them by the highest scoring cond
     "profileId": "01060c4c-a055-4c8f-9692-8a699d0c434a",
     "sessionId": "demo-session-id",
     "profileProperties": null,
-    "sessionProperties": null,
+    "sessionProperties": {
+        "unomiControlGroups": [
+            {
+                "id": "previousPerso",
+                "displayName": "Previous perso",
+                "path": "/home/previousPerso.html",
+                "timeStamp": "2021-12-15T13:52:38Z"
+            }
+        ]
+    },
     "profileSegments": null,
     "filteringResults": null,
     "processedEvents": 0,
@@ -7115,6 +7338,9 @@ sorting them by the highest scoring cond
 }</code></pre>
 </div>
 </div>
+<div class="paragraph">
+<p>In the above example we can see the profile and session were assigned to 
other control groups but not the current one (the ids are different).</p>
+</div>
 </div>
 <div class="sect5">
 <h6 id="_overrides">Overrides</h6>
@@ -7899,7 +8125,7 @@ the MVN_HOME/bin directory.</p>
 </div>
 <div class="listingblock">
 <div class="content">
-<pre class="highlight"><code>     $&gt; mvn -P 
\!integration-tests,\!performance-tests clean install</code></pre>
+<pre class="highlight"><code>     $&gt; mvn -P \!integration-tests clean 
install</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -8107,30 +8333,7 @@ to use these tests is to run them from a
 </div>
 </div>
 <div class="sect3">
-<h4 id="_running_the_performance_tests">13.1.8. Running the performance 
tests</h4>
-<div class="paragraph">
-<p>Performance tests are based on Gatling. You need to have a running context 
server or cluster of servers before
-executing the tests.</p>
-</div>
-<div class="paragraph">
-<p>Test parameteres are editable in the 
performance-tests/src/test/scala/unomi/Parameters.scala file. baseUrls should
-contains the URLs of all your cluster nodes</p>
-</div>
-<div class="paragraph">
-<p>Run the test by using the gatling.conf file in 
performance-tests/src/test/resources :</p>
-</div>
-<div class="listingblock">
-<div class="content">
-<pre class="highlight"><code>    export 
GATLING_CONF=&lt;path&gt;/performance-tests/src/test/resources
-    gatling.sh</code></pre>
-</div>
-</div>
-<div class="paragraph">
-<p>Reports are generated in performance-tests/target/results.</p>
-</div>
-</div>
-<div class="sect3">
-<h4 id="_testing_with_an_example_page">13.1.9. Testing with an example 
page</h4>
+<h4 id="_testing_with_an_example_page">13.1.8. Testing with an example 
page</h4>
 <div class="paragraph">
 <p>A default test page is provided at the following URL:</p>
 </div>
@@ -8208,7 +8411,7 @@ ARGUMENTS
 <p>The commands control the lifecycle of the Apache Unomi server and are used 
to migrate, start or stop the server.</p>
 </div>
 <table class="tableblock frame-all grid-all stretch">
-<caption class="title">Table 3. Table Lifecycle commands</caption>
+<caption class="title">Table 4. Table Lifecycle commands</caption>
 <colgroup>
 <col style="width: 33.3333%;">
 <col style="width: 33.3333%;">
@@ -8251,7 +8454,7 @@ ARGUMENTS
 <p>These commands are available once the application is running. If an 
argument is between brackets [] it means it is optional.</p>
 </div>
 <table class="tableblock frame-all grid-all stretch">
-<caption class="title">Table 4. Table Runtime commands</caption>
+<caption class="title">Table 5. Table Runtime commands</caption>
 <colgroup>
 <col style="width: 33.3333%;">
 <col style="width: 33.3333%;">


Reply via email to