Skip to content

Commit

Permalink
Fixes rabbitmq#21 issue - Add ability for RMQObjectFactory to handle …
Browse files Browse the repository at this point in the history
…properties from environment HashTable parameter of getObjectInstance method, allowing for example to instantiate client objects on Wildfly with JNDI bindings object-factory configuration
  • Loading branch information
remi.bantos committed May 29, 2017
1 parent 4d9d3ec commit f5871b8
Show file tree
Hide file tree
Showing 5 changed files with 336 additions and 53 deletions.
30 changes: 30 additions & 0 deletions doc-notes/docupdates1.1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ or a Spring bean example:
</bean>
```

or a Wildfly xml configuration example with amqp default value:

```xml
<bindings>
<object-factory name="java:global/jms/Queue" module="foo.bar" class="com.rabbitmq.jms.admin.RMQObjectFactory">
<environment>
<property name="className" value="javax.jms.Queue"/>
<property name="destinationName" value="myQueue"/>
</environment>
</object-factory>
</bindings>
```

Here is a *complete* list of the attributes/properties now available:

----
Expand Down Expand Up @@ -173,6 +186,23 @@ or a Spring bean example:
</bean>
```

or a Wildfly xml configuration example:

```xml
<bindings>
<object-factory name="java:global/jms/ConnectionFactory" module="org.jboss.genericjms.provider" class="com.rabbitmq.jms.admin.RMQObjectFactory">
<environment>
<property name="className" value="javax.jms.ConnectionFactory"/>
<property name="username" value="guest"/>
<property name="password" value="guest"/>
<property name="virtualHost" value="/"/>
<property name="host" value="localhost"/>
<property name="ssl" value="true"/>
</environment>
</object-factory>
</bindings>
```

Here is a complete list of the attributes/properties available:

