blob: 37d89258bc0712001189440faaeaf418053e3b89 [file] [log] [blame]
/*
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.api.core.Session;
import org.apache.wiki.api.exceptions.WikiException;
import java.io.Serializable;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
/**
* Keeps a queue of pending Decisions that need to be acted on by named Principals.
*
* @since 2.5
*/
public class DecisionQueue implements Serializable {
private static final long serialVersionUID = -7172912793410302533L;
private final LinkedList< Decision > m_queue = new LinkedList<>();
private volatile int m_next;
/** Constructs a new DecisionQueue. */
public DecisionQueue() {
m_next = 1000;
}
/**
* Adds a Decision to the DecisionQueue; also sets the Decision's unique identifier.
*
* @param decision the Decision to add
*/
protected synchronized void add( final Decision decision ) {
m_queue.addLast( decision );
decision.setId( nextId() );
}
/**
* Protected method that returns all pending Decisions in the queue, in order of submission. If no Decisions are pending, this
* method returns a zero-length array.
*
* @return the pending decisions
*/
protected Decision[] decisions() {
return m_queue.toArray( new Decision[ m_queue.size() ] );
}
/**
* Protected method that removes a Decision from the queue.
*
* @param decision the decision to remove
*/
protected synchronized void remove( final Decision decision ) {
m_queue.remove( decision );
}
/**
* Returns a Collection representing the current Decisions that pertain to a users's Session. The Decisions are obtained by iterating
* through the Session's Principals and selecting those Decisions whose {@link Decision#getActor()} value match. If the session
* is not authenticated, this method returns an empty Collection.
*
* @param session the wiki session
* @return the collection of Decisions, which may be empty
*/
public Collection<Decision> getActorDecisions( final Session session ) {
final ArrayList< Decision > decisions = new ArrayList<>();
if( session.isAuthenticated() ) {
final Principal[] principals = session.getPrincipals();
final Principal[] rolePrincipals = session.getRoles();
for( final Decision decision : m_queue ) {
// Iterate through the Principal set
for( final Principal principal : principals ) {
if( principal.equals( decision.getActor() ) ) {
decisions.add( decision );
}
}
// Iterate through the Role set
for( final Principal principal : rolePrincipals ) {
if( principal.equals( decision.getActor() ) ) {
decisions.add( decision );
}
}
}
}
return decisions;
}
/**
* 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.
*
* @param decision the Decision for which the Outcome will be supplied
* @param outcome the Outcome of the Decision
* @throws WikiException if the succeeding Step cannot start for any reason
*/
public void decide( final Decision decision, final Outcome outcome ) throws WikiException {
decision.decide( outcome );
if ( decision.isCompleted() ) {
remove( decision );
}
// TODO: We should fire an event indicating the Outcome, and whether the Decision completed successfully
}
/**
* Reassigns the owner of the Decision to a new owner. Under the covers, this method calls {@link Decision#reassign(Principal)}.
*
* @param decision the Decision to reassign
* @param owner the new owner
* @throws WikiException never
*/
public synchronized void reassign( final Decision decision, final Principal owner ) throws WikiException {
if( decision.isReassignable() ) {
decision.reassign( owner );
// TODO: We should fire an event indicating the reassignment
return;
}
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;
}
}