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