All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.coos.messaging.impl.DefaultEndpoint Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
/**
 * COOS - Connected Objects Operating System (www.connectedobjects.org).
 *
 * Copyright (C) 2009 Telenor ASA and Tellu AS. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 * You may also contact one of the following for additional information:
 * Telenor ASA, Snaroyveien 30, N-1331 Fornebu, Norway (www.telenor.no)
 * Tellu AS, Hagalokkveien 13, N-1383 Asker, Norway (www.tellu.no)
 */
package org.coos.messaging.impl;

import org.coos.messaging.AsyncCallback;
import org.coos.messaging.ConnectingException;
import org.coos.messaging.Consumer;
import org.coos.messaging.Endpoint;
import org.coos.messaging.EndpointException;
import org.coos.messaging.Exchange;
import org.coos.messaging.ExchangePattern;
import org.coos.messaging.InteractionHelper;
import org.coos.messaging.Link;
import org.coos.messaging.Message;
import org.coos.messaging.Notification;
import org.coos.messaging.Plugin;
import org.coos.messaging.Processor;
import org.coos.messaging.ProcessorException;
import org.coos.messaging.Producer;
import org.coos.messaging.Service;
import org.coos.messaging.SubscriptionFilter;
import org.coos.messaging.util.ExecutorService;
import org.coos.messaging.util.Executors;
import org.coos.messaging.util.Log;
import org.coos.messaging.util.LogFactory;
import org.coos.messaging.util.URIHelper;
import org.coos.messaging.util.URIProtocolHelper;
import org.coos.messaging.util.UuidGenerator;
import org.coos.messaging.util.UuidHelper;

import org.coos.module.CommonConstants;
import org.coos.module.EdgeLCMMessageFactory;
import org.coos.module.EdgeMessageProperties;
import org.coos.module.LCMEdgeMessageFactory;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;


/**
 * @author Knut Eilif Husa, Tellu AS
 * @author anders
 */
public abstract class DefaultEndpoint extends DefaultProcessor implements Endpoint {

    private String uri;
    private String endpointUuid;
    private Plugin plugin;
    private final Vector aliases = new Vector();
    private final Hashtable outLinks = new Hashtable();
    private final Vector services = new Vector();
    private final Hashtable exchanges = new Hashtable();
    private final Hashtable callbacks = new Hashtable();
    private UuidGenerator uuidGenerator = new UuidGenerator();
    private int maxPoolSize = DEFAULT_MAX_POOL_SIZE;
    protected ExecutorService threadPool;
    private long timeout;
    protected Vector deferQueue = new Vector();
    protected Log log = LogFactory.getLog(this.getClass().getName());


    private String endpointState = STATE_READY;
    private Hashtable childStates = new Hashtable();
    protected boolean heartbeat;
    protected Timer timer;

    protected DefaultEndpoint() {
    }

    public DefaultEndpoint(String uri, Processor processor) {

        // This is for test purposes since this constructor only is called in
        // tests
        this.uri = uri;
        outLinks.put("coos", processor);
        threadPool = Executors.newThreadPool(2);
        uuidGenerator = new UuidGenerator("xId-" +
                ((getName() == null) ? getEndpointUuid() : getName()));
        setEndpointState(Endpoint.STATE_RUNNING);

    }

    @Override public void setName(String name) {

        if ((name != null) && !UuidHelper.isUuid(name)) {
            aliases.addElement(name);
        }

        super.setName(name);
    }

    public Consumer createConsumer() {

        // TODO Auto-generated method stub
        return null;
    }

    public Producer createProducer() {

        // TODO Auto-generated method stub
        return null;
    }

    public String getEndpointUuid() {
        return endpointUuid;
    }

    public void setEndpointUuid(String endpointUuid) {
        endpointUuid = UuidHelper.getQualifiedUuid(endpointUuid);
        this.endpointUuid = endpointUuid;
        log.putMDC("UUID", endpointUuid);
    }

    public String getEndpointState() {
        return endpointState;
    }

    public void setEndpointState(String endpointState) {
        this.endpointState = endpointState;

        if (isStateRunning()) {

            for (int i = 0; i < deferQueue.size(); i++) {
                Message message = (Message) deferQueue.elementAt(i);
                processMessage(message);
            }

            deferQueue.removeAllElements();
        }
    }

    public void setChildEndpointState(String childName, String state) {
        childStates.put(childName, state);
    }

