org.apache.synapse.endpoints.AddressEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.synapse.endpoints.AddressEndpoint.java

Source

/*
 *  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.synapse.endpoints;

import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseConstants;
import org.apache.synapse.FaultHandler;
import org.apache.synapse.endpoints.utils.EndpointDefinition;
import org.apache.synapse.statistics.impl.EndPointStatisticsStack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Stack;

/**
 * This class represents an actual endpoint to send the message. It is responsible for sending the
 * message, performing retries if a failure occurred and informing the parent endpoint if a failure
 * couldn't be recovered.
 */
public class AddressEndpoint extends FaultHandler implements Endpoint {

    private static final Log log = LogFactory.getLog(AddressEndpoint.class);
    private static final Log trace = LogFactory.getLog(SynapseConstants.TRACE_LOGGER);

    /**
     * Name of the endpoint. Used for named endpoints which can be referred using the key attribute
     * of indirect endpoints.
     */
    private String name = null;

    /**
     * Determines if this endpoint is active or not. This variable have to be loaded always from the
     * memory as multiple threads could access it.
     */
    private volatile boolean active = true;

    /**
     * Stores the endpoint details for this endpoint. Details include EPR, WS-Addressing information,
     * WS-Security information, etc.
     */
    private EndpointDefinition endpoint = null;

    /**
     * Parent endpoint of this endpoint if this used inside another endpoint. Possible parents are
     * LoadbalanceEndpoint, SALoadbalanceEndpoint and FailoverEndpoint objects.
     */
    private Endpoint parentEndpoint = null;

    /**
     * Leaf level endpoints will be suspended for the specified time by this variable, after a
     * failure. If this is not explicitly set, it is set to -1, which causes endpoints to suspended forever.
     */
    private long suspendOnFailDuration = -1;

    /**
     * Time to recover a failed endpoint. Value of this is calculated when endpoint is set as
     * failed by adding suspendOnFailDuration to current time.
     */
    private long recoverOn = Long.MAX_VALUE;

    public EndpointDefinition getEndpoint() {
        return endpoint;
    }

    public void setEndpoint(EndpointDefinition endpoint) {
        this.endpoint = endpoint;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name.trim();
    }

    /**
     * Checks if the endpoint is active (failed or not). If endpoint is in failed state and
     * suspendOnFailDuration has elapsed, it will be set to active.
     *
     * @param synMessageContext MessageContext of the current message. This is not used here.
     * @return true if endpoint is active. false otherwise.
     */
    public boolean isActive(MessageContext synMessageContext) {

        if (!active) {
            if (System.currentTimeMillis() > recoverOn) {
                active = true;
                recoverOn = 0;
            }
        }

        return active;
    }

    /**
     * Sets if endpoint active or not. if endpoint is set as failed (active = false), the recover on
     * time is calculated so that it will be activated after the recover on time.
     *
     * @param active            true if active. false otherwise.
     * @param synMessageContext MessageContext of the current message. This is not used here.
     */
    public synchronized void setActive(boolean active, MessageContext synMessageContext) {

        // this is synchronized as recoverOn can be set to unpredictable values if two threads call
        // this method simultaneously.

        if (!active) {
            if (suspendOnFailDuration != -1) {
                recoverOn = System.currentTimeMillis() + suspendOnFailDuration;
            } else {
                recoverOn = Long.MAX_VALUE;
            }
        }

        this.active = active;
    }

