blob: 691eb818822b66da1e9b6d08c99234cc7db14e56 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.qpid.jms.jndi;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.jms.Queue;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import org.apache.qpid.jms.JmsConnectionFactory;
import org.apache.qpid.jms.JmsQueue;
import org.apache.qpid.jms.JmsTopic;
/**
* A factory of the StompJms InitialContext which contains
* {@link javax.jms.ConnectionFactory} instances as well as a child context
* called <i>destinations</i> which contain all of the current active
* destinations, in child context depending on the QoS such as transient or
* durable and queue or topic.
*
* @since 1.0
*/
public class JmsInitialContextFactory implements InitialContextFactory {
static final String[] DEFAULT_CONNECTION_FACTORY_NAMES = {
"ConnectionFactory", "QueueConnectionFactory", "TopicConnectionFactory" };
static final String DEFAULT_REMOTE_URI = "amqp://localhost:5672";
static final String CONNECTION_FACTORY_KEY_PREFIX = "connectionfactory.";
static final String QUEUE_KEY_PREFIX = "queue.";
static final String TOPIC_KEY_PREFIX = "topic.";
static final String CONNECTION_FACTORY_DEFAULT_KEY_PREFIX = "default." + CONNECTION_FACTORY_KEY_PREFIX;
static final String CONNECTION_FACTORY_PROPERTY_KEY_PREFIX = "property." + CONNECTION_FACTORY_KEY_PREFIX;
@SuppressWarnings("unchecked")
@Override
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
// Copy the environment to ensure we don't modify/reference it, it belongs to the caller.
Hashtable<Object, Object> environmentCopy = new Hashtable<Object, Object>();
environmentCopy.putAll(environment);
Map<String, Object> bindings = new ConcurrentHashMap<String, Object>();
createConnectionFactories(environmentCopy, bindings);
createQueues(environmentCopy, bindings);
createTopics(environmentCopy, bindings);
// Add sub-contexts for dynamic creation on lookup.
// "dynamicQueues/<queue-name>"
bindings.put("dynamicQueues", new LazyCreateContext() {
private static final long serialVersionUID = 6503881346214855588L;
@Override
protected Object createEntry(String name) {
return new JmsQueue(name);
}
});
// "dynamicTopics/<topic-name>"
bindings.put("dynamicTopics", new LazyCreateContext() {
private static final long serialVersionUID = 2019166796234979615L;
@Override
protected Object createEntry(String name) {
return new JmsTopic(name);
}
});
return createContext(environmentCopy, bindings);
}
private void createConnectionFactories(Hashtable<Object, Object> environment, Map<String, Object> bindings) throws NamingException {
List<String> names = getConnectionFactoryNames(environment);
Map<String, String> defaults = getConnectionFactoryDefaults(environment);
for (String name : names) {
JmsConnectionFactory factory = null;
try {
factory = createConnectionFactory(name, defaults, environment);
} catch (Exception e) {
NamingException ne = new NamingException("Exception while creating ConnectionFactory '" + name + "'.");
ne.initCause(e);
throw ne;
}
bindings.put(name, factory);
}
}
// Implementation methods
// -------------------------------------------------------------------------
protected ReadOnlyContext createContext(Hashtable<Object, Object> environment, Map<String, Object> bindings) {
return new ReadOnlyContext(environment, bindings);
}
protected JmsConnectionFactory createConnectionFactory(String name, Map<String, String> defaults, Hashtable<Object, Object> environment) throws URISyntaxException {
String cfNameKey = CONNECTION_FACTORY_KEY_PREFIX + name;
Map<String, String> props = new LinkedHashMap<String, String>();
// Add the defaults which apply to all connection factories
props.putAll(defaults);
// Add any URI entry for this specific factory name
Object o = environment.get(cfNameKey);
if (o != null) {
String value = String.valueOf(o);
if (value.trim().length() != 0) {
props.put(JmsConnectionFactory.REMOTE_URI_PROP, value);
}
}
// Add any factory-specific additional properties
props.putAll(getConnectionFactoryProperties(name, environment));
return createConnectionFactory(props);
}
protected List<String> getConnectionFactoryNames(Map<Object, Object> environment) {
List<String> list = new ArrayList<String>();
for (Iterator<Entry<Object, Object>> iter = environment.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Object, Object> entry = iter.next();
String key = String.valueOf(entry.getKey());
if (key.startsWith(CONNECTION_FACTORY_KEY_PREFIX)) {
String jndiName = key.substring(CONNECTION_FACTORY_KEY_PREFIX.length());
list.add(jndiName);
}
}
if(list.isEmpty())
{
list.addAll(Arrays.asList(DEFAULT_CONNECTION_FACTORY_NAMES));
}
return list;
}
protected Map<String, String> getConnectionFactoryDefaults(Map<Object, Object> environment) {
Map<String, String> map = new LinkedHashMap<String, String>();
map.put(JmsConnectionFactory.REMOTE_URI_PROP, DEFAULT_REMOTE_URI);
for (Iterator<Entry<Object, Object>> iter = environment.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Object, Object> entry = iter.next();
String key = String.valueOf(entry.getKey());
if (key.startsWith(CONNECTION_FACTORY_DEFAULT_KEY_PREFIX)) {
String jndiName = key.substring(CONNECTION_FACTORY_DEFAULT_KEY_PREFIX.length());
map.put(jndiName, String.valueOf(entry.getValue()));
}
}
return Collections.unmodifiableMap(map);
}
protected Map<String, String> getConnectionFactoryProperties(String factoryName, Map<Object, Object> environment) {
Map<String, String> map = new LinkedHashMap<String, String>();
String factoryPropertiesPrefix = CONNECTION_FACTORY_PROPERTY_KEY_PREFIX + factoryName + ".";
for (Iterator<Entry<Object, Object>> iter = environment.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Object, Object> entry = iter.next();
String key = String.valueOf(entry.getKey());
if (key.startsWith(factoryPropertiesPrefix)) {
String propertyName = key.substring(factoryPropertiesPrefix.length());
map.put(propertyName, String.valueOf(entry.getValue()));
}
}
return map;
}
protected void createQueues(Hashtable<Object, Object> environment, Map<String, Object> bindings) {
for (Iterator<Entry<Object, Object>> iter = environment.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Object, Object> entry = iter.next();
String key = entry.getKey().toString();
if (key.startsWith(QUEUE_KEY_PREFIX)) {
String jndiName = key.substring(QUEUE_KEY_PREFIX.length());
bindings.put(jndiName, createQueue(entry.getValue().toString()));
}
}
}
protected void createTopics(Hashtable<Object, Object> environment, Map<String, Object> bindings) {
for (Iterator<Entry<Object, Object>> iter = environment.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Object, Object> entry = iter.next();
String key = entry.getKey().toString();
if (key.startsWith(TOPIC_KEY_PREFIX)) {
String jndiName = key.substring(TOPIC_KEY_PREFIX.length());
bindings.put(jndiName, createTopic(entry.getValue().toString()));
}
}
}
/**
* Factory method to create new Queue instances
*/
protected Queue createQueue(String name) {
return new JmsQueue(name);
}
/**
* Factory method to create new Topic instances
*/
protected Topic createTopic(String name) {
return new JmsTopic(name);
}
/**
* Factory method to create a new connection factory using the given properties
*/
protected JmsConnectionFactory createConnectionFactory(Map<String, String> properties) {
JmsConnectionFactory factory = new JmsConnectionFactory();
Map<String, String> unused = factory.setProperties(properties);
if (!unused.isEmpty()) {
String msg =
" Not all properties could be set on the ConnectionFactory."
+ " Check the properties are spelled correctly."
+ " Unused properties=[" + unused + "].";
throw new IllegalArgumentException(msg);
}
return factory;
}
}