ARTEMIS-1164: NameNotFoundException when using java.naming.provider.url to set url via jndi

Support setting PROVIDER_URL on initial context to create default connection factories.
This commit is contained in:
Michael Andre Pearce 2017-05-15 17:23:52 +01:00 committed by Justin Bertram
parent 044df11694
commit a4e19b432b
4 changed files with 224 additions and 41 deletions

View File

@ -59,6 +59,16 @@ public class URIFactory<T, P> {
return schemaFactory.newObject(uri, param); return schemaFactory.newObject(uri, param);
} }
public T newObject(URI uri, Map<String, String> overrides, P param) throws Exception {
URISchema<T, P> schemaFactory = schemas.get(uri.getScheme());
if (schemaFactory == null) {
throw new NullPointerException("Schema " + uri.getScheme() + " not found");
}
return schemaFactory.newObject(uri, overrides, param);
}
public T newObject(String uri, P param) throws Exception { public T newObject(String uri, P param) throws Exception {
return newObject(new URI(uri), param); return newObject(new URI(uri), param);
} }

View File

@ -26,6 +26,13 @@ import org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQXATopicConnectionFactory; import org.apache.activemq.artemis.jms.client.ActiveMQXATopicConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQXAQueueConnectionFactory; import org.apache.activemq.artemis.jms.client.ActiveMQXAQueueConnectionFactory;
import javax.jms.ConnectionFactory;
import javax.jms.QueueConnectionFactory;
import javax.jms.TopicConnectionFactory;
import javax.jms.XAConnectionFactory;
import javax.jms.XAQueueConnectionFactory;
import javax.jms.XATopicConnectionFactory;
// XXX no javadocs // XXX no javadocs
public enum JMSFactoryType { public enum JMSFactoryType {
CF { CF {
@ -48,6 +55,11 @@ public enum JMSFactoryType {
public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) { public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) {
return new ActiveMQJMSConnectionFactory(false, transportConfigurations); return new ActiveMQJMSConnectionFactory(false, transportConfigurations);
} }
@Override
public Class connectionFactoryInterface() {
return ConnectionFactory.class;
}
}, },
QUEUE_CF { QUEUE_CF {
@Override @Override
@ -69,6 +81,11 @@ public enum JMSFactoryType {
public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) { public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) {
return new ActiveMQQueueConnectionFactory(false, transportConfigurations); return new ActiveMQQueueConnectionFactory(false, transportConfigurations);
} }
@Override
public Class connectionFactoryInterface() {
return QueueConnectionFactory.class;
}
}, },
TOPIC_CF { TOPIC_CF {
@Override @Override
@ -90,6 +107,11 @@ public enum JMSFactoryType {
public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) { public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) {
return new ActiveMQTopicConnectionFactory(false, transportConfigurations); return new ActiveMQTopicConnectionFactory(false, transportConfigurations);
} }
@Override
public Class connectionFactoryInterface() {
return TopicConnectionFactory.class;
}
}, },
XA_CF { XA_CF {
@Override @Override
@ -111,6 +133,11 @@ public enum JMSFactoryType {
public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) { public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) {
return new ActiveMQXAConnectionFactory(false, transportConfigurations); return new ActiveMQXAConnectionFactory(false, transportConfigurations);
} }
@Override
public Class connectionFactoryInterface() {
return XAConnectionFactory.class;
}
}, },
QUEUE_XA_CF { QUEUE_XA_CF {
@Override @Override
@ -132,6 +159,11 @@ public enum JMSFactoryType {
public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) { public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) {
return new ActiveMQXAQueueConnectionFactory(false, transportConfigurations); return new ActiveMQXAQueueConnectionFactory(false, transportConfigurations);
} }
@Override
public Class connectionFactoryInterface() {
return XAQueueConnectionFactory.class;
}
}, },
TOPIC_XA_CF { TOPIC_XA_CF {
@Override @Override
@ -153,6 +185,11 @@ public enum JMSFactoryType {
public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) { public ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations) {
return new ActiveMQXATopicConnectionFactory(false, transportConfigurations); return new ActiveMQXATopicConnectionFactory(false, transportConfigurations);
} }
@Override
public Class connectionFactoryInterface() {
return XATopicConnectionFactory.class;
}
}; };
public int intValue() { public int intValue() {
@ -264,5 +301,11 @@ public enum JMSFactoryType {
*/ */
public abstract ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations); public abstract ActiveMQConnectionFactory createConnectionFactoryWithoutHA(final TransportConfiguration... transportConfigurations);
/**
* Returns the connection factory interface that this JMSFactoryType creates.
*
* @return the javax.jms Class ConnectionFactory interface
*/
public abstract Class connectionFactoryInterface();
} }

