001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.camel.component; 018 019import java.net.URISyntaxException; 020import java.util.Map; 021import java.util.concurrent.CopyOnWriteArrayList; 022 023import javax.jms.Connection; 024 025import org.apache.activemq.EnhancedConnection; 026import org.apache.activemq.Service; 027import org.apache.activemq.advisory.DestinationSource; 028import org.apache.camel.CamelContext; 029import org.apache.camel.component.jms.JmsComponent; 030import org.apache.camel.component.jms.JmsConfiguration; 031import org.apache.camel.util.IntrospectionSupport; 032import org.apache.camel.util.ObjectHelper; 033import org.apache.camel.util.URISupport; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036import org.springframework.jms.connection.SingleConnectionFactory; 037import org.springframework.jms.core.JmsTemplate; 038 039/** 040 * The <a href="http://activemq.apache.org/camel/activemq.html">ActiveMQ Component</a> 041 */ 042public class ActiveMQComponent extends JmsComponent { 043 private final CopyOnWriteArrayList<SingleConnectionFactory> singleConnectionFactoryList = 044 new CopyOnWriteArrayList<SingleConnectionFactory>(); 045 private final CopyOnWriteArrayList<Service> pooledConnectionFactoryServiceList = 046 new CopyOnWriteArrayList<Service>(); 047 private static final transient Logger LOG = LoggerFactory.getLogger(ActiveMQComponent.class); 048 private boolean exposeAllQueues; 049 private CamelEndpointLoader endpointLoader; 050 051 private EnhancedConnection connection; 052 DestinationSource source; 053 054 /** 055 * Creates an <a href="http://camel.apache.org/activemq.html">ActiveMQ Component</a> 056 * 057 * @return the created component 058 */ 059 public static ActiveMQComponent activeMQComponent() { 060 return new ActiveMQComponent(); 061 } 062 063 /** 064 * Creates an <a href="http://camel.apache.org/activemq.html">ActiveMQ Component</a> 065 * connecting to the given <a href="http://activemq.apache.org/configuring-transports.html">broker URL</a> 066 * 067 * @param brokerURL the URL to connect to 068 * @return the created component 069 */ 070 public static ActiveMQComponent activeMQComponent(String brokerURL) { 071 ActiveMQComponent answer = new ActiveMQComponent(); 072 if (answer.getConfiguration() instanceof ActiveMQConfiguration) { 073 ((ActiveMQConfiguration) answer.getConfiguration()) 074 .setBrokerURL(brokerURL); 075 } 076 077 return answer; 078 } 079 080 public ActiveMQComponent() { 081 } 082 083 public ActiveMQComponent(CamelContext context) { 084 super(context); 085 } 086 087 public ActiveMQComponent(ActiveMQConfiguration configuration) { 088 super(); 089 setConfiguration(configuration); 090 } 091 092 /** 093 * Sets the broker URL to use to connect to ActiveMQ using the 094 * <a href="http://activemq.apache.org/configuring-transports.html">ActiveMQ URI format</a> 095 */ 096 public void setBrokerURL(String brokerURL) { 097 if (getConfiguration() instanceof ActiveMQConfiguration) { 098 ((ActiveMQConfiguration)getConfiguration()).setBrokerURL(brokerURL); 099 } 100 } 101 102 public void setTrustAllPackages(boolean trustAllPackages) { 103 if (getConfiguration() instanceof ActiveMQConfiguration) { 104 ((ActiveMQConfiguration)getConfiguration()).setTrustAllPackages(trustAllPackages); 105 } 106 } 107 108 public boolean isExposeAllQueues() { 109 return exposeAllQueues; 110 } 111 112 /** 113 * If enabled this will cause all Queues in the ActiveMQ broker to be eagerly populated into the CamelContext 114 * so that they can be easily browsed by any Camel tooling. This option is disabled by default. 115 */ 116 public void setExposeAllQueues(boolean exposeAllQueues) { 117 this.exposeAllQueues = exposeAllQueues; 118 } 119 120 /** 121 * Enables or disables whether a PooledConnectionFactory will be used so that when 122 * messages are sent to ActiveMQ from outside of a message consuming thread, pooling will be used rather 123 * than the default with the Spring {@link JmsTemplate} which will create a new connection, session, producer 124 * for each message then close them all down again. 125 * <p/> 126 * The default value is true. Note that this requires an extra dependency on commons-pool2. 127 */ 128 public void setUsePooledConnection(boolean usePooledConnection) { 129 if (getConfiguration() instanceof ActiveMQConfiguration) { 130 ((ActiveMQConfiguration)getConfiguration()).setUsePooledConnection(usePooledConnection); 131 } 132 } 133 134 /** 135 * Enables or disables whether a Spring {@link SingleConnectionFactory} will be used so that when 136 * messages are sent to ActiveMQ from outside of a message consuming thread, pooling will be used rather 137 * than the default with the Spring {@link JmsTemplate} which will create a new connection, session, producer 138 * for each message then close them all down again. 139 * <p/> 140 * The default value is false and a pooled connection is used by default. 141 */ 142 public void setUseSingleConnection(boolean useSingleConnection) { 143 if (getConfiguration() instanceof ActiveMQConfiguration) { 144 ((ActiveMQConfiguration)getConfiguration()).setUseSingleConnection(useSingleConnection); 145 } 146 } 147 148 protected void addPooledConnectionFactoryService(Service pooledConnectionFactoryService) { 149 pooledConnectionFactoryServiceList.add(pooledConnectionFactoryService); 150 } 151 152 protected void addSingleConnectionFactory(SingleConnectionFactory singleConnectionFactory) { 153 singleConnectionFactoryList.add(singleConnectionFactory); 154 } 155 156 @Override 157 @SuppressWarnings("unchecked") 158 protected String convertPathToActualDestination(String path, Map<String, Object> parameters) { 159 // support ActiveMQ destination options using the destination. prefix 160 // http://activemq.apache.org/destination-options.html 161 Map options = IntrospectionSupport.extractProperties(parameters, "destination."); 162 163 String query; 164 try { 165 query = URISupport.createQueryString(options); 166 } catch (URISyntaxException e) { 167 throw ObjectHelper.wrapRuntimeCamelException(e); 168 } 169 170 // if we have destination options then append them to the destination name 171 if (ObjectHelper.isNotEmpty(query)) { 172 return path + "?" + query; 173 } else { 174 return path; 175 } 176 } 177 178 @Override 179 protected void doStart() throws Exception { 180 super.doStart(); 181 182 if (isExposeAllQueues()) { 183 createDestinationSource(); 184 endpointLoader = new CamelEndpointLoader(getCamelContext(), source); 185 endpointLoader.afterPropertiesSet(); 186 } 187 188 // use OriginalDestinationPropagateStrategy by default if no custom stategy has been set 189 if (getMessageCreatedStrategy() == null) { 190 setMessageCreatedStrategy(new OriginalDestinationPropagateStrategy()); 191 } 192 } 193 194 protected void createDestinationSource() { 195 try { 196 if (source == null) { 197 if (connection == null) { 198 Connection value = getConfiguration().getConnectionFactory().createConnection(); 199 if (value instanceof EnhancedConnection) { 200 connection = (EnhancedConnection) value; 201 } else { 202 throw new IllegalArgumentException("Created JMS Connection is not an EnhancedConnection: " + value); 203 } 204 connection.start(); 205 } 206 source = connection.getDestinationSource(); 207 } 208 } catch (Throwable t) { 209 LOG.info("Can't get destination source, endpoint completer will not work", t); 210 } 211 } 212 213 @Override 214 protected void doStop() throws Exception { 215 if (source != null) { 216 source.stop(); 217 source = null; 218 } 219 if (connection != null) { 220 connection.close(); 221 connection = null; 222 } 223 for (Service s : pooledConnectionFactoryServiceList) { 224 s.stop(); 225 } 226 pooledConnectionFactoryServiceList.clear(); 227 for (SingleConnectionFactory s : singleConnectionFactoryList) { 228 s.destroy(); 229 } 230 singleConnectionFactoryList.clear(); 231 super.doStop(); 232 } 233 234 @Override 235 public void setConfiguration(JmsConfiguration configuration) { 236 if (configuration instanceof ActiveMQConfiguration) { 237 ((ActiveMQConfiguration) configuration).setActiveMQComponent(this); 238 } 239 super.setConfiguration(configuration); 240 } 241 242 @Override 243 protected JmsConfiguration createConfiguration() { 244 ActiveMQConfiguration answer = new ActiveMQConfiguration(); 245 answer.setActiveMQComponent(this); 246 return answer; 247 } 248 249}