blob: 620ca95e173a93b0ecd01fbf2bf6f16d9d234638 [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.axis2.engine;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.HandlerDescription;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.PhaseRule;
import org.apache.axis2.phaseresolver.PhaseException;
import org.apache.axis2.util.LoggingControl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A Phase is an ordered collection of Handlers.
*/
public class Phase implements Handler {
public static final String ALL_PHASES = "*";
/**
* Field log
*/
private static final Log log = LogFactory.getLog(Phase.class);
private static boolean isDebugEnabled = LoggingControl.debugLoggingAllowed && log.isDebugEnabled();
/**
* Field handlers
*/
private List<Handler> handlers;
/**
* A handler has been marked as present in both the first phase and the last phase
*/
private boolean isOneHandler;
/**
* Field phaseName
*/
private String phaseName;
/**
* Field phaseFirstSet
*/
private boolean phaseFirstSet;
/**
* Field phaseLastSet
*/
private boolean phaseLastSet;
/**
* Default constructor
*/
public Phase() {
this(null);
}
/**
* Create a named Phase
*
* @param phaseName the name for this Phase
*/
public Phase(String phaseName) {
handlers = new CopyOnWriteArrayList<Handler>();
this.phaseName = phaseName;
}
/**
* Add a handler to the Phase.
*
* @param handler the Handler to add
*/
public void addHandler(Handler handler) {
log.debug("Handler " + handler.getName() + " added to Phase " + phaseName);
if (phaseLastSet) {
// handlers.size() can not be 0 , since when setting phase last it is always > 0
if (handlers.size() == 1) {
handlers.add(0, handler);
} else {
handlers.add(handlers.size() - 2, handler);
}
} else {
handlers.add(handler);
}
}
/**
* Add a HandlerDescription to the Phase
*
* @param handlerDesc the HandlerDescription to add
* @throws PhaseException if there is a problem
*/
public void addHandler(HandlerDescription handlerDesc) throws PhaseException {
Iterator<Handler> handlers_itr = getHandlers().iterator();
while (handlers_itr.hasNext()) {
Handler hand = (Handler) handlers_itr.next();
HandlerDescription thisDesc = hand.getHandlerDesc();
if (handlerDesc.getName().equals(thisDesc.getName())) {
return;
}
}
if (isOneHandler) {
throw new PhaseException("Phase '" + this.getPhaseName()
+ "' can only have one handler, since there is a "
+ "handler with both phaseFirst and phaseLast true ");
}
if (handlerDesc.getRules().isPhaseFirst() && handlerDesc.getRules().isPhaseLast()) {
if (!handlers.isEmpty()) {
throw new PhaseException(this.getPhaseName()
+ " already contains Handlers, and "
+ handlerDesc.getName()
+ " cannot therefore be both phaseFirst and phaseLast.");
} else {
handlers.add(handlerDesc.getHandler());
isOneHandler = true;
}
} else if (handlerDesc.getRules().isPhaseFirst()) {
setPhaseFirst(handlerDesc.getHandler());
} else if (handlerDesc.getRules().isPhaseLast()) {
setPhaseLast(handlerDesc.getHandler());
} else {
insertHandler(handlerDesc);
}
}
/**
* Add a Handler at a particular index within the Phase.
*
* If we have a Phase with (H1, H2), calling addHandler(H3, 1) will result in (H1, H3, H2)
*
* @param handler the Handler to add
* @param index the position in the Phase at which to place the Handler
*/
public void addHandler(Handler handler, int index) {
if (log.isDebugEnabled()) {
log.debug("Handler " + handler.getName() + " inserted at position " + index +
" of Phase " + phaseName);
}
handlers.add(index, handler);
}
/**
* Confirm that all post-conditions of this Phase are met. After all Handlers in a
* Phase are invoke()d, this method will be called. Subclasses should override it in order
* to confirm that the purpose of the given Phase has been acheived.
*
* @param msgContext the active MessageContext
* @throws AxisFault if a post-condition has not been met, or other problems occur
*/
public void checkPostConditions(MessageContext msgContext) throws AxisFault {
// Default version does nothing
}
/**
* Check the preconditions for a Phase. This method will be called when the Phase is
* invoked, BEFORE any Handlers are invoked. Subclasses should override it in order
* to confirm that necessary preconditions are met before the Phase does its work. They
* should throw an appropriate AxisFault if not.
*
* @param msgContext the active MessageContext
* @throws AxisFault if a precondition is not met, or in case of other problem
*/
public void checkPreconditions(MessageContext msgContext) throws AxisFault {
// Default version does nothing
}
public void cleanup() {
// Default version does nothing
}
public void init(HandlerDescription handlerdesc) {
// Default version does nothing
}
private void insertHandler(HandlerDescription handlerDesc) throws PhaseException {
Handler handler = handlerDesc.getHandler();
PhaseRule rules = handler.getHandlerDesc().getRules();
String beforeName = rules.getBefore();
String afterName = rules.getAfter();
// If we don't care where it goes, tack it on at the end
if (beforeName == null && afterName == null) {
addHandler(handler);
return;
}
// Otherwise walk the list and find the right place to put it
int beforeIndex = -1, afterIndex = -1;
for (int i = 0; i < handlers.size(); i++) {
Handler tempHandler = (Handler) handlers.get(i);
if ((beforeName != null) && (beforeIndex == -1)) {
if (tempHandler.getName().equals(beforeName)) {
// Found the "before" handler
beforeIndex = i;
}
}
if ((afterName != null) && (afterIndex == -1)) {
if (tempHandler.getName().equals(afterName)) {
// Found the "after" handler
afterIndex = i;
}
}
}
if ((beforeIndex > -1) && (afterIndex >= beforeIndex)) {
throw new PhaseException("Can't insert handler because " + beforeName + " is before " +
afterName + " in Phase '" + phaseName + "'");
}
if (phaseFirstSet && beforeIndex == 0) {
throw new PhaseException("Can't insert handler before handler '"
+ beforeName
+ "', which is marked phaseFirst");
}
if (phaseLastSet && afterIndex == (handlers.size() - 1)) {
throw new PhaseException("Can't insert handler after handler '"
+ afterName
+ "', which is marked phaseLast");
}
if (beforeIndex > -1) {
handlers.add(beforeIndex, handler);
} else if (afterIndex > -1){
if (phaseLastSet){
if (handlers.size() ==1){
handlers.add(0,handler);
} else {
handlers.add(handlers.size() -2,handler);
}
} else {
if (afterIndex == (handlers.size() -1)) {
handlers.add(handler);
} else {
handlers.add(afterIndex +1,handler);
}
}
} else {
if (phaseLastSet) {
if (handlers.size() ==1){
handlers.add(0,handler);
} else {
handlers.add(handlers.size() -2,handler);
}
} else {
handlers.add(handler);
}
}
}
/**
* Invoke all the handlers in this Phase
*
* @param msgctx the current MessageContext
* @return An InvocationResponse that indicates what
* the next step in the message processing should be.
* @throws org.apache.axis2.AxisFault
*/
public final InvocationResponse invoke(MessageContext msgctx) throws AxisFault {
if (isDebugEnabled) {
log.debug(msgctx.getLogIDString() + " Checking pre-condition for Phase \"" + phaseName +
"\"");
}
InvocationResponse pi = InvocationResponse.CONTINUE;
int currentIndex = msgctx.getCurrentPhaseIndex();
if (currentIndex == 0) {
checkPreconditions(msgctx);
}
if (isDebugEnabled) {
log.debug(msgctx.getLogIDString() + " Invoking phase \"" + phaseName + "\"");
}
int handlersSize = handlers.size();
while (currentIndex < handlersSize) {
Handler handler = (Handler) handlers.get(currentIndex);
if (isDebugEnabled) {
log.debug(msgctx.getLogIDString() + " Invoking Handler '" + handler.getName() +
"' in Phase '" + phaseName + "'");
}
pi = handler.invoke(msgctx);
if (!pi.equals(InvocationResponse.CONTINUE)) {
return pi;
}
currentIndex++;
msgctx.setCurrentPhaseIndex(currentIndex);
}
if (isDebugEnabled) {
log.debug(msgctx.getLogIDString() + " Checking post-conditions for phase \"" +
phaseName + "\"");
}
msgctx.setCurrentPhaseIndex(0);
checkPostConditions(msgctx);
return pi;
}
public void flowComplete(MessageContext msgContext) {
if (isDebugEnabled) {
log.debug(msgContext.getLogIDString() + " Invoking flowComplete() in Phase \"" +
phaseName + "\"");
}
// This will be non-zero if we failed during execution of one of the
// handlers in this phase
int currentHandlerIndex = msgContext.getCurrentPhaseIndex();
if (currentHandlerIndex == 0) {
currentHandlerIndex = handlers.size();
} else {
/*We need to set it to 0 so that any previous phases will execute all
* of their handlers.*/
msgContext.setCurrentPhaseIndex(0);
}
for (; currentHandlerIndex > 0; currentHandlerIndex--) {
Handler handler = (Handler) handlers.get(currentHandlerIndex - 1);
if (isDebugEnabled) {
log.debug(msgContext.getLogIDString() + " Invoking flowComplete() for Handler '" +
handler.getName() + "' in Phase '" + phaseName + "'");
}
handler.flowComplete(msgContext);
}
}
public String toString() {
return this.getPhaseName();
}
public int getHandlerCount() {
return handlers.size();
}
public HandlerDescription getHandlerDesc() {
return null;
}
/**
* Gets all the handlers in the phase.
*
* @return Returns an ArrayList of Handlers
*/
public List<Handler> getHandlers() {
return handlers;
}
public String getName() {
return phaseName;
}
public Parameter getParameter(String name) {
return null;
}
/**
* @return Returns the name.
*/
public String getPhaseName() {
return phaseName;
}
public void setName(String phaseName) {
this.phaseName = phaseName;
}
/**
* Add a Handler to the Phase in the very first position, and ensure no other Handler
* will come before it.
*
* @param handler the Handler to add
* @throws PhaseException if another Handler is already set as phaseFirst
*/
public void setPhaseFirst(Handler handler) throws PhaseException {
if (phaseFirstSet) {
throw new PhaseException("PhaseFirst has been set already, cannot have two"
+ " phaseFirst Handlers for Phase '" + this.getPhaseName() + "'");
}
handlers.add(0, handler);
phaseFirstSet = true;
}
/**
* Add a Handler to the Phase in the very last position, and ensure no other Handler
* will come after it.
*
* @param handler the Handler to add
* @throws PhaseException if another Handler is already set as phaseLast
*/
public void setPhaseLast(Handler handler) throws PhaseException {
if (phaseLastSet) {
throw new PhaseException("PhaseLast already has been set,"
+ " cannot have two PhaseLast Handler for same phase "
+ this.getPhaseName());
}
handlers.add(handler);
phaseLastSet = true;
}
/**
* Remove a given Handler from a phase using a HandlerDescription
*
* @param handlerDesc the HandlerDescription to remove
*/
public void removeHandler(HandlerDescription handlerDesc) {
if (handlers.remove(handlerDesc.getHandler())) {
PhaseRule rule = handlerDesc.getRules();
if (rule.isPhaseFirst()) {
phaseFirstSet = false;
}
if (rule.isPhaseLast()) {
phaseLastSet = false;
}
if (rule.isPhaseFirst() && rule.isPhaseLast()) {
isOneHandler = false;
}
log.debug("removed handler " + handlerDesc.getName()
+ " from the phase " + phaseName);
} else {
log.debug("unable to remove handler " + handlerDesc.getName()
+ " from the phase " + phaseName);
}
}
}