1

我有一个应用程序,其中客户端组件在“托管”环境中运行(作为 Adob​​e InDesign 插件)。在这种“托管”环境中,似乎不可能在执行期间创建线程,而只能在应用程序启动时创建。

这个客户端组件通过 JNDI 和 RMI/IIOP 连接到 Glassfish 服务器,以执行各种 EJB 方法调用,所有这些都可以完美运行(除了一些在这里不重要的繁琐的CORBA 序列化问题)。我想让它也使用 JMS 连接,以执行一些主题阅读。我用来执行这些主题阅读的代码已经在单元测试中,确保它可以启动、阅读主题并执行所需的集成(这更像是一个集成测试而不是单元测试,但我必须确定我的应用程序通信层,不是吗?)。这段代码在单元测试中运行时可以完美运行。不幸的是,当从我的客户端组件(嵌入在 Indesign 中,并且无法创建线程)运行时,它以NullPointerException以下方式失败:

29 mai 2012 18:07:22 com.sun.enterprise.connectors.ActiveRAFactory getActiveRA
INFO: Deployed RAR [ jmsra ] has inbound artifacts, but the runtime does not support it. Providing only outbound support 
29 mai 2012 18:07:22 org.hibernate.validator.util.Version <clinit>
INFO: Hibernate Validator 4.2.0.Final
29 mai 2012 18:07:24 com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter: Version:  4.5  (Build 29-b) Compile:  Wed Feb  9 22:53:30 PST 2011
29 mai 2012 18:07:24 com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter starting: broker is EMBEDDED, connection mode is Direct
29 mai 2012 18:12:58 com.sun.messaging.jms.blc.LifecycleManagedBroker start
GRAVE: MQJMSRA_RA4001: start:Aborting:Exception starting EMBEDDED broker=java.lang.NullPointerException
29 mai 2012 18:12:58 com.sun.messaging.jms.blc.LifecycleManagedBroker start
INFO: SJSMQ LifecycleManagedBroker configuration=
    brokerInstanceName       =imqbroker
    brokerBindAddress        =null
    brokerPort               =7676
    brokerHomeDir            =C:\Java-ext\glassfish3\mq
    brokerLibDir             =C:\Java-ext\glassfish3\mq\lib
    brokerVarDir             =C:\Java-ext\glassfish3\glassfish\domains\autocat\imq
    brokerJavaDir            =C:\Program Files\Java\jdk1.6.0_30\jre
    brokerArgs               =null
    MasterBroker             =null
    brokerId                 =null
    adminUsername            =admin
    adminPassword            =<default>
    adminPassFile            =null
    ConnectionURL            =mq://localhost:7676/
    dbType                   =null
    dbProps                  ={}
    dsProps                  ={}
    useJNDIRmiServiceURL     =true
    useSSLJMXConnector       =true
    brokerEnableHA           =false
    clusterId                =null
    rmiRegistryPort          =7776
    startRmiRegistry         =true
    brokerStartTimeout       =  jmxServiceURL            =null
60000

29 mai 2012 18:12:58 com.sun.enterprise.connectors.ActiveOutboundResourceAdapter init
GRAVE: RAR6035 : Resource adapter start failed. 
javax.resource.spi.ResourceAdapterInternalException: MQJMSRA_RA4001: start:Aborting:Exception starting EMBEDDED broker=java.lang.NullPointerException
    at com.sun.messaging.jms.blc.LifecycleManagedBroker.start(LifecycleManagedBroker.java:458)
    at com.sun.messaging.jms.ra.ResourceAdapter.start(ResourceAdapter.java:380)
    at com.sun.enterprise.connectors.ActiveOutboundResourceAdapter.startResourceAdapter(ActiveOutboundResourceAdapter.java:182)
    at com.sun.enterprise.connectors.ActiveOutboundResourceAdapter.init(ActiveOutboundResourceAdapter.java:129)
    at com.sun.enterprise.connectors.ActiveRAFactory.instantiateActiveResourceAdapter(ActiveRAFactory.java:135)
    at com.sun.enterprise.connectors.ActiveRAFactory.createActiveResourceAdapter(ActiveRAFactory.java:106)
    at com.sun.enterprise.connectors.service.ResourceAdapterAdminServiceImpl.createActiveResourceAdapter(ResourceAdapterAdminServiceImpl.java:212)
    at com.sun.enterprise.connectors.ConnectorRuntime.createActiveResourceAdapter(ConnectorRuntime.java:379)
    at com.sun.enterprise.resource.naming.AdministeredObjectFactory.getObjectInstance(AdministeredObjectFactory.java:107)
    at javax.naming.spi.NamingManager.getObjectInstance(Unknown Source)
    at com.sun.enterprise.naming.impl.SerialContext.getObjectInstance(SerialContext.java:556)
    at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:514)
    at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
    at javax.naming.InitialContext.lookup(Unknown Source)
    at fr.perigee.autocat.indesign.remoting.jndi.jms.AdapterJMSListener.getConsumer(AdapterJMSListener.java:261)
    at fr.perigee.autocat.indesign.remoting.jndi.jms.AdapterJMSListener$AdapterJMSListenerRunnable.run(AdapterJMSListener.java:50)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source)
    at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
    at com.sun.messaging.jmq.jmsclient.runtime.impl.BrokerInstanceImpl.start(BrokerInstanceImpl.java:211)
    at com.sun.messaging.jms.blc.EmbeddedBrokerRunner.start(EmbeddedBrokerRunner.java:331)
    at com.sun.messaging.jms.blc.LifecycleManagedBroker.start(LifecycleManagedBroker.java:454)
    ... 24 more
Caused by: java.lang.NullPointerException
    at com.sun.messaging.jmq.jmsserver.data.TransactionList.<init>(TransactionList.java:182)
    at com.sun.messaging.jmq.jmsserver.Broker._start(Broker.java:1170)
    at com.sun.messaging.jmq.jmsserver.Broker.start(Broker.java:456)
    at com.sun.messaging.jmq.jmsserver.BrokerProcess.start(BrokerProcess.java:164)
    at com.sun.messaging.jmq.jmsserver.DirectBrokerProcess.start(DirectBrokerProcess.java:92)
    at com.sun.messaging.jmq.jmsclient.runtime.impl.BrokerInstanceImpl.start(BrokerInstanceImpl.java:206)
    ... 26 more

从我目前发现的情况来看,客户端代码获得了到 JMS 服务器的连接(连接到mq://localhost://7676),但随后无法启动 TransactionList。未编译的源代码(感谢 Jad !)表明它在那里失败:

    /* 182*/Globals.getClusterManager().addEventListener(((ClusterListener) (this)));

尝试调试时,我还发现我的客户端无法启动,org.glassfish.enterprise.iiop.util.S1ASThreadPoolManager因为同样不可能创建线程。

我想某处有问题,但是什么?我不知道。

那么,我如何告诉 glassfish 客户端环境线程只能从我的个人线程池(在应用程序启动时创建)中获取,而不是尝试创建自己的线程池并惨遭失败?

4

1 回答 1

1

精简版

我使用 maven 部署了我的应用程序,忘记了 Glassfish 的jms-core.jar,因为它是gf-client-module.jar的运行时依赖项,而我的 maven 构建只复制了编译依赖项。修复 Maven 构建修复了该问题。

长版

长版更多的是一个关于恐惧、眼泪和鲜血的故事。

那个 clusterManager 是怎么变成 null 的?

由于我最初遇到与 TransactionList 关联的 ClusterManager 的问题,因此我尝试查看com.sun.messaging.jmq.jmsserver.Globals代码是如何初始化它的。我发现它是在一个恰当地调用的方法Globals#initCLusterManager(MQAddress)中,它使用各种类参数(包括一个属性对象)加载了一个集群管理器,该集群管理器将被我的应用程序使用。什么 ?集群管理器?在客户端代码中?那是什么鬼(稍后会详细介绍)?

无论如何,该 ClusterManager 已加载,但之后设置为 null (主要是由于在集群配置中使用了环回地址 - 再一次,在 JMS客户端中非常奇怪)......所以看看它是如何初始化的显然不是正确的路径解决错误,这让我感到困惑。

测试通过但生产代码仍然存在错误时该怎么办?

正如我在问题中所说,我有一个测试,它(据我了解)完全相同。测试总是成功,生产总是失败。所以那里一定有不同的东西,不是吗?

所以我对我做了一些新的事情:我在该Globals#initClusterManager代码中放置了一个断点,并尝试使用两种代码来达到它:生产和测试。有人可能会猜到,在 prod 中达到了断点,但在 test 中没有!所以我将断点移到了某个我已经知道会到达的地方:ActiveRAFactory#getActiveRA(ConnectorDescriptor, String)...(哦等等,不,我没有把它放在那里,但是我放断点的地方告诉我执行路径变成了不同的是那个方法调用,所以我最后把断点放在那里)。

有了这个断点,我立刻注意到了一些奇怪的事情:调用

    Collection<ActiveResourceAdapter> activeRAs =  activeRAHabitat.getAllByContract(ActiveResourceAdapter.class);

根据我在 test 或 prod 中的事实返回不同的结果:我在 test 的列表中得到了 4 个元素(包括ActiveJmsResourceAdapter),但在生产中只有 3 个。

不同的 ResourceAdapter,但为什么?

然后我很困惑:然后我倾向于责怪Glassfish HK2 ,除了作为一个我还不知道的 IoC 容器之外没有其他原因......结果我错了,哦大错特错了!

启示来自 Eclipse 调试器中的表达式 eval:我输入为表达式

com.sun.enterprise.connectors.jms.system.ActiveJmsResourceAdapter.class

我得到的只是一个 ClassNotFoundException ......等等......一个 ClassNotFoundException ?这堂课在jms-core.jar?我很确定 jar 在我的生产文件夹中,不是吗?... 不 ?没有

他妈的 !

原来我用来复制该文件夹中的 jar的maven-dependency-plugin使用了复制依赖项,其includeScope配置为“编译”。

简单解决方案的疯狂错误

所以我向复制依赖项添加了另一个执行,配置为 incldueScope“运行时”,一切正常。

于 2012-06-01T07:31:35.753 回答