/* * Copyright (c) 2015, 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.event.output.adapter.jms; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.event.output.adapter.core.EventAdapterUtil; import org.wso2.carbon.event.output.adapter.core.OutputEventAdapter; import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterConfiguration; import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterException; import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterRuntimeException; import org.wso2.carbon.event.output.adapter.core.exception.TestConnectionNotSupportedException; import org.wso2.carbon.event.output.adapter.jms.internal.util.JMSConnectionFactory; import org.wso2.carbon.event.output.adapter.jms.internal.util.JMSConstants; import org.wso2.carbon.event.output.adapter.jms.internal.util.JMSEventAdapterConstants; import org.wso2.carbon.event.output.adapter.jms.internal.util.JMSMessageSender; import javax.jms.Connection; import javax.jms.Session; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.concurrent.*; public class JMSEventAdapter implements OutputEventAdapter { private static final Log log = LogFactory.getLog(JMSEventAdapter.class); private OutputEventAdapterConfiguration eventAdapterConfiguration; private Map<String, String> globalProperties; private PublisherDetails publisherDetails = null; private static ExecutorService executorService; private int tenantId; public JMSEventAdapter(OutputEventAdapterConfiguration eventAdapterConfiguration, Map<String, String> globalProperties) { this.eventAdapterConfiguration = eventAdapterConfiguration; this.globalProperties = globalProperties; } @Override public void init() throws OutputEventAdapterException { tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); //ExecutorService will be assigned if it is null if (executorService == null) { int minThread; int maxThread; long defaultKeepAliveTime; int jobQueSize; //If global properties are available those will be assigned else constant values will be assigned if (JMSEventAdapterConstants.ADAPTER_JMS_ALLOW_CONCURRENT_CONNECTIONS_NOT_ALLOWED.equals( eventAdapterConfiguration.getStaticProperties().get(JMSEventAdapterConstants.ADAPTER_JMS_ALLOW_CONCURRENT_CONNECTIONS)) ) { minThread = 1; } else if (globalProperties.get(JMSEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME) != null) { minThread = Integer.parseInt(globalProperties.get( JMSEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME)); } else { minThread = JMSEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE; } if (JMSEventAdapterConstants.ADAPTER_JMS_ALLOW_CONCURRENT_CONNECTIONS_NOT_ALLOWED.equals( eventAdapterConfiguration.getStaticProperties().get(JMSEventAdapterConstants.ADAPTER_JMS_ALLOW_CONCURRENT_CONNECTIONS))) { maxThread = 1; } else if (globalProperties.get(JMSEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME) != null) { maxThread = Integer.parseInt(globalProperties.get( JMSEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME)); } else { maxThread = JMSEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE; } if (globalProperties.get(JMSEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME) != null) { defaultKeepAliveTime = Integer.parseInt(globalProperties.get( JMSEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME)); } else { defaultKeepAliveTime = JMSEventAdapterConstants.DEFAULT_KEEP_ALIVE_TIME_IN_MILLIS; } if (globalProperties.get(JMSEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME) != null) { jobQueSize = Integer.parseInt(globalProperties.get( JMSEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME)); } else { jobQueSize = JMSEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE; } executorService = new ThreadPoolExecutor(minThread, maxThread, defaultKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(jobQueSize)); } } @Override public void testConnect() throws TestConnectionNotSupportedException { try { Hashtable<String, String> adaptorProperties = new Hashtable<String, String>(); adaptorProperties.putAll(eventAdapterConfiguration.getStaticProperties()); JMSConnectionFactory jmsConnectionFactory = new JMSConnectionFactory(adaptorProperties, eventAdapterConfiguration.getName(), adaptorProperties.get(JMSEventAdapterConstants.ADAPTER_JMS_DESTINATION), 1); Connection connection = jmsConnectionFactory.createConnection(); connection.createSession(false, Session.AUTO_ACKNOWLEDGE); connection.close(); jmsConnectionFactory.close(); } catch (Exception e) { throw new OutputEventAdapterRuntimeException(e); } } @Override public void connect() { String topicName = eventAdapterConfiguration.getStaticProperties().get( JMSEventAdapterConstants.ADAPTER_JMS_DESTINATION); Map<String, String> messageConfig = new HashMap<String, String>(); messageConfig.put(JMSConstants.PARAM_DESTINATION, topicName); publisherDetails = initPublisher(eventAdapterConfiguration, messageConfig); } @Override public void publish(Object message, Map<String, String> dynamicProperties) { try { executorService.submit(new JMSSender(message, dynamicProperties)); } catch (RejectedExecutionException e) { EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, "Job queue is full", e, log, tenantId); } } @Override public void disconnect() { if (publisherDetails != null) { publisherDetails.getJmsMessageSender().close(); publisherDetails.getJmsConnectionFactory().close(); } } @Override public void destroy() { //not required } @Override public boolean isPolled() { return false; } private PublisherDetails initPublisher( OutputEventAdapterConfiguration outputEventAdaptorConfiguration, Map<String, String> messageConfig) { PublisherDetails publisherDetails; Hashtable<String, String> adapterProperties = convertMapToHashTable(outputEventAdaptorConfiguration.getStaticProperties()); Map<String, String> jmsProperties = this.extractProperties(eventAdapterConfiguration.getStaticProperties().get( JMSEventAdapterConstants.ADAPTER_PROPERTIES)); Map<String, String> jmsSecuredProperties = this.extractProperties(eventAdapterConfiguration.getStaticProperties().get( JMSEventAdapterConstants.ADAPTER_SECURED_PROPERTIES)); if (jmsProperties != null) { adapterProperties.remove(JMSEventAdapterConstants.ADAPTER_PROPERTIES); adapterProperties.putAll(jmsProperties); } if(jmsSecuredProperties != null){ adapterProperties.remove(JMSEventAdapterConstants.ADAPTER_SECURED_PROPERTIES); adapterProperties.putAll(jmsSecuredProperties); } int maxConnections; if (JMSEventAdapterConstants.ADAPTER_JMS_ALLOW_CONCURRENT_CONNECTIONS_NOT_ALLOWED.equals( eventAdapterConfiguration.getStaticProperties().get(JMSEventAdapterConstants.ADAPTER_JMS_ALLOW_CONCURRENT_CONNECTIONS))) { maxConnections = 1; } else if (globalProperties.get(JMSEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME) != null) { maxConnections = Integer.parseInt(globalProperties.get( JMSEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME)); } else { maxConnections = JMSEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE; } JMSConnectionFactory jmsConnectionFactory = new JMSConnectionFactory(adapterProperties, outputEventAdaptorConfiguration.getName(), messageConfig.get(JMSEventAdapterConstants.ADAPTER_JMS_DESTINATION), maxConnections); JMSMessageSender jmsMessageSender = new JMSMessageSender(jmsConnectionFactory); publisherDetails = new PublisherDetails(jmsConnectionFactory, jmsMessageSender, messageConfig); return publisherDetails; } public static class PublisherDetails { private final JMSConnectionFactory jmsConnectionFactory; private final JMSMessageSender jmsMessageSender; private final Map<String, String> messageConfig; public PublisherDetails(JMSConnectionFactory jmsConnectionFactory, JMSMessageSender jmsMessageSender, Map<String, String> messageConfig) { this.jmsConnectionFactory = jmsConnectionFactory; this.jmsMessageSender = jmsMessageSender; this.messageConfig = messageConfig; } public JMSConnectionFactory getJmsConnectionFactory() { return jmsConnectionFactory; } public JMSMessageSender getJmsMessageSender() { return jmsMessageSender; } public Map<String, String> getMessageConfig() { return messageConfig; } } private Hashtable<String, String> convertMapToHashTable(Map<String, String> map) { Hashtable<String, String> table = new Hashtable<String, String>(); Iterator it = map.entrySet().iterator(); //Iterate through the hash map while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); //null values will be removed if (pair.getValue() != null) { table.put(pair.getKey().toString(), pair.getValue().toString()); } } return table; } private Map<String, String> extractProperties(String properties) { if (properties == null || properties.trim().length() == 0) { return null; } String[] entries = properties.split(JMSEventAdapterConstants.PROPERTY_SEPARATOR); String[] keyValue; Map<String, String> result = new HashMap<String, String>(); for (String property : entries) { try { keyValue = property.split(JMSEventAdapterConstants.ENTRY_SEPARATOR, 2); result.put(keyValue[0].trim(), keyValue[1].trim()); } catch (Exception e) { log.warn("JMS property '" + property + "' is not defined in the correct format.", e); } } return result; } public class JMSSender implements Runnable { private Object jmsMessage; private Map<String, String> dynamicProperties; public JMSSender(Object jmsMessage, Map<String, String> dynamicProperties) { this.jmsMessage = jmsMessage; this.dynamicProperties = dynamicProperties; } @Override public void run() { publisherDetails.getJmsMessageSender().send(jmsMessage, publisherDetails, dynamicProperties.get(JMSEventAdapterConstants.ADAPTER_JMS_HEADER)); } } }