    public String getChildEndpointState(String childName) {
        return (String) childStates.get(childName);
    }

    @Override public void setProperties(Hashtable properties) {
        this.properties = properties;

        String timoutStr = (String) properties.get(PROP_EXCHANGE_TIMEOUT);

        if (timoutStr != null) {
            timeout = Long.parseLong(timoutStr);
        } else {
            timeout = DEFAULT_TIMEOUT;
        }

        maxPoolSize = Integer.parseInt(getProperty(PROP_MAX_POOL_SIZE,
                    String.valueOf(DEFAULT_MAX_POOL_SIZE)));
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }


    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }

    public Exchange createExchange() {
        Exchange exchange = new DefaultExchange(new ExchangePattern(ExchangePattern.OutIn));

        return exchange;
    }

    public Exchange createExchange(ExchangePattern pattern) {
        Exchange exchange = new DefaultExchange(pattern);

        return exchange;
    }

    public String getEndpointUri() {
        return uri;
    }

    public void setEndpointUri(String endpointUri) {
        this.uri = endpointUri;
        log.putMDC("URI", endpointUri);
    }

    public String createUuid() {
        return uuidGenerator.generateId();
    }

    /**
     * Method that registers endpoint into lifecycle manager.
     *
     * @throws EndpointException
     *             if registration fails
     */
    private void registerLCM() throws EndpointException {
        // registration to LCM

        boolean failIfError = false;

        String lcmRegReq = (String) properties.get(PROP_LCM_REGISTRATION_REQUIRED);

        if ((lcmRegReq != null) && lcmRegReq.equals("true")) {
            failIfError = true;
        }

        log.info("Registering endpoint: " + uri + " to LifeCycleManager.");

        String pollingInterval = getProperty(PROP_LCM_POLLING_INTERVAL);
        Exchange ex;

        if (pollingInterval == null)
            ex = LCMEdgeMessageFactory.createRegisterEndpointExchange(endpointState,
                    getChildStates(), DEFAULT_LCM_POLLING_INTERVAL);
        else
            ex = LCMEdgeMessageFactory.createRegisterEndpointExchange(endpointState,
                    getChildStates(), Long.parseLong(pollingInterval));

        InteractionHelper helper = new InteractionHelper(this);
        ex = helper.request(LIFE_CYCLE_MANGER_ADDRESS, ex);

        if (ex.getFaultMessage() != null) {

            if (failIfError)
                throw new EndpointException("Registration to LifeCycleManager failed due to :" +
                    ex.getFaultMessage().getHeader(Message.ERROR_REASON));
        } else {
            Message reply = ex.getInBoundMessage();

            if ((reply == null) ||
                    reply.getHeader(Message.MESSAGE_NAME).equals(CommonConstants.REPLY_NACK)) {

                if (failIfError)
                    throw new EndpointException("Registration to lifecycle manager failed");
                    // else
                    // log.
            }
        }
    }

    private void unRegisterLCM() throws EndpointException {

        // unregistration to LCM
        log.info("UnRegistering endpoint: " + uri + " from LifeCycleManager.");

        InteractionHelper helper = new InteractionHelper(this);
        Exchange ex = LCMEdgeMessageFactory.createUnregisterEndpointExchange();
        ex = helper.request(LIFE_CYCLE_MANGER_ADDRESS, ex);

        if (ex.getFaultMessage() != null) {
            log.info("Endpoint: " + getEndpointUri() +
                ", Unregistration to LifeCycleManager failed due to: " +
                ex.getFaultMessage().getHeader(Message.ERROR_REASON));
        } else {
            Message reply = ex.getInBoundMessage();

            if ((reply == null) ||
                    reply.getHeader(Message.MESSAGE_NAME).equals(CommonConstants.REPLY_NACK)) {
                log.info("Endpoint: " + getEndpointUri() +
                    ", Unregistration to lifecycle manager failed");
            }
        }

    }


    private void reportChildren() throws EndpointException {
        log.info("Reporting state: " + endpointState + " to LifeCycleManager.");

        Exchange ex = LCMEdgeMessageFactory.createSetChildrenStatesExchange(childStates);
        InteractionHelper helper = new InteractionHelper(this);
        ex = helper.request(LIFE_CYCLE_MANGER_ADDRESS, ex);

        if (ex.getFaultMessage() != null) {
            throw new EndpointException("Children reply to LifeCycleManager failed due to :" +
                ex.getFaultMessage().getHeader(Message.ERROR_REASON));
        }

        Message reply = ex.getInBoundMessage();
        String signalName = reply.getHeader(Message.MESSAGE_NAME);

        if (signalName.equals(CommonConstants.REPLY_NACK)) {
            throw new EndpointException("Children reply to lifecycle manager failed");
        }
    }

    public void reportState() throws EndpointException {
        boolean failIfError = false;

        String lcmRegReq = (String) properties.get(PROP_LCM_REGISTRATION_REQUIRED);

        if ((lcmRegReq != null) && lcmRegReq.equals("true")) {
            failIfError = true;
        }

        log.info("Sending state: " + getEndpointState() + " to LifeCycleManager.");

        Exchange ex = LCMEdgeMessageFactory.createSetStateExchange(getEndpointState());
        InteractionHelper helper = new InteractionHelper(this);
        ex = helper.request(LIFE_CYCLE_MANGER_ADDRESS, ex);

        if (ex.getFaultMessage() != null) {

            if (failIfError)
                throw new EndpointException("Pushing state to Lifecycle Mangager failed :" +
                    ex.getFaultMessage().getHeader(Message.ERROR_REASON));
        } else {
            Message reply = ex.getInBoundMessage();
            String signalName = reply.getHeader(Message.MESSAGE_NAME);

            if (signalName.equals(CommonConstants.REPLY_NACK)) {

                if (failIfError)
                    throw new EndpointException("Pushing state to Lifecycle Manager failed.");
                    // else
                    // log.
            }
        }
    }

    public void reportChildState(String childName) throws EndpointException {
        boolean failIfError = false;

        String lcmRegReq = (String) properties.get(PROP_LCM_REGISTRATION_REQUIRED);

        if ((lcmRegReq != null) && lcmRegReq.equals("true")) {
            failIfError = true;
        }

        String childState = (String) getChildStates().get(childName);

        log.info("Sending state: " + childState + " of child: " + childName +
            " to LifeCycleManager.");

        Exchange ex = LCMEdgeMessageFactory.createRegisterEndpointChildExchange(childName,
                childState);
        InteractionHelper helper = new InteractionHelper(this);
        ex = helper.request(LIFE_CYCLE_MANGER_ADDRESS, ex);

        if (ex.getFaultMessage() != null) {

            if (failIfError)
                throw new EndpointException("Pushing child-state to Lifecycle Mangager failed :" +
                    ex.getFaultMessage().getHeader(Message.ERROR_REASON));
        } else {
            Message reply = ex.getInBoundMessage();
            String signalName = reply.getHeader(Message.MESSAGE_NAME);

            if (signalName.equals(CommonConstants.REPLY_NACK)) {

                if (failIfError)
                    throw new EndpointException("Pushing child-state to Lifecycle Manager failed.");
                    // else
                    // log.
            }
        }
    }


    /**
     * Sync processing of inBound messages
     *
     * @param exchange
     * @return
     */
    public Exchange processExchange(Exchange exchange) {

        if (exchange.isProcessed()) {
            exchange.setException(new EndpointException(
                    "Exchange can not be reused. Is already processed"));
            log.warn("Endpoint: " + uri + ", Exception processing exchange, already processed: " +
                exchange);

            return exchange;
        }

        Processor processor = prepareExchange(exchange);
        log.debug("Endpoint: " + uri + ", Processing outgoing exchange: " + exchange);

        if (exchange.getFaultMessage() != null) {
            return exchange;
        }

        synchronized (exchange) {

            try {
                processor.processMessage(exchange.getOutBoundMessage());
            } catch (ProcessorException e) {
                Message fault = new DefaultMessage();
                fault.setReceiverEndpointUri(getEndpointUri());
                fault.setHeader(Message.TYPE_MSG, Message.TYPE_ERROR);
                fault.setHeader(Message.ERROR_REASON, e.getMessage());
                fault.setHeader(Message.EXCHANGE_ID, exchange.getExchangeId());
                exchange.setFaultMessage(fault);
                exchange.setException(e);
                log.warn("Endpoint: " + uri + ", Exception processing exchange: " + exchange);

                return exchange;
            }

            ExchangePattern xp = exchange.getPattern();

            if (xp.equals(ExchangePattern.OutIn) || xp.equals(ExchangePattern.RobustOutOnly)) {

                try {
                    exchange.wait(timeout);

                    if (!exchange.isProcessed()) {
                        log.warn("Endpoint: " + uri + ", exchange: " + exchange + " timed out (" +
                            timeout + " ms).");

                        Message fault = new DefaultMessage();
                        fault.setReceiverEndpointUri(getEndpointUri());
                        fault.setHeader(Message.TYPE, Message.TYPE_ERROR);
                        fault.setHeader(Message.ERROR_REASON, "Exchange timeout");
                        fault.setHeader(Message.ERROR_CODE, "504");
                        fault.setHeader(Message.EXCHANGE_ID, exchange.getExchangeId());
                        exchange.setFaultMessage(fault);
                    }
                } catch (InterruptedException e) {
                    log.warn("Endpoint: " + uri + ", exchange: " + exchange +
                        " interrupted. Ignored.", e);
                }
            }
        }

        return exchange;
    }

    /**
     * Simple method to send a message to a receiver, using a set exchange pattern. Returns the inbound Message object from the used exchange.
     * @param msg
     * @param receiver - coos url of the receiver
     * @param exchangePattern
     * @return
     */
    public Message sendMessage(Message msg, String receiver, String exchangePattern) {
        Exchange e = createExchange(new ExchangePattern(exchangePattern));
        msg.setReceiverEndpointUri(receiver);
        e.setOutBoundMessage(msg);

        Exchange response = processExchange(e);

        return response.getInBoundMessage();
    }

    /**
     * Prepares the exchange before it is processed. This includes checking that
     * sender and receiver adresses are resolved
     *
     * @param exchange
     *            the exchange
     */
    private Processor prepareExchange(Exchange exchange) {

        try {

            //            if (!isStateRunning()&&!endpointState.equals(STATE_STARTING)) {
            //                throw new EndpointException("Endpoint not able to handle exchanges. Endpoint State is: "
            //                        + endpointState);
            //            }

            String senderUri = exchange.getOutBoundMessage().getSenderEndpointUri();
            URIHelper helper;

            if ((senderUri == null) || senderUri.equals("")) {
                helper = new URIHelper(uri);
            } else {
                helper = new URIHelper(senderUri);
            }

            helper.setEndpoint(endpointUuid);
            exchange.getOutBoundMessage().setSenderEndpointUri(helper.getEndpointUri());

            String uri = exchange.getOutBoundMessage().getReceiverEndpointUri();

            if (exchange.getExchangeId() == null) {
                exchange.setExchangeId(uuidGenerator.generateId());
            }

            ExchangePattern xPattern = exchange.getPattern();

            if (xPattern.equals(ExchangePattern.OutIn) ||
                    xPattern.equals(ExchangePattern.RobustOutOnly)) {
                exchanges.put(exchange.getExchangeId(), exchange);
            }

            if (exchange.getPattern().equals(ExchangePattern.InOut)) {

                //If this is a reply we search through the message for header values that are to be passed
                //along with the reply
                exchange.getOutBoundMessage().setHeader(Message.EXCHANGE_ID,
                    exchange.getInBoundMessage().getHeader(Message.EXCHANGE_ID));

                Message outMsg = exchange.getOutBoundMessage();
                Message inMsg = exchange.getInBoundMessage();
                Enumeration keys = inMsg.getHeaders().keys();

                while (keys.hasMoreElements()) {
                    String key = (String) keys.nextElement();

                    if (key.startsWith(Message.EXCHANGE_PREFIX)) {
                        outMsg.setHeader(key, exchange.getInBoundMessage().getHeader(key));
                    }
                }

            } else {
                exchange.getOutBoundMessage().setHeader(Message.EXCHANGE_ID,
                    exchange.getExchangeId());
            }

            exchange.getOutBoundMessage().setHeader(Message.EXCHANGE_PATTERN,
                exchange.getPattern().toString());

            if (exchange.getOutBoundMessage().getType() == null) {
                exchange.getOutBoundMessage().setHeader(Message.TYPE, Message.TYPE_MSG);
            }

            if (xPattern.equals(ExchangePattern.RobustOutOnly)) {
                long rdTimeout = timeout / 2;
                exchange.getOutBoundMessage().setHeader(Message.ROBUST_DELIVERY_TIME,
                    String.valueOf(rdTimeout));
                exchange.getOutBoundMessage().setHeader(Message.ROBUST_DELIVERY_ACK_URI,
                    helper.getEndpointUri());
            }

            String protocol = URIProtocolHelper.getProtocol(uri);

            Processor processor = resolveOutgoingProcessor(protocol);

            if (protocol.startsWith("coos")) {

                helper = new URIHelper(uri);
                exchange.getOutBoundMessage().setReceiverEndpointName(helper.getEndpoint());
                exchange.getOutBoundMessage().setSenderEndpointName(((getName() == null)
                        ? getEndpointUuid() : getName()));

            }

            return processor;

        } catch (Exception e) {
            log.warn("Exception caught by prepareExchange().", e);
            exchange.setFaultMessage(new DefaultMessage().setHeader(Message.ERROR_REASON,
                    "Exception: " + e.getClass().getName() + ", Message: " + e.getMessage()));
            exchange.setException(e);
        }

        return null;

    }

    private boolean isStateRunning() {

        if (endpointState.equals(STATE_RUNNING)) {
            return true;
        }

        if (endpointState.equals(STATE_STARTING) || endpointState.equals(STATE_INSTALLED) ||
                endpointState.equals(STATE_PAUSED) || endpointState.equals(STATE_READY) ||
                endpointState.equals(STATE_STARTUP_FAILED) ||
                endpointState.equals(STATE_UNINNSTALLED) || endpointState.equals(STATE_UPDATING) ||
                endpointState.equals(STATE_UPGRADING))
            return false;

        return true;
    }

    protected Processor resolveOutgoingProcessor(String protocol) throws EndpointException {
        Processor processor = (Processor) outLinks.get(protocol);

        if (processor == null) {
            throw new EndpointException("No channel defined for protocol: " + protocol);
        }

        return processor;
    }

    /**
     * Async processing of outbound messages
     *
     * @param exchange
     * @param callback
     */
    public void processExchange(Exchange exchange, AsyncCallback callback) {
        log.debug("Endpoint: " + uri + ", Processing outgoing exchange: " + exchange);

        Processor processor = prepareExchange(exchange);

        if (exchange.getFaultMessage() != null) {
            callback.processExchange(exchange);

            return;
        }

        exchanges.put(exchange.getExchangeId(), exchange);
        callbacks.put(exchange.getExchangeId(), callback);

        synchronized (exchange) {

            try {
                processor.processMessage(exchange.getOutBoundMessage());
            } catch (ProcessorException e) {
                Message fault = new DefaultMessage();
                fault.setHeader(Message.TYPE_MSG, Message.TYPE_ERROR);
                fault.setHeader(Message.ERROR_REASON, e.getMessage());
                fault.setHeader(Message.EXCHANGE_ID, exchange.getExchangeId());
                fault.setHeader(Message.EXCHANGE_PATTERN, exchange.getPattern().toString());
                processMessage(fault);

            }
        }
    }

    /**
     * Processing of Inbound messages
     *
     * @param msg
     */
    public void processMessage(Message msg) {

        //if(coContainer != null)
        msg.setDeserializeClassLoader(coContainer);

        String msgType = msg.getHeader(Message.TYPE);

        if (msgType.equals(Message.TYPE_MSG) || msgType.equals(Message.TYPE_ERROR)) {

            if (msg.getName().equals(Notification.NOTIFY)) {
                msg = new DefaultNotification(msg);
            }

            String xpattern = msg.getHeader(Message.EXCHANGE_PATTERN);
            ExchangePattern xp = new ExchangePattern(xpattern);
            final String xId = msg.getHeader(Message.EXCHANGE_ID);
            final Message retMsg = msg;

            try {
                retMsg.getBody();
            } catch (Exception e) {
                retMsg.setHeader(Message.TYPE, Message.TYPE_ERROR);
                retMsg.setHeader(Message.ERROR_REASON, "Deserialization error: " + e.getMessage());
            }

            Consumer consumer = createConsumer();

            // Error handling
            if (msg.getHeader(Message.TYPE).equals(Message.TYPE_ERROR)) {

                if ((xId != null) && exchanges.containsKey(xId)) {
                    final Exchange exchange = (Exchange) exchanges.remove(xId);
                    log.warn("Endpoint: " + uri + ", Processing incoming exchange: " + exchange +
                        ": fault :" + retMsg);

                    exchange.setFaultMessage(retMsg);
                    exchange.setProcessed(true);

                    if (callbacks.containsKey(xId)) {
                        threadPool.execute(new Runnable() {
                                public void run() {

                                    // this is an async return
                                    AsyncCallback callback = (AsyncCallback) callbacks.remove(xId);
                                    callback.processExchange(exchange);
                                }
                            });
                    } else {

                        // this is a sync return
                        // todo when moved to java 1.6 can check if current thread holds lock
                        // New thread is only necessary in that case
                        new Thread(new Runnable() {
                                public void run() {

                                    synchronized (exchange) {
                                        exchange.notifyAll();
                                    }
                                }
                            }).start();
                    }
                } else {
                    log.warn("Endpoint: " + uri + ", Error message:" + retMsg);
                }

            } else {

                // Message handling
                Exchange exchange = null;

                if ((xId != null) && exchanges.containsKey(xId) && !xp.isOutBoundInitiated()) {

                    // this is a return or a message to same endpoint.
                    final Exchange exchange2 = (Exchange) exchanges.remove(xId);
                    log.debug("Endpoint: " + uri + ", Processing incoming exchange: " + exchange2);

                    if (xp.equals(ExchangePattern.InOut)) {
                        exchange2.setInBoundMessage(retMsg);
                    }

                    exchange2.setProcessed(true);

                    if (callbacks.containsKey(xId)) {
                        threadPool.execute(new Runnable() {
                                public void run() {

                                    // this is an async return
                                    AsyncCallback callback = (AsyncCallback) callbacks.remove(xId);
                                    callback.processExchange(exchange2);
                                }
                            });
                    } else {

                        // this is a sync return
                        // todo when moved to java 1.6 can check if current thread holds lock
                        // New thread is only necessary in that case
                        new Thread(new Runnable() {
                                public void run() {

                                    synchronized (exchange2) {
                                        exchange2.notifyAll();
                                    }
                                }
                            }).start();
                    }
                } else if (consumer != null) {

                    if (msg.getHeader(Message.MESSAGE_NAME).equals(
                                EdgeLCMMessageFactory.EDGE_REQUEST_STATE)) {
                        threadPool.execute(new Runnable() {
                                public void run() {

                                    try {
                                        reportState();
                                    } catch (EndpointException e) {
                                        log.warn(
                                            "Exception caught by processMessage(). Message " +
                                            EdgeLCMMessageFactory.EDGE_REQUEST_STATE, e);
                                    }
                                }
                            });

                        return;
                    } else if (msg.getHeader(Message.MESSAGE_NAME).equals(
                                EdgeLCMMessageFactory.EDGE_REQUEST_CHILD_STATE)) {
                        final String childAddress = (String) msg.getBodyAsProperties().get(
                                EdgeMessageProperties.EDGE_PROP_CHILD_NAME);
                        threadPool.execute(new Runnable() {
                                public void run() {

                                    try {
                                        reportChildState(childAddress);
                                    } catch (EndpointException e) {
                                        log.warn(
                                            "Exception caught by processMessage(). Message " +
                                            EdgeLCMMessageFactory.EDGE_REQUEST_CHILD_STATE, e);
                                    }
                                }
                            });

                        return;
                    } else if (
                        msg.getHeader(Message.MESSAGE_NAME).equals(
                                EdgeLCMMessageFactory.EDGE_REQUEST_CHILDREN) &&
                            (msg.getBodyAsProperties().get(
                                    EdgeMessageProperties.EDGE_PROP_CHILDREN) == null)) {
                        threadPool.execute(new Runnable() {
                                public void run() {

                                    try {
                                        reportChildren();
                                    } catch (EndpointException e) {
                                        log.warn(
                                            "Exception caught by processMessage(). Message " +
                                            EdgeLCMMessageFactory.EDGE_REQUEST_CHILDREN, e);
                                    }
                                }
                            });

                        return;
                    }

                    // this is an initiating request, will only be handled in
                    // state running, else it will be deferred to
                    // the endpoint reaches state running
                    if (checkDefer(msg))
                        return;

                    if (xpattern.equals(ExchangePattern.OutIn)) {
                        exchange = createExchange(new ExchangePattern(ExchangePattern.InOut));
                    } else {

                        // default behaviour is inOnly
                        if (xpattern.equals(ExchangePattern.RobustOutOnly)) {
                            DefaultMessage confMsg = new DefaultMessage();
                            confMsg.setHeader(Message.DELIVERY_STATUS, Message.DELIVERY_SUCCESS);

                            Exchange e = createExchange(new ExchangePattern(
                                        ExchangePattern.RobustInOnly));
                            e.setExchangeId(msg.getHeader(Message.EXCHANGE_ID));
                            confMsg.setReceiverEndpointUri(msg.getHeader(
                                    Message.ROBUST_DELIVERY_ACK_URI));
                            e.setOutBoundMessage(confMsg);
                            log.debug("Endpoint: " + uri + ", Sending robust ack: " + e);
                            processExchange(e);
                        }

                        exchange = createExchange(new ExchangePattern(ExchangePattern.InOnly));
                    }

                    if (exchange != null) {
                        exchange.setInBoundMessage(msg);
                        exchange.setExchangeId(xId);

                        final Exchange exchange1 = exchange;
                        final Consumer consumer1 = consumer;
                        threadPool.execute(new Runnable() {
                                public void run() {

                                    // Todo might insert e semaphore here to control
                                    // concurrent access to consumer
                                    log.debug(
                                        "Endpoint: " + uri + ", Processing incoming exchange: " +
                                        exchange1);
                                    consumer1.process(exchange1);
                                }
                            });
                    }
                }
            }
        }
    }

    protected boolean checkDefer(Message msg) {

        if (ExchangePattern.InOut.equals(msg.getHeader(Message.EXCHANGE_PATTERN)) ||
                isStateRunning()) {
            return false;
        }

        log.debug("State isn't Running (" + endpointState + "). Deferring message to queue.");
        deferQueue.addElement(msg);

        return true;
    }

    public Vector getServices() {
        return services;
    }

    public final void initializeEndpoint() {
        uuidGenerator = new UuidGenerator("xId-" +
                ((getName() == null) ? getEndpointUuid() : getName()));
        threadPool = Executors.newThreadPool(maxPoolSize);
        deferQueue.removeAllElements();

        if (getEndpointState().equals(STATE_READY)) {

            try {
                preStart();
                start();
                postStart();
            } catch (Exception e) {
                log.error("Startup failed.", e);
                setEndpointState(STATE_STARTUP_FAILED);
            }
        }
    }

    protected void preStart() throws EndpointException {
        String s = (!name.equals(endpointUuid)) ? ("(name=" + name + ")") : "";
        log.info("Starting endpoint: " + endpointUuid + s);
        setEndpointState(STATE_STARTING);

        // if (producer instanceof Service && !(producer instanceof Endpoint)) {
        // services.addElement(producer);
        // ((Service) producer).start();
        // }
    }

    public void start() throws Exception {
        // Override this method
    }

    protected void postStart() throws EndpointException {
        createProducer();

        setEndpointState(STATE_RUNNING);

        // register to the life cycle manager
        String lcmRegEnabled = getProperty(PROP_LCM_REGISTRATION_ENABLED);

        if ((lcmRegEnabled == null) || !lcmRegEnabled.equalsIgnoreCase("false")) {
            registerLCM();
            heartbeat = true;
            startLCMHeartbeat();
        }

        String s = (!name.equals(endpointUuid)) ? ("(name=" + name + ")") : "";
        log.info("Successfully started endpoint: " + endpointUuid + s);
    }

    private void startLCMHeartbeat() {
        timer = new Timer("LCMTimer", true);

        long delay = Long.parseLong(getProperty(PROP_LCM_HEARTBEAT_INTERVAL, "120000"));

        if (delay > 0) {
            TimerTask task = new TimerTask() {

                    @Override public void run() {
                        threadPool.execute(new Runnable() {

                                public void run() {

                                    try {
                                        reportState();
                                    } catch (EndpointException e) {
                                    }
                                }
                            });
                    }
                };
            timer.schedule(task, delay, delay);
        }
    }

    public void stop() throws Exception {
        // Override this method
    }

    public final void shutDownEndpoint() {

        if (!isStateRunning()) {
            return;
        }

        log.info("Stopping endpoint: " + uri);
        setEndpointState(STATE_STOPPING);

        try {
            stop();
        } catch (Exception e) {
            log.error("Exception caught while stopping endpoint.", e);
        }

        for (int i = 0; i < services.size(); i++) {
            Service service = (Service) services.elementAt(i);

            try {
                service.stop();
            } catch (Exception e) {
                log.error("Exception caught while stopping endpoint.", e);
            }
        }

        // unregister to the life cycle manager
        if (timer != null)
            timer.cancel();

        String lcmRegEnabled = getProperty(PROP_LCM_REGISTRATION_ENABLED);

        if ((lcmRegEnabled == null) || !lcmRegEnabled.equalsIgnoreCase("false")) {

            try {
                unRegisterLCM();
            } catch (EndpointException e) {
                log.error("EndpointException caught while stopping endpoint.", e);
            } catch (Exception e) {
                log.error("Unknown Exception caught while stopping endpoint.", e);
            }
        }

        if (threadPool != null) // Null if endpoint was not started successfully

            // (ie couldn't connect)
            threadPool.stop();

        setEndpointState(STATE_READY);
    }


    public void addLink(String protocol, Link link) throws ConnectingException {
        outLinks.put(protocol, link);

    }

    public void addAlias(String alias) {

        if ((alias != null) && !UuidHelper.isUuid(alias) &&
                UuidHelper.isValidAliasForUuid(alias, getEndpointUuid())) {
            aliases.addElement(alias);
            updateAliases();
        } else {
            log.warn("Cannot assign this endpoint alias:" + alias +
                ". Only alias with segment 'dico', 'localcoos' or '" +
                UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(getEndpointUuid()) +
                "' is allowed.");
        }
    }

    public void removeAlias(String alias) {
        aliases.removeElement(alias);
        updateAliases();
    }

    public Vector getAliases() {
        return aliases;
    }

    private void updateAliases() {
        Link link = (Link) outLinks.get("coos");

        if (link != null) {
            Message msg = new DefaultMessage("alias", Message.TYPE_ALIAS);
            msg.setReceiverEndpointUri("coos://" + link.getDestinationUuid());
            msg.setBody(aliases);

            Exchange ex = createExchange(new ExchangePattern(ExchangePattern.OutOnly));
            ex.setOutBoundMessage(msg);
            processExchange(ex);
        }
    }

    public Processor getDefaultProcessor() {
        return this;
    }

    public Link getLink(String id) {
        return (Link) outLinks.get(id);
    }

    public void removeLink(String id) {
        outLinks.remove(id);

    }

    public void removeLinkById(String linkId) {
        // TODO Auto-generated method stub

    }

    public boolean subscribe(SubscriptionFilter filter) {
        log.debug("Endpoint: " + uri + " subscribing: " + filter);
        filter.setReceiverEndpointUri(NOTIFICATION_BROKER_ADDRESS);
        filter.setSenderEndpointUri(uri);
        filter.setHeader(Message.MESSAGE_NAME, SubscriptionFilter.SUBSCRIBE);

        Exchange ex = createExchange(new ExchangePattern(ExchangePattern.OutIn));
        ex.setOutBoundMessage(filter);
        processExchange(ex);

        if (ex.getFaultMessage() != null) {
            return false;
        }

        return true;
    }

    public void unsubscribe() {
        log.debug("Endpoint: " + uri + " unSubscribing all");

        Message msg = new DefaultMessage(SubscriptionFilter.UNSUBSCRIBE_ALL);
        msg.setReceiverEndpointUri(NOTIFICATION_BROKER_ADDRESS);
        msg.setSenderEndpointUri(uri);

        Exchange ex = createExchange(new ExchangePattern(ExchangePattern.OutOnly));
        ex.setOutBoundMessage(msg);
        processExchange(ex);
    }

    public void unsubscribe(SubscriptionFilter filter) {
        log.debug("Endpoint: " + uri + " unSubscribing: " + filter);
        filter.setReceiverEndpointUri(NOTIFICATION_BROKER_ADDRESS);
        filter.setSenderEndpointUri(uri);
        filter.setHeader(Message.MESSAGE_NAME, SubscriptionFilter.UNSUBSCRIBE);

        Exchange ex = createExchange(new ExchangePattern(ExchangePattern.OutOnly));
        ex.setOutBoundMessage(filter);
        processExchange(ex);
    }

    public void publish(Notification notification) {
        log.debug("Endpoint: " + uri + " publishing: " + notification);
        notification.setReceiverEndpointUri(NOTIFICATION_BROKER_ADDRESS);
        notification.setSenderEndpointUri(uri);

        Exchange ex = createExchange(new ExchangePattern(ExchangePattern.OutOnly));
        ex.setOutBoundMessage(notification);
        processExchange(ex);
    }

    public void setChildStates(Hashtable childStates) {
        this.childStates = childStates;
    }

    public Hashtable getChildStates() {
        return childStates;
    }

    @Override public Hashtable getProperties() {
        return properties;
    }

    public void setLinkAliases(Vector regAliases, Link outlink) {
        // Not implemented
    }

    public Plugin getPlugin() {
        return plugin;
    }

    public void setPlugin(Plugin plugin) {
        this.plugin = plugin;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy