使用 JMS Tibco EMS JNDI 资源启动 Tomcat 时来自 Catalina 的 NullPointerException

NullPointerException from Catalina when starting Tomcat with JMS Tibco EMS JNDI resources

在我的 Primefaces 应用程序中,我想使用 atmosphere framework 的 JMSBroadcaster 以便在我的应用程序的 2 个实例之间传播消息。

为此,我需要查找 (JNDI) JMS ConnectionFactoryTopic(我们使用的实现是 Tibco EMS)。

我是 JMS 的新手,我不知道如何在 Tomcat 的 context.xmlserver.xml 中配置 Tibco JMS 资源(我没有使用活动的 MQ)。我试图在 Tomcat 8 中从 EMS 声明这些 JMS 资源。 我在 tomcat8/lib/

中添加了 tibjms-7.0.1.jarjboss-jms-api_1.1_spec-1.0.1.Final.jar

但是,在 tomcat 启动时,我收到以下错误(即使没有部署任何 war):

SEVERE [main] org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans RuntimeException java.lang.NullPointerException

我无法弄清楚问题出在哪里(我不确定我是否可以获得有关此记录错误的更多详细信息)。

这是我的 tomcat 配置:

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"/>

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" />

或者,我可能也对使用从 Spring.

注入的 ConnectionFactoryTopic 配置气氛 JMSBroadcaster 的方法感兴趣

我实际上使用了 Spring 来实例化 Jms 主题...

<!-- 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>

...并创建了一个 MessageListener,它监听气氛主题并将接收到的消息发布到 Push 事件总线 ...

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);

        }
    }
}

... 并创建了一个 Spring 服务来将我的消息发布到主题而不是推送 ...

@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;
        });

    }

}

...一些抽象的实用程序...

@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));
    }

}

.. 然后,我将我的消息发布到我的应用程序的多个实例,这些实例收听相同的气氛主题(包括发送消息的应用程序)。

 pushJmsUtils.propagateMessage(canal,pushMessage);