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.jndi;
018
019import java.net.URISyntaxException;
020import java.util.ArrayList;
021import java.util.Hashtable;
022import java.util.Iterator;
023import java.util.List;
024import java.util.Map;
025import java.util.Properties;
026import java.util.StringTokenizer;
027import java.util.concurrent.ConcurrentHashMap;
028
029import javax.jms.Queue;
030import javax.jms.Topic;
031import javax.naming.Context;
032import javax.naming.NamingException;
033import javax.naming.spi.InitialContextFactory;
034
035import org.apache.activemq.ActiveMQConnectionFactory;
036import org.apache.activemq.ActiveMQXAConnectionFactory;
037import org.apache.activemq.command.ActiveMQQueue;
038import org.apache.activemq.command.ActiveMQTopic;
039
040/**
041 * A factory of the ActiveMQ InitialContext which contains
042 * {@link javax.jms.ConnectionFactory} instances as well as a child context called
043 * <i>destinations</i> which contain all of the current active destinations, in
044 * child context depending on the QoS such as transient or durable and queue or
045 * topic.
046 */
047public class ActiveMQInitialContextFactory implements InitialContextFactory {
048
049    private static final String[] DEFAULT_CONNECTION_FACTORY_NAMES = {"ConnectionFactory", "XAConnectionFactory", "QueueConnectionFactory", "TopicConnectionFactory"};
050
051    private String connectionPrefix = "connection.";
052    private String queuePrefix = "queue.";
053    private String topicPrefix = "topic.";
054
055    @Override
056    public Context getInitialContext(Hashtable environment) throws NamingException {
057        // lets create a factory
058        Map<String, Object> data = new ConcurrentHashMap<String, Object>();
059        String[] names = getConnectionFactoryNames(environment);
060        for (int i = 0; i < names.length; i++) {
061            ActiveMQConnectionFactory factory = null;
062            String name = names[i];
063
064            try {
065                factory = createConnectionFactory(name, environment);
066            } catch (Exception e) {
067                throw new NamingException("Invalid broker URL");
068
069            }
070            /*
071             * if( broker==null ) { try { broker = factory.getEmbeddedBroker(); }
072             * catch (JMSException e) { log.warn("Failed to get embedded
073             * broker", e); } }
074             */
075            data.put(name, factory);
076        }
077
078        createQueues(data, environment);
079        createTopics(data, environment);
080        /*
081         * if (broker != null) { data.put("destinations",
082         * broker.getDestinationContext(environment)); }
083         */
084        data.put("dynamicQueues", new LazyCreateContext() {
085            private static final long serialVersionUID = 6503881346214855588L;
086
087            @Override
088            protected Object createEntry(String name) {
089                return new ActiveMQQueue(name);
090            }
091        });
092        data.put("dynamicTopics", new LazyCreateContext() {
093            private static final long serialVersionUID = 2019166796234979615L;
094
095            @Override
096            protected Object createEntry(String name) {
097                return new ActiveMQTopic(name);
098            }
099        });
100
101        return createContext(environment, data);
102    }
103
104    // Properties
105    // -------------------------------------------------------------------------
106    public String getTopicPrefix() {
107        return topicPrefix;
108    }
109
110    public void setTopicPrefix(String topicPrefix) {
111        this.topicPrefix = topicPrefix;
112    }
113
114    public String getQueuePrefix() {
115        return queuePrefix;
116    }
117
118    public void setQueuePrefix(String queuePrefix) {
119        this.queuePrefix = queuePrefix;
120    }
121
122    // Implementation methods
123    // -------------------------------------------------------------------------
124
125    protected ReadOnlyContext createContext(Hashtable environment, Map<String, Object> data) {
126        return new ReadOnlyContext(environment, data);
127    }
128
129    protected ActiveMQConnectionFactory createConnectionFactory(String name, Hashtable environment) throws URISyntaxException {
130        Hashtable temp = new Hashtable(environment);
131        if (DEFAULT_CONNECTION_FACTORY_NAMES[1].equals(name)) {
132            // don't try to mod environment, it may be readonly
133            temp.put("xa", String.valueOf(true));
134        }
135        String prefix = connectionPrefix + name + ".";
136        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) {
137            Map.Entry entry = (Map.Entry)iter.next();
138            String key = (String)entry.getKey();
139            if (key.startsWith(prefix)) {
140                // Rename the key...
141                temp.remove(key);
142                key = key.substring(prefix.length());
143                temp.put(key, entry.getValue());
144            }
145        }
146        return createConnectionFactory(temp);
147    }
148
149    protected String[] getConnectionFactoryNames(Map environment) {
150        String factoryNames = (String)environment.get("connectionFactoryNames");
151        if (factoryNames != null) {
152            List<String> list = new ArrayList<String>();
153            for (StringTokenizer enumeration = new StringTokenizer(factoryNames, ","); enumeration.hasMoreTokens();) {
154                list.add(enumeration.nextToken().trim());
155            }
156            int size = list.size();
157            if (size > 0) {
158                String[] answer = new String[size];
159                list.toArray(answer);
160                return answer;
161            }
162        }
163        return DEFAULT_CONNECTION_FACTORY_NAMES;
164    }
165
166    protected void createQueues(Map<String, Object> data, Hashtable environment) {
167        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) {
168            Map.Entry entry = (Map.Entry)iter.next();
169            String key = entry.getKey().toString();
170            if (key.startsWith(queuePrefix)) {
171                String jndiName = key.substring(queuePrefix.length());
172                data.put(jndiName, createQueue(entry.getValue().toString()));
173            }
174        }
175    }
176
177    protected void createTopics(Map<String, Object> data, Hashtable environment) {
178        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) {
179            Map.Entry entry = (Map.Entry)iter.next();
180            String key = entry.getKey().toString();
181            if (key.startsWith(topicPrefix)) {
182                String jndiName = key.substring(topicPrefix.length());
183                data.put(jndiName, createTopic(entry.getValue().toString()));
184            }
185        }
186    }
187
188    /**
189     * Factory method to create new Queue instances
190     */
191    protected Queue createQueue(String name) {
192        return new ActiveMQQueue(name);
193    }
194
195    /**
196     * Factory method to create new Topic instances
197     */
198    protected Topic createTopic(String name) {
199        return new ActiveMQTopic(name);
200    }
201
202    /**
203     * Factory method to create a new connection factory from the given
204     * environment
205     */
206    protected ActiveMQConnectionFactory createConnectionFactory(Hashtable environment) throws URISyntaxException {
207        ActiveMQConnectionFactory answer = needsXA(environment) ? new ActiveMQXAConnectionFactory() : new ActiveMQConnectionFactory();
208        Properties properties = new Properties();
209        properties.putAll(environment);
210        answer.setProperties(properties);
211        return answer;
212    }
213
214    private boolean needsXA(Hashtable environment) {
215        boolean isXA = Boolean.parseBoolean((String) environment.get("xa"));
216        // property not applicable to connectionfactory so remove
217        environment.remove("xa");
218        return isXA;
219    }
220
221    public String getConnectionPrefix() {
222        return connectionPrefix;
223    }
224
225    public void setConnectionPrefix(String connectionPrefix) {
226        this.connectionPrefix = connectionPrefix;
227    }
228}