View File

@ -22,13 +22,16 @@ import javax.jms.Topic;
import javax.naming.Context; import javax.naming.Context;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory; import javax.naming.spi.InitialContextFactory;
import java.util.HashMap; import java.util.Collections;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient; import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
import org.apache.activemq.artemis.uri.ConnectionFactoryParser; import org.apache.activemq.artemis.uri.ConnectionFactoryParser;
import org.apache.activemq.artemis.uri.JMSConnectionOptions;
import org.apache.activemq.artemis.utils.uri.URISchema;
/** /**
* A factory of the ActiveMQ Artemis InitialContext which contains * A factory of the ActiveMQ Artemis InitialContext which contains
@ -39,8 +42,6 @@ import org.apache.activemq.artemis.uri.ConnectionFactoryParser;
*/ */
public class ActiveMQInitialContextFactory implements InitialContextFactory { public class ActiveMQInitialContextFactory implements InitialContextFactory {
private static final String[] DEFAULT_CONNECTION_FACTORY_NAMES = {"ConnectionFactory", "XAConnectionFactory", "QueueConnectionFactory", "TopicConnectionFactory"};
public static final String REFRESH_TIMEOUT = "refreshTimeout"; public static final String REFRESH_TIMEOUT = "refreshTimeout";
public static final String DISCOVERY_INITIAL_WAIT_TIMEOUT = "discoveryInitialWaitTimeout"; public static final String DISCOVERY_INITIAL_WAIT_TIMEOUT = "discoveryInitialWaitTimeout";
public static final String DYNAMIC_QUEUE_CONTEXT = "dynamicQueues"; public static final String DYNAMIC_QUEUE_CONTEXT = "dynamicQueues";
@ -54,13 +55,31 @@ public class ActiveMQInitialContextFactory implements InitialContextFactory {
// lets create a factory // lets create a factory
Map<String, Object> data = new ConcurrentHashMap<>(); Map<String, Object> data = new ConcurrentHashMap<>();
Map<String, ConnectionFactory> connectionFactories = new HashMap<>(); String providerUrl = (String) environment.get(javax.naming.Context.PROVIDER_URL);
if (providerUrl != null) {
try {
JMSFactoryType providedFactoryType = getFactoryType(providerUrl);
if (providedFactoryType == null) {
for (JMSFactoryType factoryType : JMSFactoryType.values()) {
String factoryName = factoryType.connectionFactoryInterface().getSimpleName();
data.put(factoryName, createConnectionFactory(providerUrl, Collections.singletonMap("type", factoryType.toString()), factoryName));
}
} else {
String factoryName = providedFactoryType.connectionFactoryInterface().getSimpleName();
data.put(factoryName, createConnectionFactory(providerUrl, factoryName));
}
} catch (Exception e) {
e.printStackTrace();
throw new NamingException("Invalid broker URL");
}
}
for (Map.Entry<?, ?> entry : environment.entrySet()) { for (Map.Entry<?, ?> entry : environment.entrySet()) {
String key = entry.getKey().toString(); String key = entry.getKey().toString();
if (key.startsWith(connectionFactoryPrefix)) { if (key.startsWith(connectionFactoryPrefix)) {
String jndiName = key.substring(connectionFactoryPrefix.length()); String jndiName = key.substring(connectionFactoryPrefix.length());
try { try {
connectionFactories.put(jndiName, createConnectionFactory((String) environment.get(key), jndiName)); data.put(jndiName, createConnectionFactory((String) environment.get(key), jndiName));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new NamingException("Invalid broker URL"); throw new NamingException("Invalid broker URL");
@ -68,21 +87,6 @@ public class ActiveMQInitialContextFactory implements InitialContextFactory {
} }
} }
if (connectionFactories.isEmpty()) {
String providerUrl = (String) environment.get(javax.naming.Context.PROVIDER_URL);
if (providerUrl != null) {
for (String factoryName : DEFAULT_CONNECTION_FACTORY_NAMES) {
try {
connectionFactories.put(factoryName, createConnectionFactory(providerUrl, factoryName));
} catch (Exception e) {
e.printStackTrace();
throw new NamingException("Invalid broker URL");
}
}
}
}
connectionFactories.forEach((name, factory) -> data.put(name, factory));
createQueues(data, environment); createQueues(data, environment);
createTopics(data, environment); createTopics(data, environment);
@ -172,4 +176,19 @@ public class ActiveMQInitialContextFactory implements InitialContextFactory {
ConnectionFactoryParser parser = new ConnectionFactoryParser(); ConnectionFactoryParser parser = new ConnectionFactoryParser();
return parser.newObject(parser.expandURI(uri), name); return parser.newObject(parser.expandURI(uri), name);
} }
/**
* Factory method to create a new connection factory from the given environment, with overrides
*/
protected ConnectionFactory createConnectionFactory(String uri, Map<String, String> overrides, String name) throws Exception {
ConnectionFactoryParser parser = new ConnectionFactoryParser();
return parser.newObject(parser.expandURI(uri), overrides, name);
}
public JMSFactoryType getFactoryType(String uri) throws Exception {
ConnectionFactoryParser parser = new ConnectionFactoryParser();
Map<String, String> queryParams = URISchema.parseQuery(parser.expandURI(uri).getQuery(), null);
String type = queryParams.get("type");
return type == null ? null : JMSConnectionOptions.convertCFType(type);
}
} }

View File

@ -35,7 +35,6 @@ import java.util.HashSet;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
@ -528,29 +527,141 @@ public class SimpleJNDIClientTest extends ActiveMQTestBase {
} }
public void testContext(Context ctx, String jndiName, JMSFactoryType expectedFactoryType) {
try {
ActiveMQConnectionFactory connectionFactory = (ActiveMQConnectionFactory) ctx.lookup(jndiName);
if (expectedFactoryType == null) {
Assert.fail("expected no factory, should have thrown NamingException");
} else {
Assert.assertEquals(expectedFactoryType.intValue(), connectionFactory.getFactoryType());
}
} catch (NamingException namingException) {
Assert.assertNull("NamingException should only occur when no ExpectedFactoryType, but one existed", expectedFactoryType);
}
}
@Test @Test
public void providerURLTest() throws NamingException { public void testProviderUrlDefault() throws NamingException, JMSException {
String url = "(tcp://somehost:62616,tcp://somehost:62616)?ha=true"; Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0");
Context ctx = new InitialContext(props);
Properties props = new Properties(); testContext(ctx, "ConnectionFactory", JMSFactoryType.CF);
props.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, ActiveMQInitialContextFactory.class.getName()); testContext(ctx, "QueueConnectionFactory", JMSFactoryType.QUEUE_CF);
props.setProperty(javax.naming.Context.PROVIDER_URL, url); testContext(ctx, "TopicConnectionFactory", JMSFactoryType.TOPIC_CF);
testContext(ctx, "XAConnectionFactory", JMSFactoryType.XA_CF);
InitialContext context = new InitialContext(props); testContext(ctx, "XAQueueConnectionFactory", JMSFactoryType.QUEUE_XA_CF);
ConnectionFactory connectionFactory = (ConnectionFactory)context.lookup("ConnectionFactory"); testContext(ctx, "XATopicConnectionFactory", JMSFactoryType.TOPIC_XA_CF);
} }
@Test @Test
public void connectionFactoryProperty() throws NamingException { public void testProviderUrlCF() throws NamingException, JMSException {
String url = "(tcp://somehost:62616,tcp://somehost:62616)?ha=true"; Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0?type=CF");
Context ctx = new InitialContext(props);
Properties props = new Properties(); testContext(ctx, "ConnectionFactory", JMSFactoryType.CF);
props.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, ActiveMQInitialContextFactory.class.getName()); testContext(ctx, "QueueConnectionFactory", null);
props.setProperty(javax.naming.Context.PROVIDER_URL, url); testContext(ctx, "TopicConnectionFactory", null);
testContext(ctx, "XAConnectionFactory", null);
testContext(ctx, "XAQueueConnectionFactory", null);
testContext(ctx, "XATopicConnectionFactory", null);
}
props.setProperty("connectionFactory.ConnectionFactory",url); @Test
public void testProviderUrlXACF() throws NamingException, JMSException {
Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0?type=XA_CF");
Context ctx = new InitialContext(props);
testContext(ctx, "ConnectionFactory", null);
testContext(ctx, "QueueConnectionFactory", null);
testContext(ctx, "TopicConnectionFactory", null);
testContext(ctx, "XAConnectionFactory", JMSFactoryType.XA_CF);
testContext(ctx, "XAQueueConnectionFactory", null);
testContext(ctx, "XATopicConnectionFactory", null);
}
@Test
public void testProviderUrlQueueCF() throws NamingException, JMSException {
Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0?type=QUEUE_CF");
Context ctx = new InitialContext(props);
testContext(ctx, "ConnectionFactory", null);
testContext(ctx, "QueueConnectionFactory", JMSFactoryType.QUEUE_CF);
testContext(ctx, "TopicConnectionFactory", null);
testContext(ctx, "XAConnectionFactory", null);
testContext(ctx, "XAQueueConnectionFactory", null);
testContext(ctx, "XATopicConnectionFactory", null);
}
@Test
public void testProviderUrlQueueXACF() throws NamingException, JMSException {
Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0?type=QUEUE_XA_CF");
Context ctx = new InitialContext(props);
testContext(ctx, "ConnectionFactory", null);
testContext(ctx, "QueueConnectionFactory", null);
testContext(ctx, "TopicConnectionFactory", null);
testContext(ctx, "XAConnectionFactory", null);
testContext(ctx, "XAQueueConnectionFactory", JMSFactoryType.QUEUE_XA_CF);
testContext(ctx, "XATopicConnectionFactory", null);
}
@Test
public void testProviderUrlTopicCF() throws NamingException, JMSException {
Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0?type=TOPIC_CF");
Context ctx = new InitialContext(props);
testContext(ctx, "ConnectionFactory", null);
testContext(ctx, "QueueConnectionFactory", null);
testContext(ctx, "TopicConnectionFactory", JMSFactoryType.TOPIC_CF);
testContext(ctx, "XAConnectionFactory", null);
testContext(ctx, "XAQueueConnectionFactory", null);
testContext(ctx, "XATopicConnectionFactory", null);
}
@Test
public void testProviderUrlTopicXACF() throws NamingException, JMSException {
Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0?type=TOPIC_XA_CF");
Context ctx = new InitialContext(props);
testContext(ctx, "ConnectionFactory", null);
testContext(ctx, "QueueConnectionFactory", null);
testContext(ctx, "TopicConnectionFactory", null);
testContext(ctx, "XAConnectionFactory", null);
testContext(ctx, "XAQueueConnectionFactory", null);
testContext(ctx, "XATopicConnectionFactory", JMSFactoryType.TOPIC_XA_CF);
}
@Test
public void testProviderUrlDefaultAndCustom() throws NamingException, JMSException {
Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, "vm://0");
props.put("connectionFactory.myConnectionFactory", "vm://0");
Context ctx = new InitialContext(props);
testContext(ctx, "ConnectionFactory", JMSFactoryType.CF);
testContext(ctx, "QueueConnectionFactory", JMSFactoryType.QUEUE_CF);
testContext(ctx, "TopicConnectionFactory", JMSFactoryType.TOPIC_CF);
testContext(ctx, "XAConnectionFactory", JMSFactoryType.XA_CF);
testContext(ctx, "XAQueueConnectionFactory", JMSFactoryType.QUEUE_XA_CF);
testContext(ctx, "XATopicConnectionFactory", JMSFactoryType.TOPIC_XA_CF);
testContext(ctx, "myConnectionFactory", JMSFactoryType.CF);
InitialContext context = new InitialContext(props);
ConnectionFactory connectionFactory = (ConnectionFactory)context.lookup("ConnectionFactory");
} }
} }