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