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

com.devebot.opflow.OpflowEngine Maven / Gradle / Ivy

There is a newer version: 0.3.1
Show newest version
package com.devebot.opflow;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.ShutdownListener;
import com.rabbitmq.client.ShutdownSignalException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
import javax.net.ssl.SSLContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.devebot.opflow.exception.OpflowBootstrapException;
import com.devebot.opflow.exception.OpflowConnectionException;
import com.devebot.opflow.exception.OpflowConsumerOverLimitException;
import com.devebot.opflow.exception.OpflowOperationException;
import com.devebot.opflow.supports.OpflowKeytool;

/**
 *
 * @author drupalex
 */
public class OpflowEngine {

    public static final String[] PARAMETER_NAMES = new String[] {
        "uri", "host", "port", "virtualHost", "username", "password", "channelMax", "frameMax", "heartbeat",
        "threadPoolType", "threadPoolSize",
        "exchangeName", "exchangeType", "exchangeDurable", "routingKey", "otherKeys", "applicationId",
        "automaticRecoveryEnabled", "topologyRecoveryEnabled", "networkRecoveryInterval",
        "pkcs12File", "pkcs12Passphrase", "caCertFile", "serverCertFile", "trustStoreFile", "trustPassphrase"
    };

    private final static Logger LOG = LoggerFactory.getLogger(OpflowEngine.class);
    private final OpflowLogTracer logTracer;
    
    private String mode;
    private ConnectionFactory factory;
    private Connection producingConnection;
    private Channel producingChannel;
    private Connection consumingConnection;
    private Channel consumingChannel;
    private List consumerInfos = new LinkedList();
    
    private String exchangeName;
    private String exchangeType;
    private Boolean exchangeDurable;
    private String routingKey;
    private String[] otherKeys;
    private String applicationId;

    public OpflowEngine(Map params) throws OpflowBootstrapException {
        params = OpflowUtil.ensureNotNull(params);
        
        final String engineId = OpflowUtil.getOptionField(params, "engineId", true);
        logTracer = OpflowLogTracer.ROOT.branch("engineId", engineId);
        
        if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                .text("Engine[${engineId}].new()")
                .stringify());
        
