【问题标题】:Mdb Glasswish Websphere MQMdb Glasswish Websphere MQ
【发布时间】:2013-04-06 10:35:13
【问题描述】:

我是 MDB 和 EE 的新手。请告诉我我错了。 我的应用程序必须与 Websphere MQ 交互(在队列中等待消息,做某事并回复)。 我正在使用 NetBeans 7.3、GlassFish 3.1、Websphere MQ 6.2、资源适配器 wmq.jmsra.rar。交互一定不是jms格式的,只有Web MQ性质的。 我正在部署适配器并创建连接池和管理对象。 在 domain.xml 中

  <connector-connection-pool description="" name="cpMqAdapter" resource-adapter-name="wmq.jmsra" connection-definition-name="javax.jms.QueueConnectionFactory" transaction-support="LocalTransaction">
  <property name="port" value="1414"></property>
  <property name="CCSID" value="866"></property>
  <property name="hostName" value="192.168.0.11"></property>
  <property name="queueManager" value="QM"></property>
  <property name="channel" value="SrvConn"></property>
  <property description="CLIENT - mq on other computer" name="transportType" value="CLIENT"></property>
</connector-connection-pool>


<admin-object-resource enabled="false" res-adapter="wmq.jmsra" res-type="javax.jms.Queue" description="" jndi-name="wmqJmsAOR" class-name="com.ibm.mq.connector.outbound.MQQueueProxy">
  <property name="priority" value="APP"></property>
  <property name="failIfQuiesce" value="true"></property>
  <property name="baseQueueManagerName" value="QM"></property>
  <property name="CCSID" value="1208"></property>
  <property name="persistence" value="APP"></property>
  <property name="encoding" value="NATIVE"></property>
  <property name="baseQueueName" value="TEST"></property>
  <property name="targetClient" value="MQ"></property>
  <property name="expiry" value="APP"></property>
</admin-object-resource>

' 在 netbeans 中,我正在创建 EE 项目和消息驱动 bean。我得到了这个代码'

   @MessageDriven(mappedName = "wmqJmsAOR", activationConfig = {
   @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto- 
   acknowledge"),
   @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")

 })
