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 86778fd4433435f8c3ab77e8379b99f92bc04298 Author: juanpablo <[email protected]> AuthorDate: Tue Jan 7 22:31:29 2020 +0100 rename WorkflowManager as DefaultWorkflowManager and extract interface (WorkflowManager) from it --- .../wiki/workflow/DefaultWorkflowManager.java | 260 +++++++++++++++++ .../org/apache/wiki/workflow/WorkflowManager.java | 315 ++++----------------- .../src/main/resources/ini/classmappings.xml | 2 +- 3 files changed, 312 insertions(+), 265 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 new file mode 100644 index 0000000..bec5649 --- /dev/null +++ b/jspwiki-main/src/main/java/org/apache/wiki/workflow/DefaultWorkflowManager.java @@ -0,0 +1,260 @@ +/* + 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.WikiEngine; +import org.apache.wiki.WikiSession; +import org.apache.wiki.api.exceptions.WikiException; +import org.apache.wiki.auth.acl.UnresolvedPrincipal; +import org.apache.wiki.event.WikiEvent; +import org.apache.wiki.event.WikiEventListener; +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.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + + +/** + * <p> + * Monitor class that tracks running Workflows. The WorkflowManager also keeps track of the names of + * users or groups expected to approve particular Workflows. + * </p> + */ +public class DefaultWorkflowManager implements WorkflowManager, WikiEventListener { + + 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; + private WikiEngine m_engine = null; + + /** + * Constructs a new WorkflowManager, with an empty workflow cache. New Workflows are automatically assigned unique identifiers, + * starting with 1. + */ + public DefaultWorkflowManager() { + m_next = 1; + m_workflows = ConcurrentHashMap.newKeySet(); + m_approvers = new ConcurrentHashMap<>(); + m_completed = new CopyOnWriteArrayList<>(); + } + + /** + * {@inheritDoc} + */ + @Override + public void start( final Workflow workflow ) throws WikiException { + m_workflows.add( workflow ); + workflow.setWorkflowManager( this ); + workflow.setId( nextId() ); + workflow.start(); + } + + /** + * {@inheritDoc} + */ + @Override + public Set< Workflow > getWorkflows() { + final Set< Workflow > workflows = ConcurrentHashMap.newKeySet(); + workflows.addAll( m_workflows ); + return workflows; + } + + /** + * {@inheritDoc} + */ + @Override + public List< Workflow > getCompletedWorkflows() { + return new CopyOnWriteArrayList< >( m_completed ); + } + + /** + * {@inheritDoc} + */ + @Override + public void initialize( final WikiEngine engine, final Properties props ) { + m_engine = engine; + + // Identify the workflows requiring approvals + for( final Object o : props.keySet() ) { + final String prop = ( String )o; + if( prop.startsWith( PROPERTY_APPROVER_PREFIX ) ) { + // For the key, everything after the prefix is the workflow name + final String key = prop.substring( PROPERTY_APPROVER_PREFIX.length() ); + if( key.length() > 0 ) { + // Only use non-null/non-blank approvers + final String approver = props.getProperty( prop ); + if( approver != null && approver.length() > 0 ) { + m_approvers.put( key, new UnresolvedPrincipal( approver ) ); + } + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean requiresApproval( final String messageKey ) { + return m_approvers.containsKey( messageKey ); + } + + /** + * {@inheritDoc} + */ + @Override + public Principal getApprover( final String messageKey ) throws WikiException { + Principal approver = m_approvers.get( messageKey ); + if ( approver == null ) { + throw new WikiException( "Workflow '" + messageKey + "' does not require approval." ); + } + + // Try to resolve UnresolvedPrincipals + if ( approver instanceof UnresolvedPrincipal ) { + final String name = approver.getName(); + approver = m_engine.getAuthorizationManager().resolvePrincipal( name ); + + // If still unresolved, throw exception; otherwise, freshen our cache + if ( approver instanceof UnresolvedPrincipal ) { + throw new WikiException( "Workflow approver '" + name + "' cannot not be resolved." ); + } + + m_approvers.put( messageKey, approver ); + } + return approver; + } + + /** + * Protected helper method that returns the associated WikiEngine + * + * @return the wiki engine + */ + protected WikiEngine getEngine() { + if ( m_engine == null ) { + throw new IllegalStateException( "WikiEngine cannot be null; please initialize WorkflowManager first." ); + } + return m_engine; + } + + /** + * Returns the DecisionQueue associated with this WorkflowManager + * + * @return the decision queue + */ + public DecisionQueue getDecisionQueue() + { + 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} + */ + @Override + public List< Workflow > getOwnerWorkflows( final WikiSession session ) { + final List< Workflow > workflows = new ArrayList<>(); + if ( session.isAuthenticated() ) { + final Principal[] sessionPrincipals = session.getPrincipals(); + for( final Workflow w : m_workflows ) { + final Principal owner = w.getOwner(); + for ( final Principal sessionPrincipal : sessionPrincipals ) { + if ( sessionPrincipal.equals( owner ) ) { + workflows.add( w ); + break; + } + } + } + } + return workflows; + } + + /** + * 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. + * + * @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; + // Add to manager + case WorkflowEvent.CREATED : add( workflow ); break; + default: break; + } + } + } + + /** + * Protected helper method that adds a newly created Workflow to the cache, and sets its {@code workflowManager} and + * {@code Id} properties if not set. + * + * @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() ); + } + m_workflows.add( workflow ); + } + + /** + * Protected helper method that removes a specified Workflow from the cache, and moves it to the workflow history list. This method + * defensively checks to see if the workflow has not yet been removed. + * + * @param workflow the workflow to remove + */ + protected void remove( final Workflow workflow ) { + if( m_workflows.contains( workflow ) ) { + m_workflows.remove( workflow ); + m_completed.add( workflow ); + } + } + +} 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 cb05a7e..8fe46cb 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 @@ -18,345 +18,132 @@ */ package org.apache.wiki.workflow; +import org.apache.wiki.WikiEngine; +import org.apache.wiki.WikiSession; +import org.apache.wiki.api.exceptions.WikiException; + import java.security.Principal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.wiki.WikiEngine; -import org.apache.wiki.WikiSession; -import org.apache.wiki.api.exceptions.WikiException; -import org.apache.wiki.auth.acl.UnresolvedPrincipal; -import org.apache.wiki.event.WikiEvent; -import org.apache.wiki.event.WikiEventListener; -import org.apache.wiki.event.WorkflowEvent; /** * <p> - * Monitor class that tracks running Workflows. The WorkflowManager also keeps track of the names of - * users or groups expected to approve particular Workflows. + * Monitor class that tracks running Workflows. The WorkflowManager also keeps track of the names of users or groups expected to approve + * particular Workflows. * </p> */ -public class WorkflowManager implements WikiEventListener { +public interface WorkflowManager { /** The workflow attribute which stores the wikiContext. */ - public static final String WF_WP_SAVE_ATTR_PRESAVE_WIKI_CONTEXT = "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> */ - public static final String WF_WP_SAVE_APPROVER = "workflow.saveWikiPage"; + String WF_WP_SAVE_APPROVER = "workflow.saveWikiPage"; /** The message key for storing the Decision text for saving a page. Value is {@value}. */ - public static final String WF_WP_SAVE_DECISION_MESSAGE_KEY = "decision.saveWikiPage"; + String WF_WP_SAVE_DECISION_MESSAGE_KEY = "decision.saveWikiPage"; /** The message key for rejecting the decision to save the page. Value is {@value}. */ - public static final String WF_WP_SAVE_REJECT_MESSAGE_KEY = "notification.saveWikiPage.reject"; + String WF_WP_SAVE_REJECT_MESSAGE_KEY = "notification.saveWikiPage.reject"; /** Fact name for storing the page name. Value is {@value}. */ - public static final String WF_WP_SAVE_FACT_PAGE_NAME = "fact.pageName"; + String WF_WP_SAVE_FACT_PAGE_NAME = "fact.pageName"; /** Fact name for storing a diff text. Value is {@value}. */ - public static final String WF_WP_SAVE_FACT_DIFF_TEXT = "fact.diffText"; + String WF_WP_SAVE_FACT_DIFF_TEXT = "fact.diffText"; /** Fact name for storing the current text. Value is {@value}. */ - public static final String WF_WP_SAVE_FACT_CURRENT_TEXT = "fact.currentText"; + String WF_WP_SAVE_FACT_CURRENT_TEXT = "fact.currentText"; /** Fact name for storing the proposed (edited) text. Value is {@value}. */ - public static final String WF_WP_SAVE_FACT_PROPOSED_TEXT = "fact.proposedText"; + String WF_WP_SAVE_FACT_PROPOSED_TEXT = "fact.proposedText"; /** Fact name for storing whether the user is authenticated or not. Value is {@value}. */ - public static final String WF_WP_SAVE_FACT_IS_AUTHENTICATED = "fact.isAuthenticated"; + String WF_WP_SAVE_FACT_IS_AUTHENTICATED = "fact.isAuthenticated"; /** The workflow attribute which stores the user profile. */ - public static final String WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE = "userProfile"; + String WF_UP_CREATE_SAVE_ATTR_SAVED_PROFILE = "userProfile"; /** The name of the key from jspwiki.properties which defines who shall approve the workflow of creating a user profile. Value is <tt>{@value}</tt> */ - public static final String WF_UP_CREATE_SAVE_APPROVER = "workflow.createUserProfile"; + String WF_UP_CREATE_SAVE_APPROVER = "workflow.createUserProfile"; /** The message key for storing the Decision text for saving a user profile. Value is {@value}. */ - public static final String WF_UP_CREATE_SAVE_DECISION_MESSAGE_KEY = "decision.createUserProfile"; + String WF_UP_CREATE_SAVE_DECISION_MESSAGE_KEY = "decision.createUserProfile"; /** Fact name for storing a the submitter name. Value is {@value}. */ - public static final String WF_UP_CREATE_SAVE_FACT_SUBMITTER = "fact.submitter"; + String WF_UP_CREATE_SAVE_FACT_SUBMITTER = "fact.submitter"; /** Fact name for storing the preferences' login name. Value is {@value}. */ - public static final String WF_UP_CREATE_SAVE_FACT_PREFS_LOGIN_NAME = "prefs.loginname"; + String WF_UP_CREATE_SAVE_FACT_PREFS_LOGIN_NAME = "prefs.loginname"; /** Fact name for storing the preferences' full name. Value is {@value}. */ - public static final String WF_UP_CREATE_SAVE_FACT_PREFS_FULL_NAME = "prefs.fullname"; + String WF_UP_CREATE_SAVE_FACT_PREFS_FULL_NAME = "prefs.fullname"; /** Fact name for storing the preferences' email. Value is {@value}. */ - public static final String WF_UP_CREATE_SAVE_FACT_PREFS_EMAIL = "prefs.email"; - - 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; + String WF_UP_CREATE_SAVE_FACT_PREFS_EMAIL = "prefs.email"; /** The prefix to use for looking up <code>jspwiki.properties</code> approval roles. */ - protected static final String PROPERTY_APPROVER_PREFIX = "jspwiki.approver."; - - /** - * Constructs a new WorkflowManager, with an empty workflow cache. New - * Workflows are automatically assigned unique identifiers, starting with 1. - */ - public WorkflowManager() - { - m_next = 1; - m_workflows = ConcurrentHashMap.newKeySet(); - m_approvers = new ConcurrentHashMap<>(); - m_completed = new CopyOnWriteArrayList<>(); - } + 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. + * 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 + * @throws WikiException if a workflow the automatically assigned ID already exist; this should not happen normally */ - public void start( Workflow workflow ) throws WikiException - { - m_workflows.add( workflow ); - workflow.setWorkflowManager( this ); - workflow.setId( nextId() ); - workflow.start(); - } + void start( Workflow workflow ) throws WikiException; /** * Returns a collection of the currently active workflows. * * @return the current workflows */ - public Collection< Workflow > getWorkflows() { - Set< Workflow > workflows = ConcurrentHashMap.newKeySet(); - workflows.addAll( m_workflows ); - return workflows; - } + Set< Workflow > getWorkflows(); /** * Returns a collection of finished workflows; that is, those that have aborted or completed. + * * @return the finished workflows */ - public List< Workflow > getCompletedWorkflows() { - return new CopyOnWriteArrayList< >( m_completed ); - } - - private WikiEngine m_engine = null; + List< Workflow > getCompletedWorkflows(); /** - * Initializes the WorkflowManager using a specfied WikiEngine and - * properties. Any properties that begin with - * {@link #PROPERTY_APPROVER_PREFIX} will be assumed to be - * Decisions that require approval. For a given property key, everything - * after the prefix denotes the Decision's message key. The property - * value indicates the Principal (Role, GroupPrincipal, WikiPrincipal) that - * must approve the Decision. For example, if the property key/value pair - * is <code>jspwiki.approver.workflow.saveWikiPage=Admin</code>, - * the Decision's message key is <code>workflow.saveWikiPage</code>. - * The Principal <code>Admin</code> will be resolved via + * Initializes the WorkflowManager using a specfied WikiEngine and properties. Any properties that begin with + * {@link #PROPERTY_APPROVER_PREFIX} will be assumed to be Decisions that require approval. For a given property key, everything + * after the prefix denotes the Decision's message key. The property value indicates the Principal (Role, GroupPrincipal, WikiPrincipal) + * that must approve the Decision. For example, if the property key/value pair is {@code jspwiki.approver.workflow.saveWikiPage=Admin}, + * the Decision's message key is <code>workflow.saveWikiPage</code>. The Principal <code>Admin</code> will be resolved via * {@link org.apache.wiki.auth.AuthorizationManager#resolvePrincipal(String)}. + * * @param engine the wiki engine to associate with this WorkflowManager * @param props the wiki engine's properties */ - public void initialize( WikiEngine engine, Properties props ) - { - m_engine = engine; - - // Identify the workflows requiring approvals - for ( Iterator<?> it = props.keySet().iterator(); it.hasNext(); ) - { - String prop = (String) it.next(); - if ( prop.startsWith( PROPERTY_APPROVER_PREFIX ) ) - { - - // For the key, everything after the prefix is the workflow name - String key = prop.substring( PROPERTY_APPROVER_PREFIX.length() ); - if ( key != null && key.length() > 0 ) - { - - // Only use non-null/non-blank approvers - String approver = props.getProperty( prop ); - if ( approver != null && approver.length() > 0 ) - { - m_approvers.put( key, new UnresolvedPrincipal( approver ) ); - } - } - } - } - } + void initialize( WikiEngine engine, Properties props ); /** - * Returns <code>true</code> if a workflow matching a particular key - * contains an approval step. + * Returns <code>true</code> if a workflow matching a particular key contains an approval step. * - * @param messageKey - * the name of the workflow; corresponds to the value returned by - * {@link Workflow#getMessageKey()}. + * @param messageKey the name of the workflow; corresponds to the value returned by {@link Workflow#getMessageKey()}. * @return the result */ - public boolean requiresApproval( String messageKey ) - { - return m_approvers.containsKey( messageKey ); - } + boolean requiresApproval( String messageKey ); /** - * Looks up and resolves the actor who approves a Decision for a particular - * Workflow, based on the Workflow's message key. If not found, or if - * Principal is Unresolved, throws WikiException. This particular - * implementation always returns the GroupPrincipal <code>Admin</code> + * Looks up and resolves the actor who approves a Decision for a particular Workflow, based on the Workflow's message key. + * If not found, or if Principal is Unresolved, throws WikiException. This particular implementation always returns the + * GroupPrincipal <code>Admin</code> * * @param messageKey the Decision's message key * @return the actor who approves Decisions * @throws WikiException if the message key was not found, or the * Principal value corresponding to the key could not be resolved */ - public Principal getApprover( String messageKey ) throws WikiException - { - Principal approver = m_approvers.get( messageKey ); - if ( approver == null ) - { - throw new WikiException( "Workflow '" + messageKey + "' does not require approval." ); - } - - // Try to resolve UnresolvedPrincipals - if ( approver instanceof UnresolvedPrincipal ) - { - String name = approver.getName(); - approver = m_engine.getAuthorizationManager().resolvePrincipal( name ); - - // If still unresolved, throw exception; otherwise, freshen our - // cache - if ( approver instanceof UnresolvedPrincipal ) - { - throw new WikiException( "Workflow approver '" + name + "' cannot not be resolved." ); - } - - m_approvers.put( messageKey, approver ); - } - return approver; - } - - /** - * Protected helper method that returns the associated WikiEngine - * - * @return the wiki engine - */ - protected WikiEngine getEngine() - { - if ( m_engine == null ) - { - throw new IllegalStateException( "WikiEngine cannot be null; please initialize WorkflowManager first." ); - } - return m_engine; - } + Principal getApprover( String messageKey ) throws WikiException; /** * Returns the DecisionQueue associated with this WorkflowManager * * @return the decision queue */ - public DecisionQueue getDecisionQueue() - { - return m_queue; - } - - private volatile int m_next; + DecisionQueue getDecisionQueue(); /** - * Returns the next available unique identifier, which is subsequently - * incremented. + * Returns the current workflows a wiki session owns. These are workflows whose {@link Workflow#getOwner()} method returns a Principal + * also possessed by the wiki session (see {@link org.apache.wiki.WikiSession#getPrincipals()}). If the wiki session is not + * authenticated, this method returns an empty Collection. * - * @return the id - */ - private synchronized int nextId() - { - int current = m_next; - m_next++; - return current; - } - - /** - * Returns the current workflows a wiki session owns. These are workflows whose - * {@link Workflow#getOwner()} method returns a Principal also possessed by the - * wiki session (see {@link org.apache.wiki.WikiSession#getPrincipals()}). If the - * wiki session is not authenticated, this method returns an empty Collection. * @param session the wiki session * @return the collection workflows the wiki session owns, which may be empty */ - public Collection< Workflow > getOwnerWorkflows( WikiSession session ) { - List<Workflow> workflows = new ArrayList<>(); - if ( session.isAuthenticated() ) { - Principal[] sessionPrincipals = session.getPrincipals(); - for ( Workflow w : m_workflows ) { - Principal owner = w.getOwner(); - for ( Principal sessionPrincipal : sessionPrincipals ) { - if ( sessionPrincipal.equals( owner ) ) { - workflows.add( w ); - break; - } - } - } - } - return workflows; - } - - /** - * Listens for {@link org.apache.wiki.event.WorkflowEvent} objects emitted by Workflows. In particular, this - * method listens for {@link org.apache.wiki.event.WorkflowEvent#CREATED}, - * {@link org.apache.wiki.event.WorkflowEvent#ABORTED} and {@link org.apache.wiki.event.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. - * - * @param event the event passed to this listener - */ - @Override - public void actionPerformed(WikiEvent event) { - if (event instanceof WorkflowEvent) { - Workflow workflow = event.getSrc(); - switch ( event.getType() ) { - case WorkflowEvent.ABORTED: - // Remove from manager - remove( workflow ); - break; - case WorkflowEvent.COMPLETED: - // Remove from manager - remove( workflow ); - break; - case WorkflowEvent.CREATED: - // Add to manager - add( workflow ); - break; - default: - break; - } - } - } - - /** - * Protected helper method that adds a newly created Workflow to the cache, and sets its - * <code>workflowManager</code> and <code>Id</code> properties if not set. - * - * @param workflow the workflow to add - */ - protected void add( Workflow workflow ) { - if ( workflow.getWorkflowManager() == null ) { - workflow.setWorkflowManager( this ); - } - if ( workflow.getId() == Workflow.ID_NOT_SET ) { - workflow.setId( nextId() ); - } - m_workflows.add( workflow ); - } - - /** - * Protected helper method that removes a specified Workflow from the cache, - * and moves it to the workflow history list. This method defensively - * checks to see if the workflow has not yet been removed. - * - * @param workflow the workflow to remove - */ - protected void remove(Workflow workflow) { - if ( m_workflows.contains( workflow ) ) { - m_workflows.remove( workflow ); - m_completed.add( workflow ); - } - } + List< Workflow > getOwnerWorkflows( WikiSession session ); } diff --git a/jspwiki-main/src/main/resources/ini/classmappings.xml b/jspwiki-main/src/main/resources/ini/classmappings.xml index 192a1ea..e005819 100644 --- a/jspwiki-main/src/main/resources/ini/classmappings.xml +++ b/jspwiki-main/src/main/resources/ini/classmappings.xml @@ -129,6 +129,6 @@ </mapping> <mapping> <requestedClass>org.apache.wiki.workflow.WorkflowManager</requestedClass> - <mappedClass>org.apache.wiki.workflow.WorkflowManager</mappedClass> + <mappedClass>org.apache.wiki.workflow.DefaultWorkflowManager</mappedClass> </mapping> </classmappings>
