in my Primefaces application I want to use atmosphere framework 's JMSBroadcaster
in order to propagate messages between 2 instances of my application.
To do that, I need to lookup (JNDI) for JMS ConnectionFactory
and Topic
(the implementation we are using is Tibco EMS).
I am very new to JMS and I cannot figure how to configure a Tibco JMS resource in Tomcat's context.xml
and server.xml
(I am not using active MQ). I am trying to declare these JMS resources from EMS in Tomcat 8.
I added tibjms-7.0.1.jar
and jboss-jms-api_1.1_spec-1.0.1.Final.jar
in tomcat8/lib/
But, at tomcat startup, I get the following error (even without any war deployed) :
SEVERE [main] org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans RuntimeException java.lang.NullPointerException
I cannot figure out how where is the problem (I am not sure I can have more details about this logged error).
Here is my tomcat configuration :
In server.xml
<Resource
id="atmosphereFactory"
name="jms/atmosphereFactory"
jndiName="atmosphereFactory"
auth="Container"
type="com.tibco.tibjms.naming.TibjmsInitialContextFactory"
factory="com.tibco.tibjms.naming.TibjmsObjectFactory"
factoryClass="com.tibco.tibjms.naming.TibjmsInitialContextFactory"
brokerName="localhost"
brokerURL="tcp://localhost:7222"
serverUrl="localhost:7222"
userName="admin"
password="" />
<Resource
id="atmosphere"
name="jms/atmosphere/test.atmo"
jndiName="atmosphere"
auth="Container"
type="com.tibco.tibjms.TibjmsTopic"
factory="com.tibco.tibjms.naming.TibjmsObjectFactory"
physicalName="test.atmo"/>
In context.xml
<ResourceLink
global="jms/atmosphereFactory"
name="jms/atmosphereFactory"
type="com.tibco.tibjms.naming.TibjmsInitialContextFactory" />
<ResourceLink
global="jms/atmosphere"
name="jms/atmosphere"
type="com.tibco.tibjms.TibjmsTopic" />
Alternatively, I might also be interested in a way to configure atmosphere's JMSBroadcaster
using ConnectionFactory
and Topic
injected from Spring.
I actually used Spring to instanciate Jms Topic...
<!-- Connection to Tibco EMS -->
<bean id="tibjmsConnectionFactory" class="com.tibco.tibjms.TibjmsConnectionFactory">
<property name="serverUrl" value="${instance.jms.server}" />
<property name="userName" value="${instance.jms.login}"/>
<property name="userPassword" value="${instance.jms.password}"/>
</bean>
<bean id="jmsTemplateEms" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="tibjmsConnectionFactory" />
<property name="explicitQosEnabled" value="true" />
<property name="deliveryMode" value="2" />
<property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE" />
<property name="sessionTransacted" value="false" />
<property name="receiveTimeout" value="${instance.wait.timeout}" />
</bean>
<bean id="pushJmsMessageListener" class="com.agipi.g2a.tiana.web.utils.PushJmsMessageListener" />
<bean id="atmosphereTopic" class="com.tibco.tibjms.TibjmsTopic">
<!-- nom du topic-->
<constructor-arg index="0" value="${instance.jms.atmosphere.topic.name}" />
</bean>
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="tibjmsConnectionFactory"/>
<property name="destination" ref="atmosphereTopic"/>
<property name="messageListener" ref="pushJmsMessageListener" />
</bean>
... and created a MessageListener which listen to atmosphere topic and publish received message to Push event bus ...
class PushJmsMessageListener implements MessageListener {
private static final Logger LOGGER = LoggerFactory.getLogger(PushJmsMessageListener.class);
private static final String PROPERTY_PUSH_CHANNEL = "pushChannel";
@Override
public void onMessage(Message message) {
try {
EventBus eventBus = EventBusFactory.getDefault().eventBus();
TextMessage testMessage = (TextMessage) message;
LOGGER.info("Reception d'un message du topic atmosphere : {}", testMessage);
String canal = testMessage.getStringProperty(PROPERTY_PUSH_CHANNEL);
Object decodedObject = new JSONDecoder().decode(testMessage.getText());
LOGGER.info("Envoi du message sur le endpoint push [canal={},objet={}]", canal, decodedObject);
eventBus.publish(canal, decodedObject);
} catch (JMSException e) {
LOGGER.error("error.receiving.jms.message", e);
}
}
}
... and created a Spring service to publish my message to the topic instead of push ...
@Service
@Scope(value = "singleton")
public class JmsAtmosphereServiceImpl implements JmsAtmosphereService {
@Autowired
@Qualifier("jmsTemplateEms")
private JmsTemplate jmsTemplate;
@Autowired
@Qualifier("atmosphereTopic")
private Topic atmosphereTopic;
@Override
public void sendMessage(String pushChannel, String jsonContent) {
jmsTemplate.send(atmosphereTopic, session -> {
TextMessage textMessage = session.createTextMessage(jsonContent);
textMessage.setStringProperty("pushChannel", pushChannel);
return textMessage;
});
}
}
... some utility to abstract ...
@Service
public class PushJmsUtils {
private static final String PUSH_DEFAULT_CHANNEL = "atmosphere";
@Autowired
private JmsAtmosphereService jmsAtmosphereService;
/**
* Propagate message JMS as JSON to JMS Atmosphere topic.
*
* @param channel push channel
* @param message object to send via push
*/
public void propagateMessage(String channel, Object message) {
String id = channel;
if (id.startsWith("/*")) {
id = PUSH_DEFAULT_CHANNEL;
}
jmsAtmosphereService.sendMessage(id, new JSONEncoder().encode(message));
}
}
.. and then, I publish my message to several instances of my application listening to the same atmosphere topic (including the application sending the message).
pushJmsUtils.propagateMessage(canal,pushMessage);