----
Expand Down
17 changes: 17 additions & 0 deletions doc-notes/docupdates1.3.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ or a Spring bean example:
</bean>
```

or a Wildfly xml configuration example:

```xml
<bindings>
<object-factory name="java:global/jms/ConnectionFactory" module="org.jboss.genericjms.provider" class="com.rabbitmq.jms.admin.RMQObjectFactory">
<environment>
<property name="className" value="javax.jms.ConnectionFactory"/>
<property name="username" value="guest"/>
<property name="password" value="guest"/>
<property name="virtualHost" value="/"/>
<property name="host" value="localhost"/>
<property name="ssl" value="true"/>
</environment>
</object-factory>
</bindings>
```

Here is a complete list of the attributes/properties available:

----
Expand Down
119 changes: 77 additions & 42 deletions src/main/java/com/rabbitmq/jms/admin/RMQObjectFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@
* destinationName=&quot;topicName&quot;/&gt;
* </pre>
* <p>
* An example Wildfly configuration for a {@link ConnectionFactory} would look like:
* </p>
* <pre>
* &lt;object-factory name=&quot;java:global/jms/ConnectionFactory&quot; module=&quot;org.jboss.genericjms.provider&quot; class=&quot;com.rabbitmq.jms.admin.RMQObjectFactory&quot;&gt;
* &lt;environment&gt;
* &lt;property name=&quot;className&quot; value=&quot;javax.jms.ConnectionFactory&quot;/&gt;
* &lt;property name=&quot;username&quot; value=&quot;guest&quot;/&gt;
* &lt;property name=&quot;password&quot; value=&quot;guest&quot;/&gt;
* &lt;property name=&quot;virtualHost&quot; value=&quot;/&quot;/&gt;
* &lt;property name=&quot;host&quot; value=&quot;localhost&quot;/&gt;
* &lt;/environment&gt;
* &lt;/object-factory&gt;
* </pre>
* <p>
* Valid types are:
* </p>
* <pre>
Expand All @@ -82,6 +96,7 @@
* <li>terminationTimeout</li>
* <li>username</li>
* <li>virtualHost</li>
* <li>className - only applies when properties are provided via environment HashTable</li>
* </ul>
* and are applied in this order, if they are present. If a property is not present, or is not set by means of the
* <code>uri</code> attribute, the default value is the same as that obtained by instantiating a
Expand All @@ -96,20 +111,27 @@
*/
public class RMQObjectFactory implements ObjectFactory {

private static final String ENV_CLASS_NAME = "className";

private final Logger logger = LoggerFactory.getLogger(RMQObjectFactory.class);

/**
* {@inheritDoc}
*/
@Override
public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> environment) throws Exception {
// We only know how to deal with <code>javax.naming.Reference</code>s
if ((obj == null) || !(obj instanceof javax.naming.Reference)) {

if ((obj == null) ) {
return null;
}
Reference ref = (Reference) obj;
Reference ref = obj instanceof Reference ? (Reference) obj : null;

if (ref == null && (environment == null || environment.isEmpty())) {
throw new NamingException("Unable to instantiate object: obj is not a Reference instance and environment table is empty");
}

String className = ref!= null ? ref.getClassName(): (String) environment.get(ENV_CLASS_NAME);

String className = ref.getClassName();
if (className == null || className.trim().length() == 0) {
throw new NamingException("Unable to instantiate object: type has not been specified");
}
Expand Down Expand Up @@ -138,59 +160,61 @@ public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?,
}

if (connectionFactory) {
return createConnectionFactory(ref, name);
return createConnectionFactory(ref, environment, name);
} else {
return createDestination(ref, name, topic);
return createDestination(ref, environment, name, topic);
}
}

/**
* Creates a RMQConnectionFactory from a Reference
* @param ref - the reference containing all properties
* @param name - the name of the object
* Creates a RMQConnectionFactory from a Reference or environment Hashtable
* @param ref the reference containing properties
* @param environment the environment containing properties
* @param name the name of the object
* @return a {@link RMQConnectionFactory} object configured
* @throws NamingException if a required property is missing or invalid
*/
public Object createConnectionFactory(Reference ref, Name name) throws NamingException {
public Object createConnectionFactory(Reference ref, Hashtable<?, ?> environment, Name name) throws NamingException {
this.logger.trace("Creating connection factory ref '{}', name '{}'.", ref, name);
RMQConnectionFactory f = new RMQConnectionFactory();

try { // set uri first, which may fail if it doesn't parse
f.setUri(getStringProperty(ref, "uri", true, f.getUri()));
f.setUri(getStringProperty(ref, environment, "uri", true, f.getUri()));
} catch (JMSException e) {
this.logger.warn("Failed to set RMQConnectionFactory properties by URI--defaults taken initially.", e);
}

// explicit properties (these override the uri, if set)
f.setHost (getStringProperty (ref, "host", true, f.getHost() ));
f.setPassword (getStringProperty (ref, "password", true, f.getPassword() ));
f.setPort (getIntProperty (ref, "port", true, f.getPort() ));
f.setQueueBrowserReadMax(getIntProperty (ref, "queueBrowserReadMax", true, f.getQueueBrowserReadMax()));
f.setOnMessageTimeoutMs (getIntProperty (ref, "onMessageTimeoutMs", true, f.getOnMessageTimeoutMs() ));
f.setSsl (getBooleanProperty(ref, "ssl", true, f.isSsl() ));
f.setTerminationTimeout (getLongProperty (ref, "terminationTimeout", true, f.getTerminationTimeout() ));
f.setUsername (getStringProperty (ref, "username", true, f.getUsername() ));
f.setVirtualHost (getStringProperty (ref, "virtualHost", true, f.getVirtualHost() ));
f.setHost (getStringProperty (ref, environment, "host", true, f.getHost() ));
f.setPassword (getStringProperty (ref, environment, "password", true, f.getPassword() ));
f.setPort (getIntProperty (ref, environment, "port", true, f.getPort() ));
f.setQueueBrowserReadMax(getIntProperty (ref, environment, "queueBrowserReadMax", true, f.getQueueBrowserReadMax()));
f.setOnMessageTimeoutMs (getIntProperty (ref, environment, "onMessageTimeoutMs", true, f.getOnMessageTimeoutMs() ));
f.setSsl (getBooleanProperty(ref, environment, "ssl", true, f.isSsl() ));
f.setTerminationTimeout (getLongProperty (ref, environment, "terminationTimeout", true, f.getTerminationTimeout() ));
f.setUsername (getStringProperty (ref, environment, "username", true, f.getUsername() ));
f.setVirtualHost (getStringProperty (ref, environment, "virtualHost", true, f.getVirtualHost() ));

return f;
}

/**
* Create a {@link RMQDestination} from a reference
* @param ref the reference containing the required properties
* @param name - the name
* @param topic - true if this is a topic, false if it is a queue (ignored if this is amqp-mapped)
* Create a {@link RMQDestination} from a Reference of environment Hashtable
* @param ref the reference containing the properties
* @param environment the environment containing the properties
* @param name the name
* @param topic true if this is a topic, false if it is a queue (ignored if this is amqp-mapped)
* @return a {@link RMQDestination} object with the destinationName configured
* @throws NamingException if the <code>destinationName</code> property is missing
*/
public Object createDestination(Reference ref, Name name, boolean topic) throws NamingException {
public Object createDestination(Reference ref, Hashtable<?, ?> environment, Name name, boolean topic) throws NamingException {
this.logger.trace("Creating destination ref '{}', name '{}' (topic={}).", ref, name, topic);
String dname = getStringProperty(ref, "destinationName", false, null);
boolean amqp = getBooleanProperty(ref, "amqp", true, false);
String dname = getStringProperty(ref, environment, "destinationName", false, null);
boolean amqp = getBooleanProperty(ref, environment, "amqp", true, false);
if (amqp) {
String amqpExchangeName = getStringProperty(ref, "amqpExchangeName", false, null);
String amqpRoutingKey = getStringProperty(ref, "amqpRoutingKey", false, null);
String amqpQueueName = getStringProperty(ref, "amqpQueueName", false, null);
String amqpExchangeName = getStringProperty(ref, environment, "amqpExchangeName", false, null);
String amqpRoutingKey = getStringProperty(ref, environment,"amqpRoutingKey", false, null);
String amqpQueueName = getStringProperty(ref, environment, "amqpQueueName", false, null);
return new RMQDestination(dname, amqpExchangeName, amqpRoutingKey, amqpQueueName);
} else {
return new RMQDestination(dname, !topic, false);
Expand All @@ -199,54 +223,60 @@ public Object createDestination(Reference ref, Name name, boolean topic) throws

/**
* Returns the value of a set property in a reference
* @param ref the reference containing the value
* @param ref the Reference containing the value
* @param environment the environment Hashtable containing the value
* @param propertyName the name of the property
* @param mayBeNull true if the property may be missing or contain a null value, in this case <code>defaultValue</code> will be returned
* @param defaultValue the defaultValue to return if the property is null and <code>mayBeNull==true</code>
* @return the String value for the property
* @throws NamingException if the property is missing and <code>mayBeNull==false</code>
*/
private String getStringProperty(Reference ref,
Hashtable<?, ?> environment,
String propertyName,
boolean mayBeNull,
String defaultValue) throws NamingException {
String content = propertyContent(ref, propertyName, mayBeNull);
String content = propertyContent(ref, environment, propertyName, mayBeNull);
if (content == null) return defaultValue;
return content;
}

/**
* Reads a property from the reference and returns the boolean value it represents
* @param ref the reference containing the value
* @param ref the Reference containing the value
* @param environment the environment Hashtable containing the value
* @param propertyName the name of the property
* @param mayBeNull true if the property may be missing or contain a null value, in this case <code>defaultValue</code> will be returned
* @param defaultValue the defaultValue to return if the property is null and <code>mayBeNull==true</code>
* @return the boolean value of the property
* @throws NamingException if the property is missing and <code>mayBeNull==false</code>
*/
private boolean getBooleanProperty(Reference ref,
Hashtable<?, ?> environment,
String propertyName,
boolean mayBeNull,
boolean defaultValue) throws NamingException {
String content = propertyContent(ref, propertyName, mayBeNull);
String content = propertyContent(ref, environment, propertyName, mayBeNull);
if (content == null) return defaultValue;
return Boolean.valueOf(content);
}

/**
* Reads a property from the reference and returns the int value it represents
* @param ref the reference
* @param ref the Reference containing the value
* @param environment the environment Hashtable containing the value
* @param propertyName the name of the property
* @param mayBeNull true if the property may be missing, in which case <code>defaultValue</code> will be returned
* @param defaultValue the default value to return if <code>mayBeNull</code> is set to true
* @return the integer value representing the property value
* @throws NamingException if the property is missing while mayBeNull is set to false, or a number format exception happened
*/
private int getIntProperty(Reference ref,
Hashtable<?, ?> environment,
String propertyName,
boolean mayBeNull,
int defaultValue) throws NamingException {
String content = propertyContent(ref, propertyName, mayBeNull);
String content = propertyContent(ref, environment, propertyName, mayBeNull);
if (content == null) return defaultValue;
try {
return Integer.parseInt(content);
Expand All @@ -259,18 +289,20 @@ private int getIntProperty(Reference ref,

/**
* Reads a property from the reference and returns the long integer value it represents
* @param ref the reference
* @param ref the Reference containing the value
* @param environment the environment Hashtable containing the value
* @param propertyName the name of the property
* @param mayBeNull true if the property may be missing, in which case <code>defaultValue</code> will be returned
* @param defaultValue the default value to return if <code>mayBeNull</code> is set to true
* @return the long integer value representing the property value
* @throws NamingException if the property is missing while mayBeNull is set to false, or a number format exception happened
*/
private long getLongProperty(Reference ref,
Hashtable<?, ?> environment,
String propertyName,
boolean mayBeNull,
long defaultValue) throws NamingException {
String content = propertyContent(ref, propertyName, mayBeNull);
String content = propertyContent(ref, environment, propertyName, mayBeNull);
if (content == null) return defaultValue;
try {
return Long.parseLong(content);
Expand All @@ -285,12 +317,15 @@ private static String propertyStringContent(RefAddr ra) {
return (ra == null ? null : ra.getContent() == null ? null : ra.getContent().toString());
}

private static String propertyContent(Reference ref, String propertyName, boolean mayBeNull) throws NamingException {
RefAddr ra = ref.get(propertyName);
if (!mayBeNull && ra == null) {
private static String environmentPropertyStringContent(Object propValue) {
return (propValue == null ? null : propValue.toString());
}

private static String propertyContent(Reference ref, Hashtable<?,?> environment, String propertyName, boolean mayBeNull) throws NamingException {
if (!mayBeNull && (ref == null || ref.get(propertyName) == null) && (environment == null || environment.get(propertyName) == null)) {
throw new NamingException(String.format("Property [%s] may not be null.", propertyName));
}
String content = propertyStringContent(ra);
String content = ref != null ? propertyStringContent(ref.get(propertyName)) : environmentPropertyStringContent(environment.get(propertyName));
if (content == null && !mayBeNull) {
throw new NamingException(String.format("Property [%s] is present but is lacking a value.", propertyName));
}
Expand Down
Loading

0 comments on commit f5871b8

Please sign in to comment.