/* * 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); } } }