        mode = params.containsKey("mode") ? params.get("mode").toString() : "engine";
        try {
            factory = new ConnectionFactory();
            
            String threadPoolType = null;
            if (params.get("threadPoolType") instanceof String) {
                threadPoolType = (String) params.get("threadPoolType");
            }
            
            Integer threadPoolSize = null;
            if (params.get("threadPoolSize") instanceof Integer) {
                threadPoolSize = (Integer)params.get("threadPoolSize");
            }
            if (threadPoolSize == null || threadPoolSize <= 0) {
                threadPoolSize = 2;
            }
            
            ExecutorService threadExecutor = null;
            if ("cached".equals(threadPoolType)) {
                threadExecutor = Executors.newCachedThreadPool();
            } else if ("fixed".equals(threadPoolType)) {
                threadExecutor = Executors.newFixedThreadPool(threadPoolSize);
            } else if ("single".equals(threadPoolType)) {
                threadExecutor = Executors.newSingleThreadExecutor();
            } else if ("single-scheduled".equals(threadPoolType)) {
                threadExecutor = Executors.newSingleThreadScheduledExecutor();
            } else if ("scheduled".equals(threadPoolType)) {
                threadExecutor = Executors.newScheduledThreadPool(threadPoolSize);
            }
            
            if (threadExecutor != null) {
                factory.setSharedExecutor(threadExecutor);
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                    .put("threadPoolType", threadPoolType)
                    .put("threadPoolSize", threadPoolSize)
                    .text("Engine[${engineId}] use SharedExecutor type: ${threadPoolType} / ${threadPoolSize}")
                    .stringify());
            } else {
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                    .put("threadPoolType", threadPoolType)
                    .put("threadPoolSize", threadPoolSize)
                    .text("Engine[${engineId}] use default SharedExecutor")
                    .stringify());
            }
            
            String uri = (String) params.get("uri");
            if (uri != null && uri.length() > 0) {
                factory.setUri(uri);
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("uri", OpflowUtil.hidePasswordInUri(uri))
                        .text("Engine[${engineId}] make connection using URI: ${uri}")
                        .stringify());
            } else {
                String host = (String) params.getOrDefault("host", "localhost");
                factory.setHost(host);
                
                Integer port = null;
                if (params.get("port") instanceof Integer) {
                    factory.setPort(port = (Integer)params.get("port"));
                }
                
                String virtualHost = null;
                if (params.get("virtualHost") instanceof String) {
                    factory.setVirtualHost(virtualHost = (String) params.get("virtualHost"));
                }
                
                String username = null;
                if (params.get("username") instanceof String) {
                    factory.setUsername(username = (String) params.get("username"));
                }
                
                String password = null;
                if (params.get("password") instanceof String) {
                    factory.setPassword(password = (String) params.get("password"));
                }
                
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                    .put("host", host)
                    .put("port", port)
                    .put("virtualHost", virtualHost)
                    .put("username", username)
                    .put("password", OpflowUtil.maskPassword(password))
                    .text("Engine[${engineId}] make connection using parameters")
                    .stringify());
            }
            
            Integer channelMax = null;
            if (params.get("channelMax") instanceof Integer) {
                factory.setRequestedChannelMax(channelMax = (Integer)params.get("channelMax"));
            }

            Integer frameMax = null;
            if (params.get("frameMax") instanceof Integer) {
                factory.setRequestedFrameMax(frameMax = (Integer)params.get("frameMax"));
            }

            Integer heartbeat;
            if (params.get("heartbeat") instanceof Integer) {
                heartbeat = (Integer)params.get("heartbeat");
                if (heartbeat < 5) heartbeat = 5;
            } else {
                heartbeat = 20; // default 20 seconds
            }
            if (heartbeat != null) {
                factory.setRequestedHeartbeat(heartbeat);
            }

            Boolean automaticRecoveryEnabled = null;
            if (params.get("automaticRecoveryEnabled") instanceof Boolean) {
                factory.setAutomaticRecoveryEnabled(automaticRecoveryEnabled = (Boolean)params.get("automaticRecoveryEnabled"));
            }

            Boolean topologyRecoveryEnabled = null;
            if (params.get("topologyRecoveryEnabled") instanceof Boolean) {
                factory.setTopologyRecoveryEnabled(topologyRecoveryEnabled = (Boolean)params.get("topologyRecoveryEnabled"));
            }

            Integer networkRecoveryInterval;
            if (params.get("networkRecoveryInterval") instanceof Integer) {
                networkRecoveryInterval = (Integer)params.get("networkRecoveryInterval");
                if (networkRecoveryInterval <= 0) networkRecoveryInterval = null;
            } else {
                networkRecoveryInterval = 2500; // change default from 5000 to 2500
            }
            if (networkRecoveryInterval != null) {
                factory.setNetworkRecoveryInterval(networkRecoveryInterval);
            }

            String pkcs12File = null;
            if (params.get("pkcs12File") instanceof String) {
                pkcs12File = (String) params.get("pkcs12File");
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("pkcs12File", pkcs12File)
                        .text("Engine[${engineId}] - PKCS12 file: ${pkcs12File}")
                        .stringify());
            }

            String pkcs12Passphrase = null;
            if (params.get("pkcs12Passphrase") instanceof String) {
                pkcs12Passphrase = (String) params.get("pkcs12Passphrase");
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("pkcs12Passphrase", OpflowUtil.maskPassword(pkcs12Passphrase))
                        .text("Engine[${engineId}] - PKCS12 passphrase: ${pkcs12Passphrase}")
                        .stringify());
            }

            String caCertFile = null;
            if (params.get("caCertFile") instanceof String) {
                caCertFile = (String) params.get("caCertFile");
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("caCertFile", caCertFile)
                        .text("Engine[${engineId}] - CA file: ${caCertFile}")
                        .stringify());
            }

            String serverCertFile = null;
            if (params.get("serverCertFile") instanceof String) {
                serverCertFile = (String) params.get("serverCertFile");
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("serverCertFile", serverCertFile)
                        .text("Engine[${engineId}] - server certificate file: ${serverCertFile}")
                        .stringify());
            }

            String trustStoreFile = null;
            if (params.get("trustStoreFile") instanceof String) {
                trustStoreFile = (String) params.get("trustStoreFile");
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("trustStoreFile", trustStoreFile)
                        .text("Engine[${engineId}] - trust keystore file: ${trustStoreFile}")
                        .stringify());
            }

            String trustPassphrase = null;
            if (params.get("trustPassphrase") instanceof String) {
                trustPassphrase = (String) params.get("trustPassphrase");
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("trustPassphrase", OpflowUtil.maskPassword(trustPassphrase))
                        .text("Engine[${engineId}] - trust keystore passphrase: ${trustPassphrase}")
                        .stringify());
            }

            SSLContext sslContext = null;
            if (pkcs12File != null && pkcs12Passphrase != null) {
                if (caCertFile != null) {
                    sslContext = OpflowKeytool.buildSSLContextWithCertFile(pkcs12File, pkcs12Passphrase, caCertFile);
                } else if (serverCertFile != null) {
                    sslContext = OpflowKeytool.buildSSLContextWithCertFile(pkcs12File, pkcs12Passphrase, serverCertFile);
                } else if (trustStoreFile != null && trustPassphrase != null) {
                    sslContext = OpflowKeytool.buildSSLContextWithKeyStore(pkcs12File, pkcs12Passphrase,
                            trustStoreFile, trustPassphrase);
                }
            }

            if (sslContext != null) {
                factory.useSslProtocol(sslContext);
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                    .text("Engine[${engineId}] use SSL Protocol")
                    .stringify());
            } else {
                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                    .text("Engine[${engineId}] SSL context is empty")
                    .stringify());
            }

            if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                    .put("channelMax", channelMax)
                    .put("frameMax", frameMax)
                    .put("heartbeat", heartbeat)
                    .put("automaticRecoveryEnabled", automaticRecoveryEnabled)
                    .put("topologyRecoveryEnabled", topologyRecoveryEnabled)
                    .put("networkRecoveryInterval", networkRecoveryInterval)
                    .text("Engine[${engineId}] make connection using parameters: "
                            + "channelMax: ${channelMax}, "
                            + "frameMax: ${frameMax}, "
                            + "heartbeat: ${heartbeat}, "
                            + "automaticRecoveryEnabled: ${automaticRecoveryEnabled}, "
                            + "topologyRecoveryEnabled: ${topologyRecoveryEnabled}, "
                            + "networkRecoveryInterval: ${networkRecoveryInterval}")
                    .stringify());

            this.assertConnection();
        } catch (Exception exception) {
            if (OpflowLogTracer.has(LOG, "error")) LOG.error(logTracer
                    .put("exceptionClass", exception.getClass().getName())
                    .put("exceptionMessage", exception.getMessage())
                    .text("Engine[${engineId}] newConnection() has failed, exception[${exceptionClass}]: ${exceptionMessage}")
                    .stringify());
            throw new OpflowConnectionException("connection refused, invalid connection parameters", exception);
        }
        
        try {
            if (params.get("exchangeName") instanceof String) {
                exchangeName = (String) params.get("exchangeName");
            }
            
            if (params.get("exchangeType") instanceof String) {
                exchangeType = (String) params.get("exchangeType");
            }
            if (exchangeType == null) exchangeType = "direct";
            
            if (params.get("exchangeDurable") instanceof Boolean) {
                exchangeDurable = (Boolean) params.get("exchangeDurable");
            }
            if (exchangeDurable == null) exchangeDurable = true;
            
            if (exchangeName != null) {
                getProducingChannel().exchangeDeclare(exchangeName, exchangeType, exchangeDurable);
            }
            
            if (params.get("routingKey") instanceof String) {
                routingKey = (String) params.get("routingKey");
            }
            
            if (params.get("otherKeys") instanceof String[]) {
                otherKeys = (String[])params.get("otherKeys");
            }
            
            if (params.get("applicationId") instanceof String) {
                applicationId = (String) params.get("applicationId");
            }
            
            if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                        .put("exchangeName", exchangeName)
                        .put("exchangeType", exchangeType)
                        .put("exchangeDurable", exchangeDurable)
                        .put("routingKey", routingKey)
                        .put("otherKeys", otherKeys)
                        .put("applicationId", applicationId)
                        .text("Engine[${engineId}] exchangeName: '${exchangeName}' and routingKeys: ${routingKey}")
                        .stringify());
        } catch (IOException exception) {
            if (OpflowLogTracer.has(LOG, "error")) LOG.error(logTracer
                    .put("exceptionClass", exception.getClass().getName())
                    .put("exceptionMessage", exception.getMessage())
                    .text("Engine[${engineId}] exchangeDeclare has failed, exception[${exceptionClass}]: ${exceptionMessage}")
                    .stringify());
            throw new OpflowBootstrapException("exchangeDeclare has failed", exception);
        } catch (TimeoutException exception) {
            if (OpflowLogTracer.has(LOG, "error")) LOG.error(logTracer
                    .put("exceptionClass", exception.getClass().getName())
                    .put("exceptionMessage", exception.getMessage())
                    .text("Engine[${engineId}] exchangeDeclare is timeout, exception[${exceptionClass}]: ${exceptionMessage}")
                    .stringify());
            throw new OpflowBootstrapException("it maybe too slow or unstable network", exception);
        }
        
        if (OpflowLogTracer.has(LOG, "info")) LOG.info(logTracer
                .text("Engine[${engineId}].new() end!")
                .stringify());
    }
    
    public void produce(final byte[] body, final Map headers) {
        produce(body, headers, null, null);
    }
    
    public void produce(final byte[] body, final Map headers, AMQP.BasicProperties.Builder propBuilder) {
        produce(body, headers, propBuilder, null);
    }
    
    public void produce(final byte[] body, final Map headers, Map override) {
        produce(body, headers, null, override);
    }
    
    public void produce(final byte[] body, final Map headers, AMQP.BasicProperties.Builder propBuilder, Map override) {
        propBuilder = (propBuilder == null) ? new AMQP.BasicProperties.Builder() : propBuilder;
        OpflowLogTracer logProduce = null;
        
        try {
            String customKey = this.routingKey;
            if (override != null && override.get("routingKey") != null) {
                customKey = (String) override.get("routingKey");
            }
            
            String appId = this.applicationId;
            if (override != null && override.get("applicationId") != null) {
                appId = (String) override.get("applicationId");
            }
            propBuilder.appId(appId);
            
            if (override != null && override.get("correlationId") != null) {
                propBuilder.correlationId(override.get("correlationId").toString());
            }
            
            if (override != null && override.get("replyTo") != null) {
                propBuilder.replyTo(override.get("replyTo").toString());
            }
            
            String requestId = OpflowUtil.getRequestId(headers, false);
            if (requestId == null) {
                headers.put("requestId", requestId = OpflowUtil.getLogID());
            }
            propBuilder.headers(headers);
            
            if (OpflowLogTracer.has(LOG, "info")) logProduce = logTracer.branch("requestId", requestId);
            
            if (OpflowLogTracer.has(LOG, "info") && logProduce != null) LOG.info(logProduce
                    .put("appId", appId)
                    .put("customKey", customKey)
                    .text("Request[${requestId}] - Engine[${engineId}] - produce() is invoked")
                    .stringify());
            
            Channel _channel = getProducingChannel();
            if (_channel == null || !_channel.isOpen()) {
                throw new OpflowOperationException("Channel is null or has been closed");
            }
            _channel.basicPublish(this.exchangeName, customKey, propBuilder.build(), body);
        } catch (IOException exception) {
            if (OpflowLogTracer.has(LOG, "error") && logProduce != null) LOG.error(logProduce
                    .put("exceptionClass", exception.getClass().getName())
                    .put("exceptionMessage", exception.getMessage())
                    .text("Request[${requestId}] - produce() has failed")
                    .stringify());
            throw new OpflowOperationException(exception);
        } catch (TimeoutException exception) {
            if (OpflowLogTracer.has(LOG, "error") && logProduce != null) LOG.error(logProduce
                    .put("exceptionClass", exception.getClass().getName())
                    .put("exceptionMessage", exception.getMessage())
                    .text("Request[${requestId}] - produce() is timeout")
                    .stringify());
            throw new OpflowOperationException(exception);
        }
    }
    
    public ConsumerInfo consume(final OpflowListener listener, final Map options) {
        final Map opts = OpflowUtil.ensureNotNull(options);
        final String _consumerId = OpflowUtil.getOptionField(opts, "consumerId", true);
        final OpflowLogTracer logConsume = logTracer.branch("consumerId", _consumerId);
        
        if (OpflowLogTracer.has(LOG, "info")) LOG.info(logConsume
                .text("Consumer[${consumerId}].consume() is invoked in Engine[${engineId}]")
                .stringify());
        try {
            final boolean _forceNewConnection = Boolean.TRUE.equals(opts.get("forceNewConnection"));
            final Boolean _forceNewChannel = Boolean.TRUE.equals(opts.get("forceNewChannel"));
            final Channel _channel = getConsumingChannel(_forceNewConnection, _forceNewChannel);
            final Connection _connection = _channel.getConnection();
            
            Integer _prefetch = null;
            if (opts.get("prefetch") instanceof Integer) {
                _prefetch = (Integer) opts.get("prefetch");
            }
            if (_prefetch != null && _prefetch > 0) {
                _channel.basicQos(_prefetch);
            }
            
            final String _queueName;
            final boolean _fixedQueue;
            String opts_queueName = (String) opts.get("queueName");
            AMQP.Queue.DeclareOk _declareOk;
            if (opts_queueName != null) {
                _declareOk = _channel.queueDeclare(opts_queueName, true, false, false, null);
                _fixedQueue = true;
            } else {
                _declareOk = _channel.queueDeclare();
                _fixedQueue = false;
            }
            _queueName = _declareOk.getQueue();
            final Integer _consumerLimit = (Integer) opts.get("consumerLimit");
            if (OpflowLogTracer.has(LOG, "trace")) LOG.trace(logConsume
                    .put("consumerCount", _declareOk.getConsumerCount())
                    .put("consumerLimit", _consumerLimit)
                    .text("Consumer[${consumerId}].consume() - consumerCount(${consumerCount})/consumerLimit(${consumerLimit})")
                    .stringify());
            if (_consumerLimit != null && _consumerLimit > 0) {
                if (_declareOk.getConsumerCount() >= _consumerLimit) {
                    if (OpflowLogTracer.has(LOG, "error")) LOG.error(logConsume
                            .put("consumerCount", _declareOk.getConsumerCount())
                            .put("consumerLimit", _consumerLimit)
                            .text("Consumer[${consumerId}].consume() - consumerCount exceed limit")
                            .stringify());
                    String errorMessage = "consumerLimit exceed: " + _declareOk.getConsumerCount() + "/" + _consumerLimit;
                    throw new OpflowConsumerOverLimitException(errorMessage);
                }
            }
            
            final Boolean _binding = (Boolean) opts.get("binding");
            if (!Boolean.FALSE.equals(_binding) && exchangeName != null) {
                if (routingKey != null) {
                    bindExchange(_channel, exchangeName, _queueName, routingKey);
                }
                if (otherKeys != null) {
                    bindExchange(_channel, exchangeName, _queueName, otherKeys);
                }
            }
            
            final String _replyToName;
            String opts_replyToName = (String) opts.get("replyTo");
            if (opts_replyToName != null) {
                _replyToName = _channel.queueDeclarePassive(opts_replyToName).getQueue();
            } else {
                _replyToName = null;
            }
            
            final Boolean _autoAck;
            if (opts.get("autoAck") != null && opts.get("autoAck") instanceof Boolean) {
                _autoAck = (Boolean) opts.get("autoAck");
            } else {
                _autoAck = Boolean.TRUE;
            }
            
            final Boolean _requeueFailure;
            if (opts.get("requeueFailure") != null && opts.get("requeueFailure") instanceof Boolean) {
                _requeueFailure = (Boolean) opts.get("requeueFailure");
            } else {
                _requeueFailure = Boolean.FALSE;
            }
            
            final Consumer _consumer = new DefaultConsumer(_channel) {
                private void invokeAck(Envelope envelope, boolean success) throws IOException {
                    if (!_autoAck) {
                        if (success) {
                            _channel.basicAck(envelope.getDeliveryTag(), false);
                        } else {
                            if (!_requeueFailure) {
                                _channel.basicAck(envelope.getDeliveryTag(), false);
                            } else {
                                _channel.basicNack(envelope.getDeliveryTag(), false, true);
                            }
                        }
                    }
                }
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body) throws IOException {
                    final String requestID = OpflowUtil.getRequestId(properties.getHeaders(), false);
                    
                    final OpflowLogTracer logRequest = logConsume.branch("requestId", requestID);
                    
                    if (OpflowLogTracer.has(LOG, "info")) LOG.info(logRequest
                            .put("appId", properties.getAppId())
                            .put("deliveryTag", envelope.getDeliveryTag())
                            .put("consumerTag", consumerTag)
                            .text("Request[${requestId}] - Consumer[${consumerId}] - consumer received a message")
                            .stringify());
                    
                    if (OpflowLogTracer.has(LOG, "trace")) {
                        if (body.length <= 4096) {
                            if (OpflowLogTracer.has(LOG, "trace")) LOG.trace(logRequest
                                    .put("bodyHead", new String(body, "UTF-8"))
                                    .put("bodyLength", body.length)
                                    .text("Request[${requestId}] body head (4096 bytes)")
                                    .stringify());
                        } else {
                            if (OpflowLogTracer.has(LOG, "trace")) LOG.trace(logRequest
                                    .put("bodyLength", body.length)
                                    .text("Request[${requestId}] body size too large (>4KB)")
                                    .stringify());
                        }
                    }
                    
                    try {
                        if (applicationId == null || applicationId.equals(properties.getAppId())) {
                            if (OpflowLogTracer.has(LOG, "trace")) LOG.trace(logRequest
                                    .text("Request[${requestId}] invoke listener.processMessage()")
                                    .stringify());
                            
                            boolean captured = listener.processMessage(body, properties, _replyToName, _channel, consumerTag);
                            
                            if (captured) {
                                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logRequest
                                        .text("Request[${requestId}] has finished successfully")
                                        .stringify());
                            } else {
                                if (OpflowLogTracer.has(LOG, "info")) LOG.info(logRequest
                                        .text("Request[${requestId}] has not matched the criteria, skipped")
                                        .stringify());
                            }
                            
                            if (OpflowLogTracer.has(LOG, "trace")) LOG.trace(logRequest
                                    .put("deliveryTag", envelope.getDeliveryTag())
                                    .put("consumerTag", consumerTag)
                                    .text("Request[${requestId}] invoke ACK")
                                    .stringify());
                            
                            invokeAck(envelope, true);
                        } else {
                            if (OpflowLogTracer.has(LOG, "info")) LOG.info(logRequest
                                    .put("applicationId", applicationId)
                                    .text("Request[${requestId}] has been rejected, mismatched applicationId")
                                    .stringify());
                            invokeAck(envelope, false);
                        }
                    } catch (Exception ex) {
                        // catch ALL of Error here: don't let it harm our service/close the channel
                        if (OpflowLogTracer.has(LOG, "error")) LOG.error(logRequest
                                .put("deliveryTag", envelope.getDeliveryTag())
                                .put("consumerTag", consumerTag)
                                .put("exceptionClass", ex.getClass().getName())
                                .put("exceptionMessage", ex.getMessage())
                                .put("autoAck", _autoAck)
                                .put("requeueFailure", _requeueFailure)
                                .text("Request[${requestId}] has been failed. Service still alive")
                                .stringify());
                        invokeAck(envelope, false);
                    }
                }
                
                @Override
                public void handleCancelOk(String consumerTag) {
                    if (OpflowLogTracer.has(LOG, "info")) LOG.info(logConsume
                            .put("consumerTag", consumerTag)
                            .text("Consumer[${consumerId}].consume() - handle CancelOk event")
                            .stringify());
                }
                
                @Override
                public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) {
                    if (OpflowLogTracer.has(LOG, "info")) LOG.info(logConsume
                            .put("consumerTag", consumerTag)
                            .text("Consumer[${consumerId}].consume() - handle ShutdownSignal event")
                            .stringify());
                }
            };
            
            final String _consumerTag = _channel.basicConsume(_queueName, _autoAck, _consumer);
            
            if (OpflowLogTracer.has(LOG, "info")) LOG.info(logConsume
                    .put("queueName", _queueName)
                    .put("consumerTag", _consumerTag)
                    .put("channelNumber", _channel.getChannelNumber())
                    .text("Consumer[${consumerId}].consume() consume the queue")
                    .stringify());
            ConsumerInfo info = new ConsumerInfo(_connection, !_forceNewConnection, 
                    _channel, !_forceNewChannel, _queueName, _fixedQueue, _consumerId, _consumerTag);
            if ("engine".equals(mode)) consumerInfos.add(info);
            return info;
        } catch(IOException exception) {
            if (OpflowLogTracer.has(LOG, "error")) LOG.error(logConsume
                    .put("exceptionClass", exception.getClass().getName())
                    .put("exceptionMessage", exception.getMessage())
                    .text("Consumer[${consumerId}].consume() - has failed")
                    .stringify());
            throw new OpflowOperationException(exception);
        } catch(TimeoutException exception) {
            if (OpflowLogTracer.has(LOG, "error")) LOG.error(logConsume
                    .put("exceptionClass", exception.getClass().getName())
                    .put("exceptionMessage", exception.getMessage())
                    .text("Consumer[${consumerId}].consume() - is timeout")
                    .stringify());
            throw new OpflowOperationException(exception);
        }
    }
    
    public interface Operator {
        public Object handleEvent(Channel channel) throws IOException;
    }
    
    public  T acquireChannel(Operator listener) throws IOException, TimeoutException {
        T output = null;
        Connection _connection = null;
        Channel _channel = null;
        try {
            _connection = factory.newConnection();
            _channel = _connection.createChannel();
            if (listener != null) output = (T) listener.handleEvent(_channel);
        } finally {
            if (_channel != null && _channel.isOpen()) _channel.close();
            if (_connection != null && _connection.isOpen()) _connection.close();
        }
        return output;
    }
    
    public void cancelConsumer(OpflowEngine.ConsumerInfo consumerInfo) {
        if (consumerInfo == null) return;
        final OpflowLogTracer logCancel = logTracer.branch("consumerId", consumerInfo.getConsumerId());
        try {
            if (OpflowLogTracer.has(LOG, "debug")) LOG.debug(logCancel
                    .put("queueName", consumerInfo.getQueueName())
                    .text("Consumer[${consumerId}].cancelConsumer() - consumer will be cancelled")
                    .stringify());

            consumerInfo.getChannel().basicCancel(consumerInfo.getConsumerTag());

            if (OpflowLogTracer.has(LOG, "debug")) LOG.debug(logCancel
                    .text("Consumer[${consumerId}].cancelConsumer() - consumer has been cancelled")
                    .stringify());

            if (!consumerInfo.isSharedConnection() || !consumerInfo.isSharedChannel()) {
                if (consumerInfo.getChannel() != null && consumerInfo.getChannel().isOpen()) {
                    if (OpflowLogTracer.has(LOG, "debug")) LOG.debug(logCancel
                            .tags("sharedConsumingChannelClosed")
                            .text("Consumer[${consumerId}] shared consumingChannel is closing")
                            .stringify());
                    consumerInfo.getChannel().close();
                }
            }

            if (!consumerInfo.isSharedConnection()) {
                if (consumerInfo.getConnection() != null && consumerInfo.getConnection().isOpen()) {
                    if (OpflowLogTracer.has(LOG, "debug")) LOG.debug(logCancel
                            .tags("sharedConsumingConnectionClosed")
                            .text("Consumer[${consumerId}] shared consumingConnection is closing")
                            .stringify());
                    consumerInfo.getConnection().close();
                }
            }
        } catch (IOException ex) {
            if (OpflowLogTracer.has(LOG, "error")) LOG.error(logCancel
                    .put("exceptionClass", ex.getClass().getName())
                    .put("exceptionMessage", ex.getMessage())
                    .text("Consumer[${consumerId}].cancelConsumer() - has failed")
                    .stringify());
        } catch (TimeoutException ex) {
            if (OpflowLogTracer.has(LOG, "error")) LOG.error(logCancel
                    .put("exceptionClass", ex.getClass().getName())
                    .put("exceptionMessage", ex.getMessage())
                    .text("Consumer[${consumerId}].cancelConsumer() - is timeout")
                    .stringify());
        }
    }
    
    public class ConsumerInfo {
        private final Connection connection;
        private final boolean sharedConnection;
        private final Channel channel;
        private final boolean sharedChannel;
        private final String queueName;
        private final boolean fixedQueue;
        private final String consumerId;
        private final String consumerTag;
        
        public ConsumerInfo(Connection connection, boolean sharedConnection, Channel channel, boolean sharedChannel, 
                String queueName, boolean fixedQueue, String consumerId, String consumerTag) {
            this.connection = connection;
            this.sharedConnection = sharedConnection;
            this.channel = channel;
            this.sharedChannel = sharedChannel;
            this.queueName = queueName;
            this.fixedQueue = fixedQueue;
            this.consumerId = consumerId;
            this.consumerTag = consumerTag;
        }

        public Connection getConnection() {
            return connection;
        }

        public boolean isSharedConnection() {
            return sharedConnection;
        }

        public Channel getChannel() {
            return channel;
        }

        public boolean isSharedChannel() {
            return sharedChannel;
        }

        public String getQueueName() {
            return queueName;
        }

        public boolean isFixedQueue() {
            return fixedQueue;
        }
        
        public String getConsumerId() {
            return consumerId;
        }

        public String getConsumerTag() {
            return consumerTag;
        }
    }
    
    public static class State {
        public static final int CONNECTION_NEW = 0;
        public static final int CONNECTION_OPENED = 1;
        public static final int CONNECTION_CLOSED = 2;
        private final int[] CONNECTION_STATES =  new int[] {
            CONNECTION_NEW, CONNECTION_OPENED, CONNECTION_CLOSED
        };
        
        private int connectionState = -1;
        
        public int getConnectionState() {
            return connectionState;
        }
        
        public State(State state) {
            this.connectionState = state.connectionState;
        }
        
        private State(int connectionState) {
            for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy