Connect jeromq-jms subscriber to zeroMQ Publisher
mueller-jens opened this issue · comments
mueller-jens commented
I am trying to connect a jms based subscriber to a plain ZeroMQ Publisher. But the subscriber does not recive any message. Is there any way to achive this?
Publisher:
Context context = ZMQ.context(1);
final Socket publisherSocket = context.socket(ZMQ.PUB);
publisherSocket.bind("tcp://*:9714");
Thread t = new Thread(() -> {
while (true) {
// Write two messages, each with an envelope and content
publisherSocket.sendMore("evt");
publisherSocket.send("TestEvent");
}
JMS Template configuration:
final JmsTemplate template = new JmsTemplate();
template.setPubSubDomain(true);
template.setConnectionFactory(connectionFactory());
template.setDefaultDestinationName(getPubServerUri(null));
template.setPubSubNoLocal(false);
template.setReceiveTimeout(100);
return template;
private TopicConnectionFactory connectionFactory() {
final TopicConnectionFactory connectionFactory = new ZmqConnectionFactory(
new String[] { getPubServerUri(null)});
return connectionFactory;
}
private ConnectionFactory connectionFactory() {
final ConnectionFactory connectionFactory = new ZmqConnectionFactory(
new String[] { getPubServerUri(null)});
return connectionFactory;
}
private String getPubServerUri(ZMQ_CHANNEL channel)
{
return "jms:topic:all?gateway.addr=tcp://*:9714&socket.addr=tcp://*:9714";
}
Subscriber:
System.out.println(jmsTemplate.receiveAndConvert());
Jeremy Miller commented
Tried this myself and I get an Unsupported exception. Not all JMS API was implemented. Will have a look into it.
mueller-jens commented
I have overridden the ZmqConnectionFactory and the ZmQConnection to overcome this:
ZmqConnectionFactory:
public class ZmqConnectionFactory extends org.zeromq.jms.ZmqConnectionFactory {
private final Map<String, ZmqURI> destinationSchema = new HashMap<String, ZmqURI>();
private String gatewayFactoryClassName = ZmqGatewayFactory.class.getCanonicalName();
private String[] packageNameExtensions = null;
/**
* Construct Zero MQ connection factory.
*/
public ZmqConnectionFactory() {
super();
}
/**
* Construct Zero MQ connection factory with the specified destination URIs.
* @param destinations the destination URIs
*/
public ZmqConnectionFactory(final String[] destinations) {
super(destinations);
}
/**
* Construct Zero MQ connection factory with the specified destination URIs.
* @param gatewayFactoryClassName the class name of the gateway factory
* @param packageNameExtensions the array of packages containing extension to ZERO MQ
* @param destinations the destination URIs
*/
public ZmqConnectionFactory(final String gatewayFactoryClassName, final String[] packageNameExtensions, final String[] destinations) {
super(gatewayFactoryClassName, packageNameExtensions, destinations);
this.gatewayFactoryClassName = gatewayFactoryClassName;
this.packageNameExtensions = packageNameExtensions;
}
/**
* @return return a factory gateway
* @throws ZmqException throws exception when factory construction fails
*/
private ZmqGatewayFactory getFactoryGateway() throws ZmqException {
try {
@SuppressWarnings("unchecked")
final Class<? extends ZmqGatewayFactory> gatewayFactoryClass = (Class<? extends ZmqGatewayFactory>) Class
.forName(gatewayFactoryClassName);
final Constructor<?> gatewayFactoryConstructor = gatewayFactoryClass.getConstructor(String[].class, Map.class);
final ZmqGatewayFactory gatewayFactory = (ZmqGatewayFactory) gatewayFactoryConstructor.newInstance(packageNameExtensions,
destinationSchema);
return gatewayFactory;
} catch (ClassNotFoundException ex) {
throw new ZmqException("Class could not be found.", ex);
} catch (NoSuchMethodException | SecurityException ex) {
throw new ZmqException("Unable to find required constructor for class: " + gatewayFactoryClassName, ex);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new ZmqException("Unable to invoke constructor for class: " + gatewayFactoryClassName, ex);
}
}
@Override
public QueueConnection createQueueConnection(final String userName, final String password) throws JMSException {
ZmqGatewayFactory gatewayFactory = getFactoryGateway();
QueueConnection connection = new ZmqConnection(gatewayFactory, destinationSchema);
return connection;
}
@Override
public TopicConnection createTopicConnection() throws JMSException {
return createTopicConnection(null, null);
}
@Override
public TopicConnection createTopicConnection(final String userName, final String password) throws JMSException {
ZmqGatewayFactory gatewayFactory = getFactoryGateway();
TopicConnection connection = new ZmqConnection(gatewayFactory, destinationSchema);
return connection;
}
@Override
public JMSContext createContext() {
return createContext(null, null, ZmqSession.AUTO_ACKNOWLEDGE);
}
@Override
public JMSContext createContext(final int sessionMode) {
return createContext(null, null, sessionMode);
}
@Override
public JMSContext createContext(final String userName, final String password) {
return createContext(userName, password, ZmqSession.AUTO_ACKNOWLEDGE);
}
@Override
public JMSContext createContext(final String userName, final String password, final int sessionMode) {
try {
ZmqGatewayFactory gatewayFactory = getFactoryGateway();
ZmqConnection connection = new ZmqConnection(gatewayFactory, destinationSchema);
ZmqJMSContext context = new ZmqJMSContext(connection, sessionMode);
return context;
} catch (ZmqException ex) {
throw new JMSRuntimeException("Unable to create context.", ex.getErrorCode(), ex);
}
}
ZmqConnection:
public class ZmqConnection extends org.zeromq.jms.ZmqConnection {
public ZmqConnection(ZmqGatewayFactory gatewayFactory, Map<String, ZmqURI> destinationSchema) {
super(gatewayFactory, destinationSchema);
//
}
@Override
public void start() throws JMSException {
}
@Override
public void stop() throws JMSException {
}
@Override
public void close() throws JMSException {
}
}
Jeremy Miller commented
I assume, it does not work. The issue is 2 fold in your example.
Firstly I always subscribe to the socket, and it nothing is provided it is set to “none”.
My bad, as no filter should be ZMQ.SUBSCRIPTION_ALL in the AbstractZMqGateway.open().
A moment of madness, but it needs an update of ZmqFilterPolicy.DEFAULT_FILTER
When this is sorted and the removal of the "unsupported exception” you already found, the consumption of the message will fault.
SEVERE: Socketing incoming failure: ZmqSocketSession [name=subscriber-1:all, socketType=SUB, socketAddr=tcp://*:9714, socketBound=false, socketIncoming=true, socketOutgoing=false, socketFlags=0, socketWaitTime=500, socketHeartbeat=false, socketAcknowledge=false]
org.zeromq.jms.ZmqException: Unable to pass ZMQ message
at org.zeromq.jms.protocol.event.ZmqStompEventHandler.createEvent(ZmqStompEventHandler.java:433)
at org.zeromq.jms.protocol.ZmqSocketSession.receiveSocket(ZmqSocketSession.java:505)
at org.zeromq.jms.protocol.ZmqSocketSession.run(ZmqSocketSession.java:323)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Which is to be expected as the default ZmqEventHandler is
is ZmqSerializeEventHandler and it cannot cope with the 2 part message you a sending. In this it is a 2 part string message that somehow has to be mapped to JMS (one way I assume). See the Json and Protobuf test examples to set event handles.
I spend the coming days fix these issues and providing an examples as, you examples seems very valid, and there are a few other fix others want added.
As a work around create a new SUBSCRIPTION_ALL filter policy and pass it on the URL as the example (but with filter=com.blar.SubscribeAllFilterPolicy (if you do not want to annotate it)
private static final String TOPIC_URI2 = "jms:topic:topic_2?socket.addr=" + TOPIC_ADDR2
+ "&filter=propertyTag&filter.subTags=NASA,APAC&filter.pubPropertyName=Region&event=stomp";
And create an event handle that matches you ZMQ message to who it should look in JMS
regards
Jeremy
… On 21 Jan 2019, at 07:08, mueller-jens ***@***.***> wrote:
I have overridden the ZmqConnectionFactory and the ZmQConnection to overcome this:
ZmqConnectionFactory:
public class ZmqConnectionFactory extends org.zeromq.jms.ZmqConnectionFactory {
private final Map<String, ZmqURI> destinationSchema = new HashMap<String, ZmqURI>();
private String gatewayFactoryClassName = ZmqGatewayFactory.class.getCanonicalName();
private String[] packageNameExtensions = null;
/**
* Construct Zero MQ connection factory.
*/
public ZmqConnectionFactory() {
super();
}
/**
* Construct Zero MQ connection factory with the specified destination URIs.
* @param destinations the destination URIs
*/
public ZmqConnectionFactory(final String[] destinations) {
super(destinations);
}
/**
* Construct Zero MQ connection factory with the specified destination URIs.
* @param gatewayFactoryClassName the class name of the gateway factory
* @param packageNameExtensions the array of packages containing extension to ZERO MQ
* @param destinations the destination URIs
*/
public ZmqConnectionFactory(final String gatewayFactoryClassName, final String[] packageNameExtensions, final String[] destinations) {
super(gatewayFactoryClassName, packageNameExtensions, destinations);
this.gatewayFactoryClassName = gatewayFactoryClassName;
this.packageNameExtensions = packageNameExtensions;
}
/**
* @return return a factory gateway
* @throws ZmqException throws exception when factory construction fails
*/
private ZmqGatewayFactory getFactoryGateway() throws ZmqException {
try {
@SuppressWarnings("unchecked")
final Class<? extends ZmqGatewayFactory> gatewayFactoryClass = (Class<? extends ZmqGatewayFactory>) Class
.forName(gatewayFactoryClassName);
final Constructor<?> gatewayFactoryConstructor = gatewayFactoryClass.getConstructor(String[].class, Map.class);
final ZmqGatewayFactory gatewayFactory = (ZmqGatewayFactory) gatewayFactoryConstructor.newInstance(packageNameExtensions,
destinationSchema);
return gatewayFactory;
} catch (ClassNotFoundException ex) {
throw new ZmqException("Class could not be found.", ex);
} catch (NoSuchMethodException | SecurityException ex) {
throw new ZmqException("Unable to find required constructor for class: " + gatewayFactoryClassName, ex);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new ZmqException("Unable to invoke constructor for class: " + gatewayFactoryClassName, ex);
}
}
@OverRide
public QueueConnection createQueueConnection(final String userName, final String password) throws JMSException {
ZmqGatewayFactory gatewayFactory = getFactoryGateway();
QueueConnection connection = new ZmqConnection(gatewayFactory, destinationSchema);
return connection;
}
@OverRide
public TopicConnection createTopicConnection() throws JMSException {
return createTopicConnection(null, null);
}
@OverRide
public TopicConnection createTopicConnection(final String userName, final String password) throws JMSException {
ZmqGatewayFactory gatewayFactory = getFactoryGateway();
TopicConnection connection = new ZmqConnection(gatewayFactory, destinationSchema);
return connection;
}
@OverRide
public JMSContext createContext() {
return createContext(null, null, ZmqSession.AUTO_ACKNOWLEDGE);
}
@OverRide
public JMSContext createContext(final int sessionMode) {
return createContext(null, null, sessionMode);
}
@OverRide
public JMSContext createContext(final String userName, final String password) {
return createContext(userName, password, ZmqSession.AUTO_ACKNOWLEDGE);
}
@OverRide
public JMSContext createContext(final String userName, final String password, final int sessionMode) {
try {
ZmqGatewayFactory gatewayFactory = getFactoryGateway();
ZmqConnection connection = new ZmqConnection(gatewayFactory, destinationSchema);
ZmqJMSContext context = new ZmqJMSContext(connection, sessionMode);
return context;
} catch (ZmqException ex) {
throw new JMSRuntimeException("Unable to create context.", ex.getErrorCode(), ex);
}
}
ZmqConnection:
public class ZmqConnection extends org.zeromq.jms.ZmqConnection {
public ZmqConnection(ZmqGatewayFactory gatewayFactory, Map<String, ZmqURI> destinationSchema) {
super(gatewayFactory, destinationSchema);
//
}
@OverRide
public void start() throws JMSException {
}
@OverRide
public void stop() throws JMSException {
}
@OverRide
public void close() throws JMSException {
}
}
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#14 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AHOnwIyZ7JFjn_-OAksoQj8gKfwxg-uzks5vFWdtgaJpZM4aIWK6>.
Jeremy Miller commented
Fixed in release 3.0