| /* |
| * 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 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 + |
| "\""); |
| } |
| |
| int currentIndex = msgctx.getCurrentPhaseIndex(); |
| |
| if (currentIndex == 0) { |
| checkPreconditions(msgctx); |
| } |
| |
| if (isDebugEnabled) { |
| log.debug(msgctx.getLogIDString() + " Invoking phase \"" + phaseName + "\""); |
| } |
| |
| int handlersSize = handlers.size(); |
| |
| for (int i= currentIndex; i < handlersSize; i++) { |
| Handler handler = (Handler) handlers.get(i); |
| |
| InvocationResponse pi = invokeHandler(handler, msgctx); |
| |
| if (!pi.equals(InvocationResponse.CONTINUE)) { |
| return pi; |
| } |
| |
| // Set phase index to the next handler |
| msgctx.setCurrentPhaseIndex(i+1); |
| } |
| |
| if (isDebugEnabled) { |
| log.debug(msgctx.getLogIDString() + " Checking post-conditions for phase \"" + |
| phaseName + "\""); |
| } |
| |
| msgctx.setCurrentPhaseIndex(0); |
| checkPostConditions(msgctx); |
| return InvocationResponse.CONTINUE; |
| } |
| |
| private InvocationResponse invokeHandler(Handler handler, MessageContext msgctx) |
| throws AxisFault { |
| if (isDebugEnabled) { |
| log.debug(msgctx.getLogIDString() + " Invoking Handler '" + handler.getName() + |
| "' in Phase '" + phaseName + "'"); |
| } |
| |
| return handler.invoke(msgctx); |
| } |
| |
| 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); |
| } |
| } |
| |
| } |