Jms Mdb-webspheremq
我是MDB和EE的新手。请告诉我我错了。 我的应用程序必须与Websphere MQ进行交互(在队列中等待消息,执行某些操作并回复)。 我使用的是NetBeans 7.3、GlassFish 3.1、Websphere MQ 6.2、resorce适配器wmq.jmsra.rar。交互必须不是jms格式,而是Web MQ性质。 我正在部署适配器并创建连接池和管理对象。 在domain.xml中Jms Mdb-webspheremq,jms,glassfish-3,ibm-mq,Jms,Glassfish 3,Ibm Mq,我是MDB和EE的新手。请告诉我我错了。 我的应用程序必须与Websphere MQ进行交互(在队列中等待消息,执行某些操作并回复)。 我使用的是NetBeans 7.3、GlassFish 3.1、Websphere MQ 6.2、resorce适配器wmq.jmsra.rar。交互必须不是jms格式,而是Web MQ性质。 我正在部署适配器并创建连接池和管理对象。 在domain.xml中 <connector-connection-pool description="" name
<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>
请告诉我为什么这个MDB没有被列在队列中(我将测试消息放在WebSphereMQ控制台中)。可能是我必须在配置中编写一些东西(现在项目作为默认的netbeans创建)
Alexei我有一个有效的解决方案。这不是最好的解决方案,但确实非常有效 我们所做的是创建一个非常简单的ActivationSpecWrapper类来扩展IBMcom.IBM.mq.connector.inbound.ActivationSpecImpl类。这个包装类有一个公共set/get属性(asJNDI)。如果该类要通过JNDI上下文读取在App server中定义的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>
问题源于IBM将主机/端口/队列管理器/通道(等)放入激活规范而不是管理对象。它属于管理对象,因为它是MDB队列的连接工厂。IBM在那里只允许两个属性
另外,如果您使用的是glassfish,oracle确实会把需要资源适配器的MDB类搞砸,因为glassfish@MessageDriven注释假定应用程序容器默认的JMS资源适配器(OpenMQ)。这意味着特定于供应商的ActivationSpecImpl不起作用,因此IMB的主机/端口自定义参数和其他激活配置属性在通过glassfish ejb jar.xml切换资源适配器之前不受注释支持
JBoss允许@ResourceAdapter注释更改资源适配器,但Glassfish仅允许通过Glassfish ejb jar.xml文件进行更改。当使用它时,您只需要用三个激活配置属性(destinationType)来注释MDB。您将在JNDI发布属性中放置的所有其他内容
glassfish ejb jar.xml应如下所示:
: jar -uvf wmq.jmsra.rar your/new/package/ActivationSpecWrapper.class
<?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>
@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的连接细节,而不是开发人员。我有一个可行的解决方案。这不是最好的解决方案,但确实非常有效 我们所做的是创建一个非常简单的ActivationSpecWrapper类来扩展IBMcom.IBM.mq.connector.inbound.ActivationSpecImpl类。这个包装类有一个公共set/get属性(asJNDI)。如果该类要通过JNDI上下文读取在App server中定义的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>
问题源于IBM将主机/端口/队列管理器/通道(等)放入激活规范而不是管理对象。它属于管理对象,因为它是MDB队列的连接工厂。IBM在那里只允许两个属性
另外,如果您使用的是glassfish,oracle确实会把需要资源适配器的MDB类搞砸,因为glassfish@MessageDriven注释假定应用程序容器默认的JMS资源适配器(OpenMQ)。这意味着特定于供应商的ActivationSpecImpl不起作用,因此IMB的主机/端口自定义参数和其他激活配置属性在通过glassfish ejb jar.xml切换资源适配器之前不受注释支持
JBoss允许@ResourceAdapter注释更改资源适配器,但Glassfish仅允许通过Glassfish ejb jar.xml文件进行更改。当使用它时,您只需要用三个激活配置属性(destinationType)来注释MDB。您将在JNDI发布属性中放置的所有其他内容
glassfish ejb jar.xml应该像