/** * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * 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.wso2.carbon.mediators.router.impl; import org.apache.synapse.ManagedLifecycle; import org.apache.synapse.MessageContext; import org.apache.synapse.SynapseLog; import org.apache.synapse.core.SynapseEnvironment; import org.apache.synapse.endpoints.Endpoint; import org.apache.synapse.mediators.AbstractMediator; import org.apache.synapse.mediators.base.SequenceMediator; import org.apache.synapse.mediators.eip.Target; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * <p>Routes the messages going through this mediator in to the specified target sequecne or to the * taregt endpoint if the specified conditions under a particular route is matching. There can be * several routes and one can specify to break after the first matching route using the * <code>breakRouter</code> attirbute in the routes and hence the route order has some impact on the * routings</p> * <p/> * <p>Normally message routing is redirecting the message, so this mediator also permits further * mediation in this path where as the message is mediated using the roted path(s) by default, but * it can be configured by the <code>continueAfter</code> attribute if required to continue further * mediation of the path</p> * <p/> * <p>Individual routes are stored as <code>Route</code> objects keeping there conditions inside it * with the routing targets as <code>Target<code> objects inside a particualr route and there is a * linked list of <code>Route</code> per mediator.</p> * * @see Route * @see org.apache.synapse.mediators.eip.Target * @see org.apache.synapse.Mediator * @see org.apache.synapse.mediators.AbstractMediator */ public class RouterMediator extends AbstractMediator implements ManagedLifecycle { /** * <p>List of routes to be checked and routed on arrival of a message. These routes has an order * when executing and hence kept in a <code>LinkedList</code>. These route will be taken in to * the order and checked for matching of the conditions specified inside the routes and then the * routing will be called over the route (i.e. message will be mediated using the target)</p> * <p/> * <p>By default if there is a matching route then the next routes will not be invoked because * the message has been routed, but this can be modified by using the <code>breakRouter</code> * attribute in the route.</p> * * @see Route * @see java.util.LinkedList */ private List<Route> routes = new LinkedList<Route>(); /** * <p>Specifies whether to continue further mediation on the current path apart from the routed * path. If the value is set to true this will not permit further mediation along the path, but * the defautl value for this is false implying by default the router stops the current path * mediation and redirects the message to the routed path</p> */ private boolean continueAfter = false; /** * <p>Routes the message depending on the specified set of routes if the routing condition is * matching over the provided message. There can be a list of routers specified in to a * particualr order, and these routes will be invoked to route the message in the specified * order.</p> * <p/> * <p>If there is a matching route found over the message then the routing will occur and after * this synchronized routing further mediation of the message through other routes specified * after the matching route will be decided by the value of the <code>breakRouter</code> * attribute of the route.</p> * <p/> * <p>By default this mediator will drop the message stopping further medaition along the * current path and this also can be modified by using the <code>continueAfter</code> attribute * of the mediator.</p> * * @param synCtx message to be routed * @return whether to continue further mediaiton or not as a boolean value * @see org.apache.synapse.Mediator#mediate(org.apache.synapse.MessageContext) * @see Route#doRoute(org.apache.synapse.MessageContext, SynapseLog) */ public boolean mediate(MessageContext synCtx) { if (synCtx.getEnvironment().isDebuggerEnabled()) { if (super.divertMediationRoute(synCtx)) { return true; } } SynapseLog synLog = getLog(synCtx); if (synLog.isTraceOrDebugEnabled()) { synLog.traceOrDebug("Start : Router mediator"); if (synLog.isTraceTraceEnabled()) { synLog.traceTrace("Message : " + synCtx.getEnvelope()); } } for (Route route : routes) { int routeState = route.doRoute(synCtx, synLog); // if the message does not match the route conditions if (Route.ROUTE_NOT_MACHING_STATE == routeState && synLog.isTraceOrDebugEnabled()) { synLog.traceOrDebug("The message does not matches the routing conditions : " + "Expression = '" + route.getExpression() + "'" + (route.getMatch() != null ? " Pattern = '" + route.getMatch().toString() + "'" : "")); } else { // get the route target for logging purposes Target routeTarget = route.getTarget(); String targetString = null; if (routeTarget != null) { // prepare a target string for loggin purposes if (routeTarget.getSequenceRef() != null) { targetString = "Sequence <" + routeTarget.getSequenceRef() + ">"; } else if (routeTarget.getSequence() != null) { targetString = "Sequence <annonymous>"; } else if (routeTarget.getEndpointRef() != null) { targetString = "Endpoint <" + routeTarget.getEndpointRef() + ">"; } else if (routeTarget.getEndpoint() != null) { targetString = "Endpoint <annonymous>"; } else { targetString = "without an endpoint or a sequence"; } } // if routed and the message may route furhter using the existing routes if (Route.ROUTED_WITH_CONTINUE_STATE == routeState && synLog.isTraceOrDebugEnabled()) { synLog.traceOrDebug("The message has been routed to the target : " + targetString + ", but further routings are allowed"); // if routed and the message should not be routed with other remaining routes } else if (Route.ROUTED_WITH_BREAK_STATE == routeState) { synLog.traceOrDebug("The message has been routed to the target : " + targetString + ", and no further routes are allowed"); // break this router permitting further routings break; } else if (Route.ROUTED_AND_DROPPED_STATE == routeState) { synLog.traceOrDebug("The message has been routed to the target : " + targetString + ", and the message is droped on the route"); return false; } } } if (synLog.isTraceOrDebugEnabled()) { synLog.traceOrDebug("End : Router mediator"); } // normally message routing is redirecting the message, so this permits further mediation // in this path where as the message is mediated using the roted path(s) by default, but it // can be configured by the continueAfter attribute if required return continueAfter; } public List<Route> getRoutes() { return routes; } public void setRoutes(List<Route> routes) { this.routes = routes; } public void addRoute(Route route) { routes.add(route); } public boolean isContinueAfter() { return continueAfter; } public void setContinueAfter(boolean continueAfter) { this.continueAfter = continueAfter; } /** * called on Router startup. initializes inline sequences and endpoints * * @param synapseEnvironment */ public void init(SynapseEnvironment synapseEnvironment) { Iterator<Route> allRoutes = routes.iterator(); //for all routes while (allRoutes.hasNext()) { Route route = allRoutes.next(); Target routingTarget = route.getTarget(); SequenceMediator synSeqForRoute; if (routingTarget != null) { synSeqForRoute = routingTarget.getSequence(); //init routing sequence so that each inline endpoints,etc get initialized if (synSeqForRoute != null) { synSeqForRoute.init(synapseEnvironment); } //init routing address endpoints Endpoint endpoint = routingTarget.getEndpoint(); if (endpoint != null) { endpoint.init(synapseEnvironment); } } } } /** * called when Router is destroyed */ public void destroy() { Iterator<Route> allRoutes = routes.iterator(); //for all routes while (allRoutes.hasNext()) { Route route = allRoutes.next(); Target routingTarget = route.getTarget(); SequenceMediator synSeqForRoute; if (routingTarget != null) { synSeqForRoute = routingTarget.getSequence(); //destroy and clean up each inline seq if (synSeqForRoute != null) { synSeqForRoute.destroy(); } } } } }