Home » synapse-1.2-src » org.apache.synapse.endpoints » [javadoc | source]

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
   10    *   http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    *  Unless required by applicable law or agreed to in writing,
   13    *  software distributed under the License is distributed on an
   14    *   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    *  KIND, either express or implied.  See the License for the
   16    *  specific language governing permissions and limitations
   17    *  under the License.
   18    */
   19   
   20   package org.apache.synapse.endpoints;
   21   
   22   import org.apache.axis2.clustering.ClusterManager;
   23   import org.apache.axis2.context.ConfigurationContext;
   24   import org.apache.commons.logging.Log;
   25   import org.apache.commons.logging.LogFactory;
   26   import org.apache.synapse.FaultHandler;
   27   import org.apache.synapse.MessageContext;
   28   import org.apache.synapse.SynapseConstants;
   29   import org.apache.synapse.core.axis2.Axis2MessageContext;
   30   import org.apache.synapse.endpoints.algorithms.AlgorithmContext;
   31   import org.apache.synapse.endpoints.algorithms.LoadbalanceAlgorithm;
   32   
   33   import java.util.List;
   34   
   35   /**
   36    * Load balance endpoint can have multiple endpoints. It will route messages according to the
   37    * specified load balancing algorithm. This will assume that all immediate child endpoints are
   38    * identical in state (state is replicated) or state is not maintained at those endpoints. If an
   39    * endpoint is failing, the failed endpoint is marked as inactive and the message to the next
   40    * endpoint obtained using the load balancing algorithm. If all the endpoints have failed and the
   41    * parent endpoint is available, onChildEndpointFail(...) method of parent endpoint is called. If
   42    * parent is not available, this will call next FaultHandler for the message context.
   43    */
   44   public class LoadbalanceEndpoint implements Endpoint {
   45   
   46       private static final Log log = LogFactory.getLog(LoadbalanceEndpoint.class);
   47       /**
   48        * Name of the endpoint. Used for named endpoints which can be referred using the key attribute
   49        * of indirect endpoints.
   50        */
   51       private String name = null;
   52   
   53       /**
   54        * List of endpoints among which the load is distributed. Any object implementing the Endpoint
   55        * interface could be used.
   56        */
   57       private List<Endpoint> endpoints = null;
   58   
   59       /**
   60        * Algorithm used for selecting the next endpoint to direct the load. Default is RoundRobin.
   61        */
   62       private LoadbalanceAlgorithm algorithm = null;
   63   
   64       /**
   65        * If this supports load balancing with failover. If true, request will be directed to the next
   66        * endpoint if the current one is failing.
   67        */
   68       private boolean failover = true;
   69   
   70       /**
   71        * Parent endpoint of this endpoint if this used inside another endpoint. Possible parents are
   72        * LoadbalanceEndpoint, SALoadbalanceEndpoint and FailoverEndpoint objects.
   73        */
   74       private Endpoint parentEndpoint = null;
   75   
   76       /**
   77        * The endpoint context , place holder for keep any runtime states related to the endpoint
   78        */
   79       private final EndpointContext endpointContext = new EndpointContext();
   80   
   81       /**
   82        * The algorithm context , place holder for keep any runtime states related to the load balance
   83        * algorithm
   84        */
   85       private final AlgorithmContext algorithmContext = new AlgorithmContext();
   86   
   87       public void send(MessageContext synMessageContext) {
   88   
   89           if (log.isDebugEnabled()) {
   90               log.debug("Start : Load-balance Endpoint");
   91           }
   92   
   93           boolean isClusteringEnable = false;
   94           // get Axis2 MessageContext and ConfigurationContext
   95           org.apache.axis2.context.MessageContext axisMC =
   96                   ((Axis2MessageContext) synMessageContext).getAxis2MessageContext();
   97           ConfigurationContext cc = axisMC.getConfigurationContext();
   98   
   99           //The check for clustering environment
  100   
  101           ClusterManager clusterManager = cc.getAxisConfiguration().getClusterManager();
  102           if (clusterManager != null &&
  103                   clusterManager.getContextManager() != null) {
  104               isClusteringEnable = true;
  105           }
  106   
  107           String endPointName = this.getName();
  108           if (endPointName == null) {
  109   
  110               if (isClusteringEnable) {
  111                   log.warn("In a clustering environment , the endpoint  name should be specified" +
  112                           "even for anonymous endpoints. Otherwise , the clustering would not be " +
  113                           "functioned correctly if there are more than one anonymous endpoints. ");
  114               }
  115               endPointName = SynapseConstants.ANONYMOUS_ENDPOINT;
  116           }
  117   
  118           if (isClusteringEnable) {
  119   
  120               // if this is a cluster environment , then set configuration context to endpoint context
  121               if (endpointContext.getConfigurationContext() == null) {
  122                   endpointContext.setConfigurationContext(cc);
  123                   endpointContext.setContextID(endPointName);
  124   
  125               }
  126               // if this is a cluster environment , then set configuration context to load balance
  127               //  algorithm context
  128               if (algorithmContext.getConfigurationContext() == null) {
  129                   algorithmContext.setConfigurationContext(cc);
  130                   algorithmContext.setContextID(endPointName);
  131               }
  132           }
  133   
  134           Endpoint endpoint = algorithm.getNextEndpoint(synMessageContext, algorithmContext);
  135           if (endpoint != null) {
  136   
  137               // We have to build the envelop if we are supporting failover.
  138               // Failover should sent the original message multiple times if failures occur. So we
  139               // have to access the envelop multiple times.
  140               if (failover) {
  141                   synMessageContext.getEnvelope().build();
  142               }
  143   
  144               endpoint.send(synMessageContext);
  145   
  146           } else {
  147               // there are no active child endpoints. so mark this endpoint as failed.
  148               setActive(false, synMessageContext);
  149   
  150               if (parentEndpoint != null) {
  151                   parentEndpoint.onChildEndpointFail(this, synMessageContext);
  152               } else {
  153                   Object o = synMessageContext.getFaultStack().pop();
  154                   if (o != null) {
  155                       ((FaultHandler) o).handleFault(synMessageContext);
  156                   }
  157               }
  158           }
  159       }
  160   
  161       public String getName() {
  162           return name;
  163       }
  164   
  165       public void setName(String name) {
  166           this.name = name.trim();
  167       }
  168   
  169       public LoadbalanceAlgorithm getAlgorithm() {
  170           return algorithm;
  171       }
  172   
  173       public void setAlgorithm(LoadbalanceAlgorithm algorithm) {
  174           this.algorithm = algorithm;
  175       }
  176   
  177       /**
  178        * If this endpoint is in inactive state, checks if all immediate child endpoints are still
  179        * failed. If so returns false. If at least one child endpoint is in active state, sets this
  180        * endpoint's state to active and returns true. As this a sessionless load balancing endpoint
  181        * having one active child endpoint is enough to consider this as active.
  182        *
  183        * @param synMessageContext MessageContext of the current message. This is not used here.
  184        * @return true if active. false otherwise.
  185        */
  186       public boolean isActive(MessageContext synMessageContext) {
  187           boolean active = endpointContext.isActive();
  188           if (!active && endpoints != null) {
  189               for (Endpoint endpoint : endpoints) {
  190                   if (endpoint.isActive(synMessageContext)) {
  191                       active = true;
  192                       endpointContext.setActive(true);
  193   
  194                       // don't break the loop though we found one active endpoint. calling isActive()
  195                       // on all child endpoints will update their active state. so this is a good
  196                       // time to do that.
  197                   }
  198               }
  199           }
  200   
  201           if (log.isDebugEnabled()) {
  202               log.debug("Endpoint  '" + name + "' is in state ' " + active + " '");
  203           }
  204   
  205           return active;
  206       }
  207   
  208       public void setActive(boolean active, MessageContext synMessageContext) {
  209           // setting a volatile boolean variable is thread safe.
  210           endpointContext.setActive(active);
  211       }
  212   
  213       public boolean isFailover() {
  214           return failover;
  215       }
  216   
  217       public void setFailover(boolean failover) {
  218           this.failover = failover;
  219       }
  220   
  221       public List<Endpoint> getEndpoints() {
  222           return endpoints;
  223       }
  224   
  225       public void setEndpoints(List<Endpoint> endpoints) {
  226           this.endpoints = endpoints;
  227       }
  228   
  229       public void setParentEndpoint(Endpoint parentEndpoint) {
  230           this.parentEndpoint = parentEndpoint;
  231       }
  232   
  233       public void onChildEndpointFail(Endpoint endpoint, MessageContext synMessageContext) {
  234   
  235           // resend (to a different endpoint) only if we support failover
  236           if (failover) {
  237               send(synMessageContext);
  238           } else {
  239               // we are not informing this to the parent endpoint as the failure of this loadbalance
  240               // endpoint. there can be more active endpoints under this, and current request has
  241               // failed only because the currently selected child endpoint has failed AND failover is
  242               // turned off in this load balance endpoint. so just call the next fault handler.
  243               Object o = synMessageContext.getFaultStack().pop();
  244               if (o != null) {
  245                   ((FaultHandler) o).handleFault(synMessageContext);
  246               }
  247           }
  248       }
  249   }

Home » synapse-1.2-src » org.apache.synapse.endpoints » [javadoc | source]