You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by ju...@apache.org on 2020/05/05 19:20:09 UTC

[jspwiki] branch master updated (76e5e27 -> acbb8ef)

This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git.


    from 76e5e27  no version bump
     new 70953e5  add format to a couple of method signatures
     new 9f27a1c  avoid registering several times the same listener on the same client
     new 66a4d67  rewrite class javadoc
     new e1e8478  Update JUnit to 5.6.2
     new f0b754c  add two new types of Workflow events to manage DecisionQueue add and removal
     new af1d4e3  Add WorkflowEventEmitter enum to emit workflow-related events and register as client on DefaultWorkflowManager, which is an event listener
     new 64e5025  no need to overload fireEvent methods, DefaultWorkflowManager will only process the workflow events it understands
     new 6d32482  format tests + add some fixes suggested by intellij
     new 38356ab  Workflow doesn't need to know about WorkflowManager + use ConcurrentHashMap for attributes to avoid synchronized in its related methods
     new c503aad  add formatting suggested by IntelliJ
     new 27e78fb  Decision doesn't need to know about WorkflowManager
     new 5255ee5  add formatting suggested by IntelliJ
     new 96e870b  throw ProviderException instead of InternalWikiException, as it refers to a page provider operation
     new f825693  Update Flexmark to 0.61.8
     new fba8cd4  Promote PluginManager#getPluginSearchPath() to Engine, as it is an operation requesting a configuration value
     new f98225f  use method from Engine
     new 7e07181  add WikiPageEvent#PAGE_REINDEX to signal that a given Page needs to be reindexed
     new 9495d83  update Lucene to 8.5.1 and maven-antrun-plugin to 3.0.0
     new c6c34fd  dependency updates: flexmark to 0.61.16, selenide to 5.11.0 and tika to 1.24.1
     new 5cc6f09  move o.a.w.workflow.Workflow#TIME_NOT_SET to o.a.w.workflow.Step#TIME_NOT_SET
     new 43b1a87  WikiEventManager: addWikiEventListener equality check inline with removeWikiEventListener equality check
     new 01ee8a5  Break class cycles between Workflow and Step in order to prepare for JSPWIKI-304 (Workflows are not Serializable)
     new 60ab922  JSPWIKI-304: make Workflow attributes Serializable
     new fb5bb53  Update Selenide to 5.11.1
     new cbbb8d3  Generalize WorkflowEventEmitter to WikiEventEmitter and move it to jspwiki-event module.
     new f571e9b  IntelliJ fix: use static call for static method.
     new bfbc9bd  Removed WorkflowManager#start( Workflow ), in favour of Workflow#start()
     new 62857b9  small test refactor
     new 0675bd0  Fire workflow events for DecisionQueue reassign and decide actions.
     new 1e92176  replace synchronized int nextId() with AtomicInteger
     new 63ea768  fix javadocs for new workflow events.
     new a050578  JSPWIKI-304: un/serialize Workflows + Decision Queue from/to disk
     new 7b35297  update flexmark to 0.61.26
     new 564bfc0  add test data file
     new acbb8ef  2.11.0-M7-git-19

The 35 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ChangeLog.md                                       |  13 +
 .../org/apache/wiki/plugin/PluginFrom210Test.java  |   3 +-
 .../src/main/java/org/apache/wiki/api/Release.java |   2 +-
 .../java/org/apache/wiki/api/core/Context.java     |   2 +-
 .../main/java/org/apache/wiki/api/core/Engine.java |  17 +-
 .../org/apache/wiki/event/WikiEventEmitter.java    |  82 +++++
 .../org/apache/wiki/event/WikiEventManager.java    |  21 +-
 .../java/org/apache/wiki/event/WikiPageEvent.java  |   9 +-
 .../java/org/apache/wiki/event/WorkflowEvent.java  |  32 +-
 .../apache/wiki/event/TestWikiEventListener.java   |  18 +-
 .../apache/wiki/event/WikiEventEmitterTest.java    |  61 ++++
 .../apache/wiki/event/WikiEventManagerTest.java    |  71 +++++
 .../src/main/java/org/apache/wiki/WikiEngine.java  |   2 +-
 .../org/apache/wiki/auth/DefaultUserManager.java   |   2 +-
 .../apache/wiki/content/DefaultPageRenamer.java    |   3 +-
 .../org/apache/wiki/filters/FilterManager.java     |   2 +-
 .../org/apache/wiki/pages/DefaultPageManager.java  |   7 +-
 .../apache/wiki/plugin/DefaultPluginManager.java   |   8 +-
 .../java/org/apache/wiki/plugin/PluginManager.java |  10 -
 .../wiki/references/DefaultReferenceManager.java   |   2 +-
 .../apache/wiki/search/DefaultSearchManager.java   |  19 +-
 .../org/apache/wiki/tasks/DefaultTasksManager.java |   4 +-
 .../java/org/apache/wiki/tasks/TasksManager.java   |   5 +-
 .../wiki/tasks/auth/SaveUserProfileTask.java       |   4 +-
 .../wiki/tasks/pages/PreSaveWikiPageTask.java      |  11 +-
 .../apache/wiki/tasks/pages/SaveWikiPageTask.java  |   8 +-
 .../wiki/variables/DefaultVariableManager.java     |   3 +-
 .../org/apache/wiki/workflow/AbstractStep.java     | 178 ++++-------
 .../java/org/apache/wiki/workflow/Decision.java    | 152 ++++-----
 .../org/apache/wiki/workflow/DecisionQueue.java    |  37 +--
 .../wiki/workflow/DefaultWorkflowManager.java      | 174 ++++++++---
 .../java/org/apache/wiki/workflow/Outcome.java     |  78 ++---
 .../org/apache/wiki/workflow/SimpleDecision.java   |  28 +-
 .../apache/wiki/workflow/SimpleNotification.java   |  54 ++--
 .../main/java/org/apache/wiki/workflow/Step.java   | 176 ++++-------
 .../org/apache/wiki/workflow/SystemPrincipal.java  |  13 +-
 .../main/java/org/apache/wiki/workflow/Task.java   |  75 ++---
 .../java/org/apache/wiki/workflow/Workflow.java    | 126 +++-----
 .../org/apache/wiki/workflow/WorkflowBuilder.java  |  11 +-
 .../org/apache/wiki/workflow/WorkflowManager.java  |  11 -
 .../src/test/java/org/apache/wiki/TestEngine.java  |  31 +-
 .../java/org/apache/wiki/auth/UserManagerTest.java |   4 +-
 .../wiki/plugin/DefaultPluginManagerTest.java      |   7 +-
 .../apache/wiki/workflow/ApprovalWorkflowTest.java | 116 +++----
 .../apache/wiki/workflow/DecisionQueueTest.java    |  65 ++--
 .../java/org/apache/wiki/workflow/FactTest.java    |  30 +-
 .../apache/wiki/workflow/SimpleDecisionTest.java   | 181 +++++------
 .../java/org/apache/wiki/workflow/TaskTest.java    |  34 +-
 .../apache/wiki/workflow/WorkflowManagerTest.java  | 136 ++++----
 .../org/apache/wiki/workflow/WorkflowTest.java     | 341 +++++++++------------
 jspwiki-main/src/test/resources/wkflmgr.ser        | Bin 0 -> 3770 bytes
 pom.xml                                            |  12 +-
 52 files changed, 1216 insertions(+), 1275 deletions(-)
 create mode 100644 jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventEmitter.java
 copy jspwiki-api/src/test/java/org/apache/wiki/api/spi/AclsSPITestImpl.java => jspwiki-event/src/test/java/org/apache/wiki/event/TestWikiEventListener.java (75%)
 create mode 100644 jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventEmitterTest.java
 create mode 100644 jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventManagerTest.java
 create mode 100644 jspwiki-main/src/test/resources/wkflmgr.ser


[jspwiki] 09/35: Workflow doesn't need to know about WorkflowManager + use ConcurrentHashMap for attributes to avoid synchronized in its related methods

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 38356ab39c413d6d4171088c89108fea8524652a
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 18:09:56 2020 +0200

    Workflow doesn't need to know about WorkflowManager + use ConcurrentHashMap for attributes to avoid synchronized in its related methods
---
 .../java/org/apache/wiki/workflow/Workflow.java    | 95 ++++------------------
 1 file changed, 15 insertions(+), 80 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
index 2cdda87..63d2ca2 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
@@ -19,8 +19,6 @@
 package org.apache.wiki.workflow;
 
 import org.apache.wiki.api.exceptions.WikiException;
-import org.apache.wiki.event.WikiEventListener;
-import org.apache.wiki.event.WikiEventManager;
 import org.apache.wiki.event.WorkflowEvent;
 
 import java.io.Serializable;
@@ -28,10 +26,11 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 
 /**
  * <p>
@@ -186,7 +185,7 @@ public class Workflow implements Serializable {
     /** State value: Workflow instantiated, but not started. */
     public static final int CREATED = -2;
 
-    /** Lazily-initialized attribute map. */
+    /** attribute map. */
     private Map< String, Object > m_attributes;
 
     /** The initial Step for this Workflow. */