public class NewMessage implements MessageListener {
public NewMessage() {
    super();
    System.out.println("I created");
}

@Override
public void onMessage(Message message) {

    System.out.println("I'm getting message");

}
`

请告诉我为什么这个 MDB 不监听队列(我将测试消息放在 Websphere MQ 控制台中)。可能是我必须在配置中写一些东西(现在项目作为默认的 netbeans 创建)。

阿列克谢

【问题讨论】:

  • 你有没有想过这个问题?我遇到了同样的问题。我没有收到任何错误,但它只是没有收到任何消息。我什至把所有的连接信息都放到了 admin-object 属性中..
  • @Armand 你好。不,这个任务被取消了。有可能我稍后会回来做这项工作

标签: jms glassfish-3 ibm-mq


【解决方案1】:

我有一个可行的解决方案。这不是最好的解决方案,但它确实工作得非常好。

我们所做的是创建一个非常简单的 ActivationSpecWrapper 类来扩展 IBM com.ibm.mq.connector.inbound.ActivationSpecImpl 类。这个包装类有一个公共的 set/get 属性 (asJNDI)。该类的目的是通过 JNDI 上下文读取应用服务器中定义的 Properties 类,该类包含要在激活 MDB 时分配的所有属性。

首先,创建新的 ActivationSpecWrapper 类。您可以将其放入您选择的任何包装中。

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.InitialContext;
import com.ibm.mq.connector.inbound.ActivationSpecImpl;

public class ActivationSpecWrapper extends ActivationSpecImpl
{

   private static final long   serialVersionUID = -529716553593856979L;

   private static final String sourceClass      = ActivationSpecWrapper.class.getName();
   private static final Logger log              = Logger.getLogger(sourceClass);

   private String              asJNDI           = null;

   public void setAsJNDI(String asJNDI)
   {
      log.config("asJNDI = " + asJNDI);
      this.asJNDI = asJNDI;

      try
      {
         final InitialContext ctx = new InitialContext();
         final Properties properties = (Properties) ctx.lookup(asJNDI);

         for (final Object key : properties.keySet())
         {
            try
            {
               final String value = properties.getProperty((String) key);
               final Object field = getSetter((String) key);
               if (field != null)
               {
                  if (field instanceof Field)
                  {
                     log.fine("Setting " + key + " via Field " + (String) key + " = " + value);
                     ((Field) field).set(this, value);

                  }
                  else
                  {
                     log.fine("Setting " + key + " via Method " + (String) key + " = " + value);
                     ((Method) field).invoke(this, value);
                  }
                  log.config(key + " = " + value);
               }
               else
               {
                  log.warning("Invalid ActivationSpec Field: " + key);
               }
            }
            catch (final NoSuchFieldException e)
            {
               log.throwing(sourceClass, "setAsJNDI", e);
            }

         }

      }
      catch (final Exception e)
      {
         log.log(Level.SEVERE, "Error looking up " + asJNDI, e);
         return;
      }

   }

   public String getAsJNDI()
   {
      return asJNDI;
   }

   private static Object getField(String fieldName) throws NoSuchFieldException
   {
      return ActivationSpecWrapper.class.getField(fieldName);
   }

   private static Object getSetter(String fieldName) throws NoSuchFieldException
   {
      try
      {
         final StringBuilder sb = new StringBuilder(fieldName.length() + 3).append("set").append(fieldName);
         sb.setCharAt(3, Character.toUpperCase(sb.charAt(3)));

         return ActivationSpecWrapper.class.getMethod(sb.toString(), String.class);
      }
      catch (final NoSuchMethodException e)
      {
         return getField(fieldName);
      }
   }
}

要实现该类,您只需修改 wmq.jmsra.rar 文件中的 META-INF/ra.xml 文件。将 ActivationSpecImpl 类的一次出现更改为您的类。这将是它使用的新传入连接工厂的 ActivationSpecWrapper 类。因此,现在您的包装类可以查看应用服务器以获取要使用的属性。

我这样做如下:

: jar -xvf wmq.jmsra.rar META-INF/ra.xml
: perl -pi -e 's/com\.ibm\.mq\.connector\.inbound\.ActivationSpecImpl/your.new.package.ActivatonSpecWrapper/g' META-INF/ra.xml
: jar -uvf wmq.jmsra.rar META-INF/ra.xml

在修改 META-INF/ra.xml 之前的样子:

<activationspec>
   <activationspec-class>
      com.ibm.mq.connector.inbound.ActivationSpecImpl
   </activationspec-class>
   <required-config-property>
      <config-property-name>destination</config-property-name>
   </required-config-property>
   <required-config-property>
      <config-property-name>destinationType</config-property-name>
   </required-config-property>
</activationspec>

更改后,META-INF/ra.xml 应该是这样的:

<activationspec>
   <activationspec-class>
      your.new.package.ActivatonSpecWrapper
   </activationspec-class>
   <required-config-property>
      <config-property-name>destination</config-property-name>
   </required-config-property>
   <required-config-property>
      <config-property-name>destinationType</config-property-name>
   </required-config-property>
</activationspec>

现在您需要将新包添加到 RAR 文件中。它应该在标准目录结构中。像这样:

: jar -uvf wmq.jmsra.rar your/new/package/ActivationSpecWrapper.class

问题源于 IBM 将主机/端口/队列管理器/通道(等)放入激活规范而不是管理对象。它属于管理对象,因为它是 MDB 队列的连接工厂。 IBM 在那里只允许两个属性。

此外,如果您使用 glassfish,oracle 确实为需要资源适配器的 MDB 类搞砸了,因为 glassfish @MessageDriven 注释假定应用程序容器默认资源适配器(OpenMQ) 用于 JMS。这意味着供应商特定的 ActivationSpecImpl 不起作用,因此 IMB 的主机/端口和其他激活配置属性的自定义参数在资源适配器切换之前不支持通过注释通过 glassfish-ejb-jar.xml。

JBoss 允许 @ResourceAdapter 注释更改资源适配器,但 Glassfish 仅允许通过 glassfish-ejb-jar.xml 进行此操作文件。当使用它时,您只需要使用三个激活配置属性(destinationType)注释您的 MDB。您将在 JNDI 发布的属性中放置的所有其他内容。

glassfish-ejb-jar.xml 应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<glassfish-ejb-jar>

    <enterprise-beans >
        <unique-id>1</unique-id>
        <ejb>
            <ejb-name>MyMDB</ejb-name>
            <mdb-resource-adapter>
                <resource-adapter-mid>wmq.jmsra</resource-adapter-mid>
                <activation-config>
                    <activation-config-property>
                        <activation-config-property-name>asJNDI</activation-config-property-name>
                        <activation-config-property-value>mq/InboundMessages</activation-config-property-value>
                    </activation-config-property>
                </activation-config>
            </mdb-resource-adapter>
        </ejb>
    </enterprise-beans> 
</glassfish-ejb-jar>

MDB @MessageDriven 注释看起来像这样:

@MessageDriven(activationConfig =
   {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/InboundMessage_queue"),
    @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true") })
public class MyMDB implement MessageListener
{
    public void onMessage(Message message)
    {
        // message handler code goes here...
    }
}

完成这项工作的最后一步是将 mq/InboundMessages 属性添加到 JDNI,以定义 MQ 侦听器资源的工厂属性。这就是它在 domain.xml 文件中的定义方式:

<custom-resource res-type="java.util.Properties" jndi-name="mq/InboundMessages" factory-class="org.glassfish.resources.custom.factory.PropertiesFactory">
  <property name="hostName" value="mqserver"></property>
  <property name="port" value="1422"></property>
  <property name="queueManager" value="MQMNGR"></property>
  <property name="channel" value="MQMNGR.SM.S1"></property>
  <property name="transportType" value="CLIENT"></property>
</custom-resource>

我希望这会有所帮助。这不是最简单的解决方案,但足够简单,而且一旦建立,它就非常便携,并且允许应用服务器管理员管理与 MQ 的连接细节,而不是开发人员。

【讨论】:

  • 您好!谢谢你,阿尔芒。一年后我回到了这份工作。你的回答很有帮助。我正在创建 glassfish-ejb-jar.xml 并将 wmq.jmsra 和 属性设置为 MQQueueManger 连接它正在工作。但是这个解决方案并不喜欢,因为描述符中包含的所有参数。你能告诉我们更多关于你的情况下带有 Wrapper 的版本和描述符中的内容吗?
  • 值得注意的是,IBM 不支持 JMS ResourceAdaptor 中的事务。实现对 XA-Transactions 的支持非常容易。只需将 com.ibm.mqetclient.jar 文件添加到 RAR 文件中,现在 MDB 即可轻松支持 XA 事务。此外,我使用 MQ7 完成所有这些操作,但它也适用于 MQ6。
  • 非常感谢您如此详细的回复
猜你喜欢
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 2019-10-25
  • 1970-01-01
  • 1970-01-01
  • 2013-11-03
  • 2013-01-03
  • 1970-01-01
相关资源
最近更新 更多