/*
* Copyright 2004-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.execution.factory;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.style.StylerUtils;
import org.springframework.util.Assert;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.execution.FlowExecutionListener;
/**
* A flow execution listener loader that stores listeners in a list-backed data structure and allows for configuration
* of which listeners should apply to which flow definitions. For trivial listener loading, see
* {@link StaticFlowExecutionListenerLoader}.
*
* @see FlowExecutionListenerCriteria
* @see StaticFlowExecutionListenerLoader
*
* @author Keith Donald
*/
public class ConditionalFlowExecutionListenerLoader implements FlowExecutionListenerLoader {
private final Log logger = LogFactory.getLog(ConditionalFlowExecutionListenerLoader.class);
/**
* The list of flow execution listeners containing {@link ConditionalFlowExecutionListenerHolder} objects. The list
* determines the conditions in which a single flow execution listener applies.
*/
private List<ConditionalFlowExecutionListenerHolder> listeners = new LinkedList<ConditionalFlowExecutionListenerHolder>();
/**
* Add a listener that will listen to executions to flows matching the specified criteria.
* @param listener the listener
* @param criteria the listener criteria
*/
public void addListener(FlowExecutionListener listener, FlowExecutionListenerCriteria criteria) {
if (listener == null) {
throw new IllegalArgumentException("The flow execution listener cannot be null");
}
if (logger.isDebugEnabled()) {
logger.debug("Adding flow execution listener " + listener + " with criteria " + criteria);
}
ConditionalFlowExecutionListenerHolder conditional = getHolder(listener);
if (conditional == null) {
conditional = new ConditionalFlowExecutionListenerHolder(listener);
listeners.add(conditional);
}
if (criteria == null) {
criteria = new FlowExecutionListenerCriteriaFactory().allFlows();
}
conditional.add(criteria);
}
/**
* Returns the array of flow execution listeners for specified flow.
* @param flowDefinition the flow definition associated with the execution to be listened to
* @return the flow execution listeners that apply
*/
public FlowExecutionListener[] getListeners(FlowDefinition flowDefinition) {
Assert.notNull(flowDefinition, "The Flow to load listeners for cannot be null");
List<FlowExecutionListener> listenersToAttach = new LinkedList<FlowExecutionListener>();
for (ConditionalFlowExecutionListenerHolder listenerHolder : listeners) {
if (listenerHolder.listenerAppliesTo(flowDefinition)) {
listenersToAttach.add(listenerHolder.getListener());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded [" + listenersToAttach.size() + "] of possible " + listeners.size()
+ " listeners for this execution request for flow '" + flowDefinition.getId()
+ "', the listeners to attach are " + StylerUtils.style(listenersToAttach));
}
return listenersToAttach.toArray(new FlowExecutionListener[listenersToAttach.size()]);
}
// internal helpers
/**
* Lookup the listener criteria holder for the listener provided.
* @param listener the listener
* @return the holder, or null if not found
*/
private ConditionalFlowExecutionListenerHolder getHolder(FlowExecutionListener listener) {
for (ConditionalFlowExecutionListenerHolder holder : listeners) {
if (holder.getListener().equals(listener)) {
return holder;
}
}
return null;
}
}