@@ -209,8 +208,6 @@ public class Workflow implements Serializable {
 
     private Step m_currentStep;
 
-    private WorkflowManager m_manager;
-
     /**
      * Constructs a new Workflow object with a supplied message key, owner Principal, and undefined unique identifier {@link #ID_NOT_SET}.
      * Once instantiated the Workflow is considered to be in the {@link #CREATED} state; a caller must explicitly invoke the
@@ -220,12 +217,11 @@ public class Workflow implements Serializable {
      * @param owner the Principal who owns the Workflow. Typically, this is the user who created and submitted it
      */
     public Workflow( final String messageKey, final Principal owner ) {
-        m_attributes = null;
+        m_attributes = new ConcurrentHashMap<>();
         m_currentStep = null;
         m_history = new LinkedList<>();
         m_id = ID_NOT_SET;
         m_key = messageKey;
-        m_manager = null;
         m_messageArgs = new ArrayList<>();
         m_owner = owner;
         m_started = false;
@@ -249,15 +245,14 @@ public class Workflow implements Serializable {
         }
 
         if( m_currentStep != null ) {
-            if( m_manager != null && m_currentStep instanceof Decision ) {
-                final Decision d = ( Decision )m_currentStep;
-                m_manager.getDecisionQueue().remove( d );
+            if( m_currentStep instanceof Decision ) {
+                WorkflowEventEmitter.fireEvent( ( Decision )m_currentStep, WorkflowEvent.DQ_REMOVAL );
             }
             m_currentStep.setOutcome( Outcome.STEP_ABORT );
             m_history.addLast( m_currentStep );
         }
         m_state = ABORTED;
-        fireEvent( WorkflowEvent.ABORTED );
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.ABORTED );
         cleanup();
     }
 
@@ -316,10 +311,7 @@ public class Workflow implements Serializable {
      * @param attr the name of the attribute
      * @return the value
      */
-    public final synchronized Object getAttribute( final String attr ) {
-        if( m_attributes == null ) {
-            return null;
-        }
+    public final Object getAttribute( final String attr ) {
         return m_attributes.get( attr );
     }
 
@@ -409,16 +401,6 @@ public class Workflow implements Serializable {
     }
 
     /**
-     * Returns the WorkflowManager that contains this Workflow.
-     *
-     * @return the workflow manager
-     */
-    public final synchronized WorkflowManager getWorkflowManager()
-    {
-        return m_manager;
-    }
-
-    /**
      * Returns a Step history for this Workflow as a List, chronologically, from the first Step to the currently executing one. The first
      * step is the first item in the array. If the Workflow has not started, this method returns a zero-length array.
      *
@@ -483,7 +465,7 @@ public class Workflow implements Serializable {
             throw new IllegalStateException( "Workflow is not paused; cannot restart." );
         }
         m_state = RUNNING;
-        fireEvent( WorkflowEvent.RUNNING );
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.RUNNING );
 
         // Process current step
         try {
@@ -502,10 +484,7 @@ public class Workflow implements Serializable {
      * @param attr the attribute name
      * @param obj  the value
      */
-    public final synchronized void setAttribute( final String attr, final Object obj ) {
-        if( m_attributes == null ) {
-            m_attributes = new HashMap<>();
-        }
+    public final void setAttribute( final String attr, final Object obj ) {
         m_attributes.put( attr, obj );
     }
 
@@ -533,16 +512,6 @@ public class Workflow implements Serializable {
     }
 
     /**
-     * Sets the WorkflowManager that contains this Workflow.
-     *
-     * @param manager the workflow manager
-     */
-    public final synchronized void setWorkflowManager( final WorkflowManager manager ) {
-        m_manager = manager;
-        addWikiEventListener( manager );
-    }
-
-    /**
      * Starts the Workflow and sets the state to {@link #RUNNING}. If the Workflow has already been started (or previously aborted), this
      * method returns an {@linkplain IllegalStateException}. If any of the Steps in this Workflow throw a WikiException, the Workflow will
      * abort and propagate the exception to callers.
@@ -558,7 +527,7 @@ public class Workflow implements Serializable {
         }
         m_started = true;
         m_state = RUNNING;
-        fireEvent( WorkflowEvent.RUNNING );
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.RUNNING );
 
         // Mark the first step as the current one & add to history
         m_currentStep = m_firstStep;
@@ -582,15 +551,13 @@ public class Workflow implements Serializable {
             throw new IllegalStateException( "Workflow is not running; cannot pause." );
         }
         m_state = WAITING;
-        fireEvent( WorkflowEvent.WAITING );
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.WAITING );
     }
 
     /**
-     * Clears the attribute map and sets the current step field to
-     * <code>null</code>.
+     * Clears the attribute map and sets the current step field to <code>null</code>.
      */
-    protected void cleanup()
-    {
+    protected void cleanup() {
         m_currentStep = null;
         m_attributes = null;
     }
@@ -602,7 +569,7 @@ public class Workflow implements Serializable {
     protected final synchronized void complete() {
         if( !isCompleted() ) {
             m_state = COMPLETED;
-            fireEvent( WorkflowEvent.COMPLETED );
+            WorkflowEventEmitter.fireEvent( this, WorkflowEvent.COMPLETED );
             cleanup();
         }
     }
@@ -661,36 +628,4 @@ public class Workflow implements Serializable {
 
     }
 
-    // events processing .......................................................
-
-    /**
-     * Registers a WikiEventListener with this instance. This is a convenience method.
-     *
-     * @param listener the event listener
-     */
-    public final synchronized void addWikiEventListener( final WikiEventListener listener ) {
-        WikiEventManager.addWikiEventListener( this, listener );
-    }
-
-    /**
-     * Un-registers a WikiEventListener with this instance. This is a convenience method.
-     *
-     * @param listener the event listener
-     */
-    public final synchronized void removeWikiEventListener( final WikiEventListener listener ) {
-        WikiEventManager.removeWikiEventListener( this, listener );
-    }
-
-    /**
-     * Fires a WorkflowEvent of the provided type to all registered listeners.
-     *
-     * @see org.apache.wiki.event.WorkflowEvent
-     * @param type the event type to be fired
-     */
-    protected final void fireEvent( final int type ) {
-        if ( WikiEventManager.isListening( this ) ) {
-            WikiEventManager.fireEvent( this, new WorkflowEvent( this, type ) );
-        }
-    }
-
 }


[jspwiki] 04/35: Update JUnit to 5.6.2

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit e1e8478833259de9d5bb3e1b9febe008e0817b20
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 17:58:49 2020 +0200

    Update JUnit to 5.6.2
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 80ef327..525c33f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,7 @@
     <jdom2.version>2.0.6</jdom2.version>
     <jetty.version>8.1.15.v20140411</jetty.version>
     <jrcs-diff.version>0.4.2</jrcs-diff.version>
-    <junit.version>5.6.1</junit.version>
+    <junit.version>5.6.2</junit.version>
     <log4j.version>1.2.17</log4j.version>
     <lucene.version>8.5.0</lucene.version>
     <mockito.version>3.3.3</mockito.version>


[jspwiki] 21/35: WikiEventManager: addWikiEventListener equality check inline with removeWikiEventListener equality check

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 43b1a87b44f42db1cc32d8ef06a65366edcfa10c
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat May 2 18:34:37 2020 +0200

    WikiEventManager: addWikiEventListener equality check inline with removeWikiEventListener equality check
    
    Fix javadocs typos + formatting suggested by IntelliJ
---
 .../org/apache/wiki/event/WikiEventManager.java    |  3 +-
 .../java/org/apache/wiki/event/WorkflowEvent.java  |  5 +-
 .../src/main/java/org/apache/wiki/WikiEngine.java  |  2 +-
 .../org/apache/wiki/filters/FilterManager.java     |  2 +-
 .../org/apache/wiki/workflow/DecisionQueue.java    | 13 ++--
 .../java/org/apache/wiki/workflow/Outcome.java     | 78 ++++++++--------------
 .../org/apache/wiki/workflow/SystemPrincipal.java  | 13 ++--
 .../src/test/java/org/apache/wiki/TestEngine.java  | 31 ++++-----
 8 files changed, 60 insertions(+), 87 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java
index 95728fd..c737158 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java
@@ -29,7 +29,6 @@ import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.Vector;
@@ -396,7 +395,7 @@ public final class WikiEventManager {
             synchronized( m_listenerList ) {
                 final boolean listenerAlreadyContained = m_listenerList.stream()
                                                                        .map( WeakReference::get )
-                                                                       .anyMatch( ref -> Objects.equals( ref, listener ) );
+                                                                       .anyMatch( ref -> ref == listener );
                 if( !listenerAlreadyContained ) {
                     return m_listenerList.add( new WeakReference<>( listener ) );
                 }
diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
index 7542790..6f40978 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
@@ -19,7 +19,6 @@
 
 package org.apache.wiki.event;
 
-
 /**
  * <p>
  * WorkflowEvent indicates that a state change to a Workflow: started, running, waiting, completed, aborted. 
@@ -43,8 +42,8 @@ public final class WorkflowEvent extends WikiEvent {
     public static final int STARTED = 10;
 
     /**
-     * fter the Workflow has been started (or re-started) using the
-     * {@link org.apache.wiki.workflow.Workflow#start()} method, 
+     * After the Workflow has been started (or re-started) using the
+     * {@link org.apache.wiki.workflow.Workflow#start()} method,
      * but before it has finished processing all Steps.
      */
     public static final int RUNNING = 20;
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/WikiEngine.java b/jspwiki-main/src/main/java/org/apache/wiki/WikiEngine.java
index 4780b90..1e91e7b 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/WikiEngine.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/WikiEngine.java
@@ -657,7 +657,7 @@ public class WikiEngine implements Engine {
     }
 
     /**
-     * Returns the {@link org.apache.wiki.workflow.WorkflowManager} associated with this WikiEngine. If the WIkiEngine has not been
+     * Returns the {@link org.apache.wiki.workflow.WorkflowManager} associated with this WikiEngine. If the WikiEngine has not been
      * initialized, this method will return <code>null</code>.
      *
      * @return the task queue
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/filters/FilterManager.java b/jspwiki-main/src/main/java/org/apache/wiki/filters/FilterManager.java
index 889c2e0..d6be6f1 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/filters/FilterManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/filters/FilterManager.java
@@ -108,7 +108,7 @@ public interface FilterManager extends ModuleManager {
     List< PageFilter > getFilterList();
     
     /**
-     * Notifies PageFilters to clean up their ressources.
+     * Notifies PageFilters to clean up their resources.
      */
     void destroy();
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
index 12cc0c1..37d8925 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
@@ -36,7 +36,7 @@ public class DecisionQueue implements Serializable {
 
     private static final long serialVersionUID = -7172912793410302533L;
 
-    private LinkedList< Decision > m_queue = new LinkedList<>();
+    private final LinkedList< Decision > m_queue = new LinkedList<>();
 
     private volatile int m_next;
 
@@ -61,9 +61,8 @@ public class DecisionQueue implements Serializable {
      *
      * @return the pending decisions 
      */
-    protected Decision[] decisions()
-    {
-        return m_queue.toArray( new Decision[m_queue.size()] );
+    protected Decision[] decisions() {
+        return m_queue.toArray( new Decision[ m_queue.size() ] );
     }
 
     /**
@@ -71,8 +70,7 @@ public class DecisionQueue implements Serializable {
      *
      * @param decision the decision to remove
      */
-    protected synchronized void remove( final Decision decision )
-    {
+    protected synchronized void remove( final Decision decision ) {
         m_queue.remove( decision );
     }
 
@@ -109,8 +107,7 @@ public class DecisionQueue implements Serializable {
 
     /**
      * Attempts to complete a Decision by calling {@link Decision#decide(Outcome)}. This will cause the Step immediately following the
-     * Decision (if any) to start. If the decision completes successfully, this method also removes the completed decision from the
-     * queue.
+     * Decision (if any) to start. If the decision completes successfully, this method also removes the completed decision from the queue.
      *
      * @param decision the Decision for which the Outcome will be supplied
      * @param outcome the Outcome of the Decision
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Outcome.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Outcome.java
index f39983f..589361b 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Outcome.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Outcome.java
@@ -21,13 +21,11 @@ package org.apache.wiki.workflow;
 import java.io.Serializable;
 
 /**
- * Resolution of a workflow Step, such as "approve," "deny," "hold," "task
- * error," or other potential resolutions.
+ * Resolution of a workflow Step, such as "approve," "deny," "hold," "task error," or other potential resolutions.
  *
  * @since 2.5
  */
-public final class Outcome implements Serializable
-{
+public final class Outcome implements Serializable {
 
     private static final long serialVersionUID = -338361947886288073L;
 
@@ -56,7 +54,7 @@ public final class Outcome implements Serializable
     public static final Outcome DECISION_REASSIGN = new Outcome( "outcome.decision.reassign", false );
 
     private static final Outcome[] OUTCOMES = new Outcome[] { STEP_COMPLETE, STEP_ABORT, STEP_CONTINUE, DECISION_ACKNOWLEDGE,
-                                                               DECISION_APPROVE, DECISION_DENY, DECISION_HOLD, DECISION_REASSIGN };
+                                                              DECISION_APPROVE, DECISION_DENY, DECISION_HOLD, DECISION_REASSIGN };
 
     private final String m_key;
 
@@ -65,16 +63,11 @@ public final class Outcome implements Serializable
     /**
      * Private constructor to prevent direct instantiation.
      *
-     * @param key
-     *            message key for the Outcome
-     * @param completion
-     *            whether this Outcome should be interpreted as the logical
-     *            completion of a Step.
+     * @param key message key for the Outcome
+     * @param completion whether this Outcome should be interpreted as the logical completion of a Step.
      */
-    private Outcome( String key, boolean completion )
-    {
-        if ( key == null )
-        {
+    private Outcome( final String key, final boolean completion ) {
+        if ( key == null ) {
             throw new IllegalArgumentException( "Key cannot be null." );
         }
         m_key = key;
@@ -82,72 +75,58 @@ public final class Outcome implements Serializable
     }
 
     /**
-     * Returns <code>true</code> if this Outcome represents a completion
-     * condition for a Step.
+     * Returns <code>true</code> if this Outcome represents a completion condition for a Step.
      *
      * @return the result
      */
-    public boolean isCompletion()
-    {
+    public boolean isCompletion() {
         return m_completion;
     }
 
     /**
-     * The i18n key for this outcome, which is prefixed by <code>outcome.</code>.
-     * If calling classes wish to return a locale-specific name for this task
-     * (such as "approve this request"), they can use this method to obtain the
-     * correct key suffix.
+     * The i18n key for this outcome, which is prefixed by <code>outcome.</code>. If calling classes wish to return a locale-specific
+     * name for this task (such as "approve this request"), they can use this method to obtain the correct key suffix.
      *
      * @return the i18n key for this outcome
      */
-    public String getMessageKey()
-    {
+    public String getMessageKey() {
         return m_key;
     }
 
     /**
-     * The hashcode of an Outcome is identical to the hashcode of its message
-     * key, multiplied by 2 if it is a "completion" Outcome.
+     * The hashcode of an Outcome is identical to the hashcode of its message key, multiplied by 2 if it is a "completion" Outcome.
+     *
      * @return the hash code
      */
-    public int hashCode()
-    {
+    public int hashCode() {
         return m_key.hashCode() * ( m_completion ? 1 : 2 );
     }
 
     /**
      * Two Outcome objects are equal if their message keys are equal.
+     *
      * @param obj the object to test
      * @return <code>true</code> if logically equal, <code>false</code> if not
      */
-    public boolean equals( Object obj )
-    {
-        if (!(obj instanceof Outcome))
-        {
+    public boolean equals( final Object obj ) {
+        if( !( obj instanceof Outcome ) ) {
             return false;
         }
-        return m_key.equals( ( (Outcome) obj ).getMessageKey() );
+        return m_key.equals( ( ( Outcome )obj ).getMessageKey() );
     }
 
     /**
-     * Returns a named Outcome. If an Outcome matching the supplied key is not
-     * found, this method throws a {@link NoSuchOutcomeException}.
+     * Returns a named Outcome. If an Outcome matching the supplied key is not found, this method throws a {@link NoSuchOutcomeException}.
      *
-     * @param key
-     *            the name of the outcome
+     * @param key the name of the outcome
      * @return the Outcome
-     * @throws NoSuchOutcomeException
-     *             if an Outcome matching the key isn't found.
+     * @throws NoSuchOutcomeException if an Outcome matching the key isn't found.
      */
-    public static Outcome forName( String key ) throws NoSuchOutcomeException
-    {
-        if ( key != null )
-        {
-            for (int i = 0; i < OUTCOMES.length; i++)
-            {
-                if ( OUTCOMES[i].m_key.equals( key ) )
-                {
-                    return OUTCOMES[i];
+    public static Outcome forName( final String key ) throws NoSuchOutcomeException {
+        if( key != null ) {
+            for( final Outcome outcome : OUTCOMES ) {
+                if( outcome.m_key.equals( key ) ) {
+                    return outcome;
                 }
             }
         }
@@ -157,8 +136,7 @@ public final class Outcome implements Serializable
     /**
      * {@inheritDoc}
      */
-    public String toString()
-    {
+    public String toString() {
         return "[Outcome:" + m_key + "]";
     }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SystemPrincipal.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SystemPrincipal.java
index 2c2893b..192c41b 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SystemPrincipal.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SystemPrincipal.java
@@ -20,12 +20,12 @@ package org.apache.wiki.workflow;
 
 import java.security.Principal;
 
+
 /**
  * System users asociated with workflow Task steps.
- * 
  */
-public final class SystemPrincipal implements Principal
-{
+public final class SystemPrincipal implements Principal {
+
     /** The JSPWiki system user */
     public static final Principal SYSTEM_USER = new SystemPrincipal( "System User" );
 
@@ -33,18 +33,17 @@ public final class SystemPrincipal implements Principal
 
     /**
      * Private constructor to prevent direct instantiation.
+     *
      * @param name the name of the Principal
      */
-    private SystemPrincipal( String name )
-    {
+    private SystemPrincipal( final String name ) {
         m_name = name;
     }
 
     /**
      * {@inheritDoc}
      */
-    public String getName()
-    {
+    public String getName() {
         return m_name;
     }
 
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/TestEngine.java b/jspwiki-main/src/test/java/org/apache/wiki/TestEngine.java
index fe13c37..148254a 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/TestEngine.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/TestEngine.java
@@ -78,7 +78,7 @@ public class TestEngine extends WikiEngine {
      * Creates WikiSession with the privileges of the administrative user. For testing purposes, obviously.
      *
      * @return the wiki session
-     * @throws WikiSecurityException
+     * @throws WikiSecurityException admin login operation had some trouble
      */
     public Session adminSession() throws WikiSecurityException {
         if ( m_adminWikiSession == null ) {
@@ -108,7 +108,7 @@ public class TestEngine extends WikiEngine {
      * Creates WikiSession with the privileges of the Janne. For testing purposes, obviously.
      *
      * @return the wiki session
-     * @throws WikiSecurityException
+     * @throws WikiSecurityException janne login operation had some trouble
      */
     public Session janneSession() throws WikiSecurityException {
         if ( m_janneWikiSession == null ) {
@@ -135,6 +135,7 @@ public class TestEngine extends WikiEngine {
      * @param entries additional configuration entries that may overwrite default test properties.
      * @return TestEngine using {@link #getTestProperties()} and additional configuration.
      */
+    @SafeVarargs
     public static TestEngine build( final Map.Entry< String, String >... entries ) {
         final Properties properties = getTestProperties();
         for( final Map.Entry< String, String > entry : entries ) {
@@ -266,7 +267,7 @@ public class TestEngine extends WikiEngine {
         }
     }
 
-    public static final Properties getTestProperties() {
+    public static Properties getTestProperties() {
         if (combinedProperties == null) {
             combinedProperties = PropertyReader.getCombinedProperties(PropertyReader.CUSTOM_JSPWIKI_CONFIG);
         }
@@ -277,7 +278,7 @@ public class TestEngine extends WikiEngine {
         return propCopy;
     }
 
-    public static final Properties getTestProperties( final String customPropFile) {
+    public static Properties getTestProperties( final String customPropFile) {
         return PropertyReader.getCombinedProperties(customPropFile);
     }
 /*
@@ -393,10 +394,11 @@ public class TestEngine extends WikiEngine {
     }
 
     /**
-     *  Adds an attachment to a page for testing purposes.
-     * @param pageName
-     * @param attachmentName
-     * @param data
+     * Adds an attachment to a page for testing purposes.
+     *
+     * @param pageName page name
+     * @param attachmentName attachment name
+     * @param data attachment data
      */
     public void addAttachment( final String pageName, final String attachmentName, final byte[] data ) throws ProviderException, IOException {
         final Attachment att = Wiki.contents().attachment( this,pageName,attachmentName );
@@ -404,13 +406,12 @@ public class TestEngine extends WikiEngine {
     }
 
     /**
-     * Convenience method that saves a wiki page by constructing a fake
-     * WikiContext and HttpServletRequest. We always want to do this using a
-     * WikiContext whose subject contains Role.ADMIN.
-     * Note: the WikiPage author will have the default value of "Guest".
-     * @param pageName
-     * @param content
-     * @throws WikiException
+     * Convenience method that saves a wiki page by constructing a fake WikiContext and HttpServletRequest. We always want to do this
+     * using a WikiContext whose subject contains Role.ADMIN. Note: the WikiPage author will have the default value of "Guest".
+     *
+     * @param pageName page name
+     * @param content page content
+     * @throws WikiException associated login operation or page save had some trouble
      */
     public void saveText( final String pageName, final String content ) throws WikiException {
         // Build new request and associate our admin session


[jspwiki] 11/35: Decision doesn't need to know about WorkflowManager

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 27e78fbd6572d51074142333a49583fd099d3f60
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 18:11:43 2020 +0200

    Decision doesn't need to know about WorkflowManager
---
 .../java/org/apache/wiki/workflow/Decision.java    | 143 ++++++++-------------
 1 file changed, 51 insertions(+), 92 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
index 003be8d..dbbabed 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
@@ -18,42 +18,36 @@
  */
 package org.apache.wiki.workflow;
 
+import org.apache.wiki.api.exceptions.WikiException;
+import org.apache.wiki.event.WorkflowEvent;
+
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.apache.wiki.api.exceptions.WikiException;
 
 /**
  * <p>
- * AbstractStep subclass that asks an actor Principal to choose an Outcome on
- * behalf of an owner (also a Principal). The actor "makes the decision" by
- * calling the {@link #decide(Outcome)} method. When this method is called, it
- * will set the Decision's Outcome to the one supplied. If the parent Workflow
- * is in the {@link Workflow#WAITING} state, it will be re-started. Any checked
- * WikiExceptions thrown by the workflow after re-start will be re-thrown to
- * callers.
+ * AbstractStep subclass that asks an actor Principal to choose an Outcome on behalf of an owner (also a Principal). The actor
+ * "makes the decision" by calling the {@link #decide(Outcome)} method. When this method is called, it will set the Decision's Outcome to
+ * the one supplied. If the parent Workflow is in the {@link Workflow#WAITING} state, it will be re-started. Any checked WikiExceptions
+ * thrown by the workflow after re-start will be re-thrown to callers.
  * </p>
  * <p>
- * When a Decision completes, its {@link #isCompleted()} method returns
- * <code>true</code>. It also tells its parent WorkflowManager to remove it
- * from the list of pending tasks by calling
- * {@link DecisionQueue#remove(Decision)}.
+ * When a Decision completes, its {@link #isCompleted()} method returns <code>true</code>. It also tells its parent WorkflowManager to
+ * remove it from the list of pending tasks by calling {@link DecisionQueue#remove(Decision)}.
  * </p>
  * <p>
- * To enable actors to choose an appropriate Outcome, Decisions can store
- * arbitrary key-value pairs called "facts." These facts can be presented by the
- * user interface to show details the actor needs to know about. Facts are added
- * by calling classes to the Decision, in order of expected presentation, by the
- * {@link #addFact(Fact)} method. They can be retrieved, in order, via
- * {@link #getFacts()}.
+ * To enable actors to choose an appropriate Outcome, Decisions can store arbitrary key-value pairs called "facts." These facts can be
+ * presented by the user interface to show details the actor needs to know about. Facts are added by calling classes to the Decision,
+ * in order of expected presentation, by the {@link #addFact(Fact)} method. They can be retrieved, in order, via {@link #getFacts()}.
  * </p>
  *
  * @since 2.5
  */
-public abstract class Decision extends AbstractStep
-{
+public abstract class Decision extends AbstractStep {
+
     private static final long serialVersionUID = -6835601038263238062L;
 
     private Principal m_actor;
@@ -65,24 +59,18 @@ public abstract class Decision extends AbstractStep
     private final List<Fact> m_facts;
 
     /**
-     * Constructs a new Decision for a required "actor" Principal, having a
-     * default Outcome.
-     * 
+     * Constructs a new Decision for a required "actor" Principal, having a default Outcome.
+     *
      * @param workflow the parent Workflow object
-     * @param messageKey the i18n message key that represents the message the
-     *            actor will see
-     * @param actor the Principal (<em>e.g.</em>, a WikiPrincipal, Role,
-     *            GroupPrincipal) who is required to select an appropriate
-     *            Outcome
-     * @param defaultOutcome the Outcome that the user interface will recommend
-     *            as the default choice
+     * @param messageKey the i18n message key that represents the message the actor will see
+     * @param actor the Principal (<em>e.g.</em>, a WikiPrincipal, Role, GroupPrincipal) who is required to select an appropriate Outcome
+     * @param defaultOutcome the Outcome that the user interface will recommend as the default choice
      */
-    public Decision( Workflow workflow, String messageKey, Principal actor, Outcome defaultOutcome )
-    {
+    public Decision( final Workflow workflow, final String messageKey, final Principal actor, final Outcome defaultOutcome ) {
         super( workflow, messageKey );
         m_actor = actor;
         m_defaultOutcome = defaultOutcome;
-        m_facts = new ArrayList<Fact>();
+        m_facts = new ArrayList<>();
         addSuccessor( defaultOutcome, null );
     }
 
@@ -91,7 +79,7 @@ public abstract class Decision extends AbstractStep
      * 
      * @param fact the new fact to add
      */
-    public final void addFact( Fact fact )
+    public final void addFact( final Fact fact )
     {
         m_facts.add( fact );
     }
@@ -112,50 +100,35 @@ public abstract class Decision extends AbstractStep
      * </p>
      * 
      * @param outcome the Outcome of the Decision
-     * @throws WikiException if the act of restarting the Workflow throws an
-     *             exception
+     * @throws WikiException if the act of restarting the Workflow throws an exception
      */
-    public void decide( Outcome outcome ) throws WikiException
-    {
+    public void decide( final Outcome outcome ) throws WikiException {
         super.setOutcome( outcome );
 
-        // If current workflow is waiting for input, restart it and remove
-        // Decision from DecisionQueue
-        Workflow w = getWorkflow();
-        if( w.getCurrentState() == Workflow.WAITING && this.equals( w.getCurrentStep() ) )
-        {
-            WorkflowManager wm = w.getWorkflowManager();
-            if( wm != null )
-            {
-                wm.getDecisionQueue().remove( this );
-            }
+        // If current workflow is waiting for input, restart it and remove Decision from DecisionQueue
+        final Workflow w = getWorkflow();
+        if( w.getCurrentState() == Workflow.WAITING && this.equals( w.getCurrentStep() ) ) {
+            WorkflowEventEmitter.fireEvent( this, WorkflowEvent.DQ_REMOVAL );
             // Restart workflow
             w.restart();
         }
     }
 
     /**
-     * Default implementation that always returns {@link Outcome#STEP_CONTINUE}
-     * if the current Outcome isn't a completion (which will be true if the
-     * {@link #decide(Outcome)} method hasn't been executed yet. This method
-     * will also add the Decision to the associated DecisionQueue.
+     * Default implementation that always returns {@link Outcome#STEP_CONTINUE} if the current Outcome isn't a completion (which will be
+     * true if the {@link #decide(Outcome)} method hasn't been executed yet. This method will also add the Decision to the associated
+     * DecisionQueue.
      * 
      * @return the Outcome of the execution
      * @throws WikiException never
      */
-    public Outcome execute() throws WikiException
-    {
-        if( getOutcome().isCompletion() )
-        {
+    public Outcome execute() throws WikiException {
+        if( getOutcome().isCompletion() ) {
             return getOutcome();
         }
 
         // Put decision in the DecisionQueue
-        WorkflowManager wm = getWorkflow().getWorkflowManager();
-        if( wm != null )
-        {
-            wm.getDecisionQueue().add( this );
-        }
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.DQ_ADDITION );
 
         // Indicate we are waiting for user input
         return Outcome.STEP_CONTINUE;
@@ -164,72 +137,58 @@ public abstract class Decision extends AbstractStep
     /**
      * {@inheritDoc}
      */
-    public final Principal getActor()
-    {
+    public final Principal getActor() {
         return m_actor;
     }
 
     /**
-     * Returns the default or suggested outcome, which must be one of those
-     * returned by {@link #getAvailableOutcomes()}. This method is guaranteed
-     * to return a non-<code>null</code> Outcome.
+     * Returns the default or suggested outcome, which must be one of those returned by {@link #getAvailableOutcomes()}. This method is
+     * guaranteed to return a non-<code>null</code> Outcome.
      * 
      * @return the default outcome.
      */
-    public Outcome getDefaultOutcome()
-    {
+    public Outcome getDefaultOutcome() {
         return m_defaultOutcome;
     }
 
     /**
-     * Returns the Facts associated with this Decision, in the order in which
-     * they were added.
+     * Returns the Facts associated with this Decision, in the order in which they were added.
      * 
      * @return the list of Facts
      */
-    public final List< Fact > getFacts()
-    {
+    public final List< Fact > getFacts() {
         return Collections.unmodifiableList( m_facts );
     }
 
     /**
-     * Returns the unique identifier for this Decision. Normally, this ID is
-     * programmatically assigned when the Decision is added to the
+     * Returns the unique identifier for this Decision. Normally, this ID is programmatically assigned when the Decision is added to the
      * DecisionQueue.
      * 
      * @return the identifier
      */
-    public final int getId()
-    {
+    public final int getId() {
         return m_id;
     }
 
     /**
-     * Returns <code>true</code> if the Decision can be reassigned to another
-     * actor. This implementation always returns <code>true</code>.
-     * 
+     * Returns <code>true</code> if the Decision can be reassigned to another actor. This implementation always returns <code>true</code>.
+     *
      * @return the result
      */
-    public boolean isReassignable()
-    {
+    public boolean isReassignable() {
         return true;
     }
 
     /**
-     * Reassigns the Decision to a new actor (that is, provide an outcome). If
-     * the Decision is not reassignable, this method throws an
+     * Reassigns the Decision to a new actor (that is, provide an outcome). If the Decision is not reassignable, this method throws an
      * IllegalArgumentException.
      * 
      * @param actor the actor to reassign the Decision to
      */
-    public final synchronized void reassign( Principal actor )
-    {
-        if( isReassignable() )
-        {
+    public final synchronized void reassign( final Principal actor ) {
+        if( isReassignable() ) {
             m_actor = actor;
-        }
-        else
-        {
+        } else {
             throw new IllegalArgumentException( "Decision cannot be reassigned." );
         }
     }
@@ -239,8 +198,8 @@ public abstract class Decision extends AbstractStep
      * 
      * @param id the identifier
      */
-    public final void setId( int id )
-    {
+    public final void setId( final int id ) {
         m_id = id;
     }
+
 }


[jspwiki] 06/35: Add WorkflowEventEmitter enum to emit workflow-related events and register as client on DefaultWorkflowManager, which is an event listener

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit af1d4e3450f78a4b9deae68502efcec395b64c59
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 18:03:06 2020 +0200

    Add WorkflowEventEmitter enum to emit workflow-related events and register as client on DefaultWorkflowManager, which is an event listener
    
    Also DefaultWorkflowManager, reacts to new Workflow events DQ_ADDITION and DQ_REMOVAL
---
 .../wiki/workflow/DefaultWorkflowManager.java      | 53 ++++++++++++++--------
 .../apache/wiki/workflow/WorkflowEventEmitter.java | 48 ++++++++++++++++++++
 2 files changed, 82 insertions(+), 19 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
index 4703763..d837611 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
@@ -24,6 +24,7 @@ import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.auth.AuthorizationManager;
 import org.apache.wiki.auth.acl.UnresolvedPrincipal;
 import org.apache.wiki.event.WikiEvent;
+import org.apache.wiki.event.WikiEventManager;
 import org.apache.wiki.event.WorkflowEvent;
 
 import java.security.Principal;
@@ -59,6 +60,7 @@ public class DefaultWorkflowManager implements WorkflowManager {
         m_workflows = ConcurrentHashMap.newKeySet();
         m_approvers = new ConcurrentHashMap<>();
         m_completed = new CopyOnWriteArrayList<>();
+        WikiEventManager.addWikiEventListener( WorkflowEventEmitter.get(), this );
     }
 
     /**
@@ -67,7 +69,6 @@ public class DefaultWorkflowManager implements WorkflowManager {
     @Override
     public void start( final Workflow workflow ) throws WikiException {
         m_workflows.add( workflow );
-        workflow.setWorkflowManager( this );
         workflow.setId( nextId() );
         workflow.start();
     }
@@ -170,16 +171,15 @@ public class DefaultWorkflowManager implements WorkflowManager {
      *
      * @return the decision queue
      */
-    @Override public DecisionQueue getDecisionQueue()
-    {
+    @Override
+    public DecisionQueue getDecisionQueue() {
         return m_queue;
     }
 
     private volatile int m_next;
 
     /**
-     * Returns the next available unique identifier, which is subsequently
-     * incremented.
+     * Returns the next available unique identifier, which is subsequently incremented.
      *
      * @return the id
      */
@@ -211,25 +211,35 @@ public class DefaultWorkflowManager implements WorkflowManager {
     }
 
     /**
-     * Listens for {@link WorkflowEvent} objects emitted by Workflows. In particular, this
-     * method listens for {@link WorkflowEvent#CREATED},
-     * {@link WorkflowEvent#ABORTED} and {@link WorkflowEvent#COMPLETED}
-     * events. If a workflow is created, it is automatically added to the cache. If one is aborted or completed, it 
-     * is automatically removed.
+     * Listens for {@link WorkflowEvent} objects emitted by Workflows. In particular, this method listens for {@link WorkflowEvent#CREATED},
+     * {@link WorkflowEvent#ABORTED}, {@link WorkflowEvent#COMPLETED} and {@link WorkflowEvent#DQ_REMOVAL} events. If a workflow is created,
+     * it is automatically added to the cache. If one is aborted or completed, it is automatically removed. If a removal from decision queue
+     * is issued, the current step from workflow, which is assumed to be a {@link Decision}, is removed from the {@link DecisionQueue}.
      * 
      * @param event the event passed to this listener
      */
     @Override
     public void actionPerformed( final WikiEvent event ) {
         if( event instanceof WorkflowEvent ) {
-            final Workflow workflow = event.getSrc();
-            switch ( event.getType() ) {
-                 // Remove from manager
-                 case WorkflowEvent.ABORTED   :
-                 case WorkflowEvent.COMPLETED : remove( workflow ); break;
+            if( event.getSrc() instanceof Workflow ) {
+                final Workflow workflow = event.getSrc();
+                switch( event.getType() ) {
+                // Remove from manager
+                case WorkflowEvent.ABORTED   :
+                case WorkflowEvent.COMPLETED : remove( workflow ); break;
                 // Add to manager
-                case WorkflowEvent.CREATED    : add( workflow ); break;
+                case WorkflowEvent.CREATED   : add( workflow ); break;
+                default: break;
+                }
+            } else if( event.getSrc() instanceof Decision ) {
+                final Decision decision = event.getSrc();
+                switch( event.getType() ) {
+                // Add to DecisionQueue
+                case WorkflowEvent.DQ_ADDITION : addToDecisionQueue( decision ); break;
+                // Remove from DecisionQueue
+                case WorkflowEvent.DQ_REMOVAL  : removeFromDecisionQueue( decision ); break;
                 default: break;
+                }
             }
         }
     }
@@ -241,9 +251,6 @@ public class DefaultWorkflowManager implements WorkflowManager {
      * @param workflow the workflow to add
      */
     protected void add( final Workflow workflow ) {
-        if ( workflow.getWorkflowManager() == null ) {
-            workflow.setWorkflowManager( this );
-        }
         if ( workflow.getId() == Workflow.ID_NOT_SET ) {
             workflow.setId( nextId() );
         }
@@ -263,4 +270,12 @@ public class DefaultWorkflowManager implements WorkflowManager {
         }
     }
 
+    protected void removeFromDecisionQueue( final Decision decision ) {
+        getDecisionQueue().remove( decision );
+    }
+
+    protected void addToDecisionQueue( final Decision decision ) {
+        getDecisionQueue().add( decision );
+    }
+
 }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
new file mode 100644
index 0000000..6ab5f86
--- /dev/null
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
@@ -0,0 +1,48 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+ */
+package org.apache.wiki.workflow;
+
+import org.apache.wiki.event.WikiEventManager;
+import org.apache.wiki.event.WorkflowEvent;
+
+
+/**
+ * Emits all kind of {@link WorkflowEvent}s.
+ */
+public enum WorkflowEventEmitter {
+
+    INSTANCE;
+
+    public static WorkflowEventEmitter get() {
+        return INSTANCE;
+    }
+
+    public static void fireEvent( final Decision decision, final int type ) {
+        if ( WikiEventManager.isListening( get() ) ) {
+            WikiEventManager.fireEvent( get(), new WorkflowEvent( decision, type ) );
+        }
+    }
+
+    public static void fireEvent( final Workflow workflow, final int type ) {
+        if ( WikiEventManager.isListening( get() ) ) {
+            WikiEventManager.fireEvent( get(), new WorkflowEvent( workflow, type ) );
+        }
+    }
+
+}


[jspwiki] 24/35: Update Selenide to 5.11.1

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit fb5bb535b34d74c66941b1e3bd5951dee97f94f4
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat May 2 21:07:14 2020 +0200

    Update Selenide to 5.11.1
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 32a71ba..25949f9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,7 +71,7 @@
     <nekohtml.version>1.9.22</nekohtml.version>
     <oro.version>2.0.8</oro.version>
     <sandler.version>0.5</sandler.version>
-    <selenide.version>5.11.0</selenide.version>
+    <selenide.version>5.11.1</selenide.version>
     <slf4j.version>1.7.30</slf4j.version>
     <stripes.version>1.7.0-async-beta</stripes.version>
     <tika.version>1.24.1</tika.version>


[jspwiki] 03/35: rewrite class javadoc

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 66a4d6758a397a376fdb7bfaeae6d37f72e13dc9
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 17:58:22 2020 +0200

    rewrite class javadoc
---
 jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java b/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java
index dbce244..6a2269e 100644
--- a/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java
@@ -45,8 +45,8 @@ import java.util.Properties;
  *  This is the main interface through which everything should go.
  *
  *  <p>
- *  There's basically only a single Engine for each web application, and you should always get it using the {@code Engine.getInstance(..)}
- *  method.
+ *  There's basically only a single Engine for each web application, and you should always get it using either the
+ *  {@code Context#getEngine()} method or through {@code Wiki.engine().find(..)} DSL methods.
  */
 public interface Engine {
 


[jspwiki] 14/35: Update Flexmark to 0.61.8

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit f825693b031b7491fc5e483f9a75e6a1e8685864
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue Apr 14 22:15:12 2020 +0200

    Update Flexmark to 0.61.8
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 525c33f..ca4fc21 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,7 +52,7 @@
     <commons-lang.version>3.10</commons-lang.version>
     <commons-text.version>1.8</commons-text.version>
     <ehcache.version>2.10.6</ehcache.version>
-    <flexmark.version>0.60.2</flexmark.version>
+    <flexmark.version>0.61.8</flexmark.version>
     <freshcookies-security.version>0.60</freshcookies-security.version>
     <gson.version>2.8.5</gson.version>
     <hsqldb.version>2.5.0</hsqldb.version>


[jspwiki] 23/35: JSPWIKI-304: make Workflow attributes Serializable

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 60ab922cb2533963e0cf8cf17a121918500c9369
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat May 2 21:06:52 2020 +0200

    JSPWIKI-304: make Workflow attributes Serializable
    
    As Context isn't Serializable, on save page Tasks we pass it as a constructor parameter instead of passing it through the Workflow attributes' map.
---
 .../src/main/java/org/apache/wiki/api/core/Context.java  |  2 +-
 .../java/org/apache/wiki/pages/DefaultPageManager.java   |  2 +-
 .../java/org/apache/wiki/tasks/DefaultTasksManager.java  |  4 ++--
 .../main/java/org/apache/wiki/tasks/TasksManager.java    |  5 +++--
 .../org/apache/wiki/tasks/auth/SaveUserProfileTask.java  |  2 +-
 .../org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java |  1 -
 .../org/apache/wiki/tasks/pages/SaveWikiPageTask.java    |  6 ++++--
 .../main/java/org/apache/wiki/workflow/AbstractStep.java |  9 +++++----
 .../src/main/java/org/apache/wiki/workflow/Decision.java |  3 ++-
 .../java/org/apache/wiki/workflow/SimpleDecision.java    |  3 ++-
 .../org/apache/wiki/workflow/SimpleNotification.java     |  3 ++-
 .../src/main/java/org/apache/wiki/workflow/Step.java     |  2 +-
 .../src/main/java/org/apache/wiki/workflow/Task.java     |  3 ++-
 .../src/main/java/org/apache/wiki/workflow/Workflow.java |  8 ++++----
 .../java/org/apache/wiki/workflow/WorkflowManager.java   |  2 --
 .../org/apache/wiki/workflow/ApprovalWorkflowTest.java   | 16 ++++------------
 16 files changed, 34 insertions(+), 37 deletions(-)

diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/core/Context.java b/jspwiki-api/src/main/java/org/apache/wiki/api/core/Context.java
index 04ebca9..f131ac8 100644
--- a/jspwiki-api/src/main/java/org/apache/wiki/api/core/Context.java
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/core/Context.java
@@ -95,7 +95,7 @@ public interface Context extends Cloneable, Command {
      *  @since 2.3.14
      *  @see org.apache.wiki.tags.InsertPageTag
      */
-    Page setRealPage( Page wikiPagePage );
+    Page setRealPage( Page wikiPage );
 
     /**
      *  Returns the handling engine.
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
index 54c9c2d..30cbe8b 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
@@ -247,7 +247,7 @@ public class DefaultPageManager implements PageManager {
         final WorkflowBuilder builder = WorkflowBuilder.getBuilder( m_engine );
         final Principal submitter = context.getCurrentUser();
         final Step prepTask = m_engine.getManager( TasksManager.class ).buildPreSaveWikiPageTask( context, proposedText );
-        final Step completionTask = m_engine.getManager( TasksManager.class ).buildSaveWikiPageTask();
+        final Step completionTask = m_engine.getManager( TasksManager.class ).buildSaveWikiPageTask( context );
         final String diffText = m_engine.getManager( DifferenceManager.class ).makeDiff( context, oldText, proposedText );
         final boolean isAuthenticated = context.getWikiSession().isAuthenticated();
         final Fact[] facts = new Fact[ 5 ];
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/DefaultTasksManager.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/DefaultTasksManager.java
index b4a91d6..7d45562 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/DefaultTasksManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/DefaultTasksManager.java
@@ -45,8 +45,8 @@ public class DefaultTasksManager implements TasksManager {
      * {@inheritDoc}
      */
     @Override
-    public Step buildSaveWikiPageTask() {
-        return new SaveWikiPageTask();
+    public Step buildSaveWikiPageTask( final Context context ) {
+        return new SaveWikiPageTask( context );
     }
     
     /**
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/TasksManager.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/TasksManager.java
index 1d1b1ae..3c56f87 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/TasksManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/TasksManager.java
@@ -52,10 +52,11 @@ public interface TasksManager {
     
     /**
      * Builds a save WikiPage task.
-     * 
+     *
+     * @param context associated wiki context.
      * @return a save WikiPage task.
      */
-    Step buildSaveWikiPageTask();
+    Step buildSaveWikiPageTask( Context context );
     
     /**
      * Builds a save user profile task.
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
index 18325b3..fd6d413 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
@@ -68,7 +68,7 @@ public class SaveUserProfileTask extends Task {
                                                  profile.getFullname(),
                                                  profile.getEmail(),
                                                  m_engine.getURL( ContextEnum.WIKI_LOGIN.getRequestContext(), null, null ) );
-                MailUtil.sendMessage( m_engine.getWikiProperties(), to, subject, content);
+                MailUtil.sendMessage( m_engine.getWikiProperties(), to, subject, content );
             } catch ( final AddressException e) {
                 LOG.debug( e.getMessage(), e );
             } catch ( final MessagingException me ) {
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java
index 5e65649..8aeca27 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java
@@ -73,7 +73,6 @@ public class PreSaveWikiPageTask extends Task {
         final String saveText = m_context.getEngine().getManager( FilterManager.class ).doPreSaveFiltering(m_context, m_proposedText);
 
         // Stash the wiki context, old and new text as workflow attributes
-        getWorkflowContext().put( WorkflowManager.WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT, m_context );
         getWorkflowContext().put( WorkflowManager.WF_WP_SAVE_FACT_PROPOSED_TEXT, saveText );
         return Outcome.STEP_COMPLETE;
     }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java
index 0063c40..53ce0b0 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java
@@ -38,11 +38,14 @@ public class SaveWikiPageTask extends Task {
 
     private static final long serialVersionUID = 3190559953484411420L;
 
+    final Context context;
+
     /**
      * Creates the Task.
      */
-    public SaveWikiPageTask() {
+    public SaveWikiPageTask( final Context context ) {
         super( TasksManager.WIKIPAGE_SAVE_TASK_MESSAGE_KEY );
+        this.context = context;
     }
 
     /**
@@ -51,7 +54,6 @@ public class SaveWikiPageTask extends Task {
     @Override
     public Outcome execute() throws WikiException {
         // Retrieve attributes
-        final Context context = ( Context )getWorkflowContext().get( WorkflowManager.WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT );
         final String proposedText = ( String )getWorkflowContext().get( WorkflowManager.WF_WP_SAVE_FACT_PROPOSED_TEXT );
 
         final Engine engine = context.getEngine();
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
index 414aa20..ca575dd 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
@@ -20,6 +20,7 @@ package org.apache.wiki.workflow;
 
 import org.apache.wiki.api.exceptions.WikiException;
 
+import java.io.Serializable;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -55,7 +56,7 @@ public abstract class AbstractStep implements Step {
     private int workflowId;
 
     /** attribute map. */
-    private Map< String, Object > workflowContext;
+    private Map< String, Serializable > workflowContext;
 
     private Outcome m_outcome;
 
@@ -89,7 +90,7 @@ public abstract class AbstractStep implements Step {
      * @param messageKey the Step's message key, such as {@code decision.editPageApproval}. By convention, the message prefix should
      *                   be a lower-case version of the Step's type, plus a period (<em>e.g.</em>, {@code task.} and {@code decision.}).
      */
-    public AbstractStep( final int workflowId, final Map< String, Object > workflowContext, final String messageKey ) {
+    public AbstractStep( final int workflowId, final Map< String, Serializable > workflowContext, final String messageKey ) {
         this( messageKey );
         setWorkflow( workflowId, workflowContext );
     }
@@ -216,7 +217,7 @@ public abstract class AbstractStep implements Step {
      * @param workflowId the parent workflow id to set
      * @param workflowContext the parent workflow context to set
      */
-    public final synchronized void setWorkflow( final int workflowId, final Map< String, Object > workflowContext ) {
+    public final synchronized void setWorkflow( final int workflowId, final Map< String, Serializable > workflowContext ) {
         this.workflowId = workflowId;
         this.workflowContext = workflowContext;
     }
@@ -225,7 +226,7 @@ public abstract class AbstractStep implements Step {
         return workflowId;
     }
 
-    public Map< String, Object > getWorkflowContext() {
+    public Map< String, Serializable > getWorkflowContext() {
         return workflowContext;
     }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
index 07749c1..9e4f97e 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
@@ -21,6 +21,7 @@ package org.apache.wiki.workflow;
 import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.event.WorkflowEvent;
 
+import java.io.Serializable;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -68,7 +69,7 @@ public abstract class Decision extends AbstractStep {
      * @param actor the Principal (<em>e.g.</em>, a WikiPrincipal, Role, GroupPrincipal) who is required to select an appropriate Outcome
      * @param defaultOutcome the Outcome that the user interface will recommend as the default choice
      */
-    public Decision( final int workflowId, final Map< String, Object > workflowContext, final String messageKey, final Principal actor, final Outcome defaultOutcome ) {
+    public Decision( final int workflowId, final Map< String, Serializable > workflowContext, final String messageKey, final Principal actor, final Outcome defaultOutcome ) {
         super( workflowId, workflowContext, messageKey );
         m_actor = actor;
         m_defaultOutcome = defaultOutcome;
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java
index bae296a..8efd257 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java
@@ -18,6 +18,7 @@
  */
 package org.apache.wiki.workflow;
 
+import java.io.Serializable;
 import java.security.Principal;
 import java.util.Map;
 
@@ -38,7 +39,7 @@ public class SimpleDecision extends Decision {
      * @param messageKey the message key that describes the Decision, which will be presented in the UI
      * @param actor the Principal (<em>e.g.</em>, WikiPrincipal, GroupPrincipal, Role) who will decide
      */
-    public SimpleDecision( final int workflowId, final Map< String, Object > workflowContext, final String messageKey, final Principal actor ) {
+    public SimpleDecision( final int workflowId, final Map< String, Serializable > workflowContext, final String messageKey, final Principal actor ) {
         super( workflowId, workflowContext, messageKey, actor, Outcome.DECISION_APPROVE );
 
         // Add the other default outcomes
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java
index 44d88a2..fbae727 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java
@@ -20,6 +20,7 @@ package org.apache.wiki.workflow;
 
 import org.apache.wiki.api.exceptions.WikiException;
 
+import java.io.Serializable;
 import java.security.Principal;
 import java.util.Map;
 
@@ -43,7 +44,7 @@ public final class SimpleNotification extends Decision {
      * @param messageKey the message key
      * @param actor the Principal who will acknowledge the message
      */
-    public SimpleNotification( final int workflowId, final Map< String, Object > workflowContext, final String messageKey, final Principal actor ) {
+    public SimpleNotification( final int workflowId, final Map< String, Serializable > workflowContext, final String messageKey, final Principal actor ) {
         super( workflowId, workflowContext, messageKey, actor, Outcome.DECISION_ACKNOWLEDGE );
     }
     
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
index 5d890cc..c73bcef 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
@@ -188,6 +188,6 @@ public interface Step extends Serializable {
      * @param workflowId the parent workflow id to set
      * @param workflowContext the parent workflow context to set
      */
-    void setWorkflow( final int workflowId, final Map< String, Object > workflowContext );
+    void setWorkflow( final int workflowId, final Map< String, Serializable > workflowContext );
 
 }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java
index 5e560ee..49b5585 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java
@@ -18,6 +18,7 @@
  */
 package org.apache.wiki.workflow;
 
+import java.io.Serializable;
 import java.security.Principal;
 import java.util.Map;
 
@@ -58,7 +59,7 @@ public abstract class Task extends AbstractStep {
      * @param workflowContext the parent workflow context to set
      * @param messageKey      the i18n message key
      */
-    public Task( final int workflowId, final Map< String, Object > workflowContext, final String messageKey ) {
+    public Task( final int workflowId, final Map< String, Serializable > workflowContext, final String messageKey ) {
         this( messageKey );
         setWorkflow( workflowId, workflowContext );
     }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
index 42c6c2f..f06dc16 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
@@ -105,7 +105,7 @@ import java.util.concurrent.atomic.AtomicInteger;
  * </p>
  * <ul>
  * <li><strong>Named attributes</strong> are simple key-value pairs that Workflow participants can get or set. Keys are Strings; values
- * can be any Object. Named attributes are set with {@link #setAttribute(String, Object)} and retrieved with {@link #getAttribute(String)}.</li>
+ * can be any Object. Named attributes are set with {@link #setAttribute(String, Serializable)} and retrieved with {@link #getAttribute(String)}.</li>
  * <li><strong>Message arguments</strong> are used in combination with JSPWiki's {@link org.apache.wiki.i18n.InternationalizationManager} to
  * create language-independent user interface messages. The message argument array is retrieved via {@link #getMessageArguments()}; the
  * first two array elements will always be these: a String representing work flow owner's name, and a String representing the current
@@ -186,7 +186,7 @@ public class Workflow implements Serializable {
     public static final int CREATED = -2;
 
     /** attribute map. */
-    private Map< String, Object > m_attributes;
+    private Map< String, Serializable > m_attributes;
 
     /** The initial Step for this Workflow. */
     private Step m_firstStep;
@@ -321,7 +321,7 @@ public class Workflow implements Serializable {
      *
      * @return workflow's attributes.
      */
-    public final Map< String, Object > getAttributes() {
+    public final Map< String, Serializable > getAttributes() {
         return m_attributes;
     }
 
@@ -495,7 +495,7 @@ public class Workflow implements Serializable {
      * @param attr the attribute name
      * @param obj  the value
      */
-    public final void setAttribute( final String attr, final Object obj ) {
+    public final void setAttribute( final String attr, final Serializable obj ) {
         m_attributes.put( attr, obj );
     }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java
index a0cfdd2..064b93b 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java
@@ -36,8 +36,6 @@ import java.util.Set;
  */
 public interface WorkflowManager extends WikiEventListener, Initializable {
 
-    /** The workflow attribute which stores the wikiContext. */
-    String WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT = "wikiContext";
     /** The name of the key from jspwiki.properties which defines who shall approve the workflow of storing a wikipage.  Value is <tt>{@value}</tt> */
     String WF_WP_SAVE_APPROVER = "workflow.saveWikiPage";
     /** The message key for storing the Decision text for saving a page.  Value is {@value}. */
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
index ba05915..6dbb9ee 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
@@ -229,26 +229,18 @@ public class ApprovalWorkflowTest {
         // Create a sample test page and try to save it
         final String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();
         final String text = "This is a test!";
-        try {
-            m_engine.saveTextAsJanne(pageName, text);
-        } catch( final WikiException e ) {
-            Assertions.assertTrue( e instanceof FilterException );
-            Assertions.assertEquals( "Page save aborted.", e.getMessage() );
-            return;
-        }
-        Assertions.fail( "Page save should have thrown a FilterException, but didn't." );
+        final FilterException fe = Assertions.assertThrows( FilterException.class, () -> m_engine.saveTextAsJanne( pageName, text ) );
+        Assertions.assertEquals( "Page save aborted.", fe.getMessage() );
     }
 
     /**
-     * Sample "prep task" that sets an attribute in the workflow indicating
-     * that it ran successfully,
+     * Sample "prep task" that sets an attribute in the workflow indicating that it ran successfully,
      */
     public static class TestPrepTask extends Task {
 
         private static final long serialVersionUID = 1L;
 
-        public TestPrepTask( final String messageKey )
-        {
+        public TestPrepTask( final String messageKey ) {
             super( messageKey );
         }
 


[jspwiki] 34/35: add test data file

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 564bfc0dea425497060b71ef809e388faf3de2cd
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue May 5 21:16:50 2020 +0200

    add test data file
---
 jspwiki-main/src/test/resources/wkflmgr.ser | Bin 0 -> 3770 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/jspwiki-main/src/test/resources/wkflmgr.ser b/jspwiki-main/src/test/resources/wkflmgr.ser
new file mode 100644
index 0000000..4a69d74
Binary files /dev/null and b/jspwiki-main/src/test/resources/wkflmgr.ser differ


[jspwiki] 12/35: add formatting suggested by IntelliJ

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 5255ee58442d32a6b8f77c398802629fb6e571a5
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 19:21:33 2020 +0200

    add formatting suggested by IntelliJ
---
 .../main/java/org/apache/wiki/workflow/Step.java   | 166 ++++++++-------------
 1 file changed, 62 insertions(+), 104 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
index dc17422..7ed8561 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
@@ -18,78 +18,61 @@
  */
 package org.apache.wiki.workflow;
 
+import org.apache.wiki.api.exceptions.WikiException;
+
 import java.io.Serializable;
 import java.security.Principal;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.wiki.api.exceptions.WikiException;
-
 /**
  * <p>
- * Discrete unit of work in a Workflow, such as a {@link Decision} or a
- * {@link Task}. Decisions require user input, while Tasks do not. All Steps,
- * however, possess these properties:
+ * Discrete unit of work in a Workflow, such as a {@link Decision} or a {@link Task}. Decisions require user input, while Tasks do not.
+ * All Steps, however, possess these properties:
  * </p>
  * <ul>
- * <li><strong>actor</strong>: the Principal responsible for executing the
- * Step; returned by {@link Step#getActor()}.</li>
- * <li><strong>availableOutcomes</strong>: a collection of possible
- * "outcomes," such as "approve decision" ({@link Outcome#DECISION_APPROVE}),
- * "reassign decision" ({@link Outcome#DECISION_REASSIGN}), "abort step" ({@link Outcome#STEP_ABORT})
- * and others. The range of possible Outcomes for the Step is returned by
- * {@link Step#getAvailableOutcomes()}; see the Outcome class for more details.</li>
- * <li><strong>errors</strong>: an collection of Strings indicating errors
- * returned by the Step. These values are returned by {@link Step#getErrors()}.</li>
- * <li><strong>started</strong> and <strong>completed</strong>: whether the
- * Step has started/finished. These values are returned by
+ * <li><strong>actor</strong>: the Principal responsible for executing the Step; returned by {@link Step#getActor()}.</li>
+ * <li><strong>availableOutcomes</strong>: a collection of possible "outcomes," such as "approve decision" ({@link Outcome#DECISION_APPROVE}),
+ * "reassign decision" ({@link Outcome#DECISION_REASSIGN}), "abort step" ({@link Outcome#STEP_ABORT}) and others. The range of possible
+ * Outcomes for the Step is returned by {@link Step#getAvailableOutcomes()}; see the Outcome class for more details.</li>
+ * <li><strong>errors</strong>: an collection of Strings indicating errors returned by the Step. These values are returned by
+ * {@link Step#getErrors()}.</li>
+ * <li><strong>started</strong> and <strong>completed</strong>: whether the Step has started/finished. These values are returned by
  * {@link Step#isStarted()} and {@link Step#isCompleted()}.</li>
- * <li><strong>startTime</strong> and <strong>endTime</strong>: the time when
- * the Step started and finished. These values are returned by
+ * <li><strong>startTime</strong> and <strong>endTime</strong>: the time when the Step started and finished. These values are returned by
  * {@link Step#getStartTime()} and {@link Step#getEndTime()}, respectively.</li>
  * <li><strong>workflow</strong>: the parent Workflow. </li>
  * </ul>
  * <p>
- * Steps contain a {@link #getMessageKey()} method that returns a key that can
- * be used with the {@link org.apache.wiki.i18n.InternationalizationManager}.
- * See also {@link Workflow#getMessageArguments()}, which is a convenience
- * method that returns message arguments.
+ * Steps contain a {@link #getMessageKey()} method that returns a key that can be used with the {@link org.apache.wiki.i18n.InternationalizationManager}.
+ * See also {@link Workflow#getMessageArguments()}, which is a convenience method that returns message arguments.
  * </p>
  * 
  * @since 2.5
  */
-public interface Step extends Serializable
-{
+public interface Step extends Serializable {
 
     /**
-     * Adds a successor Step to this one, which will be triggered by a supplied
-     * Outcome. Implementations should respect the order in which Outcomes are
-     * added; {@link #getAvailableOutcomes()} should return them in the same
-     * order they were added.
+     * Adds a successor Step to this one, which will be triggered by a supplied Outcome. Implementations should respect the order in which
+     * Outcomes are added; {@link #getAvailableOutcomes()} should return them in the same order they were added.
      * 
-     * @param outcome
-     *            the Outcome triggering a particular successor Step
-     * @param step
-     *            the Step to associated with this Outcomes (<code>null</code>
-     *            denotes no Steps)
+     * @param outcome the Outcome triggering a particular successor Step
+     * @param step the Step to associated with this Outcomes (<code>null</code> denotes no Steps)
      */
     void addSuccessor( Outcome outcome, Step step );
 
     /**
-     * Returns a Collection of available outcomes, such as "approve", "deny" or
-     * "reassign", in the order in which they were added via
-     * {@link #addSuccessor(Outcome, Step)}. Concrete implementations should
-     * always return a defensive copy of the outcomes, not the original backing
-     * collection.
+     * Returns a Collection of available outcomes, such as "approve", "deny" or "reassign", in the order in which they were added via
+     * {@link #addSuccessor(Outcome, Step)}. Concrete implementations should always return a defensive copy of the outcomes, not the
+     * original backing collection.
      * 
      * @return the set of outcomes
      */
     Collection< Outcome > getAvailableOutcomes();
 
     /**
-     * Returns a List of error strings generated by this Step. If this Step
-     * generated no errors, this method returns a zero-length array.
+     * Returns a List of error strings generated by this Step. If this Step generated no errors, this method returns a zero-length array.
      * 
      * @return the errors
      */
@@ -97,151 +80,126 @@ public interface Step extends Serializable
 
     /**
      * <p>
-     * Executes the processing for this Step and returns an Outcome indicating
-     * if it succeeded ({@link Outcome#STEP_COMPLETE} or
-     * {@link Outcome#STEP_ABORT}). Processing instructions can do just about
-     * anything, such as executing custom business logic or changing the Step's
-     * final outcome via {@link #setOutcome(Outcome)}. A return value of
-     * <code>STEP_COMPLETE</code> indicates that the instructions executed completely,
-     * without errors; <code>STEP_ABORT</code> indicates that the Step and its
-     * parent Workflow should be aborted (that is, fail silently without error).
-     * If the execution step encounters any errors, it should throw a
+     * Executes the processing for this Step and returns an Outcome indicating if it succeeded ({@link Outcome#STEP_COMPLETE} or
+     * {@link Outcome#STEP_ABORT}). Processing instructions can do just about anything, such as executing custom business logic or
+     * changing the Step's final outcome via {@link #setOutcome(Outcome)}. A return value of <code>STEP_COMPLETE</code> indicates
+     * that the instructions executed completely, without errors; <code>STEP_ABORT</code> indicates that the Step and its parent
+     * Workflow should be aborted (that is, fail silently without error). If the execution step encounters any errors, it should throw a
      * WikiException or a subclass.
      * </p>
      * <p>
-     * Note that successful execution of this methods does not necessarily mean
-     * that the Step is considered "complete"; rather, it just means that it has
-     * executed. Therefore, it is possible that <code>execute</code> could run
-     * multiple times.
+     * Note that successful execution of this methods does not necessarily mean that the Step is considered "complete"; rather, it just
+     * means that it has executed. Therefore, it is possible that <code>execute</code> could run multiple times.
      * </p>
      * 
      * @return the result of the Step, expressed as an Outcome
-     * @throws WikiException
-     *             if the step encounters errors while executing
+     * @throws WikiException if the step encounters errors while executing
      */
     Outcome execute() throws WikiException;
 
     /**
-     * The Principal responsible for completing this Step, such as a system user
-     * or actor assigned to a Decision.
+     * The Principal responsible for completing this Step, such as a system user or actor assigned to a Decision.
      * 
      * @return the responsible Principal
      */
     Principal getActor();
 
     /**
-     * The end time for this Step. This value should be set when the step
-     * completes. Returns {@link Workflow#TIME_NOT_SET} if not completed yet.
+     * The end time for this Step. This value should be set when the step completes. Returns {@link Workflow#TIME_NOT_SET} if not completed
+     * yet.
      * 
      * @return the end time
      */
     Date getEndTime();
 
     /**
-     * Message key for human-friendly name of this Step, including any parameter
-     * substitutions. By convention, the message prefix should be a lower-case
-     * version of the Step's type, plus a period (<em>e.g.</em>,
-     * <code>task.</code> and <code>decision.</code>).
+     * Message key for human-friendly name of this Step, including any parameter substitutions. By convention, the message prefix should be
+     * a lower-case version of the Step's type, plus a period (<em>e.g.</em>, <code>task.</code> and <code>decision.</code>).
      * 
      * @return the message key for this Step.
      */
     String getMessageKey();
 
     /**
-     * Returns the message arguments for this Step, typically by delegating to the
-     * parent Workflow's {@link Workflow#getMessageArguments()} method.
+     * Returns the message arguments for this Step, typically by delegating to the parent Workflow's {@link Workflow#getMessageArguments()}
+     * method.
      * 
      * @return the message arguments.
      */
     Serializable[] getMessageArguments();
 
     /**
-     * Returns the Outcome of this Step's processing; by default,
-     * {@link Outcome#STEP_CONTINUE}.
+     * Returns the Outcome of this Step's processing; by default, {@link Outcome#STEP_CONTINUE}.
      * 
      * @return the outcome
      */
     Outcome getOutcome();
 
     /**
-     * The start time for this Step. Returns {@link Workflow#TIME_NOT_SET} if
-     * not started yet.
+     * The start time for this Step. Returns {@link Workflow#TIME_NOT_SET} if not started yet.
      * 
      * @return the start time
      */
     Date getStartTime();
 
     /**
-     * Gets the Workflow that is the parent of this Step.
-     * 
-     * @return the workflow
-     */
-    Workflow getWorkflow();
-
-    /**
-     * Determines whether the Step is completed; if not, it is by definition
-     * awaiting action by the owner or in process. If a Step has completed, it
-     * <em>must also</em> return a non-<code>null</code> result for
-     * {@link #getOutcome()}.
+     * Determines whether the Step is completed; if not, it is by definition awaiting action by the owner or in process. If a Step has
+     * completed, it <em>must also</em> return a non-<code>null</code> result for {@link #getOutcome()}.
      * 
-     * @return <code>true</code> if the Step has completed; <code>false</code>
-     *         if not.
+     * @return <code>true</code> if the Step has completed; <code>false</code> if not.
      */
     boolean isCompleted();
 
     /**
      * Determines whether the Step has started.
      * 
-     * @return <code>true</code> if the Step has started; <code>false</code>
-     *         if not.
+     * @return <code>true</code> if the Step has started; <code>false</code> if not.
      */
     boolean isStarted();
 
     /**
-     * Starts the Step, and sets the start time to the moment when this method
-     * is first invoked. If this Step has already been started, this method
-     * throws an {@linkplain IllegalStateException}. If the Step cannot
-     * be started because the underlying implementation encounters an error,
-     * it the implementation should throw a WikiException.
+     * Starts the Step, and sets the start time to the moment when this method is first invoked. If this Step has already been started,
+     * this method throws an {@linkplain IllegalStateException}. If the Step cannot be started because the underlying implementation
+     * encounters an error, it the implementation should throw a WikiException.
      * 
      * @throws WikiException if the step encounters errors while starting
      */
     void start() throws WikiException;
 
     /**
-     * Sets the current Outcome for the step. If the Outcome is a "completion"
-     * Outcome, it should also sets the completon time and mark the Step as
-     * complete. Once a Step has been marked complete, this method cannot be
-     * called again. If the supplied Outcome is not in the set returned by
-     * {@link #getAvailableOutcomes()}, or is not  {@link Outcome#STEP_CONTINUE}
-     * or {@link Outcome#STEP_ABORT}, this method returns an
-     * IllegalArgumentException. If the caller attempts to set an Outcome
-     * and the Step has already completed, this method throws an 
-     * IllegalStateException.
+     * Sets the current Outcome for the step. If the Outcome is a "completion" Outcome, it should also sets the completon time and mark the
+     * Step as complete. Once a Step has been marked complete, this method cannot be called again. If the supplied Outcome is not in the
+     * set returned by {@link #getAvailableOutcomes()}, or is not  {@link Outcome#STEP_CONTINUE} or {@link Outcome#STEP_ABORT}, this method
+     * returns an IllegalArgumentException. If the caller attempts to set an Outcome and the Step has already completed, this method throws
+     * an IllegalStateException.
      * 
      * @param outcome whether the step should be considered completed
      */
     void setOutcome( Outcome outcome );
 
     /**
-     * Convenience method that returns the owner of the Workflow by delegating
-     * to {@link Workflow#getOwner()}.
+     * Convenience method that returns the owner of the Workflow by delegating to {@link Workflow#getOwner()}.
      * 
      * @return the owner of the Workflow
      */
     Principal getOwner();
 
     /**
-     * Identifies the next Step for a particular Outcome; if there is no next
-     * Step for this Outcome, this method returns <code>null</code>.
+     * Identifies the next Step for a particular Outcome; if there is no next Step for this Outcome, this method returns <code>null</code>.
      * 
-     * @param outcome
-     *            the outcome
+     * @param outcome the outcome
      * @return the next step
      */
     Step getSuccessor( Outcome outcome );
 
     /**
+     * Gets the Workflow that is the parent of this Step.
+     *
+     * @return the workflow
+     */
+    Workflow getWorkflow();
+
+    /**
      * Sets the parent Workflow post-construction. Should be called after building a {@link Step}.
      *
      * @param workflow the parent workflow to set


[jspwiki] 16/35: use method from Engine

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit f98225f90485e7f5996438eddbe89e85323beea7
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue Apr 14 22:18:38 2020 +0200

    use method from Engine
---
 .../main/java/org/apache/wiki/variables/DefaultVariableManager.java    | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/variables/DefaultVariableManager.java b/jspwiki-main/src/main/java/org/apache/wiki/variables/DefaultVariableManager.java
index d080702..a45591a 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/variables/DefaultVariableManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/variables/DefaultVariableManager.java
@@ -31,7 +31,6 @@ import org.apache.wiki.filters.FilterManager;
 import org.apache.wiki.i18n.InternationalizationManager;
 import org.apache.wiki.modules.InternalModule;
 import org.apache.wiki.pages.PageManager;
-import org.apache.wiki.plugin.PluginManager;
 import org.apache.wiki.preferences.Preferences;
 
 import javax.servlet.http.HttpServletRequest;
@@ -350,7 +349,7 @@ public class DefaultVariableManager implements VariableManager {
         }
 
         public String getPluginpath() {
-            final String s = m_context.getEngine().getManager( PluginManager.class ).getPluginSearchPath();
+            final String s = m_context.getEngine().getPluginSearchPath();
 
             return ( s == null ) ? "-" : s;
         }


[jspwiki] 18/35: update Lucene to 8.5.1 and maven-antrun-plugin to 3.0.0

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 9495d838e46b47d15fed9c7695f1ae6a1cb57da3
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 18 21:31:26 2020 +0200

    update Lucene to 8.5.1 and maven-antrun-plugin to 3.0.0
---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index ca4fc21..895d97c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,7 +66,7 @@
     <jrcs-diff.version>0.4.2</jrcs-diff.version>
     <junit.version>5.6.2</junit.version>
     <log4j.version>1.2.17</log4j.version>
-    <lucene.version>8.5.0</lucene.version>
+    <lucene.version>8.5.1</lucene.version>
     <mockito.version>3.3.3</mockito.version>
     <nekohtml.version>1.9.22</nekohtml.version>
     <oro.version>2.0.8</oro.version>
@@ -79,7 +79,7 @@
     <wro4j.version>1.8.0</wro4j.version>
     <xmlrpc.version>2.0.1</xmlrpc.version>
 
-    <plugin.antrun.version>1.8</plugin.antrun.version>
+    <plugin.antrun.version>3.0.0</plugin.antrun.version>
     <plugin.assembly.version>3.2.0</plugin.assembly.version>
     <plugin.clean.version>3.1.0</plugin.clean.version>
     <plugin.compiler.version>3.8.1</plugin.compiler.version>


[jspwiki] 25/35: Generalize WorkflowEventEmitter to WikiEventEmitter and move it to jspwiki-event module.

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit cbbb8d39963a54f07f17aacce372b4c5b6c352dd
Author: juanpablo <ju...@apache.org>
AuthorDate: Sun May 3 19:56:04 2020 +0200

    Generalize WorkflowEventEmitter to WikiEventEmitter and move it to jspwiki-event module.
    
    All fireEvent methods scattered throughout the code should be slowly moved to this class.
---
 .../org/apache/wiki/event/WikiEventEmitter.java    | 82 ++++++++++++++++++++++
 .../apache/wiki/event/WikiEventEmitterTest.java    | 61 ++++++++++++++++
 .../java/org/apache/wiki/workflow/Decision.java    |  5 +-
 .../wiki/workflow/DefaultWorkflowManager.java      |  3 +-
 .../java/org/apache/wiki/workflow/Workflow.java    | 19 ++---
 .../apache/wiki/workflow/WorkflowEventEmitter.java | 55 ---------------
 6 files changed, 158 insertions(+), 67 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventEmitter.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventEmitter.java
new file mode 100644
index 0000000..579f7c0
--- /dev/null
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventEmitter.java
@@ -0,0 +1,82 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+ */
+package org.apache.wiki.event;
+
+import java.util.Set;
+
+
+/**
+ * Emits all kind of {@link org.apache.wiki.event.WikiEvent}s.
+ */
+public enum WikiEventEmitter {
+
+    INSTANCE;
+
+    public static WikiEventEmitter get() {
+        return INSTANCE;
+    }
+
+    /**
+     * Fires a Workflow Event from provided source and workflow type.
+     *
+     * @param src the source of the event, which can be any object: a wiki page, group or authentication/authentication/group manager.
+     * @param type the type of event
+     * @return fired {@link WorkflowEvent} or {@code null} if the {@link WikiEventEmitter} instance hasn't listeners attached.
+     */
+    public static WorkflowEvent fireWorkflowEvent( final Object src, final int type ) {
+        return fireEvent( new WorkflowEvent( src, type ) );
+    }
+
+    static < T extends WikiEvent > T fireEvent( final T event ) {
+        if( WikiEventManager.isListening( WikiEventEmitter.get() ) ) {
+            WikiEventManager.fireEvent( WikiEventEmitter.get(), event );
+            return event;
+        }
+        return null;
+    }
+
+    /**
+     * Registers a {@link WikiEventListener} so it listens events fired from the {@link WikiEventEmitter} instance. Every other
+     * {@link WikiEventListener} of the same type, listening events from the {@link WikiEventEmitter} instance will stop listening events
+     * from it. This ensures events received by the {@link WikiEventListener} will only process the events once.
+     *
+     * @param listener {@link WikiEventListener}
+     */
+    public static void attach( final WikiEventListener listener ) {
+        if( WikiEventManager.isListening( get() ) ) {
+            final Set< WikiEventListener > attachedListeners = WikiEventManager.getWikiEventListeners( WikiEventEmitter.get() );
+            attachedListeners.stream()
+                             .filter( l -> listener.getClass().isAssignableFrom( l.getClass() ) )
+                             .forEach( WikiEventManager::removeWikiEventListener );
+        }
+        register( listener );
+    }
+
+    /**
+     * Registers a {@link WikiEventListener} so it listens events fired from the {@link WikiEventEmitter} instance. Events received by the
+     * {@link WikiEventListener} could process the events more than once or, several instances of the same {@link WikiEventListener} would
+     * be able to receive the same event.
+     *
+     * @param listener {@link WikiEventListener}
+     */
+    public static void register( final WikiEventListener listener ) {
+        WikiEventManager.addWikiEventListener( WikiEventEmitter.get(), listener );
+    }
+
+}
diff --git a/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventEmitterTest.java b/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventEmitterTest.java
new file mode 100644
index 0000000..40cf552
--- /dev/null
+++ b/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventEmitterTest.java
@@ -0,0 +1,61 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+ */
+package org.apache.wiki.event;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+
+public class WikiEventEmitterTest {
+
+    @BeforeEach
+    public void setUp() {
+        // Ensure no listeners are attached to WikiEventEmitter instance
+        WikiEventManager.getWikiEventListeners( WikiEventEmitter.get() ).forEach( WikiEventManager::removeWikiEventListener );
+    }
+
+    @Test
+    public void shouldCheckFireWorkflowEvent() {
+        Assertions.assertNull( WikiEventEmitter.fireWorkflowEvent( "test", WorkflowEvent.CREATED ) );
+
+        WikiEventEmitter.attach( new TestWikiEventListener() );
+        final WorkflowEvent we = WikiEventEmitter.fireWorkflowEvent( "test", WorkflowEvent.CREATED );
+        Assertions.assertNotNull( we );
+        Assertions.assertEquals( WorkflowEvent.CREATED, we.getType() );
+        Assertions.assertEquals( "test", we.getSource() );
+    }
+
+    @Test
+    public void shouldCheckAttach() {
+        Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( WikiEventEmitter.get() ).size() );
+        WikiEventEmitter.attach( new TestWikiEventListener() );
+        WikiEventEmitter.attach( new TestWikiEventListener() );
+        Assertions.assertEquals( 1, WikiEventManager.getWikiEventListeners( WikiEventEmitter.get() ).size() );
+    }
+
+    @Test
+    public void shouldCheckRegister() {
+        Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( WikiEventEmitter.get() ).size() );
+        WikiEventEmitter.register( new TestWikiEventListener() );
+        WikiEventEmitter.register( new TestWikiEventListener() );
+        Assertions.assertEquals( 2, WikiEventManager.getWikiEventListeners( WikiEventEmitter.get() ).size() );
+    }
+
+}
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
index 9e4f97e..a4e145c 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
@@ -19,6 +19,7 @@
 package org.apache.wiki.workflow;
 
 import org.apache.wiki.api.exceptions.WikiException;
+import org.apache.wiki.event.WikiEventEmitter;
 import org.apache.wiki.event.WorkflowEvent;
 
 import java.io.Serializable;
@@ -107,7 +108,7 @@ public abstract class Decision extends AbstractStep {
      */
     public void decide( final Outcome outcome ) throws WikiException {
         super.setOutcome( outcome );
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.DQ_REMOVAL );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.DQ_REMOVAL );
     }
 
     /**
@@ -124,7 +125,7 @@ public abstract class Decision extends AbstractStep {
         }
 
         // Put decision in the DecisionQueue
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.DQ_ADDITION );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.DQ_ADDITION );
 
         // Indicate we are waiting for user input
         return Outcome.STEP_CONTINUE;
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
index 723b5c0..7efeaaf 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
@@ -25,6 +25,7 @@ import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.auth.AuthorizationManager;
 import org.apache.wiki.auth.acl.UnresolvedPrincipal;
 import org.apache.wiki.event.WikiEvent;
+import org.apache.wiki.event.WikiEventEmitter;
 import org.apache.wiki.event.WorkflowEvent;
 
 import java.security.Principal;
@@ -61,7 +62,7 @@ public class DefaultWorkflowManager implements WorkflowManager {
         m_workflows = ConcurrentHashMap.newKeySet();
         m_approvers = new ConcurrentHashMap<>();
         m_completed = new CopyOnWriteArrayList<>();
-        WorkflowEventEmitter.registerListener( this );
+        WikiEventEmitter.attach( this );
     }
 
     /**
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
index f06dc16..10386c6 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
@@ -19,6 +19,7 @@
 package org.apache.wiki.workflow;
 
 import org.apache.wiki.api.exceptions.WikiException;
+import org.apache.wiki.event.WikiEventEmitter;
 import org.apache.wiki.event.WorkflowEvent;
 
 import java.io.Serializable;
@@ -226,7 +227,7 @@ public class Workflow implements Serializable {
         m_owner = owner;
         m_started = false;
         m_state = CREATED;
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.CREATED );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.CREATED );
     }
 
     /**
@@ -247,13 +248,13 @@ public class Workflow implements Serializable {
 
         if( m_currentStep != null ) {
             if( m_currentStep instanceof Decision ) {
-                WorkflowEventEmitter.fireEvent( m_currentStep, WorkflowEvent.DQ_REMOVAL );
+                WikiEventEmitter.fireWorkflowEvent( m_currentStep, WorkflowEvent.DQ_REMOVAL );
             }
             m_currentStep.setOutcome( Outcome.STEP_ABORT );
             m_history.addLast( m_currentStep );
         }
         m_state = ABORTED;
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.ABORTED );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.ABORTED );
         cleanup();
     }
 
@@ -474,9 +475,9 @@ public class Workflow implements Serializable {
         if( m_state != WAITING ) {
             throw new IllegalStateException( "Workflow is not paused; cannot restart." );
         }
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.STARTED );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.STARTED );
         m_state = RUNNING;
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.RUNNING );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.RUNNING );
 
         // Process current step
         try {
@@ -536,11 +537,11 @@ public class Workflow implements Serializable {
         if( m_started ) {
             throw new IllegalStateException( "Workflow has already started." );
         }
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.STARTED );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.STARTED );
         m_started = true;
         m_state = RUNNING;
 
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.RUNNING );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.RUNNING );
         // Mark the first step as the current one & add to history
         m_currentStep = m_firstStep;
         m_history.add( m_currentStep );
@@ -563,7 +564,7 @@ public class Workflow implements Serializable {
             throw new IllegalStateException( "Workflow is not running; cannot pause." );
         }
         m_state = WAITING;
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.WAITING );
+        WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.WAITING );
     }
 
     /**
@@ -581,7 +582,7 @@ public class Workflow implements Serializable {
     protected final synchronized void complete() {
         if( !isCompleted() ) {
             m_state = COMPLETED;
-            WorkflowEventEmitter.fireEvent( this, WorkflowEvent.COMPLETED );
+            WikiEventEmitter.fireWorkflowEvent( this, WorkflowEvent.COMPLETED );
             cleanup();
         }
     }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
deleted file mode 100644
index 8ecabd5..0000000
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you 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.
- */
-package org.apache.wiki.workflow;
-
-import org.apache.wiki.event.WikiEventListener;
-import org.apache.wiki.event.WikiEventManager;
-import org.apache.wiki.event.WorkflowEvent;
-
-import java.util.Set;
-
-
-/**
- * Emits all kind of {@link WorkflowEvent}s.
- */
-public enum WorkflowEventEmitter {
-
-    INSTANCE;
-
-    public static WorkflowEventEmitter get() {
-        return INSTANCE;
-    }
-
-    public static void fireEvent( final Object src, final int type ) {
-        if ( WikiEventManager.isListening( get() ) ) {
-            WikiEventManager.fireEvent( get(), new WorkflowEvent( src, type ) );
-        }
-    }
-
-    public static void registerListener( final WikiEventListener listener ) {
-        if ( WikiEventManager.isListening( get() ) ) {
-            final Set< WikiEventListener > attachedListeners = WikiEventManager.getWikiEventListeners( get() );
-            attachedListeners.stream()
-                             .filter( l -> listener.getClass().isAssignableFrom( l.getClass() ) )
-                             .forEach( WikiEventManager::removeWikiEventListener );
-        }
-        WikiEventManager.addWikiEventListener( WorkflowEventEmitter.get(), listener );
-    }
-
-}


[jspwiki] 07/35: no need to overload fireEvent methods, DefaultWorkflowManager will only process the workflow events it understands

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 64e50252e084d1fe3f48a05787efb04ab7bcc535
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 18:07:34 2020 +0200

    no need to overload fireEvent methods, DefaultWorkflowManager will only process the workflow events it understands
---
 .../java/org/apache/wiki/workflow/WorkflowEventEmitter.java    | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
index 6ab5f86..8c2f899 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
@@ -33,15 +33,9 @@ public enum WorkflowEventEmitter {
         return INSTANCE;
     }
 
-    public static void fireEvent( final Decision decision, final int type ) {
+    public static void fireEvent( final Object src, final int type ) {
         if ( WikiEventManager.isListening( get() ) ) {
-            WikiEventManager.fireEvent( get(), new WorkflowEvent( decision, type ) );
-        }
-    }
-
-    public static void fireEvent( final Workflow workflow, final int type ) {
-        if ( WikiEventManager.isListening( get() ) ) {
-            WikiEventManager.fireEvent( get(), new WorkflowEvent( workflow, type ) );
+            WikiEventManager.fireEvent( get(), new WorkflowEvent( src, type ) );
         }
     }
 


[jspwiki] 02/35: avoid registering several times the same listener on the same client

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 9f27a1ce4cce3820d907b3dfe5286bb52498bcea
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 17:57:52 2020 +0200

    avoid registering several times the same listener on the same client
---
 .../org/apache/wiki/event/WikiEventManager.java    | 22 ++++---
 .../apache/wiki/event/TestWikiEventListener.java   | 35 +++++++++++
 .../apache/wiki/event/WikiEventManagerTest.java    | 71 ++++++++++++++++++++++
 3 files changed, 121 insertions(+), 7 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java
index dc069e9..95728fd 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java
@@ -29,6 +29,7 @@ import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.Vector;
@@ -230,16 +231,17 @@ public final class WikiEventManager {
     }
 
     /**
-     *  Un-registers a WikiEventListener from any WikiEventDelegate client managed by this WikiEventManager. Since this is a one-to-one
-     *  relation, the first match will be returned upon removal; a true return value indicates the WikiEventListener was found and removed.
+     * Un-registers a WikiEventListener from any WikiEventDelegate client managed by this WikiEventManager. A true return value indicates
+     * the WikiEventListener was found and removed.
      *
      * @param listener the event listener
      * @return true if the listener was found and removed.
      */
     public static boolean removeWikiEventListener( final WikiEventListener listener ) {
+        boolean removed = false;
         // get the Map.entry object for the entire Map, then check match on entry (listener)
         final WikiEventManager mgr = getInstance();
-        final Map< Object, WikiEventDelegate > sources = mgr.getDelegates();
+        final Map< Object, WikiEventDelegate > sources =  Collections.synchronizedMap( mgr.getDelegates() );
         synchronized( sources ) {
             // get an iterator over the Map.Enty objects in the map
             for( final Map.Entry< Object, WikiEventDelegate > entry : sources.entrySet() ) {
@@ -248,11 +250,11 @@ public final class WikiEventManager {
 
                 // now see if we can remove the listener from the delegate (delegate may be null because this is a weak reference)
                 if( delegate != null && delegate.removeWikiEventListener( listener ) ) {
-                    return true; // was removed
+                    removed = true; // was removed
                 }
             }
         }
-        return false;
+        return removed;
     }
 
     /**
@@ -387,13 +389,19 @@ public final class WikiEventManager {
         /**
          *  Adds <tt>listener</tt> as a listener for events fired by the WikiEventDelegate.
          *
-         * @param listener   the WikiEventListener to be added
+         * @param listener the WikiEventListener to be added
          * @return true if the listener was added (i.e., it was not already in the list and was added)
          */
         public boolean addWikiEventListener( final WikiEventListener listener ) {
             synchronized( m_listenerList ) {
-                return m_listenerList.add( new WeakReference<>(listener) );
+                final boolean listenerAlreadyContained = m_listenerList.stream()
+                                                                       .map( WeakReference::get )
+                                                                       .anyMatch( ref -> Objects.equals( ref, listener ) );
+                if( !listenerAlreadyContained ) {
+                    return m_listenerList.add( new WeakReference<>( listener ) );
+                }
             }
+            return false;
         }
 
         /**
diff --git a/jspwiki-event/src/test/java/org/apache/wiki/event/TestWikiEventListener.java b/jspwiki-event/src/test/java/org/apache/wiki/event/TestWikiEventListener.java
new file mode 100644
index 0000000..8372e0a
--- /dev/null
+++ b/jspwiki-event/src/test/java/org/apache/wiki/event/TestWikiEventListener.java
@@ -0,0 +1,35 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+ */
+package org.apache.wiki.event;
+
+public class TestWikiEventListener implements WikiEventListener {
+
+    int invoked = 0;
+
+    /** {@inheritDoc} */
+    @Override
+    public void actionPerformed( final WikiEvent event ) {
+        invoked++;
+    }
+
+    public int getInvoked() {
+        return invoked;
+    }
+
+}
diff --git a/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventManagerTest.java b/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventManagerTest.java
new file mode 100644
index 0000000..8902201
--- /dev/null
+++ b/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventManagerTest.java
@@ -0,0 +1,71 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+ */
+package org.apache.wiki.event;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+
+public class WikiEventManagerTest {
+
+    @Test
+    public void shouldCheckRegisterUnregister() {
+        final String client1 = "test1";
+        final String client2 = "test2";
+        final TestWikiEventListener listener = new TestWikiEventListener();
+        WikiEventManager.addWikiEventListener( client1, listener );
+        Assertions.assertEquals( 1, WikiEventManager.getWikiEventListeners( client1 ).size() );
+        Assertions.assertTrue( WikiEventManager.isListening( client1 ) );
+
+        WikiEventManager.removeWikiEventListener( client1, listener );
+        Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client1 ).size() );
+        Assertions.assertFalse( WikiEventManager.isListening( client1 ) );
+
+        WikiEventManager.addWikiEventListener( client1, listener );
+        WikiEventManager.addWikiEventListener( client2, listener );
+        WikiEventManager.removeWikiEventListener( listener );
+        Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client1 ).size() );
+        Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client2 ).size() );
+    }
+
+    @Test
+    public void shouldCheckAddingSameWikiEventListenerSeveralTimesOnlyGetsRegisteredOnce() {
+        final String client = "test3";
+        final TestWikiEventListener listener = new TestWikiEventListener();
+        WikiEventManager.addWikiEventListener( client, listener );
+        WikiEventManager.addWikiEventListener( client, listener );
+
+        Assertions.assertEquals( 1, WikiEventManager.getWikiEventListeners( client ).size() );
+
+        WikiEventManager.removeWikiEventListener( client, listener );
+        Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client ).size() );
+    }
+
+    @Test
+    public void shouldCheckEventsFiring() {
+        final String client = "test4";
+        final TestWikiEventListener listener = new TestWikiEventListener();
+        WikiEventManager.addWikiEventListener( client, listener );
+        WikiEventManager.fireEvent( client, new WikiPageEvent( "object which fires the event", WikiPageEvent.PAGE_REQUESTED, "page" ) );
+
+        Assertions.assertEquals( 1, listener.getInvoked() );
+        WikiEventManager.removeWikiEventListener( listener ); // dispose listener; if not done, listener would still be attached to test4 on other tests
+    }
+
+}


[jspwiki] 28/35: small test refactor

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 62857b905460a05ccfcfff5287b477b594512198
Author: juanpablo <ju...@apache.org>
AuthorDate: Sun May 3 20:03:40 2020 +0200

    small test refactor
---
 .../test/java/org/apache/wiki/workflow/WorkflowManagerTest.java  | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
index 3db7311..5ec58c7 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
@@ -94,14 +94,7 @@ public class WorkflowManagerTest {
         Assertions.assertEquals( new GroupPrincipal( "Admin" ), wm.getApprover( "workflow.bar" ) );
 
         // 'saveWikiPage' workflow doesn't require approval, so we will need to catch an Exception
-        try {
-            Assertions.assertEquals( new GroupPrincipal( "Admin" ), wm.getApprover( "workflow.saveWikiPage" ) );
-        } catch( final WikiException e ) {
-            // Swallow
-            return;
-        }
-        // We should never get here
-        Assertions.fail( "Workflow.bar doesn't need approval!" );
+        Assertions.assertThrows( WikiException.class, () -> wm.getApprover( "workflow.saveWikiPage" ) );
     }
 
 }


[jspwiki] 27/35: Removed WorkflowManager#start( Workflow ), in favour of Workflow#start()

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit bfbc9bd5058396a54a7c66f5655e0d3823cd86d9
Author: juanpablo <ju...@apache.org>
AuthorDate: Sun May 3 20:02:04 2020 +0200

    Removed WorkflowManager#start( Workflow ), in favour of Workflow#start()
    
    The former was a simple pass-through of the latter, without providing anything else.
---
 .../src/main/java/org/apache/wiki/auth/DefaultUserManager.java   | 2 +-
 .../src/main/java/org/apache/wiki/pages/DefaultPageManager.java  | 2 +-
 .../java/org/apache/wiki/workflow/DefaultWorkflowManager.java    | 8 --------
 .../src/main/java/org/apache/wiki/workflow/WorkflowManager.java  | 9 ---------
 .../test/java/org/apache/wiki/workflow/WorkflowManagerTest.java  | 4 ++--
 5 files changed, 4 insertions(+), 21 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/auth/DefaultUserManager.java b/jspwiki-main/src/main/java/org/apache/wiki/auth/DefaultUserManager.java
index 776f741..605994c 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/auth/DefaultUserManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/auth/DefaultUserManager.java
@@ -273,7 +273,7 @@ public class DefaultUserManager implements UserManager {
                                                                  null );
 
         workflow.setAttribute( WorkflowManager.WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE, profile );
-        m_engine.getManager( WorkflowManager.class ).start( workflow );
+        workflow.start();
 
         final boolean approvalRequired = workflow.getCurrentStep() instanceof Decision;
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
index 30cbe8b..3a318bb 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
@@ -264,7 +264,7 @@ public class DefaultPageManager implements PageManager {
                                                                  facts,
                                                                  completionTask,
                                                                  rejectKey );
-        m_engine.getManager( WorkflowManager.class ).start( workflow );
+        workflow.start();
 
         // Let callers know if the page-save requires approval
         if ( workflow.getCurrentStep() instanceof Decision ) {
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
index 7efeaaf..fb6e648 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
@@ -69,14 +69,6 @@ public class DefaultWorkflowManager implements WorkflowManager {
      * {@inheritDoc}
      */
     @Override
-    public void start( final Workflow workflow ) throws WikiException {
-        workflow.start();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public Set< Workflow > getWorkflows() {
         final Set< Workflow > workflows = ConcurrentHashMap.newKeySet();
         workflows.addAll( m_workflows );
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java
index 064b93b..bd255dd 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowManager.java
@@ -72,15 +72,6 @@ public interface WorkflowManager extends WikiEventListener, Initializable {
     String PROPERTY_APPROVER_PREFIX = "jspwiki.approver.";
 
     /**
-     * Adds a new workflow to the set of workflows and starts it. The new workflow is automatically assigned a unique ID. If another
-     * workflow with the same ID already exists, this method throws a WikIException.
-     *
-     * @param workflow the workflow to start
-     * @throws WikiException if a workflow the automatically assigned ID already exist; this should not happen normally
-     */
-    void start( Workflow workflow ) throws WikiException;
-
-    /**
      * Returns a collection of the currently active workflows.
      *
      * @return the current workflows
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
index 8975859..3db7311 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
@@ -54,7 +54,7 @@ public class WorkflowManagerTest {
     public void testStart() throws WikiException {
         // Once we start the workflow, it should show that it's started and the WM should have assigned it an ID
         Assertions.assertFalse( w.isStarted() );
-        wm.start( w );
+        w.start();
         Assertions.assertNotEquals( Workflow.ID_NOT_SET, w.getId() );
         Assertions.assertTrue( w.isStarted() );
     }
@@ -66,7 +66,7 @@ public class WorkflowManagerTest {
         Assertions.assertEquals( 0, wm.getCompletedWorkflows().size() );
 
         // After starting, there should be 1 in the cache
-        wm.start( w );
+        w.start();
         Assertions.assertEquals( 1, wm.getWorkflows().size() );
         Assertions.assertEquals( 0, wm.getCompletedWorkflows().size() );
         final Workflow workflow = wm.getWorkflows().iterator().next();


[jspwiki] 22/35: Break class cycles between Workflow and Step in order to prepare for JSPWIKI-304 (Workflows are not Serializable)

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 01ee8a5d43b529dcd5cd98bd17a4e0e13c271ba8
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat May 2 19:41:30 2020 +0200

    Break class cycles between Workflow and Step in order to prepare for JSPWIKI-304 (Workflows are not Serializable)
---
 .../wiki/tasks/auth/SaveUserProfileTask.java       |  2 +-
 .../wiki/tasks/pages/PreSaveWikiPageTask.java      | 12 +--
 .../apache/wiki/tasks/pages/SaveWikiPageTask.java  |  4 +-
 .../org/apache/wiki/workflow/AbstractStep.java     | 60 ++++++--------
 .../java/org/apache/wiki/workflow/Decision.java    | 17 ++--
 .../wiki/workflow/DefaultWorkflowManager.java      | 45 +++++-----
 .../org/apache/wiki/workflow/SimpleDecision.java   | 27 +++---
 .../apache/wiki/workflow/SimpleNotification.java   | 53 +++++-------
 .../main/java/org/apache/wiki/workflow/Step.java   | 29 ++-----
 .../main/java/org/apache/wiki/workflow/Task.java   | 74 +++++++----------
 .../java/org/apache/wiki/workflow/Workflow.java    | 21 ++++-
 .../org/apache/wiki/workflow/WorkflowBuilder.java  |  8 +-
 .../apache/wiki/workflow/WorkflowEventEmitter.java | 13 +++
 .../java/org/apache/wiki/auth/UserManagerTest.java |  4 +-
 .../apache/wiki/workflow/ApprovalWorkflowTest.java | 95 +++++++++-------------
 .../apache/wiki/workflow/DecisionQueueTest.java    | 51 ++++++------
 .../apache/wiki/workflow/SimpleDecisionTest.java   |  8 +-
 .../java/org/apache/wiki/workflow/TaskTest.java    | 10 +--
 .../apache/wiki/workflow/WorkflowManagerTest.java  | 13 ++-
 .../org/apache/wiki/workflow/WorkflowTest.java     |  9 +-
 20 files changed, 244 insertions(+), 311 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
index 3cb09a0..18325b3 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
@@ -48,7 +48,7 @@ public class SaveUserProfileTask extends Task {
     @Override
     public Outcome execute() throws WikiException {
         // Retrieve user profile
-        final UserProfile profile = ( UserProfile )getWorkflow().getAttribute( WorkflowManager.WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE );
+        final UserProfile profile = ( UserProfile )getWorkflowContext().get( WorkflowManager.WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE );
 
         // Save the profile (userdatabase will take care of timestamps for us)
         m_engine.getManager( UserManager.class ).getUserDatabase().save( profile );
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java
index c2ed0ac..5e65649 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/PreSaveWikiPageTask.java
@@ -19,14 +19,12 @@
 package org.apache.wiki.tasks.pages;
 
 import org.apache.wiki.api.core.Context;
-import org.apache.wiki.api.core.Engine;
 import org.apache.wiki.api.core.Page;
 import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.filters.FilterManager;
 import org.apache.wiki.tasks.TasksManager;
 import org.apache.wiki.workflow.Outcome;
 import org.apache.wiki.workflow.Task;
-import org.apache.wiki.workflow.Workflow;
 import org.apache.wiki.workflow.WorkflowManager;
 
 import java.security.Principal;
@@ -60,10 +58,6 @@ public class PreSaveWikiPageTask extends Task {
      */
     @Override
     public Outcome execute() throws WikiException {
-        // Retrieve attributes
-        final Engine engine = m_context.getEngine();
-        final Workflow workflow = getWorkflow();
-
         // Get the wiki page
         final Page page = m_context.getPage();
 
@@ -76,11 +70,11 @@ public class PreSaveWikiPageTask extends Task {
         }
 
         // Run the pre-save filters. If any exceptions, add error to list, abort, and redirect
-        final String saveText = engine.getManager( FilterManager.class ).doPreSaveFiltering(m_context, m_proposedText);
+        final String saveText = m_context.getEngine().getManager( FilterManager.class ).doPreSaveFiltering(m_context, m_proposedText);
 
         // Stash the wiki context, old and new text as workflow attributes
-        workflow.setAttribute( WorkflowManager.WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT, m_context );
-        workflow.setAttribute( WorkflowManager.WF_WP_SAVE_FACT_PROPOSED_TEXT, saveText );
+        getWorkflowContext().put( WorkflowManager.WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT, m_context );
+        getWorkflowContext().put( WorkflowManager.WF_WP_SAVE_FACT_PROPOSED_TEXT, saveText );
         return Outcome.STEP_COMPLETE;
     }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java
index 3f83d08..0063c40 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/tasks/pages/SaveWikiPageTask.java
@@ -51,8 +51,8 @@ public class SaveWikiPageTask extends Task {
     @Override
     public Outcome execute() throws WikiException {
         // Retrieve attributes
-        final Context context = ( Context ) getWorkflow().getAttribute( WorkflowManager.WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT );
-        final String proposedText = (String) getWorkflow().getAttribute( WorkflowManager.WF_WP_SAVE_FACT_PROPOSED_TEXT );
+        final Context context = ( Context )getWorkflowContext().get( WorkflowManager.WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT );
+        final String proposedText = ( String )getWorkflowContext().get( WorkflowManager.WF_WP_SAVE_FACT_PROPOSED_TEXT );
 
         final Engine engine = context.getEngine();
         final Page page = context.getPage();
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
index e545990..414aa20 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
@@ -20,7 +20,6 @@ package org.apache.wiki.workflow;
 
 import org.apache.wiki.api.exceptions.WikiException;
 
-import java.io.Serializable;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -53,7 +52,10 @@ public abstract class AbstractStep implements Step {
 
     private final Map< Outcome, Step > m_successors;
 
-    private Workflow m_workflow;
+    private int workflowId;
+
+    /** attribute map. */
+    private Map< String, Object > workflowContext;
 
     private Outcome m_outcome;
 
@@ -63,7 +65,7 @@ public abstract class AbstractStep implements Step {
 
     /**
      * Protected constructor that creates a new Step with a specified message key. After construction, the method
-     * {@link #setWorkflow(Workflow)} should be called.
+     * {@link #setWorkflow(int, Map)} should be called.
      *
      * @param messageKey the Step's message key, such as {@code decision.editPageApproval}. By convention, the message prefix should
      *                   be a lower-case version of the Step's type, plus a period (<em>e.g.</em>, {@code task.} and {@code decision.}).
@@ -82,13 +84,14 @@ public abstract class AbstractStep implements Step {
     /**
      * Constructs a new Step belonging to a specified Workflow and having a specified message key.
      *
-     * @param workflow the workflow the Step belongs to
+     * @param workflowId the parent workflow id to set
+     * @param workflowContext the parent workflow context to set
      * @param messageKey the Step's message key, such as {@code decision.editPageApproval}. By convention, the message prefix should
      *                   be a lower-case version of the Step's type, plus a period (<em>e.g.</em>, {@code task.} and {@code decision.}).
      */
-    public AbstractStep( final Workflow workflow, final String messageKey ) {
+    public AbstractStep( final int workflowId, final Map< String, Object > workflowContext, final String messageKey ) {
         this( messageKey );
-        setWorkflow( workflow );
+        setWorkflow( workflowId, workflowContext );
     }
 
     /**
@@ -133,16 +136,6 @@ public abstract class AbstractStep implements Step {
     /**
      * {@inheritDoc}
      */
-    public final Serializable[] getMessageArguments() {
-        if( m_workflow == null ) {
-            return new Serializable[ 0 ];
-        }
-        return m_workflow.getMessageArguments();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     public final String getMessageKey() {
         return m_key;
     }
@@ -157,16 +150,6 @@ public abstract class AbstractStep implements Step {
     /**
      * {@inheritDoc}
      */
-    public Principal getOwner() {
-        if( m_workflow == null ) {
-            return null;
-        }
-        return m_workflow.getOwner();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     public final Date getStartTime() {
         return m_start;
     }
@@ -174,13 +157,6 @@ public abstract class AbstractStep implements Step {
     /**
      * {@inheritDoc}
      */
-    public final synchronized Workflow getWorkflow() {
-        return m_workflow;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     public final boolean isCompleted() {
         return m_completed;
     }
@@ -235,12 +211,22 @@ public abstract class AbstractStep implements Step {
     // --------------------------Helper methods--------------------------
 
     /**
-     * method that sets the parent Workflow post-construction.
+     * method that sets the parent Workflow id and context post-construction.
      *
-     * @param workflow the parent workflow to set
+     * @param workflowId the parent workflow id to set
+     * @param workflowContext the parent workflow context to set
      */
-    public final synchronized void setWorkflow( final Workflow workflow ) {
-        m_workflow = workflow;
+    public final synchronized void setWorkflow( final int workflowId, final Map< String, Object > workflowContext ) {
+        this.workflowId = workflowId;
+        this.workflowContext = workflowContext;
+    }
+
+    public int getWorkflowId() {
+        return workflowId;
+    }
+
+    public Map< String, Object > getWorkflowContext() {
+        return workflowContext;
     }
 
     /**
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
index dbbabed..07749c1 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Decision.java
@@ -25,6 +25,7 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -61,13 +62,14 @@ public abstract class Decision extends AbstractStep {
     /**
      * Constructs a new Decision for a required "actor" Principal, having a default Outcome.
      *
-     * @param workflow the parent Workflow object
+     * @param workflowId the parent workflow id to set
+     * @param workflowContext the parent workflow context to set
      * @param messageKey the i18n message key that represents the message the actor will see
      * @param actor the Principal (<em>e.g.</em>, a WikiPrincipal, Role, GroupPrincipal) who is required to select an appropriate Outcome
      * @param defaultOutcome the Outcome that the user interface will recommend as the default choice
      */
-    public Decision( final Workflow workflow, final String messageKey, final Principal actor, final Outcome defaultOutcome ) {
-        super( workflow, messageKey );
+    public Decision( final int workflowId, final Map< String, Object > workflowContext, final String messageKey, final Principal actor, final Outcome defaultOutcome ) {
+        super( workflowId, workflowContext, messageKey );
         m_actor = actor;
         m_defaultOutcome = defaultOutcome;
         m_facts = new ArrayList<>();
@@ -104,14 +106,7 @@ public abstract class Decision extends AbstractStep {
      */
     public void decide( final Outcome outcome ) throws WikiException {
         super.setOutcome( outcome );
-
-        // If current workflow is waiting for input, restart it and remove Decision from DecisionQueue
-        final Workflow w = getWorkflow();
-        if( w.getCurrentState() == Workflow.WAITING && this.equals( w.getCurrentStep() ) ) {
-            WorkflowEventEmitter.fireEvent( this, WorkflowEvent.DQ_REMOVAL );
-            // Restart workflow
-            w.restart();
-        }
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.DQ_REMOVAL );
     }
 
     /**
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
index d837611..723b5c0 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
@@ -18,19 +18,20 @@
  */
 package org.apache.wiki.workflow;
 
+import org.apache.log4j.Logger;
 import org.apache.wiki.api.core.Engine;
 import org.apache.wiki.api.core.Session;
 import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.auth.AuthorizationManager;
 import org.apache.wiki.auth.acl.UnresolvedPrincipal;
 import org.apache.wiki.event.WikiEvent;
-import org.apache.wiki.event.WikiEventManager;
 import org.apache.wiki.event.WorkflowEvent;
 
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -45,6 +46,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
  */
 public class DefaultWorkflowManager implements WorkflowManager {
 
+    private static final Logger LOG = Logger.getLogger( DefaultWorkflowManager.class );
+
     private final DecisionQueue m_queue = new DecisionQueue();
     private final Set< Workflow > m_workflows;
     private final Map< String, Principal > m_approvers;
@@ -52,15 +55,13 @@ public class DefaultWorkflowManager implements WorkflowManager {
     private Engine m_engine = null;
 
     /**
-     * Constructs a new WorkflowManager, with an empty workflow cache. New Workflows are automatically assigned unique identifiers,
-     * starting with 1.
+     * Constructs a new WorkflowManager, with an empty workflow cache.
      */
     public DefaultWorkflowManager() {
-        m_next = 1;
         m_workflows = ConcurrentHashMap.newKeySet();
         m_approvers = new ConcurrentHashMap<>();
         m_completed = new CopyOnWriteArrayList<>();
-        WikiEventManager.addWikiEventListener( WorkflowEventEmitter.get(), this );
+        WorkflowEventEmitter.registerListener( this );
     }
 
     /**
@@ -68,8 +69,6 @@ public class DefaultWorkflowManager implements WorkflowManager {
      */
     @Override
     public void start( final Workflow workflow ) throws WikiException {
-        m_workflows.add( workflow );
-        workflow.setId( nextId() );
         workflow.start();
     }
 
@@ -176,19 +175,6 @@ public class DefaultWorkflowManager implements WorkflowManager {
         return m_queue;
     }
 
-    private volatile int m_next;
-
-    /**
-     * Returns the next available unique identifier, which is subsequently incremented.
-     *
-     * @return the id
-     */
-    private synchronized int nextId() {
-        final int current = m_next;
-        m_next++;
-        return current;
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -251,9 +237,6 @@ public class DefaultWorkflowManager implements WorkflowManager {
      * @param workflow the workflow to add
      */
     protected void add( final Workflow workflow ) {
-        if ( workflow.getId() == Workflow.ID_NOT_SET ) {
-            workflow.setId( nextId() );
-        }
         m_workflows.add( workflow );
     }
 
@@ -271,7 +254,21 @@ public class DefaultWorkflowManager implements WorkflowManager {
     }
 
     protected void removeFromDecisionQueue( final Decision decision ) {
-        getDecisionQueue().remove( decision );
+        // If current workflow is waiting for input, restart it and remove Decision from DecisionQueue
+        final int workflowId = decision.getWorkflowId();
+        final Optional< Workflow > optw = m_workflows.stream().filter( w -> w.getId() == workflowId ).findAny();
+        if( optw.isPresent() ) {
+            final Workflow w = optw.get();
+            if( w.getCurrentState() == Workflow.WAITING && decision.equals( w.getCurrentStep() ) ) {
+                getDecisionQueue().remove( decision );
+                // Restart workflow
+                try {
+                    w.restart();
+                } catch( final WikiException e ) {
+                    LOG.error( "restarting workflow #" + w.getId() + " caused " + e.getMessage(), e );
+                }
+            }
+        }
     }
 
     protected void addToDecisionQueue( final Decision decision ) {
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java
index 181c355..bae296a 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleDecision.java
@@ -19,30 +19,27 @@
 package org.apache.wiki.workflow;
 
 import java.security.Principal;
+import java.util.Map;
+
 
 /**
- * Decision subclass that includes two available Outcomes:
- * {@link Outcome#DECISION_APPROVE} or {@link Outcome#DECISION_DENY}.
- * The Decision is reassignable, and the default Outcome is 
- * {@link Outcome#DECISION_APPROVE}.
- * 
+ * Decision subclass that includes two available Outcomes: {@link Outcome#DECISION_APPROVE} or {@link Outcome#DECISION_DENY}.
+ * The Decision is reassignable, and the default Outcome is {@link Outcome#DECISION_APPROVE}.
  */
-public class SimpleDecision extends Decision
-{
+public class SimpleDecision extends Decision {
 
     private static final long serialVersionUID = 8192213077644617341L;
 
     /**
      * Constructs a new SimpleDecision assigned to a specified actor.
-     * @param workflow the parent Workflow
-     * @param messageKey the message key that describes the Decision, which
-     * will be presented in the UI
-     * @param actor the Principal (<em>e.g.</em>, WikiPrincipal,
-     * GroupPrincipal, Role) who will decide
+     *
+     * @param workflowId the parent workflow id to set
+     * @param workflowContext the parent workflow context to set
+     * @param messageKey the message key that describes the Decision, which will be presented in the UI
+     * @param actor the Principal (<em>e.g.</em>, WikiPrincipal, GroupPrincipal, Role) who will decide
      */
-    public SimpleDecision( Workflow workflow, String messageKey, Principal actor )
-    {
-        super( workflow, messageKey, actor, Outcome.DECISION_APPROVE );
+    public SimpleDecision( final int workflowId, final Map< String, Object > workflowContext, final String messageKey, final Principal actor ) {
+        super( workflowId, workflowContext, messageKey, actor, Outcome.DECISION_APPROVE );
 
         // Add the other default outcomes
         super.addSuccessor( Outcome.DECISION_DENY, null );
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java
index d2cfdb0..44d88a2 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/SimpleNotification.java
@@ -18,59 +18,50 @@
  */
 package org.apache.wiki.workflow;
 
-import java.security.Principal;
-
 import org.apache.wiki.api.exceptions.WikiException;
 
+import java.security.Principal;
+import java.util.Map;
+
 /**
- * Decision subclass used for notifications that includes only one available Outcome:
- * {@link Outcome#DECISION_ACKNOWLEDGE}. The Decision is not reassignable, and
- * the default Outcome is {@link Outcome#DECISION_ACKNOWLEDGE}.
+ * Decision subclass used for notifications that includes only one available Outcome: {@link Outcome#DECISION_ACKNOWLEDGE}. The Decision is
+ * not reassignable, and the default Outcome is {@link Outcome#DECISION_ACKNOWLEDGE}.
  * 
  * @since 2.5
  */
-public final class SimpleNotification extends Decision
-{
+public final class SimpleNotification extends Decision {
 
     private static final long serialVersionUID = -3392947495169819527L;
 
     /**
-     * Constructs a new SimpleNotification object with a supplied message key,
-     * associated Workflow, and named actor who must acknowledge the message.
-     * The notification is placed in the Principal's list of queued Decisions.
-     * Because the only available Outcome is
-     * {@link Outcome#DECISION_ACKNOWLEDGE}, the actor can only acknowledge the
-     * message.
+     * Constructs a new SimpleNotification object with a supplied message key, associated Workflow, and named actor who must acknowledge
+     * the message. The notification is placed in the Principal's list of queued Decisions. Because the only available Outcome is
+     * {@link Outcome#DECISION_ACKNOWLEDGE}, the actor can only acknowledge the message.
      * 
-     * @param workflow
-     *            the Workflow to associate this notification with
-     * @param messageKey
-     *            the message key
-     * @param actor
-     *            the Principal who will acknowledge the message
+     * @param workflowId the parent workflow id to set
+     * @param workflowContext the parent workflow context to set
+     * @param messageKey the message key
+     * @param actor the Principal who will acknowledge the message
      */
-    public SimpleNotification( Workflow workflow, String messageKey, Principal actor )
-    {
-        super( workflow, messageKey, actor, Outcome.DECISION_ACKNOWLEDGE );
+    public SimpleNotification( final int workflowId, final Map< String, Object > workflowContext, final String messageKey, final Principal actor ) {
+        super( workflowId, workflowContext, messageKey, actor, Outcome.DECISION_ACKNOWLEDGE );
     }
     
     /**
-     * Convenience method that simply calls {@link #decide(Outcome)} 
-     * with the value {@link Outcome#DECISION_ACKNOWLEDGE}.
+     * Convenience method that simply calls {@link #decide(Outcome)} with the value {@link Outcome#DECISION_ACKNOWLEDGE}.
+     *
      * @throws WikiException never
      */
-    public void acknowledge() throws WikiException
-    {
+    public void acknowledge() throws WikiException {
         this.decide( Outcome.DECISION_ACKNOWLEDGE  );
     }
 
     /**
-     * Notifications cannot be re-assigned, so this method always returns
-     * <code>false</code>.
-     * @return <code>false</code> always
+     * Notifications cannot be re-assigned, so this method always returns <code>false</code>.
+     *
+     * @return <code>false</code> always.
      */
-    public boolean isReassignable()
-    {
+    public boolean isReassignable() {
         return false;
     }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
index 50e3327..5d890cc 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
@@ -25,6 +25,8 @@ import java.security.Principal;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
+
 
 /**
  * <p>
@@ -124,14 +126,6 @@ public interface Step extends Serializable {
     String getMessageKey();
 
     /**
-     * Returns the message arguments for this Step, typically by delegating to the parent Workflow's {@link Workflow#getMessageArguments()}
-     * method.
-     * 
-     * @return the message arguments.
-     */
-    Serializable[] getMessageArguments();
-
-    /**
      * Returns the Outcome of this Step's processing; by default, {@link Outcome#STEP_CONTINUE}.
      * 
      * @return the outcome
@@ -181,13 +175,6 @@ public interface Step extends Serializable {
     void setOutcome( Outcome outcome );
 
     /**
-     * Convenience method that returns the owner of the Workflow by delegating to {@link Workflow#getOwner()}.
-     * 
-     * @return the owner of the Workflow
-     */
-    Principal getOwner();
-
-    /**
      * Identifies the next Step for a particular Outcome; if there is no next Step for this Outcome, this method returns <code>null</code>.
      * 
      * @param outcome the outcome
@@ -196,17 +183,11 @@ public interface Step extends Serializable {
     Step getSuccessor( Outcome outcome );
 
     /**
-     * Gets the Workflow that is the parent of this Step.
-     *
-     * @return the workflow
-     */
-    Workflow getWorkflow();
-
-    /**
      * Sets the parent Workflow post-construction. Should be called after building a {@link Step}.
      *
-     * @param workflow the parent workflow to set
+     * @param workflowId the parent workflow id to set
+     * @param workflowContext the parent workflow context to set
      */
-    void setWorkflow( Workflow workflow );
+    void setWorkflow( final int workflowId, final Map< String, Object > workflowContext );
 
 }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java
index dd88086..5e560ee 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Task.java
@@ -19,93 +19,77 @@
 package org.apache.wiki.workflow;
 
 import java.security.Principal;
+import java.util.Map;
+
 
 /**
- * AbstractStep subclass that executes instructions, uninterrupted, and results
- * in an Outcome. Concrete classes only need to implement {@link Task#execute()}.
- * When the execution step completes, <code>execute</code> must return
- * {@link Outcome#STEP_COMPLETE}, {@link Outcome#STEP_CONTINUE} or
- * {@link Outcome#STEP_ABORT}. Subclasses can add any errors by calling the
- * helper method {@link AbstractStep#addError(String)}. The execute method should
- * <em>generally</em> capture and add errors to the error list instead of
+ * AbstractStep subclass that executes instructions, uninterrupted, and results in an Outcome. Concrete classes only need to implement
+ * {@link Task#execute()}. When the execution step completes, <code>execute</code> must return {@link Outcome#STEP_COMPLETE},
+ * {@link Outcome#STEP_CONTINUE} or {@link Outcome#STEP_ABORT}. Subclasses can add any errors by calling the helper method
+ * {@link AbstractStep#addError(String)}. The execute method should <em>generally</em> capture and add errors to the error list instead of
  * throwing a WikiException.
  * <p>
  *
  * @since 2.5
  */
-public abstract class Task extends AbstractStep
-{
+public abstract class Task extends AbstractStep {
+
     private static final long serialVersionUID = 4630293957752430807L;
-    
+
     private Step m_successor = null;
 
     /**
-     * Protected constructor that creates a new Task with a specified message key.
-     * After construction, the protected method {@link #setWorkflow(Workflow)} should be
-     * called.
+     * Public constructor that creates a new Task with a specified message key. After construction, the protected method
+     * {@link #setWorkflow(int, Map)} should be called.
      *
-     * @param messageKey
-     *            the Step's message key, such as
-     *            <code>decision.editPageApproval</code>. By convention, the
-     *            message prefix should be a lower-case version of the Step's
-     *            type, plus a period (<em>e.g.</em>, <code>task.</code>
-     *            and <code>decision.</code>).
+     * @param messageKey the Step's message key, such as <code>decision.editPageApproval</code>. By convention, the message prefix should be
+     *                   a lower-case version of the Step's type, plus a period (<em>e.g.</em>, <code>task.</code> and <code>decision.</code>).
      */
-    public Task( String messageKey )
-    {
+    public Task( final String messageKey ) {
         super( messageKey );
         super.addSuccessor( Outcome.STEP_COMPLETE, null );
         super.addSuccessor( Outcome.STEP_ABORT, null );
     }
 
     /**
-     * Constructs a new instance of a Task, with an associated Workflow and
-     * message key.
+     * Constructs a new instance of a Task, with an associated Workflow and message key.
      *
-     * @param workflow
-     *            the associated workflow
-     * @param messageKey
-     *            the i18n message key
+     * @param workflowId      the parent workflow id to set
+     * @param workflowContext the parent workflow context to set
+     * @param messageKey      the i18n message key
      */
-    public Task( Workflow workflow, String messageKey )
-    {
+    public Task( final int workflowId, final Map< String, Object > workflowContext, final String messageKey ) {
         this( messageKey );
-        setWorkflow( workflow );
+        setWorkflow( workflowId, workflowContext );
     }
 
     /**
      * Returns {@link SystemPrincipal#SYSTEM_USER}.
+     *
      * @return the system principal
      */
-    public final Principal getActor()
-    {
+    public final Principal getActor() {
         return SystemPrincipal.SYSTEM_USER;
     }
 
     /**
-     * Sets the successor Step to this one, which will be triggered if the Task
-     * completes successfully (that is, {@link Step#getOutcome()} returns
-     * {@link Outcome#STEP_COMPLETE}. This method is really a convenient
-     * shortcut for {@link Step#addSuccessor(Outcome, Step)}, where the first
-     * parameter is {@link Outcome#STEP_COMPLETE}.
+     * Sets the successor Step to this one, which will be triggered if the Task completes successfully (that is, {@link Step#getOutcome()}
+     * returns {@link Outcome#STEP_COMPLETE}. This method is really a convenient shortcut for {@link Step#addSuccessor(Outcome, Step)},
+     * where the first parameter is {@link Outcome#STEP_COMPLETE}.
      *
-     * @param step
-     *            the successor
+     * @param step the successor
      */
-    public final synchronized void setSuccessor( Step step )
-    {
+    public final synchronized void setSuccessor( final Step step ) {
         m_successor = step;
     }
 
     /**
-     * Identifies the next Step after this Task finishes successfully. This
-     * method will always return the value set in method
+     * Identifies the next Step after this Task finishes successfully. This method will always return the value set in method
      * {@link #setSuccessor(Step)}, regardless of the current completion state.
      *
      * @return the next step
      */
-    public final synchronized Step getSuccessor()
-    {
+    public final synchronized Step getSuccessor() {
         return m_successor;
     }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
index 7657b27..42c6c2f 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
@@ -30,6 +30,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 
 /**
@@ -164,6 +165,8 @@ public class Workflow implements Serializable {
 
     private static final long serialVersionUID = 5228149040690660032L;
 
+    private static final AtomicInteger idsCounter = new AtomicInteger( 1 );
+
     /** ID value: the workflow ID has not been set. */
     public static final int ID_NOT_SET = 0;
 
@@ -217,12 +220,13 @@ public class Workflow implements Serializable {
         m_attributes = new ConcurrentHashMap<>();
         m_currentStep = null;
         m_history = new LinkedList<>();
-        m_id = ID_NOT_SET;
+        m_id = idsCounter.getAndIncrement();
         m_key = messageKey;
         m_messageArgs = new ArrayList<>();
         m_owner = owner;
         m_started = false;
         m_state = CREATED;
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.CREATED );
     }
 
     /**
@@ -243,7 +247,7 @@ public class Workflow implements Serializable {
 
         if( m_currentStep != null ) {
             if( m_currentStep instanceof Decision ) {
-                WorkflowEventEmitter.fireEvent( ( Decision )m_currentStep, WorkflowEvent.DQ_REMOVAL );
+                WorkflowEventEmitter.fireEvent( m_currentStep, WorkflowEvent.DQ_REMOVAL );
             }
             m_currentStep.setOutcome( Outcome.STEP_ABORT );
             m_history.addLast( m_currentStep );
@@ -313,6 +317,15 @@ public class Workflow implements Serializable {
     }
 
     /**
+     * Retrieves workflow's attributes.
+     *
+     * @return workflow's attributes.
+     */
+    public final Map< String, Object > getAttributes() {
+        return m_attributes;
+    }
+
+    /**
      * The end time for this Workflow, expressed as a system time number. This value is equal to the end-time value returned by the final
      * Step's {@link Step#getEndTime()} method, if the workflow has completed. Otherwise, this method returns {@link Step#TIME_NOT_SET}.
      *
@@ -461,6 +474,7 @@ public class Workflow implements Serializable {
         if( m_state != WAITING ) {
             throw new IllegalStateException( "Workflow is not paused; cannot restart." );
         }
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.STARTED );
         m_state = RUNNING;
         WorkflowEventEmitter.fireEvent( this, WorkflowEvent.RUNNING );
 
@@ -522,10 +536,11 @@ public class Workflow implements Serializable {
         if( m_started ) {
             throw new IllegalStateException( "Workflow has already started." );
         }
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.STARTED );
         m_started = true;
         m_state = RUNNING;
-        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.RUNNING );
 
+        WorkflowEventEmitter.fireEvent( this, WorkflowEvent.RUNNING );
         // Mark the first step as the current one & add to history
         m_currentStep = m_firstStep;
         m_history.add( m_currentStep );
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java
index 9a8e7f2..b497147 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java
@@ -117,7 +117,7 @@ public final class WorkflowBuilder {
         if ( decisionRequired ) {
             // Look up the name of the approver (user or group) listed in jspwiki.properties; approvals go to the approver's decision queue
             final Principal approverPrincipal = mgr.getApprover( workflowApproverKey );
-            final Decision decision = new SimpleDecision( workflow, decisionKey, approverPrincipal );
+            final Decision decision = new SimpleDecision( workflow.getId(), workflow.getAttributes(), decisionKey, approverPrincipal );
 
             // Add facts to the Decision, if any were supplied
             if( facts != null ) {
@@ -132,7 +132,7 @@ public final class WorkflowBuilder {
 
             // If rejected, sent a notification
             if ( rejectedMessageKey != null ) {
-                final SimpleNotification rejectNotification = new SimpleNotification( workflow, rejectedMessageKey, submitter );
+                final SimpleNotification rejectNotification = new SimpleNotification( workflow.getId(), workflow.getAttributes(), rejectedMessageKey, submitter );
                 decision.addSuccessor( Outcome.DECISION_DENY, rejectNotification );
             }
 
@@ -158,9 +158,9 @@ public final class WorkflowBuilder {
 
         // Make sure our tasks have this workflow as the parent, then return
         if( prepTask != null ) {
-            prepTask.setWorkflow( workflow );
+            prepTask.setWorkflow( workflow.getId(), workflow.getAttributes() );
         }
-        completionTask.setWorkflow( workflow );
+        completionTask.setWorkflow( workflow.getId(), workflow.getAttributes() );
         return workflow;
     }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
index 8c2f899..8ecabd5 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowEventEmitter.java
@@ -18,9 +18,12 @@
  */
 package org.apache.wiki.workflow;
 
+import org.apache.wiki.event.WikiEventListener;
 import org.apache.wiki.event.WikiEventManager;
 import org.apache.wiki.event.WorkflowEvent;
 
+import java.util.Set;
+
 
 /**
  * Emits all kind of {@link WorkflowEvent}s.
@@ -39,4 +42,14 @@ public enum WorkflowEventEmitter {
         }
     }
 
+    public static void registerListener( final WikiEventListener listener ) {
+        if ( WikiEventManager.isListening( get() ) ) {
+            final Set< WikiEventListener > attachedListeners = WikiEventManager.getWikiEventListeners( get() );
+            attachedListeners.stream()
+                             .filter( l -> listener.getClass().isAssignableFrom( l.getClass() ) )
+                             .forEach( WikiEventManager::removeWikiEventListener );
+        }
+        WikiEventManager.addWikiEventListener( WorkflowEventEmitter.get(), listener );
+    }
+
 }
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/auth/UserManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/auth/UserManagerTest.java
index 7565109..aecf7de 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/auth/UserManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/auth/UserManagerTest.java
@@ -326,7 +326,7 @@ public class UserManagerTest {
         Assertions.assertEquals( new Fact( WorkflowManager.WF_UP_CREATE_SAVE_FACT_PREFS_LOGIN_NAME, profile.getLoginName() ), facts.get( 1 ) );
         Assertions.assertEquals( new Fact( WorkflowManager.WF_UP_CREATE_SAVE_FACT_SUBMITTER, session.getUserPrincipal().getName() ), facts.get( 2 ) );
         Assertions.assertEquals( new Fact( WorkflowManager.WF_UP_CREATE_SAVE_FACT_PREFS_EMAIL, profile.getEmail() ), facts.get( 3 ) );
-        Assertions.assertEquals( profile, d.getWorkflow().getAttribute( WorkflowManager.WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE ) );
+        Assertions.assertEquals( profile, d.getWorkflowContext().get( WorkflowManager.WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE ) );
 
         // Approve the profile
         d.decide( Outcome.DECISION_APPROVE );
@@ -377,7 +377,7 @@ public class UserManagerTest {
         Assertions.assertEquals( new Fact( WorkflowManager.WF_UP_CREATE_SAVE_FACT_PREFS_LOGIN_NAME, profile.getLoginName() ), facts.get( 1 ) );
         Assertions.assertEquals( new Fact( WorkflowManager.WF_UP_CREATE_SAVE_FACT_SUBMITTER, session.getUserPrincipal().getName() ), facts.get( 2 ) );
         Assertions.assertEquals( new Fact( WorkflowManager.WF_UP_CREATE_SAVE_FACT_PREFS_EMAIL, profile.getEmail() ), facts.get( 3 ) );
-        Assertions.assertEquals( profile, d.getWorkflow().getAttribute( WorkflowManager.WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE ) );
+        Assertions.assertEquals( profile, d.getWorkflowContext().get( WorkflowManager.WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE ) );
 
         // Approve the profile
         d.decide( Outcome.DECISION_DENY );
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
index 7f25b9e..ba05915 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
@@ -28,36 +28,22 @@ import org.apache.wiki.auth.WikiPrincipal;
 import org.apache.wiki.filters.FilterManager;
 import org.apache.wiki.pages.PageManager;
 import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import java.security.Principal;
 import java.util.Collection;
 import java.util.List;
-import java.util.Properties;
 
-public class ApprovalWorkflowTest {
-
-    WorkflowBuilder m_builder;
-    TestEngine m_engine;
-    WorkflowManager m_wm;
-    DecisionQueue m_dq;
-
-    @BeforeEach
-    public void setUp() throws Exception {
-        final Properties props = TestEngine.getTestProperties();
+import static org.apache.wiki.TestEngine.with;
 
-        // Explicitly turn on Admin approvals for page saves and our sample approval workflow
-        props.put("jspwiki.approver.workflow.saveWikiPage", "Admin");
-        props.put( "jspwiki.approver.workflow.approvalWorkflow", Users.JANNE );
 
-        // Start the wiki engine
-        m_engine = new TestEngine( props );
-        m_wm = m_engine.getManager( WorkflowManager.class );
-        m_dq = m_wm.getDecisionQueue();
-        m_builder = WorkflowBuilder.getBuilder( m_engine );
-    }
+public class ApprovalWorkflowTest {
 
+    static TestEngine m_engine = TestEngine.build( with( "jspwiki.approver.workflow.saveWikiPage", "Admin" ),
+                                                   with( "jspwiki.approver.workflow.approvalWorkflow", Users.JANNE ) );
+    static WorkflowManager m_wm = m_engine.getManager( WorkflowManager.class );
+    static DecisionQueue m_dq = m_wm.getDecisionQueue();
+    static WorkflowBuilder m_builder = WorkflowBuilder.getBuilder( m_engine );
 
     @Test
     public void testBuildApprovalWorkflow() throws WikiException {
@@ -66,15 +52,15 @@ public class ApprovalWorkflowTest {
         final Task prepTask = new TestPrepTask( "task.preSaveWikiPage" );
         final String decisionKey = "decision.saveWikiPage";
         final Fact[] facts = new Fact[3];
-        facts[0] = new Fact("fact1", 1 );
-        facts[1] = new Fact("fact2","A factual String");
-        facts[2] = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
+        facts[ 0 ] = new Fact( "fact1", 1 );
+        facts[ 1 ] = new Fact( "fact2", "A factual String" );
+        facts[ 2 ] = new Fact( "fact3", Outcome.DECISION_ACKNOWLEDGE );
         final Task completionTask = new TestPrepTask( "task.saveWikiPage" );
         final String rejectedMessageKey = "notification.saveWikiPage.reject";
 
-        final Workflow w = m_builder.buildApprovalWorkflow(submitter, workflowApproverKey,
-                                                   prepTask, decisionKey, facts,
-                                                   completionTask, rejectedMessageKey);
+        final Workflow w = m_builder.buildApprovalWorkflow( submitter, workflowApproverKey,
+                                                            prepTask, decisionKey, facts,
+                                                            completionTask, rejectedMessageKey );
 
         // Check to see if the workflow built correctly
         Assertions.assertFalse( w.isStarted() || w.isCompleted() || w.isAborted() );
@@ -137,10 +123,10 @@ public class ApprovalWorkflowTest {
         final String workflowApproverKey = "workflow.approvalWorkflow";
         final Task prepTask = new TestPrepTask( "task.preSaveWikiPage" );
         final String decisionKey = "decision.saveWikiPage";
-        final Fact[] facts = new Fact[3];
-        facts[0] = new Fact("fact1", 1 );
-        facts[1] = new Fact("fact2","A factual String");
-        facts[2] = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
+        final Fact[] facts = new Fact[ 3 ];
+        facts[ 0 ] = new Fact( "fact1", 1 );
+        facts[ 1 ] = new Fact( "fact2", "A factual String" );
+        facts[ 2 ] = new Fact( "fact3", Outcome.DECISION_ACKNOWLEDGE );
         final Task completionTask = new TestPrepTask( "task.saveWikiPage" );
         final String rejectedMessageKey = "notification.saveWikiPage.reject";
 
@@ -177,25 +163,23 @@ public class ApprovalWorkflowTest {
         // Create a sample test page and try to save it
         final String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();
         final String text = "This is a test!";
-        try {
-            m_engine.saveTextAsJanne( pageName, text );
-        } catch( final DecisionRequiredException e ) {
-            // Swallow exception, because it is expected...
-        }
+
+        // Expected exception...
+        Assertions.assertThrows( DecisionRequiredException.class, () -> m_engine.saveTextAsJanne( pageName, text ) );
 
         // How do we know the workflow works? Well, first of all the page shouldn't exist yet...
-        Assertions.assertFalse( m_engine.getManager( PageManager.class ).wikiPageExists(pageName));
+        Assertions.assertFalse( m_engine.getManager( PageManager.class ).wikiPageExists( pageName ) );
 
         // Second, GroupPrincipal Admin should see a Decision in its queue
         Collection< Decision > decisions = m_dq.getActorDecisions( m_engine.adminSession() );
-        Assertions.assertEquals(1, decisions.size());
+        Assertions.assertEquals( 1, decisions.size() );
 
         // Now, approve the decision and it should go away, and page should appear.
         final Decision decision = decisions.iterator().next();
-        decision.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertTrue( m_engine.getManager( PageManager.class ).wikiPageExists(pageName));
+        decision.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertTrue( m_engine.getManager( PageManager.class ).wikiPageExists( pageName ) );
         decisions = m_dq.getActorDecisions( m_engine.adminSession() );
-        Assertions.assertEquals(0, decisions.size());
+        Assertions.assertEquals( 0, decisions.size() );
 
         // Delete the page we created
         m_engine.getManager( PageManager.class ).deletePage( pageName );
@@ -213,27 +197,27 @@ public class ApprovalWorkflowTest {
         }
 
         // How do we know the workflow works? Well, first of all the page shouldn't exist yet...
-        Assertions.assertFalse( m_engine.getManager( PageManager.class ).wikiPageExists(pageName));
+        Assertions.assertFalse( m_engine.getManager( PageManager.class ).wikiPageExists( pageName ) );
 
         // ...and there should be a Decision in GroupPrincipal Admin's queue
         Collection< Decision > decisions = m_dq.getActorDecisions( m_engine.adminSession() );
-        Assertions.assertEquals(1, decisions.size());
+        Assertions.assertEquals( 1, decisions.size() );
 
         // Now, DENY the decision and the page should still not exist...
         Decision decision = decisions.iterator().next();
-        decision.decide(Outcome.DECISION_DENY);
-        Assertions.assertFalse( m_engine.getManager( PageManager.class ).wikiPageExists(pageName) );
+        decision.decide( Outcome.DECISION_DENY );
+        Assertions.assertFalse( m_engine.getManager( PageManager.class ).wikiPageExists( pageName ) );
 
         // ...but there should also be a notification decision in Janne's queue
         decisions = m_dq.getActorDecisions( m_engine.janneSession() );
-        Assertions.assertEquals(1, decisions.size());
+        Assertions.assertEquals( 1, decisions.size() );
         decision = decisions.iterator().next();
-        Assertions.assertEquals(WorkflowManager.WF_WP_SAVE_REJECT_MESSAGE_KEY, decision.getMessageKey());
+        Assertions.assertEquals( WorkflowManager.WF_WP_SAVE_REJECT_MESSAGE_KEY, decision.getMessageKey() );
 
         // Once Janne disposes of the notification, his queue should be empty
-        decision.decide(Outcome.DECISION_ACKNOWLEDGE);
+        decision.decide( Outcome.DECISION_ACKNOWLEDGE );
         decisions = m_dq.getActorDecisions( m_engine.janneSession() );
-        Assertions.assertEquals(0, decisions.size());
+        Assertions.assertEquals( 0, decisions.size() );
     }
 
     @Test
@@ -245,12 +229,9 @@ public class ApprovalWorkflowTest {
         // Create a sample test page and try to save it
         final String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();
         final String text = "This is a test!";
-        try
-        {
+        try {
             m_engine.saveTextAsJanne(pageName, text);
-        }
-        catch ( final WikiException e )
-        {
+        } catch( final WikiException e ) {
             Assertions.assertTrue( e instanceof FilterException );
             Assertions.assertEquals( "Page save aborted.", e.getMessage() );
             return;
@@ -262,8 +243,8 @@ public class ApprovalWorkflowTest {
      * Sample "prep task" that sets an attribute in the workflow indicating
      * that it ran successfully,
      */
-    public static class TestPrepTask extends Task
-    {
+    public static class TestPrepTask extends Task {
+
         private static final long serialVersionUID = 1L;
 
         public TestPrepTask( final String messageKey )
@@ -273,7 +254,7 @@ public class ApprovalWorkflowTest {
 
         @Override
         public Outcome execute() {
-            getWorkflow().setAttribute( getMessageKey(), "Completed" );
+            getWorkflowContext().put( getMessageKey(), "Completed" );
             setOutcome( Outcome.STEP_COMPLETE );
             return Outcome.STEP_COMPLETE;
         }
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java
index 9ac1201..fdcf1f9 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java
@@ -54,12 +54,12 @@ public class DecisionQueueTest {
         adminSession = m_engine.adminSession();
         janneSession = m_engine.janneSession();
         w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
-        d1 = new SimpleDecision(w, "decision1.key", new GroupPrincipal("Admin"));
-        d2 = new SimpleDecision(w, "decision2.key", new WikiPrincipal("Owner2"));
-        d3 = new SimpleDecision(w, "decision3.key", janneSession.getUserPrincipal());
-        m_queue.add(d1);
-        m_queue.add(d2);
-        m_queue.add(d3);
+        d1 = new SimpleDecision( w.getId(), w.getAttributes(), "decision1.key", new GroupPrincipal( "Admin" ) );
+        d2 = new SimpleDecision( w.getId(), w.getAttributes(), "decision2.key", new WikiPrincipal( "Owner2" ) );
+        d3 = new SimpleDecision( w.getId(), w.getAttributes(), "decision3.key", janneSession.getUserPrincipal() );
+        m_queue.add( d1 );
+        m_queue.add( d2 );
+        m_queue.add( d3 );
     }
 
     @Test
@@ -150,38 +150,37 @@ public class DecisionQueueTest {
     }
 
     @Test
-    public void testDecisionWorkflow() throws WikiException
-    {
+    public void testDecisionWorkflow() throws WikiException {
         final Principal janne = janneSession.getUserPrincipal();
 
         // Clean out the queue first
-        m_queue.remove(d1);
-        m_queue.remove(d2);
-        m_queue.remove(d3);
+        m_queue.remove( d1 );
+        m_queue.remove( d2 );
+        m_queue.remove( d3 );
 
         // Create a workflow with 3 steps, with a Decision for Janne in the middle
-        w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
-        final Step startTask = new TaskTest.NormalTask(w);
-        final Step endTask = new TaskTest.NormalTask(w);
-        final Decision decision = new SimpleDecision(w, "decision.Actor1Decision", janne);
-        startTask.addSuccessor(Outcome.STEP_COMPLETE, decision);
-        decision.addSuccessor(Outcome.DECISION_APPROVE, endTask);
-        w.setFirstStep(startTask);
+        w = new Workflow( "workflow.key", new WikiPrincipal( "Owner1" ) );
+        final Step startTask = new TaskTest.NormalTask( w );
+        final Step endTask = new TaskTest.NormalTask( w );
+        final Decision decision = new SimpleDecision( w.getId(), w.getAttributes(), "decision.Actor1Decision", janne );
+        startTask.addSuccessor( Outcome.STEP_COMPLETE, decision );
+        decision.addSuccessor( Outcome.DECISION_APPROVE, endTask );
+        w.setFirstStep( startTask );
 
         // Start the workflow, and verify that the Decision is the current Step
         w.start();
-        Assertions.assertEquals(decision, w.getCurrentStep());
+        Assertions.assertEquals( decision, w.getCurrentStep() );
 
         // Verify that it's also in Janne's DecisionQueue
-        Collection< Decision > decisions = m_queue.getActorDecisions(janneSession);
-        Assertions.assertEquals(1, decisions.size());
-        final Decision d = (Decision)decisions.iterator().next();
-        Assertions.assertEquals(decision, d);
+        Collection< Decision > decisions = m_queue.getActorDecisions( janneSession );
+        Assertions.assertEquals( 1, decisions.size() );
+        final Decision d = ( Decision )decisions.iterator().next();
+        Assertions.assertEquals( decision, d );
 
         // Make Decision, and verify that it's gone from the queue
-        m_queue.decide(decision, Outcome.DECISION_APPROVE);
-        decisions = m_queue.getActorDecisions(janneSession);
-        Assertions.assertEquals(0, decisions.size());
+        m_queue.decide( decision, Outcome.DECISION_APPROVE );
+        decisions = m_queue.getActorDecisions( janneSession );
+        Assertions.assertEquals( 0, decisions.size() );
     }
 
 }
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
index 5bf3539..6cd4e86 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
@@ -36,7 +36,7 @@ public class SimpleDecisionTest {
     @BeforeEach
     public void setUp() throws Exception {
         m_workflow = new Workflow( "workflow.key", new WikiPrincipal( "Owner1" ) );
-        m_decision = new SimpleDecision( m_workflow, "decision.key", new WikiPrincipal( "Actor1" ) );
+        m_decision = new SimpleDecision( m_workflow.getId(), m_workflow.getAttributes(), "decision.key", new WikiPrincipal( "Actor1" ) );
     }
 
     @Test
@@ -79,11 +79,11 @@ public class SimpleDecisionTest {
     @Test
     public void testSuccessors() {
         // If the decision is approved, branch to another decision (d2)
-        final Step d2 = new SimpleDecision( m_workflow, "decision2.key", new WikiPrincipal( "Actor1" ) );
+        final Step d2 = new SimpleDecision( m_workflow.getId(), m_workflow.getAttributes(), "decision2.key", new WikiPrincipal( "Actor1" ) );
         m_decision.addSuccessor( Outcome.DECISION_APPROVE, d2 );
 
         // If the decision is denied, branch to another decision (d3)
-        final Step d3 = new SimpleDecision( m_workflow, "decision3.key", new WikiPrincipal( "Actor1" ) );
+        final Step d3 = new SimpleDecision( m_workflow.getId(), m_workflow.getAttributes(), "decision3.key", new WikiPrincipal( "Actor1" ) );
         m_decision.addSuccessor( Outcome.DECISION_DENY, d3 );
 
         Assertions.assertEquals( d2, m_decision.getSuccessor( Outcome.DECISION_APPROVE ) );
@@ -148,7 +148,7 @@ public class SimpleDecisionTest {
 
     @Test
     public void testGetWorkflow() {
-        Assertions.assertEquals( m_workflow, m_decision.getWorkflow() );
+        Assertions.assertEquals( m_workflow.getId(), m_decision.getWorkflowId() );
     }
 
     @Test
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java
index 6e330c0..53612e9 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java
@@ -40,7 +40,7 @@ public class TaskTest
 
         public NormalTask( final Workflow workflow)
         {
-            super(workflow, "task.normal");
+            super(workflow.getId(), workflow.getAttributes(), "task.normal");
         }
         public Outcome execute() throws WikiException
         {
@@ -56,7 +56,7 @@ public class TaskTest
 
         public ErrorTask( final Workflow workflow)
         {
-            super(workflow, "task.error");
+            super(workflow.getId(), workflow.getAttributes(), "task.error");
         }
         public Outcome execute() throws WikiException
         {
@@ -86,11 +86,11 @@ public class TaskTest
     public void testSuccessors()
     {
         // If task finishes normally, branch to a decision (d1)
-        final Step d1 = new SimpleDecision(m_workflow, "decision1.key", new WikiPrincipal("Actor1"));
+        final Step d1 = new SimpleDecision(m_workflow.getId(), m_workflow.getAttributes(), "decision1.key", new WikiPrincipal("Actor1"));
         m_task.addSuccessor(Outcome.STEP_COMPLETE, d1);
 
         // If the task aborts, branch to an alternate decision (d2)
-        final Step d2 = new SimpleDecision(m_workflow, "decision2.key", new WikiPrincipal("Actor2"));
+        final Step d2 = new SimpleDecision(m_workflow.getId(), m_workflow.getAttributes(), "decision2.key", new WikiPrincipal("Actor2"));
         m_task.addSuccessor(Outcome.STEP_ABORT, d2);
 
         Assertions.assertEquals(d1, m_task.getSuccessor(Outcome.STEP_COMPLETE));
@@ -171,7 +171,7 @@ public class TaskTest
     @Test
     public void testGetWorkflow()
     {
-        Assertions.assertEquals(m_workflow, m_task.getWorkflow());
+        Assertions.assertEquals(m_workflow.getId(), m_task.getWorkflowId() );
     }
 
     @Test
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
index 2597ca9..8975859 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
@@ -41,7 +41,7 @@ public class WorkflowManagerTest {
         w = new Workflow( "workflow.key", new WikiPrincipal( "Owner1" ) );
         final Step startTask = new TaskTest.NormalTask( w );
         final Step endTask = new TaskTest.NormalTask( w );
-        final Decision decision = new SimpleDecision( w, "decision.editWikiApproval", new WikiPrincipal( "Actor1" ) );
+        final Decision decision = new SimpleDecision( w.getId(), w.getAttributes(), "decision.editWikiApproval", new WikiPrincipal( "Actor1" ) );
         startTask.addSuccessor( Outcome.STEP_COMPLETE, decision );
         decision.addSuccessor( Outcome.DECISION_APPROVE, endTask );
         w.setFirstStep( startTask );
@@ -52,9 +52,7 @@ public class WorkflowManagerTest {
 
     @Test
     public void testStart() throws WikiException {
-        // Once we start the workflow, it should show that it's started
-        // and the WM should have assigned it an ID
-        Assertions.assertEquals( Workflow.ID_NOT_SET, w.getId() );
+        // Once we start the workflow, it should show that it's started and the WM should have assigned it an ID
         Assertions.assertFalse( w.isStarted() );
         wm.start( w );
         Assertions.assertNotEquals( Workflow.ID_NOT_SET, w.getId() );
@@ -63,17 +61,16 @@ public class WorkflowManagerTest {
 
     @Test
     public void testWorkflows() throws WikiException {
-        // There should be no workflows in the cache, and none in completed list
-        Assertions.assertEquals( 0, wm.getWorkflows().size() );
+        // After Workflow being created, it gets added to the workflows cache, there should be none in the completed list
+        Assertions.assertEquals( 1, wm.getWorkflows().size() );
         Assertions.assertEquals( 0, wm.getCompletedWorkflows().size() );
 
-        // After starting, there should be 1 in the cache, with ID=1
+        // After starting, there should be 1 in the cache
         wm.start( w );
         Assertions.assertEquals( 1, wm.getWorkflows().size() );
         Assertions.assertEquals( 0, wm.getCompletedWorkflows().size() );
         final Workflow workflow = wm.getWorkflows().iterator().next();
         Assertions.assertEquals( w, workflow );
-        Assertions.assertEquals( 1, workflow.getId() );
 
         // After forcing a decision on step 2, the workflow should complete and vanish from the cache
         final Decision d = ( Decision )w.getCurrentStep();
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
index 84b7444..6064c28 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
@@ -32,6 +32,8 @@ import java.util.Date;
 
 public class WorkflowTest {
 
+    WorkflowManager workflowsEventListener;
+
     Workflow w;
 
     Task initTask;
@@ -44,6 +46,9 @@ public class WorkflowTest {
 
     @BeforeEach
     public void setUp() throws Exception {
+        // listen to workflow events
+        workflowsEventListener = new DefaultWorkflowManager();
+
         // Create workflow; owner is test user
         w = new Workflow( "workflow.myworkflow", new WikiPrincipal( "Owner1" ) );
 
@@ -55,7 +60,7 @@ public class WorkflowTest {
 
         // Create an intermetidate decision step
         final Principal actor = new GroupPrincipal( "Admin" );
-        decision = new SimpleDecision( w, "decision.AdminDecision", actor );
+        decision = new SimpleDecision( w.getId(), w.getAttributes(), "decision.AdminDecision", actor );
 
         // Hook the steps together
         initTask.addSuccessor( Outcome.STEP_COMPLETE, decision );
@@ -74,7 +79,6 @@ public class WorkflowTest {
         Assertions.assertNull( w.getCurrentStep() );
         Assertions.assertNull( w.getCurrentActor() );
         Assertions.assertEquals( 0, w.getHistory().size() );
-        Assertions.assertEquals( Workflow.ID_NOT_SET, w.getId() );
         Assertions.assertEquals( new WikiPrincipal( "Owner1" ), w.getOwner() );
         Assertions.assertEquals( Workflow.CREATED, w.getCurrentState() );
         Assertions.assertEquals( Step.TIME_NOT_SET, w.getStartTime() );
@@ -355,7 +359,6 @@ public class WorkflowTest {
 
     @Test
     public void testSetId() {
-        Assertions.assertEquals( Workflow.ID_NOT_SET, w.getId() );
         w.setId( 1001 );
         Assertions.assertEquals( 1001, w.getId() );
     }


[jspwiki] 30/35: replace synchronized int nextId() with AtomicInteger

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 1e92176c6f4a62b32d5ed40a04f5401289747a80
Author: juanpablo <ju...@apache.org>
AuthorDate: Sun May 3 22:02:15 2020 +0200

    replace synchronized int nextId() with AtomicInteger
---
 .../java/org/apache/wiki/workflow/DecisionQueue.java   | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
index 679d714..a3fc33e 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
@@ -28,6 +28,8 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicInteger;
+
 
 /**
  * Keeps a queue of pending Decisions that need to be acted on by named Principals.
@@ -40,11 +42,10 @@ public class DecisionQueue implements Serializable {
 
     private final LinkedList< Decision > m_queue = new LinkedList<>();
 
-    private volatile int m_next;
+    private final AtomicInteger next = new AtomicInteger( 1_000 );
 
     /** Constructs a new DecisionQueue. */
     public DecisionQueue() {
-        m_next = 1000;
     }
 
     /**
@@ -54,7 +55,7 @@ public class DecisionQueue implements Serializable {
      */
     protected synchronized void add( final Decision decision ) {
         m_queue.addLast( decision );
-        decision.setId( nextId() );
+        decision.setId( next.getAndIncrement() );
     }
 
     /**
@@ -141,15 +142,4 @@ public class DecisionQueue implements Serializable {
         throw new IllegalStateException( "Reassignments not allowed for this decision." );
     }
 
-    /**
-     * Returns the next available unique identifier, which is subsequently incremented.
-     *
-     * @return the id
-     */
-    private synchronized int nextId() {
-        final int current = m_next;
-        m_next++;
-        return current;
-    }
-
 }


[jspwiki] 33/35: update flexmark to 0.61.26

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 7b3529740db4112f09f16b9fd71f671f64f3ce41
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue May 5 21:16:13 2020 +0200

    update flexmark to 0.61.26
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 25949f9..f2a6add 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,7 +52,7 @@
     <commons-lang.version>3.10</commons-lang.version>
     <commons-text.version>1.8</commons-text.version>
     <ehcache.version>2.10.6</ehcache.version>
-    <flexmark.version>0.61.16</flexmark.version>
+    <flexmark.version>0.61.26</flexmark.version>
     <freshcookies-security.version>0.60</freshcookies-security.version>
     <gson.version>2.8.5</gson.version>
     <hsqldb.version>2.5.0</hsqldb.version>


[jspwiki] 05/35: add two new types of Workflow events to manage DecisionQueue add and removal

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit f0b754cd467db5cfad46848771c6b86beceb059d
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 17:59:34 2020 +0200

    add two new types of Workflow events to manage DecisionQueue add and removal
---
 .../java/org/apache/wiki/event/WorkflowEvent.java   | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
index d9be3b9..7542790 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
@@ -58,6 +58,12 @@ public final class WorkflowEvent extends WikiEvent {
     /** If a Step has elected to abort the Workflow. */
     public static final int ABORTED = 50;
 
+    /** When the workflow wishes to add a Decision to the DecisionQueue */
+    public static final int DQ_ADDITION = 60;
+
+    /** When the workflow wishes to remove a Decision from the DecisionQueue */
+    public static final int DQ_REMOVAL = 70;
+
     /**
      * Constructs a new instance of this event type, which signals a security event has occurred. 
      * The <code>source</code> parameter is required, and may not be <code>null</code>. When the 
@@ -96,13 +102,14 @@ public final class WorkflowEvent extends WikiEvent {
      */
     public String eventName( final int type ) {
         switch( type ) {
-            case CREATED:   return "CREATED";
-            case ABORTED:   return "ABORTED";
-            case COMPLETED: return "COMPLETED";
-            case RUNNING:   return "RUNNING";
-            case STARTED:   return "STARTED";
-            case WAITING:   return "WAITING";
-            default:        return super.eventName();
+            case CREATED:    return "CREATED";
+            case ABORTED:    return "ABORTED";
+            case COMPLETED:  return "COMPLETED";
+            case RUNNING:    return "RUNNING";
+            case STARTED:    return "STARTED";
+            case WAITING:    return "WAITING";
+            case DQ_REMOVAL: return "DQ_REMOVAL";
+            default:         return super.eventName();
         }
     }
 


[jspwiki] 17/35: add WikiPageEvent#PAGE_REINDEX to signal that a given Page needs to be reindexed

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 7e07181cf489b879dcee79b73f776e5615b361ab
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue Apr 14 22:21:36 2020 +0200

    add WikiPageEvent#PAGE_REINDEX to signal that a given Page needs to be reindexed
---
 .../java/org/apache/wiki/event/WikiPageEvent.java     |  3 +++
 .../org/apache/wiki/pages/DefaultPageManager.java     |  3 +--
 .../org/apache/wiki/search/DefaultSearchManager.java  | 19 +++++++++++++------
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java
index e5c1ec4..c9e28a1 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java
@@ -160,6 +160,9 @@ public class WikiPageEvent extends WikiEvent {
      * @since 2.4.65 */
     public static final int PAGE_DELETED         = 27;
 
+    /** Indicates a wiki page reindex event (a page was changed when requested to a provided) */
+    public static final int PAGE_REINDEX         = 28;
+
     private String m_pagename;
 
     // ............
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
index 3cade26..54c9c2d 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
@@ -45,7 +45,6 @@ import org.apache.wiki.event.WikiPageEvent;
 import org.apache.wiki.event.WikiSecurityEvent;
 import org.apache.wiki.providers.RepositoryModifiedException;
 import org.apache.wiki.references.ReferenceManager;
-import org.apache.wiki.search.SearchManager;
 import org.apache.wiki.tasks.TasksManager;
 import org.apache.wiki.ui.CommandResolver;
 import org.apache.wiki.util.ClassUtil;
@@ -188,7 +187,7 @@ public class DefaultPageManager implements PageManager {
             final Page p = m_provider.getPageInfo( pageName, version );
 
             m_engine.getManager( ReferenceManager.class ).updateReferences( p );
-            m_engine.getManager( SearchManager.class ).reindexPage( p );
+            fireEvent( WikiPageEvent.PAGE_REINDEX, p.getName() );
             text = m_provider.getPageText( pageName, version );
         }
 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java b/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java
index fd00d44..8ac4c81 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/search/DefaultSearchManager.java
@@ -74,7 +74,7 @@ public class DefaultSearchManager extends BasePageFilter implements SearchManage
      */
     public DefaultSearchManager( final Engine engine, final Properties properties ) throws FilterException {
         initialize( engine, properties );
-        WikiEventManager.getInstance().addWikiEventListener( m_engine.getManager( PageManager.class ), this );
+        WikiEventManager.addWikiEventListener( m_engine.getManager( PageManager.class ), this );
 
         // TODO: Replace with custom annotations. See JSPWIKI-566
         WikiAjaxDispatcherServlet.registerServlet( JSON_SEARCH, new JSONSearch() );
@@ -261,12 +261,19 @@ public class DefaultSearchManager extends BasePageFilter implements SearchManage
     /** {@inheritDoc} */
     @Override
     public void actionPerformed( final WikiEvent event ) {
-        if( event instanceof WikiPageEvent && event.getType() == WikiPageEvent.PAGE_DELETE_REQUEST ) {
+        if( event instanceof WikiPageEvent ) {
             final String pageName = ( ( WikiPageEvent ) event ).getPageName();
-
-            final Page p = m_engine.getManager( PageManager.class ).getPage( pageName );
-            if( p != null ) {
-                pageRemoved( p );
+            if( event.getType() == WikiPageEvent.PAGE_DELETE_REQUEST ) {
+                final Page p = m_engine.getManager( PageManager.class ).getPage( pageName );
+                if( p != null ) {
+                    pageRemoved( p );
+                }
+            }
+            if( event.getType() == WikiPageEvent.PAGE_REINDEX ) {
+                final Page p = m_engine.getManager( PageManager.class ).getPage( pageName );
+                if( p != null ) {
+                    reindexPage( p );
+                }
             }
         }
     }


[jspwiki] 08/35: format tests + add some fixes suggested by intellij

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 6d324825b99004f3df56ca11f085e753cdd7a3ad
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 18:08:29 2020 +0200

    format tests + add some fixes suggested by intellij
---
 .../apache/wiki/workflow/ApprovalWorkflowTest.java |   9 +-
 .../apache/wiki/workflow/DecisionQueueTest.java    |  14 +-
 .../java/org/apache/wiki/workflow/FactTest.java    |  30 +-
 .../apache/wiki/workflow/SimpleDecisionTest.java   | 181 +++++------
 .../apache/wiki/workflow/WorkflowManagerTest.java  |  96 +++---
 .../org/apache/wiki/workflow/WorkflowTest.java     | 338 +++++++++------------
 6 files changed, 287 insertions(+), 381 deletions(-)

diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
index d5772d5..7f25b9e 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/ApprovalWorkflowTest.java
@@ -75,7 +75,6 @@ public class ApprovalWorkflowTest {
         final Workflow w = m_builder.buildApprovalWorkflow(submitter, workflowApproverKey,
                                                    prepTask, decisionKey, facts,
                                                    completionTask, rejectedMessageKey);
-        w.setWorkflowManager( m_engine.getManager( WorkflowManager.class ) );
 
         // Check to see if the workflow built correctly
         Assertions.assertFalse( w.isStarted() || w.isCompleted() || w.isAborted() );
@@ -83,7 +82,6 @@ public class ApprovalWorkflowTest {
         Assertions.assertEquals( "workflow.approvalWorkflow", w.getMessageKey() );
         Assertions.assertEquals( Workflow.CREATED, w.getCurrentState() );
         Assertions.assertEquals( new WikiPrincipal("Submitter"), w.getOwner() );
-        Assertions.assertEquals( m_engine.getManager( WorkflowManager.class ), w.getWorkflowManager() );
         Assertions.assertEquals( 0, w.getHistory().size() );
 
         // Our dummy "task complete" attributes should still be null
@@ -146,10 +144,9 @@ public class ApprovalWorkflowTest {
         final Task completionTask = new TestPrepTask( "task.saveWikiPage" );
         final String rejectedMessageKey = "notification.saveWikiPage.reject";
 
-        final Workflow w = m_builder.buildApprovalWorkflow(submitter, workflowApproverKey,
-                                                   prepTask, decisionKey, facts,
-                                                   completionTask, rejectedMessageKey);
-        w.setWorkflowManager( m_engine.getManager( WorkflowManager.class ) );
+        final Workflow w = m_builder.buildApprovalWorkflow( submitter, workflowApproverKey,
+                                                            prepTask, decisionKey, facts,
+                                                            completionTask, rejectedMessageKey );
 
         // Start the workflow
         w.start();
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java
index 0f3eab4..9ac1201 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/DecisionQueueTest.java
@@ -29,12 +29,10 @@ import org.junit.jupiter.api.Test;
 
 import java.security.Principal;
 import java.util.Collection;
-import java.util.Properties;
 
-public class DecisionQueueTest
-{
+public class DecisionQueueTest {
 
-    TestEngine m_engine;
+    TestEngine m_engine = TestEngine.build();
 
     DecisionQueue m_queue;
 
@@ -51,16 +49,11 @@ public class DecisionQueueTest
     Session adminSession;
 
     @BeforeEach
-    public void setUp() throws Exception
-    {
-
-        final Properties props = TestEngine.getTestProperties();
-        m_engine = new TestEngine(props);
+    public void setUp() throws Exception {
         m_queue = m_engine.getManager( WorkflowManager.class ).getDecisionQueue();
         adminSession = m_engine.adminSession();
         janneSession = m_engine.janneSession();
         w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
-        w.setWorkflowManager( m_engine.getManager( WorkflowManager.class ) );
         d1 = new SimpleDecision(w, "decision1.key", new GroupPrincipal("Admin"));
         d2 = new SimpleDecision(w, "decision2.key", new WikiPrincipal("Owner2"));
         d3 = new SimpleDecision(w, "decision3.key", janneSession.getUserPrincipal());
@@ -168,7 +161,6 @@ public class DecisionQueueTest
 
         // Create a workflow with 3 steps, with a Decision for Janne in the middle
         w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
-        w.setWorkflowManager( m_engine.getManager( WorkflowManager.class ) );
         final Step startTask = new TaskTest.NormalTask(w);
         final Step endTask = new TaskTest.NormalTask(w);
         final Decision decision = new SimpleDecision(w, "decision.Actor1Decision", janne);
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/FactTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/FactTest.java
index ea0aaf1..ba73065 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/FactTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/FactTest.java
@@ -18,27 +18,25 @@
  */
 package org.apache.wiki.workflow;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import org.junit.jupiter.api.Assertions;
 
-public class FactTest
-{
+public class FactTest {
 
     @Test
-    public void testCreate()
-    {
-        Fact f1 = new Fact("fact1",new Integer(1));
-        Fact f2 = new Fact("fact2","A factual String");
-        Fact f3 = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
-
-        Assertions.assertEquals("fact1", f1.getMessageKey());
-        Assertions.assertEquals("fact2", f2.getMessageKey());
-        Assertions.assertEquals("fact3", f3.getMessageKey());
-
-        Assertions.assertEquals(new Integer(1), f1.getValue());
-        Assertions.assertEquals("A factual String", f2.getValue());
-        Assertions.assertEquals(Outcome.DECISION_ACKNOWLEDGE, f3.getValue());
+    public void testCreate() {
+        final Fact f1 = new Fact( "fact1", 1 );
+        final Fact f2 = new Fact( "fact2", "A factual String" );
+        final Fact f3 = new Fact( "fact3", Outcome.DECISION_ACKNOWLEDGE );
+
+        Assertions.assertEquals( "fact1", f1.getMessageKey() );
+        Assertions.assertEquals( "fact2", f2.getMessageKey() );
+        Assertions.assertEquals( "fact3", f3.getMessageKey() );
+
+        Assertions.assertEquals( 1, f1.getValue() );
+        Assertions.assertEquals( "A factual String", f2.getValue() );
+        Assertions.assertEquals( Outcome.DECISION_ACKNOWLEDGE, f3.getValue() );
     }
 
 }
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
index a2c11b5..409e40d 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
@@ -18,186 +18,165 @@
  */
 package org.apache.wiki.workflow;
 
-import java.util.Collection;
-import java.util.List;
-
 import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.auth.WikiPrincipal;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-public class SimpleDecisionTest
-{
+import java.util.Collection;
+import java.util.List;
+
+
+public class SimpleDecisionTest {
 
     Workflow m_workflow;
     Decision m_decision;
 
     @BeforeEach
-    public void setUp() throws Exception
-    {
-
-        m_workflow = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
-        m_decision = new SimpleDecision(m_workflow, "decision.key", new WikiPrincipal("Actor1"));
+    public void setUp() throws Exception {
+        m_workflow = new Workflow( "workflow.key", new WikiPrincipal( "Owner1" ) );
+        m_decision = new SimpleDecision( m_workflow, "decision.key", new WikiPrincipal( "Actor1" ) );
     }
 
     @Test
-    public void testAddFacts()
-    {
-        Fact f1 = new Fact("fact1",new Integer(1));
-        Fact f2 = new Fact("fact2","A factual String");
-        Fact f3 = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
-        m_decision.addFact(f1);
-        m_decision.addFact(f2);
-        m_decision.addFact(f3);
+    public void testAddFacts() {
+        final Fact f1 = new Fact( "fact1", Integer.valueOf( 1 ) );
+        final Fact f2 = new Fact( "fact2", "A factual String" );
+        final Fact f3 = new Fact( "fact3", Outcome.DECISION_ACKNOWLEDGE );
+        m_decision.addFact( f1 );
+        m_decision.addFact( f2 );
+        m_decision.addFact( f3 );
 
         // The facts should be available, and returned in order
-        List< Fact > facts = m_decision.getFacts();
-        Assertions.assertEquals(f1, facts.get(0));
-        Assertions.assertEquals(f2, facts.get(1));
-        Assertions.assertEquals(f3, facts.get(2));
+        final List< Fact > facts = m_decision.getFacts();
+        Assertions.assertEquals( f1, facts.get( 0 ) );
+        Assertions.assertEquals( f2, facts.get( 1 ) );
+        Assertions.assertEquals( f3, facts.get( 2 ) );
     }
 
     @Test
-    public void testGetActor()
-    {
-       Assertions.assertEquals(new WikiPrincipal("Actor1"), m_decision.getActor());
+    public void testGetActor() {
+        Assertions.assertEquals( new WikiPrincipal( "Actor1" ), m_decision.getActor() );
     }
 
     @Test
-    public void testGetDefaultOutcome()
-    {
-        Assertions.assertEquals(Outcome.DECISION_APPROVE, m_decision.getDefaultOutcome());
+    public void testGetDefaultOutcome() {
+        Assertions.assertEquals( Outcome.DECISION_APPROVE, m_decision.getDefaultOutcome() );
     }
 
     @Test
-    public void testIsReassignable()
-    {
-        Assertions.assertTrue(m_decision.isReassignable());
+    public void testIsReassignable() {
+        Assertions.assertTrue( m_decision.isReassignable() );
     }
 
     @Test
-    public void testReassign()
-    {
-        m_decision.reassign(new WikiPrincipal("Actor2"));
-        Assertions.assertEquals(new WikiPrincipal("Actor2"), m_decision.getActor());
+    public void testReassign() {
+        m_decision.reassign( new WikiPrincipal( "Actor2" ) );
+        Assertions.assertEquals( new WikiPrincipal( "Actor2" ), m_decision.getActor() );
     }
 
     @Test
-    public void testSuccessors()
-    {
+    public void testSuccessors() {
         // If the decision is approved, branch to another decision (d2)
-        Step d2 = new SimpleDecision(m_workflow, "decision2.key", new WikiPrincipal("Actor1"));
-        m_decision.addSuccessor(Outcome.DECISION_APPROVE, d2);
+        final Step d2 = new SimpleDecision( m_workflow, "decision2.key", new WikiPrincipal( "Actor1" ) );
+        m_decision.addSuccessor( Outcome.DECISION_APPROVE, d2 );
 
         // If the decision is denied, branch to another decision (d3)
-        Step d3 = new SimpleDecision(m_workflow, "decision3.key", new WikiPrincipal("Actor1"));
-        m_decision.addSuccessor(Outcome.DECISION_DENY, d3);
+        final Step d3 = new SimpleDecision( m_workflow, "decision3.key", new WikiPrincipal( "Actor1" ) );
+        m_decision.addSuccessor( Outcome.DECISION_DENY, d3 );
 
-        Assertions.assertEquals(d2, m_decision.getSuccessor(Outcome.DECISION_APPROVE));
-        Assertions.assertEquals(d3, m_decision.getSuccessor(Outcome.DECISION_DENY));
+        Assertions.assertEquals( d2, m_decision.getSuccessor( Outcome.DECISION_APPROVE ) );
+        Assertions.assertEquals( d3, m_decision.getSuccessor( Outcome.DECISION_DENY ) );
 
         // The other Outcomes should return null when looked up
-        Assertions.assertNull(m_decision.getSuccessor(Outcome.DECISION_HOLD));
-        Assertions.assertNull(m_decision.getSuccessor(Outcome.DECISION_REASSIGN));
-        Assertions.assertNull(m_decision.getSuccessor(Outcome.STEP_ABORT));
+        Assertions.assertNull( m_decision.getSuccessor( Outcome.DECISION_HOLD ) );
+        Assertions.assertNull( m_decision.getSuccessor( Outcome.DECISION_REASSIGN ) );
+        Assertions.assertNull( m_decision.getSuccessor( Outcome.STEP_ABORT ) );
     }
 
     @Test
-    public void testErrors()
-    {
-        m_decision.addError("Error deciding something.");
-        m_decision.addError("Error deciding something else.");
+    public void testErrors() {
+        m_decision.addError( "Error deciding something." );
+        m_decision.addError( "Error deciding something else." );
 
-        List< String > errors = m_decision.getErrors();
-        Assertions.assertEquals(2, errors.size());
-        Assertions.assertEquals("Error deciding something.", errors.get(0));
-        Assertions.assertEquals("Error deciding something else.", errors.get(1));
+        final List< String > errors = m_decision.getErrors();
+        Assertions.assertEquals( 2, errors.size() );
+        Assertions.assertEquals( "Error deciding something.", errors.get( 0 ) );
+        Assertions.assertEquals( "Error deciding something else.", errors.get( 1 ) );
     }
 
     @Test
-    public void testAvailableOutcomes()
-    {
-        Collection< Outcome > outcomes = m_decision.getAvailableOutcomes();
-        Assertions.assertTrue(outcomes.contains(Outcome.DECISION_APPROVE));
-        Assertions.assertTrue(outcomes.contains(Outcome.DECISION_DENY));
-        Assertions.assertFalse(outcomes.contains(Outcome.DECISION_HOLD));
-        Assertions.assertFalse(outcomes.contains(Outcome.DECISION_REASSIGN));
-        Assertions.assertFalse(outcomes.contains(Outcome.STEP_ABORT));
-        Assertions.assertFalse(outcomes.contains(Outcome.STEP_COMPLETE));
+    public void testAvailableOutcomes() {
+        final Collection< Outcome > outcomes = m_decision.getAvailableOutcomes();
+        Assertions.assertTrue( outcomes.contains( Outcome.DECISION_APPROVE ) );
+        Assertions.assertTrue( outcomes.contains( Outcome.DECISION_DENY ) );
+        Assertions.assertFalse( outcomes.contains( Outcome.DECISION_HOLD ) );
+        Assertions.assertFalse( outcomes.contains( Outcome.DECISION_REASSIGN ) );
+        Assertions.assertFalse( outcomes.contains( Outcome.STEP_ABORT ) );
+        Assertions.assertFalse( outcomes.contains( Outcome.STEP_COMPLETE ) );
     }
 
     @Test
-    public void testGetEndTime() throws WikiException
-    {
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, m_decision.getEndTime());
+    public void testGetEndTime() throws WikiException {
+        Assertions.assertEquals( Workflow.TIME_NOT_SET, m_decision.getEndTime() );
         m_decision.start();
-        m_decision.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertTrue((Workflow.TIME_NOT_SET  !=  m_decision.getEndTime()));
+        m_decision.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertTrue( ( Workflow.TIME_NOT_SET != m_decision.getEndTime() ) );
     }
 
     @Test
-    public void testGetMessageKey()
-    {
-        Assertions.assertEquals("decision.key",m_decision.getMessageKey());
+    public void testGetMessageKey() {
+        Assertions.assertEquals( "decision.key", m_decision.getMessageKey() );
     }
 
     @Test
-    public void testGetOutcome() throws WikiException
-    {
-        Assertions.assertEquals(Outcome.STEP_CONTINUE,m_decision.getOutcome());
+    public void testGetOutcome() throws WikiException {
+        Assertions.assertEquals( Outcome.STEP_CONTINUE, m_decision.getOutcome() );
         m_decision.start();
-        m_decision.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertEquals(Outcome.DECISION_APPROVE, m_decision.getOutcome());
+        m_decision.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertEquals( Outcome.DECISION_APPROVE, m_decision.getOutcome() );
     }
 
     @Test
-    public void testGetStartTime() throws WikiException
-    {
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, m_decision.getStartTime());
+    public void testGetStartTime() throws WikiException {
+        Assertions.assertEquals( Workflow.TIME_NOT_SET, m_decision.getStartTime() );
         m_decision.start();
-        m_decision.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertTrue((Workflow.TIME_NOT_SET  !=  m_decision.getStartTime()));
+        m_decision.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertTrue( ( Workflow.TIME_NOT_SET != m_decision.getStartTime() ) );
     }
 
     @Test
-    public void testGetWorkflow()
-    {
-        Assertions.assertEquals(m_workflow, m_decision.getWorkflow());
+    public void testGetWorkflow() {
+        Assertions.assertEquals( m_workflow, m_decision.getWorkflow() );
     }
 
     @Test
-    public void testIsCompleted() throws WikiException
-    {
-        Assertions.assertFalse(m_decision.isCompleted());
+    public void testIsCompleted() throws WikiException {
+        Assertions.assertFalse( m_decision.isCompleted() );
         m_decision.start();
-        m_decision.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertTrue(m_decision.isCompleted());
+        m_decision.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertTrue( m_decision.isCompleted() );
     }
 
     @Test
-    public void testIsStarted() throws WikiException
-    {
-        Assertions.assertFalse(m_decision.isStarted());
+    public void testIsStarted() throws WikiException {
+        Assertions.assertFalse( m_decision.isStarted() );
         m_decision.start();
-        Assertions.assertTrue(m_decision.isStarted());
+        Assertions.assertTrue( m_decision.isStarted() );
     }
 
     @Test
-    public void testStartTwice() throws WikiException
-    {
+    public void testStartTwice() throws WikiException {
         m_decision.start();
-        try
-        {
+        try {
             m_decision.start();
-        }
-        catch (IllegalStateException e)
-        {
+        } catch( final IllegalStateException e ) {
             // Swallow
             return;
         }
         // We should never get here
-        Assertions.fail("Decision allowed itself to be started twice!");
+        Assertions.fail( "Decision allowed itself to be started twice!" );
     }
 
 }
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
index f6b8a19..2597ca9 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
@@ -27,96 +27,84 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import java.util.Properties;
 
-public class WorkflowManagerTest
-{
+public class WorkflowManagerTest {
+
     protected Workflow w;
     protected WorkflowManager wm;
-    protected WikiEngine m_engine;
+    protected WikiEngine m_engine = TestEngine.build();
 
     @BeforeEach
-    public void setUp() throws Exception
-    {
-        final Properties props = TestEngine.getTestProperties();
-        m_engine = new TestEngine(props);
+    public void setUp() throws Exception {
         wm = m_engine.getManager( WorkflowManager.class );
         // Create a workflow with 3 steps, with a Decision in the middle
-        w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
-        w.setWorkflowManager( m_engine.getManager( WorkflowManager.class ) );
-        final Step startTask = new TaskTest.NormalTask(w);
-        final Step endTask = new TaskTest.NormalTask(w);
-        final Decision decision = new SimpleDecision(w, "decision.editWikiApproval", new WikiPrincipal("Actor1"));
-        startTask.addSuccessor(Outcome.STEP_COMPLETE, decision);
-        decision.addSuccessor(Outcome.DECISION_APPROVE, endTask);
-        w.setFirstStep(startTask);
+        w = new Workflow( "workflow.key", new WikiPrincipal( "Owner1" ) );
+        final Step startTask = new TaskTest.NormalTask( w );
+        final Step endTask = new TaskTest.NormalTask( w );
+        final Decision decision = new SimpleDecision( w, "decision.editWikiApproval", new WikiPrincipal( "Actor1" ) );
+        startTask.addSuccessor( Outcome.STEP_COMPLETE, decision );
+        decision.addSuccessor( Outcome.DECISION_APPROVE, endTask );
+        w.setFirstStep( startTask );
 
         // Add a message argument to the workflow with the page name
-        w.addMessageArgument("MyPage");
+        w.addMessageArgument( "MyPage" );
     }
 
     @Test
-    public void testStart() throws WikiException
-    {
+    public void testStart() throws WikiException {
         // Once we start the workflow, it should show that it's started
         // and the WM should have assigned it an ID
-        Assertions.assertEquals(Workflow.ID_NOT_SET, w.getId());
-        Assertions.assertFalse(w.isStarted());
-        wm.start(w);
-        Assertions.assertFalse(Workflow.ID_NOT_SET == w.getId());
-        Assertions.assertTrue(w.isStarted());
+        Assertions.assertEquals( Workflow.ID_NOT_SET, w.getId() );
+        Assertions.assertFalse( w.isStarted() );
+        wm.start( w );
+        Assertions.assertNotEquals( Workflow.ID_NOT_SET, w.getId() );
+        Assertions.assertTrue( w.isStarted() );
     }
 
     @Test
-    public void testWorkflows() throws WikiException
-    {
+    public void testWorkflows() throws WikiException {
         // There should be no workflows in the cache, and none in completed list
-        Assertions.assertEquals(0, wm.getWorkflows().size());
-        Assertions.assertEquals(0, wm.getCompletedWorkflows().size());
+        Assertions.assertEquals( 0, wm.getWorkflows().size() );
+        Assertions.assertEquals( 0, wm.getCompletedWorkflows().size() );
 
         // After starting, there should be 1 in the cache, with ID=1
-        wm.start(w);
-        Assertions.assertEquals(1, wm.getWorkflows().size());
-        Assertions.assertEquals(0, wm.getCompletedWorkflows().size());
-        final Workflow workflow = (Workflow)wm.getWorkflows().iterator().next();
-        Assertions.assertEquals(w, workflow);
-        Assertions.assertEquals(1, workflow.getId());
+        wm.start( w );
+        Assertions.assertEquals( 1, wm.getWorkflows().size() );
+        Assertions.assertEquals( 0, wm.getCompletedWorkflows().size() );
+        final Workflow workflow = wm.getWorkflows().iterator().next();
+        Assertions.assertEquals( w, workflow );
+        Assertions.assertEquals( 1, workflow.getId() );
 
         // After forcing a decision on step 2, the workflow should complete and vanish from the cache
-        final Decision d = (Decision)w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertEquals(0, wm.getWorkflows().size());
-        Assertions.assertEquals(1, wm.getCompletedWorkflows().size());
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertEquals( 0, wm.getWorkflows().size() );
+        Assertions.assertEquals( 1, wm.getCompletedWorkflows().size() );
     }
 
     @Test
-    public void testRequiresApproval()
-    {
+    public void testRequiresApproval() {
         // Test properties says we need approvals for workflow.saveWikiPage & workflow.foo
-        Assertions.assertFalse(wm.requiresApproval("workflow.saveWikiPage"));
-        Assertions.assertTrue(wm.requiresApproval("workflow.foo"));
-        Assertions.assertTrue(wm.requiresApproval("workflow.bar"));
+        Assertions.assertFalse( wm.requiresApproval( "workflow.saveWikiPage" ) );
+        Assertions.assertTrue( wm.requiresApproval( "workflow.foo" ) );
+        Assertions.assertTrue( wm.requiresApproval( "workflow.bar" ) );
     }
 
     @Test
-    public void testGetApprover() throws WikiException
-    {
+    public void testGetApprover() throws WikiException {
         // Test properties says workflow.saveWikiPage approver is GP Admin; workflow.foo is 'janne'
-        Assertions.assertEquals(new WikiPrincipal("janne", WikiPrincipal.LOGIN_NAME), wm.getApprover("workflow.foo"));
-        Assertions.assertEquals(new GroupPrincipal("Admin"), wm.getApprover("workflow.bar"));
+        Assertions.assertEquals( new WikiPrincipal( "janne", WikiPrincipal.LOGIN_NAME ), wm.getApprover( "workflow.foo" ) );
+        Assertions.assertEquals( new GroupPrincipal( "Admin" ), wm.getApprover( "workflow.bar" ) );
 
         // 'saveWikiPage' workflow doesn't require approval, so we will need to catch an Exception
-        try
-        {
-            Assertions.assertEquals(new GroupPrincipal("Admin"), wm.getApprover("workflow.saveWikiPage"));
-        }
-        catch ( final WikiException e)
-        {
+        try {
+            Assertions.assertEquals( new GroupPrincipal( "Admin" ), wm.getApprover( "workflow.saveWikiPage" ) );
+        } catch( final WikiException e ) {
             // Swallow
             return;
         }
         // We should never get here
-        Assertions.fail("Workflow.bar doesn't need approval!");
+        Assertions.fail( "Workflow.bar doesn't need approval!" );
     }
 
 }
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
index 7b9850d..d600e0b 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
@@ -29,8 +29,9 @@ import java.math.BigDecimal;
 import java.security.Principal;
 import java.util.Date;
 
-public class WorkflowTest
-{
+
+public class WorkflowTest {
+
     Workflow w;
 
     Task initTask;
@@ -42,370 +43,321 @@ public class WorkflowTest
     String ATTR = "TestAttribute";
 
     @BeforeEach
-    public void setUp() throws Exception
-    {
+    public void setUp() throws Exception {
         // Create workflow; owner is test user
-        w = new Workflow("workflow.myworkflow", new WikiPrincipal("Owner1"));
+        w = new Workflow( "workflow.myworkflow", new WikiPrincipal( "Owner1" ) );
 
         // Create custom initialization task
-        initTask = new TaskTest.NormalTask(w);
+        initTask = new TaskTest.NormalTask( w );
 
         // Create finish task
-        finishTask = new TaskTest.NormalTask(w);
+        finishTask = new TaskTest.NormalTask( w );
 
         // Create an intermetidate decision step
-        Principal actor = new GroupPrincipal("Admin");
-        decision = new SimpleDecision(w, "decision.AdminDecision", actor);
+        final Principal actor = new GroupPrincipal( "Admin" );
+        decision = new SimpleDecision( w, "decision.AdminDecision", actor );
 
         // Hook the steps together
-        initTask.addSuccessor(Outcome.STEP_COMPLETE, decision);
-        decision.addSuccessor(Outcome.DECISION_APPROVE, finishTask);
+        initTask.addSuccessor( Outcome.STEP_COMPLETE, decision );
+        decision.addSuccessor( Outcome.DECISION_APPROVE, finishTask );
 
         // Stash page name as message attribute
-        w.addMessageArgument("MyPage");
+        w.addMessageArgument( "MyPage" );
 
         // Set workflow's first step
-        w.setFirstStep(initTask);
+        w.setFirstStep( initTask );
     }
 
     @Test
-    public void testWorkflow()
-    {
+    public void testWorkflow() {
         // Make sure everything is set to their proper default values
-        Assertions.assertNull(w.getCurrentStep());
-        Assertions.assertNull(w.getCurrentActor());
-        Assertions.assertEquals(0, w.getHistory().size());
-        Assertions.assertEquals(Workflow.ID_NOT_SET, w.getId());
-        Assertions.assertNull(w.getWorkflowManager());
-        Assertions.assertEquals(new WikiPrincipal("Owner1"), w.getOwner());
-        Assertions.assertEquals(Workflow.CREATED, w.getCurrentState());
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, w.getStartTime());
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, w.getEndTime());
-    }
-
-    @Test
-    public void testSetWorkflowManager()
-    {
-        Assertions.assertNull(w.getWorkflowManager());
-        WorkflowManager m = new DefaultWorkflowManager();
-        w.setWorkflowManager(m);
-        Assertions.assertEquals(m, w.getWorkflowManager());
+        Assertions.assertNull( w.getCurrentStep() );
+        Assertions.assertNull( w.getCurrentActor() );
+        Assertions.assertEquals( 0, w.getHistory().size() );
+        Assertions.assertEquals( Workflow.ID_NOT_SET, w.getId() );
+        Assertions.assertEquals( new WikiPrincipal( "Owner1" ), w.getOwner() );
+        Assertions.assertEquals( Workflow.CREATED, w.getCurrentState() );
+        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getStartTime() );
+        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getEndTime() );
     }
 
     @Test
-    public void testGetSetAttribute()
-    {
-        Assertions.assertNull(w.getAttribute(ATTR));
-        w.setAttribute(ATTR, "Test String");
-        Assertions.assertNotNull(w.getAttribute(ATTR));
-        Assertions.assertEquals("Test String", w.getAttribute(ATTR));
+    public void testGetSetAttribute() {
+        Assertions.assertNull( w.getAttribute( ATTR ) );
+        w.setAttribute( ATTR, "Test String" );
+        Assertions.assertNotNull( w.getAttribute( ATTR ) );
+        Assertions.assertEquals( "Test String", w.getAttribute( ATTR ) );
     }
 
     @Test
-    public void testGetMessageArgs() throws WikiException
-    {
+    public void testGetMessageArgs() throws WikiException {
         Object[] args;
 
         // Before start, arg1=Owner1, arg2=- (no current actor), arg3=MyPage
         args = w.getMessageArguments();
-        Assertions.assertEquals("Owner1", args[0]);
-        Assertions.assertEquals("-",      args[1]);
-        Assertions.assertEquals("MyPage", args[2]);
+        Assertions.assertEquals( "Owner1", args[ 0 ] );
+        Assertions.assertEquals( "-", args[ 1 ] );
+        Assertions.assertEquals( "MyPage", args[ 2 ] );
 
         // After start (at Decision), arg1=Owner1, arg2=Admin, arg3=MyPage
         w.start();
         args = w.getMessageArguments();
-        Assertions.assertEquals("Owner1", args[0]);
-        Assertions.assertEquals("Admin", args[1]);
-        Assertions.assertEquals("MyPage", args[2]);
+        Assertions.assertEquals( "Owner1", args[ 0 ] );
+        Assertions.assertEquals( "Admin", args[ 1 ] );
+        Assertions.assertEquals( "MyPage", args[ 2 ] );
 
         // After end, arg1=Owner1, arg2=-, arg3=MyPage
-        decision.decide(Outcome.DECISION_APPROVE);
+        decision.decide( Outcome.DECISION_APPROVE );
         args = w.getMessageArguments();
-        Assertions.assertEquals("Owner1", args[0]);
-        Assertions.assertEquals("-", args[1]);
-        Assertions.assertEquals("MyPage", args[2]);
+        Assertions.assertEquals( "Owner1", args[ 0 ] );
+        Assertions.assertEquals( "-", args[ 1 ] );
+        Assertions.assertEquals( "MyPage", args[ 2 ] );
     }
 
     @Test
-    public void testGetMessageArgObjects()
-    {
+    public void testGetMessageArgObjects() {
         // Try passing some valid object types: Date, Number
-        w.addMessageArgument(new Date());
-        w.addMessageArgument(new Integer(1));
-        w.addMessageArgument(new Double(2));
-        w.addMessageArgument(new BigDecimal(3.14));
+        w.addMessageArgument( new Date() );
+        w.addMessageArgument( Integer.valueOf( 1 ) );
+        w.addMessageArgument( 2d );
+        w.addMessageArgument( new BigDecimal( "3.14" ) );
 
         // Try passing an invalid one: e.g., a Workflow (it should Assertions.fail)
-        try
-        {
-            w.addMessageArgument(w);
-        }
-        catch (IllegalArgumentException e)
-        {
+        try {
+            w.addMessageArgument( w );
+        } catch( final IllegalArgumentException e ) {
             // Swallow
             return;
         }
         // We should never get here
-        Assertions.fail("Illegal argument passed...");
+        Assertions.fail( "Illegal argument passed..." );
     }
 
     @Test
-    public void testGetMessageKey()
-    {
-        Assertions.assertEquals("workflow.myworkflow", w.getMessageKey());
+    public void testGetMessageKey() {
+        Assertions.assertEquals( "workflow.myworkflow", w.getMessageKey() );
     }
 
     @Test
-    public void testGetOwner()
-    {
-        Assertions.assertEquals(new WikiPrincipal("Owner1"), w.getOwner());
+    public void testGetOwner() {
+        Assertions.assertEquals( new WikiPrincipal( "Owner1" ), w.getOwner() );
     }
 
     @Test
-    public void testStart() throws WikiException
-    {
-        Assertions.assertFalse(w.isStarted());
+    public void testStart() throws WikiException {
+        Assertions.assertFalse( w.isStarted() );
         w.start();
-        Assertions.assertTrue(w.isStarted());
+        Assertions.assertTrue( w.isStarted() );
     }
 
     @Test
-    public void testWaitstate() throws WikiException
-    {
+    public void testWaitstate() throws WikiException {
         w.start();
 
         // Default workflow should have hit the Decision step and put itself
         // into WAITING
-        Assertions.assertEquals(Workflow.WAITING, w.getCurrentState());
+        Assertions.assertEquals( Workflow.WAITING, w.getCurrentState() );
     }
 
     @Test
-    public void testRestart() throws WikiException
-    {
+    public void testRestart() throws WikiException {
         w.start();
 
         // Default workflow should have hit the Decision step and put itself
         // into WAITING
-        Assertions.assertEquals(Workflow.WAITING, w.getCurrentState());
+        Assertions.assertEquals( Workflow.WAITING, w.getCurrentState() );
         w.restart();
-        Assertions.assertEquals(Workflow.WAITING, w.getCurrentState());
+        Assertions.assertEquals( Workflow.WAITING, w.getCurrentState() );
     }
 
     @Test
-    public void testAbortBeforeStart() throws WikiException
-    {
+    public void testAbortBeforeStart() throws WikiException {
         // Workflow hasn't been started yet
-        Assertions.assertFalse(w.isAborted());
+        Assertions.assertFalse( w.isAborted() );
         w.abort();
-        Assertions.assertTrue(w.isAborted());
+        Assertions.assertTrue( w.isAborted() );
 
         // Try to start anyway
-        try
-        {
+        try {
             w.start();
-        }
-        catch (IllegalStateException e)
-        {
+        } catch( final IllegalStateException e ) {
             // Swallow
             return;
         }
         // We should never get here
-        Assertions.fail("Workflow allowed itself to be started even though it was aborted!");
+        Assertions.fail( "Workflow allowed itself to be started even though it was aborted!" );
     }
 
     @Test
-    public void testAbortDuringWait() throws WikiException
-    {
+    public void testAbortDuringWait() throws WikiException {
         // Start workflow, then abort while in WAITING state
-        Assertions.assertFalse(w.isAborted());
+        Assertions.assertFalse( w.isAborted() );
         w.start();
         w.abort();
-        Assertions.assertTrue(w.isAborted());
+        Assertions.assertTrue( w.isAborted() );
 
         // Try to restart anyway
-        try
-        {
+        try {
             w.restart();
-        }
-        catch (IllegalStateException e)
-        {
+        } catch( final IllegalStateException e ) {
             // Swallow
             return;
         }
         // We should never get here
-        Assertions.fail("Workflow allowed itself to be re-started even though it was aborted!");
+        Assertions.fail( "Workflow allowed itself to be re-started even though it was aborted!" );
     }
 
     @Test
-    public void testAbortAfterCompletion() throws WikiException
-    {
+    public void testAbortAfterCompletion() throws WikiException {
         // Start workflow, then abort after completion
-        Assertions.assertFalse(w.isAborted());
+        Assertions.assertFalse( w.isAborted() );
         w.start();
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
 
         // Try to abort anyway
-        try
-        {
+        try {
             w.abort();
-            Assertions.assertTrue(w.isAborted());
-        }
-        catch (IllegalStateException e)
-        {
+            Assertions.assertTrue( w.isAborted() );
+        } catch( final IllegalStateException e ) {
             // Swallow
             return;
         }
         // We should never get here
-        Assertions.fail("Workflow allowed itself to be aborted even though it was completed!");
+        Assertions.fail( "Workflow allowed itself to be aborted even though it was completed!" );
     }
 
     @Test
-    public void testCurrentState() throws WikiException
-    {
-        Assertions.assertEquals(Workflow.CREATED, w.getCurrentState());
+    public void testCurrentState() throws WikiException {
+        Assertions.assertEquals( Workflow.CREATED, w.getCurrentState() );
         w.start();
-        Assertions.assertEquals(Workflow.WAITING, w.getCurrentState());
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertEquals(Workflow.COMPLETED, w.getCurrentState());
+        Assertions.assertEquals( Workflow.WAITING, w.getCurrentState() );
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertEquals( Workflow.COMPLETED, w.getCurrentState() );
     }
 
     @Test
-    public void testCurrentStep() throws WikiException
-    {
-        Assertions.assertNull(w.getCurrentStep());
+    public void testCurrentStep() throws WikiException {
+        Assertions.assertNull( w.getCurrentStep() );
         w.start();
 
         // Workflow stops at the decision step
-        Assertions.assertEquals(decision, w.getCurrentStep());
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
+        Assertions.assertEquals( decision, w.getCurrentStep() );
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
 
         // After we decide, it blows through step 3 and leaves us with a null
         // step (done)
-        Assertions.assertNull(w.getCurrentStep());
+        Assertions.assertNull( w.getCurrentStep() );
     }
 
     @Test
-    public void testPreviousStep() throws WikiException
-    {
+    public void testPreviousStep() throws WikiException {
         // If not started, no previous steps available for anything
-        Assertions.assertNull(w.getPreviousStep());
-        Assertions.assertEquals(null, w.previousStep(initTask));
-        Assertions.assertEquals(null, w.previousStep(decision));
-        Assertions.assertEquals(null, w.previousStep(finishTask));
+        Assertions.assertNull( w.getPreviousStep() );
+        Assertions.assertNull( w.previousStep( initTask ) );
+        Assertions.assertNull( w.previousStep( decision ) );
+        Assertions.assertNull( w.previousStep( finishTask ) );
 
         // Once we start, initTask and decisions' predecessors are known, but
         // finish task is indeterminate
         w.start();
-        Assertions.assertEquals(null, w.previousStep(initTask));
-        Assertions.assertEquals(initTask, w.previousStep(decision));
-        Assertions.assertEquals(null, w.previousStep(finishTask));
+        Assertions.assertNull( w.previousStep( initTask ) );
+        Assertions.assertEquals( initTask, w.previousStep( decision ) );
+        Assertions.assertNull( w.previousStep( finishTask ) );
 
         // Once we decide, the finish task returns the correct predecessor
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertEquals(null, w.previousStep(initTask));
-        Assertions.assertEquals(initTask, w.previousStep(decision));
-        Assertions.assertEquals(decision, w.previousStep(finishTask));
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertNull( w.previousStep( initTask ) );
+        Assertions.assertEquals( initTask, w.previousStep( decision ) );
+        Assertions.assertEquals( decision, w.previousStep( finishTask ) );
     }
 
     @Test
-    public void testCurrentActor() throws WikiException
-    {
+    public void testCurrentActor() throws WikiException {
         // Before starting, actor should be null
-        Assertions.assertNull(w.getCurrentActor());
+        Assertions.assertNull( w.getCurrentActor() );
 
         // After starting, actor should be GroupPrincipal Admin
         w.start();
-        Assertions.assertEquals(new GroupPrincipal("Admin"), w.getCurrentActor());
+        Assertions.assertEquals( new GroupPrincipal( "Admin" ), w.getCurrentActor() );
 
         // After decision, actor should be null again
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertNull(w.getCurrentActor());
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertNull( w.getCurrentActor() );
     }
 
     @Test
-    public void testHistory() throws WikiException
-    {
-        Assertions.assertEquals(0, w.getHistory().size());
+    public void testHistory() throws WikiException {
+        Assertions.assertEquals( 0, w.getHistory().size() );
         w.start();
-        Assertions.assertEquals(2, w.getHistory().size());
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertEquals(3, w.getHistory().size());
+        Assertions.assertEquals( 2, w.getHistory().size() );
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertEquals( 3, w.getHistory().size() );
     }
 
     @Test
-    public void testGetStartTime() throws WikiException
-    {
+    public void testGetStartTime() throws WikiException {
         // Start time should be not be set until we start the workflow
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, w.getStartTime());
+        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getStartTime() );
         w.start();
-        Assertions.assertFalse(Workflow.TIME_NOT_SET == w.getStartTime());
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertFalse(Workflow.TIME_NOT_SET == w.getStartTime());
+        Assertions.assertNotSame( Workflow.TIME_NOT_SET, w.getStartTime() );
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertNotSame( Workflow.TIME_NOT_SET, w.getStartTime() );
     }
 
     @Test
-    public void testGetEndTime() throws WikiException
-    {
+    public void testGetEndTime() throws WikiException {
         // End time should be not set until we finish all 3 steps
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, w.getEndTime());
+        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getEndTime() );
         w.start();
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, w.getEndTime());
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertFalse(Workflow.TIME_NOT_SET == w.getEndTime());
+        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getEndTime() );
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertNotSame( Workflow.TIME_NOT_SET, w.getEndTime() );
     }
 
     @Test
-    public void testIsCompleted() throws WikiException
-    {
+    public void testIsCompleted() throws WikiException {
         // Workflow isn't completed until we finish all 3 steps
-        Assertions.assertFalse(w.isCompleted());
+        Assertions.assertFalse( w.isCompleted() );
         w.start();
-        Assertions.assertFalse(w.isCompleted());
-        Decision d = (Decision) w.getCurrentStep();
-        d.decide(Outcome.DECISION_APPROVE);
-        Assertions.assertTrue(w.isCompleted());
+        Assertions.assertFalse( w.isCompleted() );
+        final Decision d = ( Decision )w.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        Assertions.assertTrue( w.isCompleted() );
     }
 
     @Test
-    public void testIsStarted() throws WikiException
-    {
-        Assertions.assertFalse(w.isStarted());
+    public void testIsStarted() throws WikiException {
+        Assertions.assertFalse( w.isStarted() );
         w.start();
-        Assertions.assertTrue(w.isStarted());
+        Assertions.assertTrue( w.isStarted() );
     }
 
     @Test
-    public void testStartTwice() throws WikiException
-    {
+    public void testStartTwice() throws WikiException {
         w.start();
-        try
-        {
+        try {
             w.start();
-        }
-        catch (IllegalStateException e)
-        {
+        } catch( final IllegalStateException e ) {
             // Swallow
             return;
         }
         // We should never get here
-        Assertions.fail("Workflow allowed itself to be started twice!");
+        Assertions.fail( "Workflow allowed itself to be started twice!" );
     }
 
     @Test
-    public void testSetId()
-    {
-        Assertions.assertEquals(Workflow.ID_NOT_SET, w.getId());
-        w.setId(1001);
-        Assertions.assertEquals(1001, w.getId());
+    public void testSetId() {
+        Assertions.assertEquals( Workflow.ID_NOT_SET, w.getId() );
+        w.setId( 1001 );
+        Assertions.assertEquals( 1001, w.getId() );
     }
 
 }


[jspwiki] 29/35: Fire workflow events for DecisionQueue reassign and decide actions.

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 0675bd015ba005dd2fdc7bb777b15eca5d0630f1
Author: juanpablo <ju...@apache.org>
AuthorDate: Sun May 3 21:54:46 2020 +0200

    Fire workflow events for DecisionQueue reassign and decide actions.
---
 .../src/main/java/org/apache/wiki/event/WorkflowEvent.java          | 6 ++++++
 .../src/main/java/org/apache/wiki/workflow/DecisionQueue.java       | 6 ++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
index 6f40978..76caffa 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
@@ -63,6 +63,12 @@ public final class WorkflowEvent extends WikiEvent {
     /** When the workflow wishes to remove a Decision from the DecisionQueue */
     public static final int DQ_REMOVAL = 70;
 
+    /** When the workflow wishes to remove a Decision from the DecisionQueue */
+    public static final int DQ_DECIDE = 80;
+
+    /** When the workflow wishes to remove a Decision from the DecisionQueue */
+    public static final int DQ_REASSIGN = 90;
+
     /**
      * Constructs a new instance of this event type, which signals a security event has occurred. 
      * The <code>source</code> parameter is required, and may not be <code>null</code>. When the 
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
index 37d8925..679d714 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DecisionQueue.java
@@ -20,6 +20,8 @@ package org.apache.wiki.workflow;
 
 import org.apache.wiki.api.core.Session;
 import org.apache.wiki.api.exceptions.WikiException;
+import org.apache.wiki.event.WikiEventEmitter;
+import org.apache.wiki.event.WorkflowEvent;
 
 import java.io.Serializable;
 import java.security.Principal;
@@ -119,7 +121,7 @@ public class DecisionQueue implements Serializable {
             remove( decision );
         }
 
-        // TODO: We should fire an event indicating the Outcome, and whether the Decision completed successfully
+        WikiEventEmitter.fireWorkflowEvent( decision, WorkflowEvent.DQ_DECIDE );
     }
 
     /**
@@ -133,7 +135,7 @@ public class DecisionQueue implements Serializable {
         if( decision.isReassignable() ) {
             decision.reassign( owner );
 
-            // TODO: We should fire an event indicating the reassignment
+            WikiEventEmitter.fireWorkflowEvent( decision, WorkflowEvent.DQ_REASSIGN );
             return;
         }
         throw new IllegalStateException( "Reassignments not allowed for this decision." );


[jspwiki] 15/35: Promote PluginManager#getPluginSearchPath() to Engine, as it is an operation requesting a configuration value

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit fba8cd440cf763b8c996363cb22c33ed0a9dbaa5
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue Apr 14 22:17:30 2020 +0200

    Promote PluginManager#getPluginSearchPath() to Engine, as it is an operation requesting a configuration value
---
 .../test/java/org/apache/wiki/plugin/PluginFrom210Test.java |  3 ++-
 .../src/main/java/org/apache/wiki/api/core/Engine.java      | 13 +++++++++++++
 .../java/org/apache/wiki/plugin/DefaultPluginManager.java   |  8 +-------
 .../src/main/java/org/apache/wiki/plugin/PluginManager.java | 10 ----------
 .../org/apache/wiki/plugin/DefaultPluginManagerTest.java    |  7 ++++---
 5 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/jspwiki-210-adapters/src/test/java/org/apache/wiki/plugin/PluginFrom210Test.java b/jspwiki-210-adapters/src/test/java/org/apache/wiki/plugin/PluginFrom210Test.java
index 134a3ad..d325451 100644
--- a/jspwiki-210-adapters/src/test/java/org/apache/wiki/plugin/PluginFrom210Test.java
+++ b/jspwiki-210-adapters/src/test/java/org/apache/wiki/plugin/PluginFrom210Test.java
@@ -22,6 +22,7 @@ import org.apache.wiki.TestEngine;
 import org.apache.wiki.WikiContext;
 import org.apache.wiki.WikiEngine;
 import org.apache.wiki.WikiPage;
+import org.apache.wiki.api.core.Engine;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -33,7 +34,7 @@ public class PluginFrom210Test {
     @Test
     public void testPluginNotUsingPublicApiStillWorks() throws Exception {
         final Properties props = TestEngine.getTestProperties();
-        props.setProperty( PluginManager.PROP_SEARCHPATH, "com.example.plugins" );
+        props.setProperty( Engine.PROP_SEARCHPATH, "com.example.plugins" );
         final WikiEngine engine = TestEngine.build( props );
         final PluginManager pm = engine.getManager( PluginManager.class );
         final WikiContext context = new WikiContext( engine, new WikiPage( engine, "Testpage" ) );
diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java b/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java
index 6a2269e..8f054af 100644
--- a/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/core/Engine.java
@@ -21,6 +21,7 @@ package org.apache.wiki.api.core;
 import org.apache.log4j.Logger;
 import org.apache.wiki.api.exceptions.ProviderException;
 import org.apache.wiki.event.WikiEventListener;
+import org.apache.wiki.util.TextUtil;
 
 import javax.servlet.ServletContext;
 import java.io.File;
@@ -65,6 +66,9 @@ public interface Engine {
     /** Property start for any interwiki reference. */
     String PROP_INTERWIKIREF = "jspwiki.interWikiRef.";
 
+    /** The property name defining which packages will be searched for plugin classes. */
+    String PROP_SEARCHPATH = "jspwiki.plugin.searchPath";
+
     /** If true, then the user name will be stored with the page data.*/
     String PROP_STOREUSERNAME= "jspwiki.storeUserName";
 
@@ -162,6 +166,15 @@ public interface Engine {
     String getTemplateDir();
 
     /**
+     * Returns plugins' search path.
+     *
+     * @return plugins' search path.
+     */
+    default String getPluginSearchPath() {
+        return TextUtil.getStringProperty( getWikiProperties(), PROP_SEARCHPATH, null );
+    }
+
+    /**
      *  Returns the moment when this engine was started.
      *
      *  @since 2.0.15.
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java b/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java
index 02a5fbb..207f3ee 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/plugin/DefaultPluginManager.java
@@ -178,7 +178,7 @@ public class DefaultPluginManager extends BaseModuleManager implements PluginMan
      */
     public DefaultPluginManager( final Engine engine, final Properties props ) {
         super( engine );
-        final String packageNames = props.getProperty( PROP_SEARCHPATH );
+        final String packageNames = props.getProperty( Engine.PROP_SEARCHPATH );
         if ( packageNames != null ) {
             final StringTokenizer tok = new StringTokenizer( packageNames, "," );
             while( tok.hasMoreTokens() ) {
@@ -227,12 +227,6 @@ public class DefaultPluginManager extends BaseModuleManager implements PluginMan
 		return m_pluginPattern;
 	}
 
-    /** {@inheritDoc} */
-    @Override
-    public String getPluginSearchPath() {
-    	return TextUtil.getStringProperty( m_engine.getWikiProperties(), PROP_SEARCHPATH, null );
-    }
-
 	/**
      *  Attempts to locate a plugin class from the class path set in the property file.
      *
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java b/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java
index a7fee6d..aa5f752 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/plugin/PluginManager.java
@@ -31,9 +31,6 @@ import java.util.ResourceBundle;
 
 public interface PluginManager extends ModuleManager {
 
-    /** The property name defining which packages will be searched for plugin classes. */
-    String PROP_SEARCHPATH = "jspwiki.plugin.searchPath";
-
     /** The property name defining which external jars will be added to the classpath when searching for plugin classes. */
     String PROP_EXTERNALJARS = "jspwiki.plugin.externalJars";
 
@@ -76,13 +73,6 @@ public interface PluginManager extends ModuleManager {
      * @return plugin insert pattern.
      */
     Pattern getPluginPattern();
-    
-    /**
-     * Returns plugins' search path.
-     * 
-     * @return plugins' search path.
-     */
-    String getPluginSearchPath();
 
     /**
      * Executes a plugin class in the given context.
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/plugin/DefaultPluginManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/plugin/DefaultPluginManagerTest.java
index 015f686..0db4b27 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/plugin/DefaultPluginManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/plugin/DefaultPluginManagerTest.java
@@ -22,6 +22,7 @@ package org.apache.wiki.plugin;
 import org.apache.wiki.TestEngine;
 import org.apache.wiki.WikiContext;
 import org.apache.wiki.WikiEngine;
+import org.apache.wiki.api.core.Engine;
 import org.apache.wiki.api.exceptions.ProviderException;
 import org.apache.wiki.api.spi.Wiki;
 import org.apache.wiki.pages.PageManager;
@@ -66,7 +67,7 @@ public class DefaultPluginManagerTest {
 
     @Test
     public void testSimpleInsertNoPackage2() throws Exception {
-        props.setProperty( DefaultPluginManager.PROP_SEARCHPATH, "com.foo" );
+        props.setProperty( Engine.PROP_SEARCHPATH, "com.foo" );
         final DefaultPluginManager m = new DefaultPluginManager( engine, props );
         final String res = m.execute( context,"{INSERT SamplePlugin2 WHERE text=foobar}" );
         Assertions.assertEquals( "foobar", res );
@@ -74,7 +75,7 @@ public class DefaultPluginManagerTest {
 
     @Test
     public void testSimpleInsertNoPackage3() throws Exception {
-        props.setProperty( DefaultPluginManager.PROP_SEARCHPATH, "com.foo" );
+        props.setProperty( Engine.PROP_SEARCHPATH, "com.foo" );
         final DefaultPluginManager m = new DefaultPluginManager( engine, props );
         final String res = m.execute( context,"{INSERT SamplePlugin3 WHERE text=foobar}" );
         Assertions.assertEquals( "foobar", res );
@@ -83,7 +84,7 @@ public class DefaultPluginManagerTest {
     /** Check that in all cases org.apache.wiki.plugin is searched. */
     @Test
     public void testSimpleInsertNoPackage4() throws Exception {
-        props.setProperty( DefaultPluginManager.PROP_SEARCHPATH, "com.foo,blat.blaa" );
+        props.setProperty( Engine.PROP_SEARCHPATH, "com.foo,blat.blaa" );
         final DefaultPluginManager m = new DefaultPluginManager( engine, props );
         final String res = m.execute( context,"{INSERT SamplePlugin WHERE text=foobar}" );
         Assertions.assertEquals( "foobar", res );


[jspwiki] 32/35: JSPWIKI-304: un/serialize Workflows + Decision Queue from/to disk

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit a0505787b880145c6bfe90fd51368d00273328ba
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue May 5 21:06:26 2020 +0200

    JSPWIKI-304: un/serialize Workflows + Decision Queue from/to disk
---
 .../wiki/workflow/DefaultWorkflowManager.java      | 75 ++++++++++++++++++++--
 .../apache/wiki/workflow/WorkflowManagerTest.java  | 34 +++++++++-
 2 files changed, 102 insertions(+), 7 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
index fb6e648..b1444f4 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java
@@ -18,6 +18,7 @@
  */
 package org.apache.wiki.workflow;
 
+import org.apache.commons.lang3.time.StopWatch;
 import org.apache.log4j.Logger;
 import org.apache.wiki.api.core.Engine;
 import org.apache.wiki.api.core.Session;
@@ -28,6 +29,14 @@ import org.apache.wiki.event.WikiEvent;
 import org.apache.wiki.event.WikiEventEmitter;
 import org.apache.wiki.event.WorkflowEvent;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.List;
@@ -48,11 +57,15 @@ import java.util.concurrent.CopyOnWriteArrayList;
 public class DefaultWorkflowManager implements WorkflowManager {
 
     private static final Logger LOG = Logger.getLogger( DefaultWorkflowManager.class );
+    static final String SERIALIZATION_FILE = "wkflmgr.ser";
 
-    private final DecisionQueue m_queue = new DecisionQueue();
-    private final Set< Workflow > m_workflows;
-    private final Map< String, Principal > m_approvers;
-    private final List< Workflow > m_completed;
+    /** We use this also a generic serialization id */
+    private static final long serialVersionUID = 6L;
+
+    DecisionQueue m_queue = new DecisionQueue();
+    Set< Workflow > m_workflows;
+    final Map< String, Principal > m_approvers;
+    List< Workflow > m_completed;
     private Engine m_engine = null;
 
     /**
@@ -111,6 +124,59 @@ public class DefaultWorkflowManager implements WorkflowManager {
                 }
             }
         }
+
+        unserializeFromDisk( new File( m_engine.getWorkDir(), SERIALIZATION_FILE ) );
+    }
+
+    /**
+     *  Reads the serialized data from the disk back to memory.
+     *
+     * @return the date when the data was last written on disk or {@code 0} if there has been problems reading from disk.
+     */
+    @SuppressWarnings( "unchecked" )
+    synchronized long unserializeFromDisk( final File f ) {
+        long saved = 0L;
+        final StopWatch sw = new StopWatch();
+        sw.start();
+        try( final ObjectInputStream in = new ObjectInputStream( new BufferedInputStream( new FileInputStream( f ) ) ) ) {
+            final long ver = in.readLong();
+            if( ver != serialVersionUID ) {
+                LOG.warn( "File format has changed; Unable to recover workflows and decision queue from disk." );
+            } else {
+                saved        = in.readLong();
+                m_workflows  = ( Set< Workflow > )in.readObject();
+                m_queue      = ( DecisionQueue )in.readObject();
+                m_completed  = ( List< Workflow > )in.readObject();
+                LOG.debug( "Read serialized data successfully in " + sw );
+            }
+        } catch( final IOException | ClassNotFoundException e ) {
+            LOG.error( "unable to recover from disk workflows and decision queue: " + e.getMessage(), e );
+        }
+        sw.stop();
+
+        return saved;
+    }
+
+    /**
+     *  Serializes workflows and decisionqueue to disk.  The format is private, don't touch it.
+     */
+    synchronized void serializeToDisk( final File f ) {
+        try( final ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( f ) ) ) ) {
+            final StopWatch sw = new StopWatch();
+            sw.start();
+
+            out.writeLong( serialVersionUID );
+            out.writeLong( System.currentTimeMillis() ); // Timestamp
+            out.writeObject( m_workflows );
+            out.writeObject( m_queue );
+            out.writeObject( m_completed );
+
+            sw.stop();
+
+            LOG.debug( "serialization done - took " + sw );
+        } catch( final IOException ioe ) {
+            LOG.error( "Unable to serialize!", ioe );
+        }
     }
 
     /**
@@ -220,6 +286,7 @@ public class DefaultWorkflowManager implements WorkflowManager {
                 default: break;
                 }
             }
+            serializeToDisk( new File( m_engine.getWorkDir(), SERIALIZATION_FILE ) );
         }
     }
 
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
index 5ec58c7..6735029 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowManagerTest.java
@@ -23,20 +23,22 @@ import org.apache.wiki.WikiEngine;
 import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.auth.GroupPrincipal;
 import org.apache.wiki.auth.WikiPrincipal;
+import org.apache.wiki.event.WorkflowEvent;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import java.io.File;
+
 
 public class WorkflowManagerTest {
 
-    protected Workflow w;
-    protected WorkflowManager wm;
     protected WikiEngine m_engine = TestEngine.build();
+    protected WorkflowManager wm = m_engine.getManager( WorkflowManager.class );
+    protected Workflow w;
 
     @BeforeEach
     public void setUp() throws Exception {
-        wm = m_engine.getManager( WorkflowManager.class );
         // Create a workflow with 3 steps, with a Decision in the middle
         w = new Workflow( "workflow.key", new WikiPrincipal( "Owner1" ) );
         final Step startTask = new TaskTest.NormalTask( w );
@@ -97,4 +99,30 @@ public class WorkflowManagerTest {
         Assertions.assertThrows( WikiException.class, () -> wm.getApprover( "workflow.saveWikiPage" ) );
     }
 
+    @Test
+    public void testSerializeUnserialize() throws WikiException {
+        final DefaultWorkflowManager dwm = new DefaultWorkflowManager();
+        dwm.initialize( m_engine, TestEngine.getTestProperties() );
+
+        dwm.unserializeFromDisk( new File( "./target/test-classes", DefaultWorkflowManager.SERIALIZATION_FILE ) );
+        Assertions.assertEquals( 1, dwm.m_workflows.size() );
+        Assertions.assertEquals( 1, dwm.m_queue.decisions().length );
+        Assertions.assertEquals( 0, dwm.m_completed.size() );
+
+        final Workflow workflow = dwm.m_workflows.iterator().next();
+        final Decision d = ( Decision )workflow.getCurrentStep();
+        d.decide( Outcome.DECISION_APPROVE );
+        dwm.actionPerformed( new WorkflowEvent( workflow, WorkflowEvent.COMPLETED ) );
+        dwm.actionPerformed( new WorkflowEvent( d, WorkflowEvent.DQ_REMOVAL ) );
+        Assertions.assertEquals( 0, dwm.getWorkflows().size() );
+        Assertions.assertEquals( 0, dwm.m_queue.decisions().length );
+        Assertions.assertEquals( 1, dwm.getCompletedWorkflows().size() );
+        dwm.serializeToDisk( new File( "./target/test-classes", DefaultWorkflowManager.SERIALIZATION_FILE ) );
+
+        dwm.unserializeFromDisk( new File( "./target/test-classes", DefaultWorkflowManager.SERIALIZATION_FILE ) );
+        Assertions.assertEquals( 0, dwm.m_workflows.size() );
+        Assertions.assertEquals( 0, dwm.m_queue.decisions().length );
+        Assertions.assertEquals( 1, dwm.m_completed.size() );
+    }
+
 }


[jspwiki] 01/35: add format to a couple of method signatures

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 70953e537fcef36cf13adb889308ce2a8cc96a5f
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 17:56:18 2020 +0200

    add format to a couple of method signatures
---
 .../src/main/java/org/apache/wiki/event/WikiPageEvent.java          | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java
index 199fd4d..e5c1ec4 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiPageEvent.java
@@ -197,7 +197,8 @@ public class WikiPageEvent extends WikiEvent {
      *
      * @return a String representation of the type
      */
-    @Override public String eventName() {
+    @Override
+    public String eventName() {
         switch ( getType() ) {
             case PAGE_LOCK:            return "PAGE_LOCK";
             case PAGE_UNLOCK:          return "PAGE_UNLOCK";
@@ -233,7 +234,8 @@ public class WikiPageEvent extends WikiEvent {
      *
      * @return a String description of the type
      */
-    @Override public String getTypeDescription() {
+    @Override
+    public String getTypeDescription() {
         switch ( getType() ) {
             case PAGE_LOCK:            return "page lock event";
             case PAGE_UNLOCK:          return "page unlock event";


[jspwiki] 19/35: dependency updates: flexmark to 0.61.16, selenide to 5.11.0 and tika to 1.24.1

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit c6c34fdf930ce2af255f8439847daee145a7e914
Author: juanpablo <ju...@apache.org>
AuthorDate: Thu Apr 23 21:50:56 2020 +0200

    dependency updates: flexmark to 0.61.16, selenide to 5.11.0 and tika to 1.24.1
---
 pom.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pom.xml b/pom.xml
index 895d97c..32a71ba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,7 +52,7 @@
     <commons-lang.version>3.10</commons-lang.version>
     <commons-text.version>1.8</commons-text.version>
     <ehcache.version>2.10.6</ehcache.version>
-    <flexmark.version>0.61.8</flexmark.version>
+    <flexmark.version>0.61.16</flexmark.version>
     <freshcookies-security.version>0.60</freshcookies-security.version>
     <gson.version>2.8.5</gson.version>
     <hsqldb.version>2.5.0</hsqldb.version>
@@ -71,10 +71,10 @@
     <nekohtml.version>1.9.22</nekohtml.version>
     <oro.version>2.0.8</oro.version>
     <sandler.version>0.5</sandler.version>
-    <selenide.version>5.10.0</selenide.version>
+    <selenide.version>5.11.0</selenide.version>
     <slf4j.version>1.7.30</slf4j.version>
     <stripes.version>1.7.0-async-beta</stripes.version>
-    <tika.version>1.24</tika.version>
+    <tika.version>1.24.1</tika.version>
     <tomcat.version>9.0.34</tomcat.version>
     <wro4j.version>1.8.0</wro4j.version>
     <xmlrpc.version>2.0.1</xmlrpc.version>


[jspwiki] 10/35: add formatting suggested by IntelliJ

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit c503aad85e6ec31f2fe7c1f18d9714426d4a3603
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 18:10:34 2020 +0200

    add formatting suggested by IntelliJ
---
 .../org/apache/wiki/workflow/AbstractStep.java     | 135 +++++++--------------
 1 file changed, 47 insertions(+), 88 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
index d2c77d0..7045438 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
@@ -18,6 +18,8 @@
  */
 package org.apache.wiki.workflow;
 
+import org.apache.wiki.api.exceptions.WikiException;
+
 import java.io.Serializable;
 import java.security.Principal;
 import java.util.ArrayList;
@@ -29,17 +31,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.wiki.api.exceptions.WikiException;
-
 /**
- * Abstact superclass that provides a complete implementation of most
- * Step methods; subclasses need only implement {@link #execute()} and
+ * Abstract superclass that provides a complete implementation of most Step methods; subclasses need only implement {@link #execute()} and
  * {@link #getActor()}.
  *
  * @since 2.5
  */
-public abstract class AbstractStep implements Step
-{
+public abstract class AbstractStep implements Step {
 
     private static final long serialVersionUID = 8635678679349653768L;
 
@@ -53,7 +51,7 @@ public abstract class AbstractStep implements Step
 
     private boolean m_completed;
 
-    private final Map<Outcome, Step> m_successors;
+    private final Map< Outcome, Step > m_successors;
 
     private Workflow m_workflow;
 
@@ -64,44 +62,31 @@ public abstract class AbstractStep implements Step
     private boolean m_started;
 
     /**
-     * Protected constructor that creates a new Step with a specified message key.
-     * After construction, the method {@link #setWorkflow(Workflow)} should be
-     * called.
+     * Protected constructor that creates a new Step with a specified message key. After construction, the method
+     * {@link #setWorkflow(Workflow)} should be called.
      *
-     * @param messageKey
-     *            the Step's message key, such as
-     *            <code>decision.editPageApproval</code>. By convention, the
-     *            message prefix should be a lower-case version of the Step's
-     *            type, plus a period (<em>e.g.</em>, <code>task.</code>
-     *            and <code>decision.</code>).
+     * @param messageKey the Step's message key, such as {@code decision.editPageApproval}. By convention, the message prefix should
+     *                   be a lower-case version of the Step's type, plus a period (<em>e.g.</em>, {@code task.} and {@code decision.}).
      */
-    protected AbstractStep( String messageKey )
-    {
+    protected AbstractStep( final String messageKey ) {
         m_started = false;
         m_start = Workflow.TIME_NOT_SET;
         m_completed = false;
         m_end = Workflow.TIME_NOT_SET;
-        m_errors = new ArrayList<String>();
+        m_errors = new ArrayList<>();
         m_outcome = Outcome.STEP_CONTINUE;
         m_key = messageKey;
-        m_successors = new LinkedHashMap<Outcome, Step>();
+        m_successors = new LinkedHashMap<>();
     }
 
     /**
-     * Constructs a new Step belonging to a specified Workflow and having a
-     * specified message key.
+     * Constructs a new Step belonging to a specified Workflow and having a specified message key.
      *
-     * @param workflow
-     *            the workflow the Step belongs to
-     * @param messageKey
-     *            the Step's message key, such as
-     *            <code>decision.editPageApproval</code>. By convention, the
-     *            message prefix should be a lower-case version of the Step's
-     *            type, plus a period (<em>e.g.</em>, <code>task.</code>
-     *            and <code>decision.</code>).
+     * @param workflow the workflow the Step belongs to
+     * @param messageKey the Step's message key, such as {@code decision.editPageApproval}. By convention, the message prefix should
+     *                   be a lower-case version of the Step's type, plus a period (<em>e.g.</em>, {@code task.} and {@code decision.}).
      */
-    public AbstractStep( Workflow workflow, String messageKey )
-    {
+    public AbstractStep( final Workflow workflow, final String messageKey ) {
         this( messageKey );
         setWorkflow( workflow );
     }
@@ -109,25 +94,22 @@ public abstract class AbstractStep implements Step
     /**
      * {@inheritDoc}
      */
-    public final void addSuccessor(Outcome outcome, Step step)
-    {
+    public final void addSuccessor( final Outcome outcome, final Step step ) {
         m_successors.put( outcome, step );
     }
 
     /**
      * {@inheritDoc}
      */
-    public final Collection< Outcome > getAvailableOutcomes()
-    {
-        Set<Outcome> outcomes = m_successors.keySet();
+    public final Collection< Outcome > getAvailableOutcomes() {
+        final Set< Outcome > outcomes = m_successors.keySet();
         return Collections.unmodifiableCollection( outcomes );
     }
 
     /**
      * {@inheritDoc}
      */
-    public final List< String > getErrors()
-    {
+    public final List< String > getErrors() {
         return Collections.unmodifiableList( m_errors );
     }
 
@@ -144,19 +126,16 @@ public abstract class AbstractStep implements Step
     /**
      * {@inheritDoc}
      */
-    public final Date getEndTime()
-    {
+    public final Date getEndTime() {
         return m_end;
     }
 
     /**
      * {@inheritDoc}
      */
-    public final Serializable[] getMessageArguments()
-    {
-        if ( m_workflow == null )
-        {
-            return new Serializable[0];
+    public final Serializable[] getMessageArguments() {
+        if( m_workflow == null ) {
+            return new Serializable[ 0 ];
         }
         return m_workflow.getMessageArguments();
     }
@@ -164,26 +143,22 @@ public abstract class AbstractStep implements Step
     /**
      * {@inheritDoc}
      */
-    public final String getMessageKey()
-    {
+    public final String getMessageKey() {
         return m_key;
     }
 
     /**
      * {@inheritDoc}
      */
-    public final synchronized Outcome getOutcome()
-    {
+    public final synchronized Outcome getOutcome() {
         return m_outcome;
     }
 
     /**
      * {@inheritDoc}
      */
-    public Principal getOwner()
-    {
-        if ( m_workflow == null )
-        {
+    public Principal getOwner() {
+        if( m_workflow == null ) {
             return null;
         }
         return m_workflow.getOwner();
@@ -192,55 +167,45 @@ public abstract class AbstractStep implements Step
     /**
      * {@inheritDoc}
      */
-    public final Date getStartTime()
-    {
+    public final Date getStartTime() {
         return m_start;
     }
 
     /**
      * {@inheritDoc}
      */
-    public final synchronized Workflow getWorkflow()
-    {
+    public final synchronized Workflow getWorkflow() {
         return m_workflow;
     }
 
     /**
      * {@inheritDoc}
      */
-    public final boolean isCompleted()
-    {
+    public final boolean isCompleted() {
         return m_completed;
     }
 
     /**
      * {@inheritDoc}
      */
-    public final boolean isStarted()
-    {
+    public final boolean isStarted() {
         return m_started;
     }
 
     /**
      * {@inheritDoc}
      */
-    public final synchronized void setOutcome(Outcome outcome)
-    {
+    public final synchronized void setOutcome( final Outcome outcome ) {
         // Is this an allowed Outcome?
-        if ( !m_successors.containsKey( outcome ) )
-        {
-            if ( !Outcome.STEP_CONTINUE.equals( outcome ) &&
-                 !Outcome.STEP_ABORT.equals( outcome ) )
-            {
-                 throw new IllegalArgumentException( "Outcome " + outcome.getMessageKey() + " is not supported for this Step." );
+        if( !m_successors.containsKey( outcome ) ) {
+            if( !Outcome.STEP_CONTINUE.equals( outcome ) && !Outcome.STEP_ABORT.equals( outcome ) ) {
+                throw new IllegalArgumentException( "Outcome " + outcome.getMessageKey() + " is not supported for this Step." );
             }
         }
 
         // Is this a "completion" outcome?
-        if ( outcome.isCompletion() )
-        {
-            if ( m_completed )
-            {
+        if( outcome.isCompletion() ) {
+            if( m_completed ) {
                 throw new IllegalStateException( "Step has already been marked complete; cannot set again." );
             }
             m_completed = true;
@@ -252,10 +217,8 @@ public abstract class AbstractStep implements Step
     /**
      * {@inheritDoc}
      */
-    public final synchronized void start() throws WikiException
-    {
-        if ( m_started )
-        {
+    public final synchronized void start() throws WikiException {
+        if( m_started ) {
             throw new IllegalStateException( "Step already started." );
         }
         m_started = true;
@@ -265,8 +228,7 @@ public abstract class AbstractStep implements Step
     /**
      * {@inheritDoc}
      */
-    public final Step getSuccessor( Outcome outcome )
-    {
+    public final Step getSuccessor( final Outcome outcome ) {
         return m_successors.get( outcome );
     }
 
@@ -274,22 +236,19 @@ public abstract class AbstractStep implements Step
 
     /**
      * method that sets the parent Workflow post-construction.
+     *
      * @param workflow the parent workflow to set
      */
-    public final synchronized void setWorkflow( Workflow workflow )
-    {
+    public final synchronized void setWorkflow( final Workflow workflow ) {
         m_workflow = workflow;
     }
 
     /**
-     * Protected helper method that adds a String representing an error message
-     * to the Step's cached errors list.
+     * Protected helper method that adds a String representing an error message to the Step's cached errors list.
      *
-     * @param message
-     *            the error message
+     * @param message the error message
      */
-    protected final synchronized void addError( String message )
-    {
+    protected final synchronized void addError( final String message ) {
         m_errors.add( message );
     }
 


[jspwiki] 31/35: fix javadocs for new workflow events.

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 63ea76821826148b0962cc109477e7bc529322ed
Author: juanpablo <ju...@apache.org>
AuthorDate: Sun May 3 22:03:31 2020 +0200

    fix javadocs for new workflow events.
---
 jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
index 76caffa..10f0d48 100644
--- a/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
+++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WorkflowEvent.java
@@ -63,10 +63,10 @@ public final class WorkflowEvent extends WikiEvent {
     /** When the workflow wishes to remove a Decision from the DecisionQueue */
     public static final int DQ_REMOVAL = 70;
 
-    /** When the workflow wishes to remove a Decision from the DecisionQueue */
+    /** When the decision queue decides the outcome of a Decision */
     public static final int DQ_DECIDE = 80;
 
-    /** When the workflow wishes to remove a Decision from the DecisionQueue */
+    /** When the decision queue reassigns a Decision */
     public static final int DQ_REASSIGN = 90;
 
     /**


[jspwiki] 35/35: 2.11.0-M7-git-19

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit acbb8efae07c22e5ac5ad925b9c432b587a1c61d
Author: juanpablo <ju...@apache.org>
AuthorDate: Tue May 5 21:17:13 2020 +0200

    2.11.0-M7-git-19
---
 ChangeLog.md                                               | 13 +++++++++++++
 jspwiki-api/src/main/java/org/apache/wiki/api/Release.java |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/ChangeLog.md b/ChangeLog.md
index 7e70096..abff20b 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -19,6 +19,19 @@ under the License.
 
 **2020-04-09  Juan Pablo Santos (juanpablo AT apache DOT org)**
 
+* _2.11.0-M7-git-19_
+
+* [JSPWIKI-304](https://issues.apache.org/jira/browse/JSPWIKI-304): Workflows are not Serializable
+
+* Dependency updates
+    * Flexmark to 0.61.26
+    * JUnit to 5.6.2
+    * Lucene to 8.5.1
+    * Selenide to 5.11.1
+    * Tika to 1.24
+
+**2020-04-09  Juan Pablo Santos (juanpablo AT apache DOT org)**
+
 * _2.11.0-M7-git-18_
 
 * [JSPWIKI-303](https://issues.apache.org/jira/browse/JSPWIKI-303): [JSPWiki API](https://jspwiki-wiki.apache.org/Wiki.jsp?page=JSPWikiPublicAPI) library creation
diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java b/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java
index 2ff709b..04d1e73 100644
--- a/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java
@@ -69,7 +69,7 @@ public final class Release {
      *  <p>
      *  If the build identifier is empty, it is not added.
      */
-    public static final String     BUILD         = "git-18";
+    public static final String     BUILD         = "git-19";
 
     /**
      *  This is the generic version string you should use when printing out the version.  It is of


[jspwiki] 26/35: IntelliJ fix: use static call for static method.

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit f571e9b240342539de9b267928a115592fa71874
Author: juanpablo <ju...@apache.org>
AuthorDate: Sun May 3 19:56:50 2020 +0200

    IntelliJ fix: use static call for static method.
---
 .../main/java/org/apache/wiki/references/DefaultReferenceManager.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/references/DefaultReferenceManager.java b/jspwiki-main/src/main/java/org/apache/wiki/references/DefaultReferenceManager.java
index 5db59b1..7495ab2 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/references/DefaultReferenceManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/references/DefaultReferenceManager.java
@@ -239,7 +239,7 @@ public class DefaultReferenceManager extends BasePageFilter implements Reference
         sw.stop();
         log.info( "Cross reference scan done in "+sw );
 
-        WikiEventManager.getInstance().addWikiEventListener( m_engine.getManager( PageManager.class ), this );
+        WikiEventManager.addWikiEventListener( m_engine.getManager( PageManager.class ), this );
     }
 
     /**


[jspwiki] 13/35: throw ProviderException instead of InternalWikiException, as it refers to a page provider operation

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 96e870b43c36bc658c41b9ceb9f17ac864ffdbec
Author: juanpablo <ju...@apache.org>
AuthorDate: Sat Apr 11 19:22:44 2020 +0200

    throw ProviderException instead of InternalWikiException, as it refers to a page provider operation
---
 .../src/main/java/org/apache/wiki/content/DefaultPageRenamer.java      | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/content/DefaultPageRenamer.java b/jspwiki-main/src/main/java/org/apache/wiki/content/DefaultPageRenamer.java
index 9d64ecc..571fff6 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/content/DefaultPageRenamer.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/content/DefaultPageRenamer.java
@@ -19,7 +19,6 @@
 package org.apache.wiki.content;
 
 import org.apache.log4j.Logger;
-import org.apache.wiki.InternalWikiException;
 import org.apache.wiki.api.core.Attachment;
 import org.apache.wiki.api.core.Context;
 import org.apache.wiki.api.core.Engine;
@@ -110,7 +109,7 @@ public class DefaultPageRenamer implements PageRenamer {
         //  Add a comment to the page notifying what changed.  This adds a new revision to the repo with no actual change.
         toPage = engine.getManager( PageManager.class ).getPage( renameToClean );
         if( toPage == null ) {
-            throw new InternalWikiException( "Rename seems to have failed for some strange reason - please check logs!" );
+            throw new ProviderException( "Rename seems to have failed for some strange reason - please check logs!" );
         }
         toPage.setAttribute( Page.CHANGENOTE, fromPage.getName() + " ==> " + toPage.getName() );
         toPage.setAuthor( context.getCurrentUser().getName() );


[jspwiki] 20/35: move o.a.w.workflow.Workflow#TIME_NOT_SET to o.a.w.workflow.Step#TIME_NOT_SET

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git

commit 5cc6f09ce80b8efc96986f4317acaf621fa0588e
Author: juanpablo <ju...@apache.org>
AuthorDate: Thu Apr 23 21:52:19 2020 +0200

    move o.a.w.workflow.Workflow#TIME_NOT_SET to o.a.w.workflow.Step#TIME_NOT_SET
---
 .../org/apache/wiki/workflow/AbstractStep.java     |  4 ++--
 .../main/java/org/apache/wiki/workflow/Step.java   |  7 ++++--
 .../java/org/apache/wiki/workflow/Workflow.java    | 11 ++++-----
 .../org/apache/wiki/workflow/WorkflowBuilder.java  |  3 +--
 .../apache/wiki/workflow/SimpleDecisionTest.java   |  8 +++----
 .../java/org/apache/wiki/workflow/TaskTest.java    | 28 +++++++++++-----------
 .../org/apache/wiki/workflow/WorkflowTest.java     | 18 +++++++-------
 7 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
index 7045438..e545990 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/AbstractStep.java
@@ -70,9 +70,9 @@ public abstract class AbstractStep implements Step {
      */
     protected AbstractStep( final String messageKey ) {
         m_started = false;
-        m_start = Workflow.TIME_NOT_SET;
+        m_start = Step.TIME_NOT_SET;
         m_completed = false;
-        m_end = Workflow.TIME_NOT_SET;
+        m_end = Step.TIME_NOT_SET;
         m_errors = new ArrayList<>();
         m_outcome = Outcome.STEP_CONTINUE;
         m_key = messageKey;
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
index 7ed8561..50e3327 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Step.java
@@ -53,6 +53,9 @@ import java.util.List;
  */
 public interface Step extends Serializable {
 
+    /** Time value: the start or end time has not been set. */
+    public static final Date TIME_NOT_SET = new Date( 0 );
+
     /**
      * Adds a successor Step to this one, which will be triggered by a supplied Outcome. Implementations should respect the order in which
      * Outcomes are added; {@link #getAvailableOutcomes()} should return them in the same order they were added.
@@ -105,7 +108,7 @@ public interface Step extends Serializable {
     Principal getActor();
 
     /**
-     * The end time for this Step. This value should be set when the step completes. Returns {@link Workflow#TIME_NOT_SET} if not completed
+     * The end time for this Step. This value should be set when the step completes. Returns {@link #TIME_NOT_SET} if not completed
      * yet.
      * 
      * @return the end time
@@ -136,7 +139,7 @@ public interface Step extends Serializable {
     Outcome getOutcome();
 
     /**
-     * The start time for this Step. Returns {@link Workflow#TIME_NOT_SET} if not started yet.
+     * The start time for this Step. Returns {@link #TIME_NOT_SET} if not started yet.
      * 
      * @return the start time
      */
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
index 63d2ca2..7657b27 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/Workflow.java
@@ -164,9 +164,6 @@ public class Workflow implements Serializable {
 
     private static final long serialVersionUID = 5228149040690660032L;
 
-    /** Time value: the start or end time has not been set. */
-    public static final Date TIME_NOT_SET = new Date( 0 );
-
     /** ID value: the workflow ID has not been set. */
     public static final int ID_NOT_SET = 0;
 
@@ -317,7 +314,7 @@ public class Workflow implements Serializable {
 
     /**
      * The end time for this Workflow, expressed as a system time number. This value is equal to the end-time value returned by the final
-     * Step's {@link Step#getEndTime()} method, if the workflow has completed. Otherwise, this method returns {@link #TIME_NOT_SET}.
+     * Step's {@link Step#getEndTime()} method, if the workflow has completed. Otherwise, this method returns {@link Step#TIME_NOT_SET}.
      *
      * @return the end time
      */
@@ -328,7 +325,7 @@ public class Workflow implements Serializable {
                 return last.getEndTime();
             }
         }
-        return TIME_NOT_SET;
+        return Step.TIME_NOT_SET;
     }
 
     /**
@@ -391,13 +388,13 @@ public class Workflow implements Serializable {
     /**
      * The start time for this Workflow, expressed as a system time number. This value is equal to the start-time value returned by the
      * first Step's {@link Step#getStartTime()} method, if the workflow has started already. Otherwise, this method returns
-     * {@link #TIME_NOT_SET}.
+     * {@link Step#TIME_NOT_SET}.
      *
      * @return the start time
      */
     public final Date getStartTime()
     {
-        return isStarted() ? m_firstStep.getStartTime() : TIME_NOT_SET;
+        return isStarted() ? m_firstStep.getStartTime() : Step.TIME_NOT_SET;
     }
 
     /**
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java
index 95afafb..9a8e7f2 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/WorkflowBuilder.java
@@ -115,8 +115,7 @@ public final class WorkflowBuilder {
 
         // If Decision required, create a simple approval workflow
         if ( decisionRequired ) {
-            // Look up the name of the approver (user or group) listed in jspwiki.properties;
-            // approvals go to the approver's decision cue
+            // Look up the name of the approver (user or group) listed in jspwiki.properties; approvals go to the approver's decision queue
             final Principal approverPrincipal = mgr.getApprover( workflowApproverKey );
             final Decision decision = new SimpleDecision( workflow, decisionKey, approverPrincipal );
 
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
index 409e40d..5bf3539 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/SimpleDecisionTest.java
@@ -119,10 +119,10 @@ public class SimpleDecisionTest {
 
     @Test
     public void testGetEndTime() throws WikiException {
-        Assertions.assertEquals( Workflow.TIME_NOT_SET, m_decision.getEndTime() );
+        Assertions.assertEquals( Step.TIME_NOT_SET, m_decision.getEndTime() );
         m_decision.start();
         m_decision.decide( Outcome.DECISION_APPROVE );
-        Assertions.assertTrue( ( Workflow.TIME_NOT_SET != m_decision.getEndTime() ) );
+        Assertions.assertTrue( ( Step.TIME_NOT_SET != m_decision.getEndTime() ) );
     }
 
     @Test
@@ -140,10 +140,10 @@ public class SimpleDecisionTest {
 
     @Test
     public void testGetStartTime() throws WikiException {
-        Assertions.assertEquals( Workflow.TIME_NOT_SET, m_decision.getStartTime() );
+        Assertions.assertEquals( Step.TIME_NOT_SET, m_decision.getStartTime() );
         m_decision.start();
         m_decision.decide( Outcome.DECISION_APPROVE );
-        Assertions.assertTrue( ( Workflow.TIME_NOT_SET != m_decision.getStartTime() ) );
+        Assertions.assertTrue( ( Step.TIME_NOT_SET != m_decision.getStartTime() ) );
     }
 
     @Test
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java
index 0eebdb1..6e330c0 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/TaskTest.java
@@ -18,15 +18,15 @@
  */
 package org.apache.wiki.workflow;
 
-import java.util.Collection;
-import java.util.List;
-
 import org.apache.wiki.api.exceptions.WikiException;
 import org.apache.wiki.auth.WikiPrincipal;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import java.util.Collection;
+import java.util.List;
+
 public class TaskTest
 {
 
@@ -38,7 +38,7 @@ public class TaskTest
     {
         private static final long serialVersionUID = 1L;
 
-        public NormalTask(Workflow workflow)
+        public NormalTask( final Workflow workflow)
         {
             super(workflow, "task.normal");
         }
@@ -54,7 +54,7 @@ public class TaskTest
     {
         private static final long serialVersionUID = 1L;
 
-        public ErrorTask(Workflow workflow)
+        public ErrorTask( final Workflow workflow)
         {
             super(workflow, "task.error");
         }
@@ -86,11 +86,11 @@ public class TaskTest
     public void testSuccessors()
     {
         // If task finishes normally, branch to a decision (d1)
-        Step d1 = new SimpleDecision(m_workflow, "decision1.key", new WikiPrincipal("Actor1"));
+        final Step d1 = new SimpleDecision(m_workflow, "decision1.key", new WikiPrincipal("Actor1"));
         m_task.addSuccessor(Outcome.STEP_COMPLETE, d1);
 
         // If the task aborts, branch to an alternate decision (d2)
-        Step d2 = new SimpleDecision(m_workflow, "decision2.key", new WikiPrincipal("Actor2"));
+        final Step d2 = new SimpleDecision(m_workflow, "decision2.key", new WikiPrincipal("Actor2"));
         m_task.addSuccessor(Outcome.STEP_ABORT, d2);
 
         Assertions.assertEquals(d1, m_task.getSuccessor(Outcome.STEP_COMPLETE));
@@ -110,7 +110,7 @@ public class TaskTest
         m_task.addError("Error deciding something.");
         m_task.addError("Error deciding something else.");
 
-        List< String > errors = m_task.getErrors();
+        final List< String > errors = m_task.getErrors();
         Assertions.assertEquals(2, errors.size());
         Assertions.assertEquals("Error deciding something.", errors.get(0));
         Assertions.assertEquals("Error deciding something else.", errors.get(1));
@@ -119,7 +119,7 @@ public class TaskTest
     @Test
     public void testAvailableOutcomes()
     {
-        Collection< Outcome > outcomes = m_task.getAvailableOutcomes();
+        final Collection< Outcome > outcomes = m_task.getAvailableOutcomes();
         Assertions.assertFalse(outcomes.contains(Outcome.DECISION_APPROVE));
         Assertions.assertFalse(outcomes.contains(Outcome.DECISION_DENY));
         Assertions.assertFalse(outcomes.contains(Outcome.DECISION_HOLD));
@@ -131,10 +131,10 @@ public class TaskTest
     @Test
     public void testGetEndTime() throws WikiException
     {
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, m_task.getEndTime());
+        Assertions.assertEquals(Step.TIME_NOT_SET, m_task.getEndTime());
         m_task.start();
         m_task.setOutcome(m_task.execute());
-        Assertions.assertTrue((Workflow.TIME_NOT_SET  !=  m_task.getEndTime()));
+        Assertions.assertTrue((Step.TIME_NOT_SET  !=  m_task.getEndTime()));
     }
 
     @Test
@@ -162,10 +162,10 @@ public class TaskTest
     @Test
     public void testGetStartTime() throws WikiException
     {
-        Assertions.assertEquals(Workflow.TIME_NOT_SET, m_task.getStartTime());
+        Assertions.assertEquals(Step.TIME_NOT_SET, m_task.getStartTime());
         m_task.start();
         m_task.execute();
-        Assertions.assertTrue((Workflow.TIME_NOT_SET  !=  m_task.getStartTime()));
+        Assertions.assertTrue((Step.TIME_NOT_SET  !=  m_task.getStartTime()));
     }
 
     @Test
@@ -199,7 +199,7 @@ public class TaskTest
         {
             m_task.start();
         }
-        catch (IllegalStateException e)
+        catch ( final IllegalStateException e)
         {
             // Swallow
             return;
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
index d600e0b..84b7444 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/workflow/WorkflowTest.java
@@ -77,8 +77,8 @@ public class WorkflowTest {
         Assertions.assertEquals( Workflow.ID_NOT_SET, w.getId() );
         Assertions.assertEquals( new WikiPrincipal( "Owner1" ), w.getOwner() );
         Assertions.assertEquals( Workflow.CREATED, w.getCurrentState() );
-        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getStartTime() );
-        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getEndTime() );
+        Assertions.assertEquals( Step.TIME_NOT_SET, w.getStartTime() );
+        Assertions.assertEquals( Step.TIME_NOT_SET, w.getEndTime() );
     }
 
     @Test
@@ -118,7 +118,7 @@ public class WorkflowTest {
     public void testGetMessageArgObjects() {
         // Try passing some valid object types: Date, Number
         w.addMessageArgument( new Date() );
-        w.addMessageArgument( Integer.valueOf( 1 ) );
+        w.addMessageArgument( 1 );
         w.addMessageArgument( 2d );
         w.addMessageArgument( new BigDecimal( "3.14" ) );
 
@@ -303,23 +303,23 @@ public class WorkflowTest {
     @Test
     public void testGetStartTime() throws WikiException {
         // Start time should be not be set until we start the workflow
-        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getStartTime() );
+        Assertions.assertEquals( Step.TIME_NOT_SET, w.getStartTime() );
         w.start();
-        Assertions.assertNotSame( Workflow.TIME_NOT_SET, w.getStartTime() );
+        Assertions.assertNotSame( Step.TIME_NOT_SET, w.getStartTime() );
         final Decision d = ( Decision )w.getCurrentStep();
         d.decide( Outcome.DECISION_APPROVE );
-        Assertions.assertNotSame( Workflow.TIME_NOT_SET, w.getStartTime() );
+        Assertions.assertNotSame( Step.TIME_NOT_SET, w.getStartTime() );
     }
 
     @Test
     public void testGetEndTime() throws WikiException {
         // End time should be not set until we finish all 3 steps
-        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getEndTime() );
+        Assertions.assertEquals( Step.TIME_NOT_SET, w.getEndTime() );
         w.start();
-        Assertions.assertEquals( Workflow.TIME_NOT_SET, w.getEndTime() );
+        Assertions.assertEquals( Step.TIME_NOT_SET, w.getEndTime() );
         final Decision d = ( Decision )w.getCurrentStep();
         d.decide( Outcome.DECISION_APPROVE );
-        Assertions.assertNotSame( Workflow.TIME_NOT_SET, w.getEndTime() );
+        Assertions.assertNotSame( Step.TIME_NOT_SET, w.getEndTime() );
     }
 
     @Test