    /**
     * Sends the message through this endpoint. This method just handles statistics related functions
     * and gives the message to the Synapse environment to send. It does not add any endpoint
     * specific details to the message context. These details are added only to the cloned message
     * context by the Axis2FlexibleMepClient. So that we can reuse the original message context for
     * resending through different endpoints.
     *
     * @param synCtx MessageContext sent by client to Synapse
     */
    public void send(MessageContext synCtx) {

        boolean traceOn = isTraceOn(synCtx);
        boolean traceOrDebugOn = isTraceOrDebugOn(traceOn);

        if (traceOrDebugOn) {
            traceOrDebug(traceOn, "Start : Address Endpoint");

            if (traceOn && trace.isTraceEnabled()) {
                trace.trace("Message : " + synCtx.getEnvelope());
            }
        }

        String endPointName = this.getName();
        if (endPointName == null) {
            endPointName = SynapseConstants.ANONYMOUS_ENDPOINT;
        }

        // Setting Required property to collect the End Point statistics
        boolean statisticsEnable = (SynapseConstants.STATISTICS_ON == endpoint.getStatisticsState());
        if (statisticsEnable) {
            EndPointStatisticsStack endPointStatisticsStack = null;
            Object statisticsStackObj = synCtx.getProperty(org.apache.synapse.SynapseConstants.ENDPOINT_STATS);
            if (statisticsStackObj == null) {
                endPointStatisticsStack = new EndPointStatisticsStack();
                synCtx.setProperty(org.apache.synapse.SynapseConstants.ENDPOINT_STATS, endPointStatisticsStack);
            } else if (statisticsStackObj instanceof EndPointStatisticsStack) {
                endPointStatisticsStack = (EndPointStatisticsStack) statisticsStackObj;
            }
            if (endPointStatisticsStack != null) {
                boolean isFault = synCtx.getEnvelope().getBody().hasFault();
                endPointStatisticsStack.put(endPointName, System.currentTimeMillis(), !synCtx.isResponse(),
                        statisticsEnable, isFault);
            }
        }

        if (endpoint.getAddress() != null) {
            if (traceOrDebugOn) {
                traceOrDebug(traceOn, "Sending message to endpoint : " + endPointName + " resolves to address = "
                        + endpoint.getAddress());
                traceOrDebug(traceOn,
                        "SOAPAction: " + (synCtx.getSoapAction() != null ? synCtx.getSoapAction() : "null"));
                traceOrDebug(traceOn,
                        "WSA-Action: " + (synCtx.getWSAAction() != null ? synCtx.getWSAAction() : "null"));

                if (traceOn && trace.isTraceEnabled()) {
                    trace.trace("Envelope : \n" + synCtx.getEnvelope());
                }
            }
        }

        // register this as the immediate fault handler for this message.
        synCtx.pushFaultHandler(this);

        // add this as the last endpoint to process this message. it is used by statistics code.
        synCtx.setProperty(SynapseConstants.PROCESSED_ENDPOINT, this);

        synCtx.getEnvironment().send(endpoint, synCtx);
    }

    public void onChildEndpointFail(Endpoint endpoint, MessageContext synMessageContext) {
        // nothing to do as this is a leaf level endpoint
    }

    public void setParentEndpoint(Endpoint parentEndpoint) {
        this.parentEndpoint = parentEndpoint;
    }

    public long getSuspendOnFailDuration() {
        return suspendOnFailDuration;
    }

    public void setSuspendOnFailDuration(long suspendOnFailDuration) {
        this.suspendOnFailDuration = suspendOnFailDuration;
    }

    public void onFault(MessageContext synCtx) {
        // perform retries here

        // if this endpoint has actually failed, inform the parent.
        setActive(false, synCtx);

        if (parentEndpoint != null) {
            parentEndpoint.onChildEndpointFail(this, synCtx);
        } else {
            Stack faultStack = synCtx.getFaultStack();
            if (!faultStack.isEmpty()) {
                ((FaultHandler) faultStack.pop()).handleFault(synCtx);
            }
        }
    }

    /**
     * Should this mediator perform tracing? True if its explicitly asked to
     * trace, or its parent has been asked to trace and it does not reject it
     * @param msgCtx the current message
     * @return true if tracing should be performed
     */
    protected boolean isTraceOn(MessageContext msgCtx) {
        return (endpoint.getTraceState() == SynapseConstants.TRACING_ON)
                || (endpoint.getTraceState() == SynapseConstants.TRACING_UNSET
                        && msgCtx.getTracingState() == SynapseConstants.TRACING_ON);
    }

    /**
     * Is tracing or debug logging on?
     * @param isTraceOn is tracing known to be on?
     * @return true, if either tracing or debug logging is on
     */
    protected boolean isTraceOrDebugOn(boolean isTraceOn) {
        return isTraceOn || log.isDebugEnabled();
    }

    /**
     * Perform Trace and Debug logging of a message @INFO (trace) and DEBUG (log)
     * @param traceOn is runtime trace on for this message?
     * @param msg the message to log/trace
     */
    protected void traceOrDebug(boolean traceOn, String msg) {
        if (traceOn) {
            trace.info(msg);
        }
        if (log.isDebugEnabled()) {
            log.debug(msg);
        }
    }
}