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

io.fabric8.mq.controller.multiplexer.Multiplexer Maven / Gradle / Ivy

/*
 *
 *  * Copyright 2005-2015 Red Hat, Inc.
 *  * Red Hat 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 io.fabric8.mq.controller.multiplexer;

import io.fabric8.mq.controller.AsyncExecutors;
import io.fabric8.mq.controller.MessageDistribution;
import io.fabric8.mq.controller.TransportChangedListener;
import io.fabric8.mq.controller.model.InboundConnection;
import io.fabric8.mq.controller.model.Model;
import io.fabric8.mq.controller.model.Multiplex;
import io.fabric8.mq.controller.util.TransportConnectionState;
import io.fabric8.mq.controller.util.TransportConnectionStateRegister;
import org.apache.activemq.command.*;
import org.apache.activemq.state.ConsumerState;
import org.apache.activemq.state.ProducerState;
import org.apache.activemq.state.SessionState;
import org.apache.activemq.transport.DefaultTransportListener;
import org.apache.activemq.transport.FutureResponse;
import org.apache.activemq.transport.ResponseCallback;
import org.apache.activemq.transport.Transport;
import org.apache.activemq.util.IdGenerator;
import org.apache.activemq.util.ServiceStopper;
import org.apache.activemq.util.ServiceSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

public class Multiplexer extends ServiceSupport implements Multiplex, TransportChangedListener {

    private static final Logger LOG = LoggerFactory.getLogger(Multiplexer.class);
    private final String name;
    private final AsyncExecutors asyncExecutors;
    private final MessageDistribution messageDistribution;
    private final TransportConnectionStateRegister transportConnectionStateRegister;
    private final Map inputs;
    private final Map consumerIdMultiplexerInputMap;
    private final IdGenerator inputId;
    private final ConnectionInfo multiplexerConnectionInfo;
    private final SessionInfo multiplexerSessionInfo; //for advisories
    private final AtomicLong sessionIdGenerator;
    private final AtomicLong producerIdGenerator;
    private final AtomicLong consumerIdGenerator;
    private final AtomicLong transactionIdGenerator;
    private final AtomicLong inputCount;
    private final AtomicReference attachedToBroker;
    private Model model;
    private String userName;
    private String password;

    public Multiplexer(Model model, String name, AsyncExecutors asyncExecutors, MessageDistribution messageDistribution) {
        this.model = model;
        this.name = name;
        this.asyncExecutors = asyncExecutors;
        this.messageDistribution = messageDistribution;
        this.transportConnectionStateRegister = new TransportConnectionStateRegister();
        inputs = new ConcurrentHashMap<>();
        consumerIdMultiplexerInputMap = new ConcurrentHashMap<>();
        inputId = new IdGenerator("InTransport");
        multiplexerConnectionInfo = new ConnectionInfo(new ConnectionId(inputId.generateSanitizedId()));
        multiplexerSessionInfo = new SessionInfo(multiplexerConnectionInfo, -1);
        sessionIdGenerator = new AtomicLong();
        producerIdGenerator = new AtomicLong();
        consumerIdGenerator = new AtomicLong();
        transactionIdGenerator = new AtomicLong();
        inputCount = new AtomicLong();
        userName = "";
        password = "";
        attachedToBroker = new AtomicReference<>(new CountDownLatch(1));
    }

    public Model getModel() {
        return model;
    }

    public int getInputSize() {
        return inputs.size();
    }

    public void onFailure(Throwable e) {
        if (isStopping() || isStopped()) {
            LOG.debug("Transport error: {}", e.getMessage(), e);
        } else {
            try {
                LOG.error("Transport error: {} ", e.getMessage(), e);
                stop();
            } catch (Throwable ex) {
            }
        }

    }

    public String getName() {
        return name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public long getNextSessionId() {
        return sessionIdGenerator.incrementAndGet();
    }

    public long getNextProducerId() {
        return producerIdGenerator.incrementAndGet();
    }

    public long getNextConsumerId() {
        return consumerIdGenerator.incrementAndGet();
    }

    public long getNextTransactionId() {
        return transactionIdGenerator.incrementAndGet();
    }

    public ConnectionInfo getMultiplexerConnectionInfo() {
        return multiplexerConnectionInfo;
    }

    public SessionInfo getMultiplexerSessionInfo() {
        return multiplexerSessionInfo;
    }

    public void addInput(String protocol, Transport transport) throws Exception {
        if (transport != null && !isStopping() && !isStopped()) {
            String name = getName() + ".input." + inputCount.getAndIncrement();
            MultiplexerInput multiplexerInput = new MultiplexerInput(this, name, protocol, asyncExecutors, transportConnectionStateRegister, transport);
            inputs.put(transport, multiplexerInput);
            multiplexerInput.start();
        }
    }

    public void removeInput(MultiplexerInput multiplexerInput) {
        if (multiplexerInput != null) {
            if (inputs.remove(multiplexerInput.getInput()) != null) {

                List removeList = new ArrayList<>();
                for (Map.Entry keyEntry : consumerIdMultiplexerInputMap.entrySet()) {
                    if (keyEntry.getValue().equals(multiplexerInput)) {
                        removeList.add(keyEntry.getKey());
                    }
                }
                for (ConsumerId consumerId : removeList) {
                    consumerIdMultiplexerInputMap.remove(consumerId);
                }
            }
        }
    }

    public List getInboundConnections() {
        List list = new ArrayList<>();
        for (InboundConnection inboundConnection : inputs.values()) {
            list.add(inboundConnection);
        }
        return list;
    }

    public void removeInput(Transport transport) {
        MultiplexerInput multiplexerInput = inputs.get(transport);
        removeInput(multiplexerInput);
    }

    public void sendOutAll(final MultiplexerInput input, final Command command) {
        waitForBroker();
        if (command != null) {
            try {
                if (command.isResponseRequired()) {
                    final int commandId = command.getCommandId();

                    messageDistribution.asyncSendAll(command, new ResponseCallback() {
                        @Override
                        public void onCompletion(FutureResponse futureResponse) {
                            try {
                                Response response = futureResponse.getResult();
                                process(input, commandId, response);
                            } catch (Throwable e) {
                                e.printStackTrace();
                                onFailure(e);
                            }
                        }
                    });
                } else {
                    messageDistribution.sendAll(command);
                }
            } catch (Throwable e) {
                e.printStackTrace();
                onFailure(e);
            }
        }
    }

    public void sendOut(final MultiplexerInput input, ActiveMQDestination destination, Command command) {
        waitForBroker();
        if (command != null) {
            try {
                if (command.isResponseRequired()) {
                    final int commandId = command.getCommandId();

                    messageDistribution.asyncSend(destination, command, new ResponseCallback() {
                        @Override
                        public void onCompletion(FutureResponse futureResponse) {
                            try {
                                Response response = futureResponse.getResult();
                                process(input, commandId, response);
                            } catch (Throwable e) {
                                onFailure(e);
                            }
                        }
                    });
                } else {
                    messageDistribution.send(destination, command);
                }
            } catch (Throwable e) {
                onFailure(e);
            }
        }
    }

    public void registerConsumer(ConsumerId consumerId, MultiplexerInput input) {
        consumerIdMultiplexerInputMap.put(consumerId, input);
    }

    public void unregisterConsumer(ConsumerId consumerId) {
        consumerIdMultiplexerInputMap.remove(consumerId);
    }

    @Override
    public void transportCreated(String brokerId, Transport transport) {
        if (isStarted()) {
            try {
                for (TransportConnectionState transportConnectionState : transportConnectionStateRegister.listConnectionStates()) {

                    ConnectionInfo connectionInfo = transportConnectionState.getInfo();
                    transport.oneway(connectionInfo);

                    int sessionCount = transportConnectionState.getSessionStates().size();
                    int consumerCount = 0;
                    int producerCount = 0;
                    for (SessionState sessionState : transportConnectionState.getSessionStates()) {
                        SessionInfo sessionInfo = sessionState.getInfo();
                        transport.oneway(sessionInfo);
                        consumerCount = sessionState.getConsumerStates().size();
                        for (ConsumerState consumerState : sessionState.getConsumerStates()) {
                            ConsumerInfo consumerInfo = consumerState.getInfo();
                            transport.oneway(consumerInfo);
                        }
                        producerCount = sessionState.getProducerStates().size();
                        for (ProducerState producerState : sessionState.getProducerStates()) {
                            ProducerInfo producerInfo = producerState.getInfo();
                            transport.oneway(producerInfo);
                        }
                    }
                    LOG.info("Sent to " + transport + " Connection Info " + connectionInfo.getClientId() + " [ sessions = " + sessionCount + ",consumers = " + consumerCount + ",producers=" + producerCount + "]");
                }
            } catch (Throwable e) {
                LOG.error("Failed to update connection state ", e);
            }
        }
        CountDownLatch countDownLatch = attachedToBroker.get();
        countDownLatch.countDown();

    }

    @Override
    public void transportDestroyed(String brokerId) {
        if (messageDistribution.getCurrentConnectedBrokerCount() == 0) {
            attachedToBroker.set(new CountDownLatch(1));
        }
    }

    @Override
    protected void doStart() throws Exception {

        messageDistribution.setTransportListener(new DefaultTransportListener() {
            @Override
            public void onCommand(Object o) {
                try {
                    processCommand(o);
                } catch (Throwable error) {
                    onFailure(error);
                }
            }

            @Override
            public void onException(IOException error) {
                if (!isStopping()) {
                    error.printStackTrace();
                    onFailure(error);
                }
            }
        });

        multiplexerConnectionInfo.setClientId(getName());
        multiplexerConnectionInfo.setUserName(getUserName());
        multiplexerConnectionInfo.setPassword(getPassword());
        transportConnectionStateRegister.registerConnectionState(multiplexerConnectionInfo.getConnectionId(), multiplexerConnectionInfo);
        transportConnectionStateRegister.addSession(multiplexerSessionInfo);
        messageDistribution.addTransportCreatedListener(this);
        messageDistribution.start();
        if (messageDistribution.getCurrentConnectedBrokerCount() > 0) {
            messageDistribution.sendAll(multiplexerConnectionInfo);
            messageDistribution.sendAll(multiplexerSessionInfo);
            CountDownLatch countDownLatch = attachedToBroker.get();
            countDownLatch.countDown();
        }
        model.add(this);
    }

    @Override
    protected void doStop(ServiceStopper serviceStopper) {
        messageDistribution.removeTransportCreatedListener(this);
        transportConnectionStateRegister.clear();
        try {
            if (!messageDistribution.isStopped()) {
                messageDistribution.sendAll(new ShutdownInfo(), true);
            }
            serviceStopper.stop(messageDistribution);
        } catch (Throwable e) {
        }
        model.remove(this);
    }

    protected void processCommand(Object o) throws Exception {
        Command command = (Command) o;
        if (command.isResponse()) {
            LOG.error("Unexpected response " + command);
        } else if (command.isMessageDispatch()) {
            MessageDispatch messageDispatch = (MessageDispatch) command;
            ConsumerId consumerId = messageDispatch.getConsumerId();
            MultiplexerInput input = consumerIdMultiplexerInputMap.get(consumerId);
            if (input != null) {
                input.oneway(messageDispatch);
            } else {
                LOG.debug("Couldn't find MultiplexerInput for consumerId:" + consumerId);
            }
        } else if (command.isBrokerInfo() || command.isWireFormatInfo()) {
            //not a lot to do with this
        } else if (command.getClass() == ConnectionError.class) {
            ConnectionError ce = (ConnectionError) command;
            onFailure(ce.getException());
        } else {

            switch (command.getDataStructureType()) {
                case KeepAliveInfo.DATA_STRUCTURE_TYPE:
                case ShutdownInfo.DATA_STRUCTURE_TYPE:
                case ConnectionControl.DATA_STRUCTURE_TYPE:
                    break;
                default:
                    LOG.warn("Unexpected remote command: {}", command);
            }
        }

    }

    protected void doAsyncProcess(Runnable run) {
        asyncExecutors.execute(run);
    }

    protected void process(MultiplexerInput input, int realCorrelationId, Response response) throws IOException {

        if (response.isException()) {
            ExceptionResponse er = (ExceptionResponse) response;
            onFailure(er.getException());
        } else {
            Response copy = new Response();
            response.copy(copy);
            copy.setCorrelationId(realCorrelationId);
            input.oneway(copy);
        }
    }

    private void waitForBroker() {
        CountDownLatch countDownLatch = attachedToBroker.get();
        try {
            while (!isStopping()) {
                if (countDownLatch.await(100, TimeUnit.MILLISECONDS)) {
                    break;
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy