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.lang.reflect.Constructor;
020import javax.jms.ConnectionFactory;
021
022import org.apache.activemq.Service;
023import org.apache.activemq.spring.ActiveMQConnectionFactory;
024import org.apache.camel.component.jms.JmsConfiguration;
025import org.springframework.jms.connection.JmsTransactionManager;
026import org.springframework.jms.connection.SingleConnectionFactory;
027import org.springframework.jms.core.JmsTemplate;
028import org.springframework.transaction.PlatformTransactionManager;
029
030/**
031 *
032 */
033public class ActiveMQConfiguration extends JmsConfiguration {
034    private ActiveMQComponent activeMQComponent;
035    private String brokerURL = ActiveMQConnectionFactory.DEFAULT_BROKER_URL;
036    private boolean useSingleConnection = false;
037    private boolean usePooledConnection = true;
038    private boolean trustAllPackages;
039
040    public ActiveMQConfiguration() {
041    }
042
043    public String getBrokerURL() {
044        return brokerURL;
045    }
046
047    /**
048     * Sets the broker URL to use to connect to ActiveMQ using the
049     * <a href="http://activemq.apache.org/configuring-transports.html">ActiveMQ URI format</a>
050     *
051     * @param brokerURL the URL of the broker.
052     */
053    public void setBrokerURL(String brokerURL) {
054        this.brokerURL = brokerURL;
055    }
056
057    public boolean isUseSingleConnection() {
058        return useSingleConnection;
059    }
060
061    /**
062     * @deprecated - use JmsConfiguration#getUsername()
063     * @see JmsConfiguration#getUsername()
064     */
065    @Deprecated
066    public String getUserName() {
067        return getUsername();
068    }
069
070    /**
071     * @deprecated - use JmsConfiguration#setUsername(String)
072     * @see JmsConfiguration#setUsername(String)
073     */
074    @Deprecated
075    public void setUserName(String userName) {
076        setUsername(userName);
077    }
078
079    /**
080     * Enables or disables whether a Spring {@link SingleConnectionFactory} will be used so that when
081     * messages are sent to ActiveMQ from outside of a message consuming thread, pooling will be used rather
082     * than the default with the Spring {@link JmsTemplate} which will create a new connection, session, producer
083     * for each message then close them all down again.
084     * <p/>
085     * The default value is false and a pooled connection is used by default.
086     */
087    public void setUseSingleConnection(boolean useSingleConnection) {
088        this.useSingleConnection = useSingleConnection;
089    }
090
091    public boolean isUsePooledConnection() {
092        return usePooledConnection;
093    }
094
095    /**
096     * Enables or disables whether a PooledConnectionFactory will be used so that when
097     * messages are sent to ActiveMQ from outside of a message consuming thread, pooling will be used rather
098     * than the default with the Spring {@link JmsTemplate} which will create a new connection, session, producer
099     * for each message then close them all down again.
100     * <p/>
101     * The default value is true. Note that this requires an extra dependency on commons-pool2.
102     */
103    public void setUsePooledConnection(boolean usePooledConnection) {
104        this.usePooledConnection = usePooledConnection;
105    }
106
107    public boolean isTrustAllPackages() {
108        return trustAllPackages;
109    }
110
111    /**
112     * ObjectMessage objects depend on Java serialization of marshal/unmarshal object payload.
113     * This process is generally considered unsafe as malicious payload can exploit the host system.
114     * That's why starting with versions 5.12.2 and 5.13.0, ActiveMQ enforces users to explicitly whitelist packages
115     * that can be exchanged using ObjectMessages.
116     * <br/>
117     * This option can be set to <tt>true</tt> to trust all packages (eg whitelist is *).
118     * <p/>
119     * See more details at: http://activemq.apache.org/objectmessage.html
120     */
121    public void setTrustAllPackages(boolean trustAllPackages) {
122        this.trustAllPackages = trustAllPackages;
123    }
124
125    /**
126     * Factory method to create a default transaction manager if one is not specified
127     */
128    @Override
129    protected PlatformTransactionManager createTransactionManager() {
130        JmsTransactionManager answer = new JmsTransactionManager(getConnectionFactory());
131        answer.afterPropertiesSet();
132        return answer;
133    }
134
135    protected void setActiveMQComponent(ActiveMQComponent activeMQComponent) {
136        this.activeMQComponent = activeMQComponent;
137    }
138
139    @Override
140    protected ConnectionFactory createConnectionFactory() {
141        ActiveMQConnectionFactory answer = new ActiveMQConnectionFactory();
142        answer.setTrustAllPackages(trustAllPackages);
143        if (getUsername() != null) {
144            answer.setUserName(getUsername());
145        }
146        if (getPassword() != null) {
147            answer.setPassword(getPassword());
148        }
149        if (answer.getBeanName() == null) {
150            answer.setBeanName("Camel");
151        }
152        answer.setBrokerURL(getBrokerURL());
153        if (isUseSingleConnection()) {
154            SingleConnectionFactory scf = new SingleConnectionFactory(answer);
155            if (activeMQComponent != null) {
156                activeMQComponent.addSingleConnectionFactory(scf);
157            }
158            return scf;
159        }
160        else if (isUsePooledConnection()) {
161            ConnectionFactory pcf = createPooledConnectionFactory(answer);
162            if (activeMQComponent != null) {
163                activeMQComponent.addPooledConnectionFactoryService((Service) pcf);
164            }
165            return pcf;
166        }
167        else {
168            return answer;
169        }
170    }
171
172    protected ConnectionFactory createPooledConnectionFactory(ActiveMQConnectionFactory connectionFactory) {
173        // lets not use classes directly to avoid a runtime dependency on commons-pool2
174        // for folks not using this option
175        try {
176            Class type = loadClass("org.apache.activemq.pool.PooledConnectionFactory", getClass().getClassLoader());
177            Constructor constructor = type.getConstructor(org.apache.activemq.ActiveMQConnectionFactory.class);
178            return (ConnectionFactory) constructor.newInstance(connectionFactory);
179        }
180        catch (Exception e) {
181            throw new RuntimeException("Failed to instantiate PooledConnectionFactory: " + e, e);
182        }
183    }
184
185    public static Class<?> loadClass(String name, ClassLoader loader) throws ClassNotFoundException {
186        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
187        if (contextClassLoader != null) {
188            try {
189                return contextClassLoader.loadClass(name);
190            }
191            catch (ClassNotFoundException e) {
192                try {
193                    return loader.loadClass(name);
194                }
195                catch (ClassNotFoundException e1) {
196                    throw e1;
197                }
198            }
199        } else {
200            return loader.loadClass(name);
201        }
202    }
203}