/* * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.transport.jms.receiver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wso2.carbon.messaging.CarbonMessageProcessor; import org.wso2.carbon.messaging.ServerConnector; import org.wso2.carbon.messaging.exceptions.ServerConnectorException; import org.wso2.carbon.transport.jms.exception.JMSConnectorException; import org.wso2.carbon.transport.jms.factory.CachedJMSConnectionFactory; import org.wso2.carbon.transport.jms.factory.JMSConnectionFactory; import org.wso2.carbon.transport.jms.factory.PooledJMSConnectionFactory; import org.wso2.carbon.transport.jms.utils.JMSConstants; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; /** * This is the transport receiver for JMS. */ public class JMSServerConnector extends ServerConnector { private static final Logger logger = LoggerFactory.getLogger(JMSServerConnector.class); /** * The {@link CarbonMessageProcessor} instance represents the carbon message processor that handles the out going * messages. */ private CarbonMessageProcessor carbonMessageProcessor; /** * The {@link JMSConnectionFactory} instance represents the jms connection factory related with this server * connector. */ private JMSConnectionFactory jmsConnectionFactory = null; /** * The number of concurrent consumers that needs to be created. */ private int numOfConcurrentConsumers = 1; /** * List of {@link JMSMessageConsumer} instances that are created for this connector instance. */ private List<JMSMessageConsumer> messageConsumers; /** * The {@link String} instance represents the jms connection user-name. */ private String userName; /** * The {@link String} instance represents the jms connection password. */ private String password; /** * The {@link Properties} instance represents the jms connection properties. */ private Properties properties; /** * The retry interval (in milli seconds) if the connection is lost or if the connection cannot be established. */ private long retryInterval = 10000; /** * The maximum retry count, for retrying to establish a jms connection with the jms provider. */ private int maxRetryCount = 5; /** * Tells to use a message receiver instead of a message listener. */ private boolean useReceiver = false; /** * The nature of the connection factory to use. */ private String connectionFactoryNature = JMSConstants.DEFAULT_CONNECTION_FACTORY; /** * Creates a jms server connector with the id. * * @param id Unique identifier for the server connector. * @param properties require to initialize */ public JMSServerConnector(String id, Map<String, String> properties) { super(id, properties); } /** * Creates a jms server connector with the protocol name. * @param properties need to initialize. */ public JMSServerConnector(Map<String, String> properties) { super(JMSConstants.PROTOCOL_JMS, properties); } /** * Close the connection, session and consumers. * * @throws JMSConnectorException Exception that can be thrown when trying to close the connection, session * and message consumer */ void closeAll() throws JMSConnectorException { JMSConnectorException exception = null; for (JMSMessageConsumer messageConsumer : messageConsumers) { try { messageConsumer.closeAll(); } catch (JMSConnectorException e) { if (exception == null) { exception = new JMSConnectorException("Error closing the consumers for service " + id, e); } else { exception.addSuppressed(e); } } } messageConsumers = null; if (exception != null) { throw exception; } } /** * {@inheritDoc} */ @Override public void setMessageProcessor(CarbonMessageProcessor carbonMessageProcessor) { this.carbonMessageProcessor = carbonMessageProcessor; } /** * {@inheritDoc} */ @Override public void init() throws ServerConnectorException { /* not needed for jms, as this will be called in server start-up. We will not know about the destination at server start-up. We will get to know about that in service deployment. */ } /** * {@inheritDoc} */ @Override public void destroy() throws JMSConnectorException { closeAll(); } /** * {@inheritDoc} */ @Override public void stop() throws JMSConnectorException { closeAll(); } /** * {@inheritDoc} */ @Override protected void beginMaintenance() throws JMSConnectorException { for (JMSMessageConsumer messageConsumer : messageConsumers) { messageConsumer.stop(); } } /** * {@inheritDoc} */ @Override protected void endMaintenance() throws JMSConnectorException { for (JMSMessageConsumer messageConsumer : messageConsumers) { messageConsumer.start(); } } @Override public void start() throws ServerConnectorException { properties = new Properties(); Set<Map.Entry<String, String>> set = getProperties().entrySet(); for (Map.Entry<String, String> entry : set) { String mappedParameter = JMSConstants.MAPPING_PARAMETERS.get(entry.getKey()); if (mappedParameter != null) { properties.put(mappedParameter, entry.getValue()); } } userName = getProperties().get(JMSConstants.CONNECTION_USERNAME); password = getProperties().get(JMSConstants.CONNECTION_PASSWORD); String retryIntervalParam = super.properties.get(JMSConstants.RETRY_INTERVAL); if (retryIntervalParam != null) { try { this.retryInterval = Long.parseLong(retryIntervalParam); } catch (NumberFormatException ex) { logger.error("Provided value for retry interval is invalid, using the default retry interval value " + this.retryInterval); } } String maxRetryCountParam = super.properties.get(JMSConstants.MAX_RETRY_COUNT); if (maxRetryCountParam != null) { try { this.maxRetryCount = Integer.parseInt(maxRetryCountParam); } catch (NumberFormatException ex) { logger.error("Provided value for max retry count is invalid, using the default max retry count " + this.maxRetryCount); } } String useReceiverParam = super.properties.get(JMSConstants.USE_RECEIVER); if (useReceiverParam != null) { useReceiver = Boolean.parseBoolean(useReceiverParam); } String concurrentConsumers = super.properties.get(JMSConstants.CONCURRENT_CONSUMERS); if (concurrentConsumers != null) { try { numOfConcurrentConsumers = Integer.parseInt(concurrentConsumers); } catch (NumberFormatException e) { logger.error("Provided value for " + JMSConstants.CONCURRENT_CONSUMERS + " is invalid. Using the default value of " + numOfConcurrentConsumers); } } String connectionFactoryType = properties.getProperty(JMSConstants.CONNECTION_FACTORY_TYPE); if (connectionFactoryType != null) { if (JMSConstants.DESTINATION_TYPE_TOPIC.equalsIgnoreCase(connectionFactoryType)) { String subDurable = properties.getProperty(JMSConstants.PARAM_SUB_DURABLE); if (!Boolean.parseBoolean(subDurable) && numOfConcurrentConsumers > 1) { // If this is a non durable topic subscription then concurrent consumers should not be allowed // since each subscription will get a duplicate of the same message throw new JMSConnectorException("Concurrent consumers are not allowed for non-durable topic " + "connections"); } } } String connectionFacNatureParam = super.properties.get(JMSConstants.CONNECTION_FACTORY_NATURE); if (connectionFacNatureParam != null) { connectionFactoryNature = connectionFacNatureParam; } startConsuming(); } /** * Start message consuming threads. * * @throws JMSConnectorException when consumer creation is failed due to a JMS layer error */ void startConsuming() throws JMSConnectorException { try { if (jmsConnectionFactory == null) { switch (connectionFactoryNature) { case JMSConstants.CACHED_CONNECTION_FACTORY : jmsConnectionFactory = new CachedJMSConnectionFactory(properties); break; case JMSConstants.POOLED_CONNECTION_FACTORY : jmsConnectionFactory = new PooledJMSConnectionFactory(properties); break; default : jmsConnectionFactory = new JMSConnectionFactory(properties); } } messageConsumers = new ArrayList<>(); for (int i = 0; i < numOfConcurrentConsumers; i++) { JMSMessageConsumerBuilder consumerBuilder = new JMSMessageConsumerBuilder(jmsConnectionFactory, carbonMessageProcessor, id); consumerBuilder.setUseReceiver(useReceiver) .setUsername(userName) .setPassword(password) .setRetryInterval(retryInterval) .setMaxRetryCount(maxRetryCount); messageConsumers.add(consumerBuilder.build()); } } catch (JMSConnectorException e) { if (null == jmsConnectionFactory) { throw new JMSConnectorException("Cannot create the jms connection factory. please check the connection" + " properties and re-deploy the jms service.", e); } throw e; } } }