How to configure jpos channel header with spaces - iso8583

I came across an issue, when the jpos channel header string has spaces. I configured that in the channel adaptor configuration as below, but when I start the Q2 server, it seems it trims the header value. As a result of that, I'm not getting any response from the jpos server for certain requests.
<channel-adaptor class="org.jpos.q2.iso.ChannelAdaptor" logger="Q2" name="my-channel">
<channel class="CBCChannel" logger="Q2"
packager="org.jpos.iso.packager.GenericPackager" header="ISOHEADER ">
<property name="packager-config" value="/path/to/PACKAGER/iso87ascii.xml" />
<property name="host" value="xxx.xx.xx.xx"/>
<property name="port" value="yyyy" />
</channel>
<in>channel-send</in>
<out>channel-receive</out>
<property name="timeout" value="300000" />
<property name="keep-alive" value="true" />
<reconnect-delay>10000</reconnect-delay>
</channel-adaptor>
The CBCChannel just extends the RawChannel
public class CBCChannel extends RawChannel {
public CBCChannel() throws ISOException {
}
public CBCChannel(String host, int port, ISOPackager p, byte[] header) {
super(host, port, p, header);
}
public CBCChannel(ISOPackager p, byte[] header) throws IOException {
super(p, header);
}
public CBCChannel(ISOPackager p, byte[] header, ServerSocket serverSocket) throws IOException {
super(p, header, serverSocket);
}
}
Is there any way to configure channel header which contains spaces without neglecting the spaces?

I guess you only need to override setHeader method:
public CBCChannel extends RawChannel {
....
public void setHeader(String header){
super.setHeader(header.getBytes());
}
}
But you would only be doing what BaseChannel does in regard to the header. Are you sure you need a RawChannel based channel?

Related

Spring AMQP application configuration from XML to Java

I'm struggling with rewriting RabbitMQ application configuration from XML to Java. Sadly once the code is executed, quite general error appears:
org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException:
Failed to invoke target method 'receiveMessage' with
argument type = [class [B], value = [{[B#3bd0e47}]
...
Caused by: java.lang.NoSuchMethodException: com.mycompany.MessageListener.receiveMessage([B)
Application works if I base my configuration on XML, listed below.
I tried to rewrite it, basing on Spring Integration, AMQP, Rabbit documentation. Nevertheless, spring configuration documentation is mostly xml based, hence my question.
XML conf:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/integration/amqp
http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<rabbit:connection-factory id="connectionFactory" host="mycompany-host"
username="mycompany-username"
password="mycompany-password"
virtual-host="mycompany-vhost"/>
<rabbit:template id="mycompany-template" connection-factory="connectionFactory" />
<rabbit:admin id="admin" connection-factory="connectionFactory" />
<!-- ##### -->
<rabbit:queue id="queue-id" name="queue-name" declared-by="admin"/>
<rabbit:direct-exchange name="mycompany-incoming-events" declared-by="admin">
<rabbit:bindings>
<rabbit:binding queue="queue-name" key="" />
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- ##### -->
<int-amqp:inbound-channel-adapter channel="mycompany-channel"
queue-names="queue-name" connection-factory="connectionFactory" />
<int:chain input-channel="mycompany-channel">
<int:transformer>
<bean class="com.mycompany.MyCompanyParser"/>
</int:transformer>
<int:filter expression="payload.header != null"/>
<int:transformer>
<bean class="com.mycompany.MyCompanyHeaderEnricher"/>
</int:transformer>
<int:recipient-list-router>
<int:recipient channel="dataSubmittedChannel"/>
</int:recipient-list-router>
</int:chain>
<int:chain input-channel="dataSubmittedChannel">
<int:filter expression="headers.mycompany_enriched_header.name().equals('MY_COMPANY_CONSTRAINT')" />
<int:service-activator>
<bean class="com.mycompany.MessageListener"/>
</int:service-activator>
</int:chain>
</beans>
Java listener:
#Component
public class MessageListener {
public void receiveMessage(final MyCompanyParsedType msg){
System.out.println(msg.toString());
}
}
After some rewriting I managed to came up with this Java based configuration:
import com.nxcs3.gamefetcher.configuration.SampleConfiguration;
import com.nxcs3.gamefetcher.listener.GameMessageListener;
import nxcs.drept.nxcs2events.EventHeadersEnricher;
import nxcs.drept.nxcs2events.EventParser;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter;
import org.springframework.integration.dsl.IntegrationFlow;
#SpringBootApplication
public class MyCompanySpringBootApp {
public static final String MESSAGE_QUEUE = "queue-name";
public static final String MESSAGE_EXCHANGE = "mycompany-incoming-events";
public static void main(String[] args) {
SpringApplication.run(MyCompanySpringBootApp.class);
}
#Bean
public DirectExchange exchange(){
return new DirectExchange(MESSAGE_EXCHANGE);
}
#Bean
public Queue queue(){
return new Queue(MESSAGE_QUEUE, true);
}
#Bean
public Binding binding(Queue queue){
return BindingBuilder.bind(queue).to(exchange()).with(MESSAGE_QUEUE);
}
#Bean
MessageListenerAdapter listenerAdapter(MessageListener receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
#Bean
public IntegrationFlow flow(){
return f -> f.log()
.transform(new MyCompanyParser())
.filter("payload.header != null")
.transform(new MyCompanyHeaderEnricher())
.filter("headers.mycompany_enriched_header.name().equals('MY_COMPANY_CONSTRAINT')");
}
#Bean
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(MESSAGE_QUEUE);
container.setMessageListener(listenerAdapter);
return container;
}
}
I supply connection details through yaml.
As I mentioned previously, I clearly miss something.
Any ideas where did the configuration went wrong?
Added section after comments, proposed solution:
So I removed MessageListenerAdapter and replaced it using AmqpInboundChannelAdapter and #ServiceActivator
Result would look like:
#SpringBootApplication
public class MyCompanySpringBootApp {
public static final String MESSAGE_QUEUE = "queue-name";
public static final String MESSAGE_EXCHANGE = "mycompany-incoming-events";
public static void main(String[] args) {
SpringApplication.run(MyCompanySpringBootApp.class);
}
#Bean
public DirectExchange exchange(){
return new DirectExchange(MESSAGE_EXCHANGE);
}
#Bean
public Queue queue(){
return new Queue(MESSAGE_QUEUE, true);
}
#Bean
public Binding binding(Queue queue){
return BindingBuilder.bind(queue).to(exchange()).with(MESSAGE_QUEUE);
}
#Bean
public AmqpInboundChannelAdapter
channelAdapter(SimpleMessageListenerContainer container){
AmqpInboundChannelAdapter amqpInboundChannelAdapter = new
AmqpInboundChannelAdapter(container);
amqpInboundChannelAdapter.setOutputChannelName("adapter");
return amqpInboundChannelAdapter;
}
#Bean
public MessageListener handler(){
return new MessageListener();
}
#Bean
public IntegrationFlow flow(){
return f -> f.log()
.transform(new MyCompanyParser())
.filter("payload.header != null")
.transform(new MyCompanyHeaderEnricher())
.filter("headers.mycompany_enriched_header.name().equals('MY_COMPANY_CONSTRAINT')");
}
#Bean
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(MESSAGE_QUEUE);
container.setMessageListener(listenerAdapter);
return container;
}
}
and listener:
#Component
public class MessageListener {
#ServiceActivator(inputChannel = "adapter")
public void receiveMessage(final MyCompanyParsedType msg){
System.out.println(msg.toString());
}
}
Which brings us a little bit closer, because messages are being accepted and processed inside of receiveMessage method.
However somehow coming messages do not pass through IntegrationFlow filters. Messages appear to be totally random. I added imports
The MessageListenerAdapter uses a SimpleMessageConverter by default.
And its logic is based on the presence of the contentType property.
According to your error, that sounds like there is no this property in the consumed message, therefore it falls back to the message.getBody(), which is byte[] anyway.
You may consider to specify a desired MessageConverter into that MessageListenerAdapter, e.g. SerializerMessageConverter with the ignoreContentType = true.

Bugs about Spring Redis Template or Redis?

This issue almost driven me crazy! I use spring Redis template as the Redis client portal to manage my cache items in Redis. Recently I try to store some important data in it (expire time is about 60s) , but sometimes ( occasionally) it is deleted after several seconds without any sign! I check my code again and again, no other delete entries. I took many experiments and only a litter of cause was found:
1. when the my web application started, during about the fore five minutes, the phenomenon occurs frequently (probability is about 1/3), but after that time, everything is ok.
2. Retrieving the data immediately after set is always right, even in the error situation. But after several seconds, it disappears. Yes you may think of that there must be some other delete operations exists in my codes. I have check it very carefully, and the answer is no :(.
My spring-redis.xml's content is as following:
<bean id="parentJedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" abstract="true"
p:timeout="50"
p:database="0">
<constructor-arg index="0" ref="sentinelConfig"/>
<constructor-arg index="1" ref="jedisPoolConfig"/>
</bean>
<bean id="jedisConnFactory" parent="parentJedisConnFactory" />
<bean id="nullSupportedRedisCacheTemplate"
class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnFactory">
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="com.***.KryoRedisSerializer"/>
</property>
</bean>
And below is the Redis client implement:
#Repository("redisCache")
public class RedisCache implements Cache{
#Autowired
#Qualifier("nullSupportedRedisCacheTemplate")
private RedisTemplate<String, Object> nullSupportedRedisCacheTemplate;
private ValueOperations<String, Object> opsValue;
#PostConstruct
public void init(){
opsValue = nullSupportedRedisCacheTemplate.opsForValue();
}
#Override
public <T> void set(String key, T obj) {
set(key, obj, StaticConfiguration.DEFAULT_EXPIRE_TIME);
}
#Override
public <T> void set(String key, T obj, long expireTime) {
opsValue.set(key, obj, expireTime, TimeUnit.MILLISECONDS);
nullSupportedRedisCacheTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
}
#SuppressWarnings("unchecked")
#Override
public <T> T get(String key) {
return (T) opsValue.get(key);
}
#Override
public void remove(String key) {
nullSupportedRedisCacheTemplate.delete(key);
}
#Override
public <T> void asynSet(String key, T obj) {
asynSet(key, obj, StaticConfiguration.DEFAULT_EXPIRE_TIME);
}
#Override
public <T> void asynSet(String key, T obj, long expireTime) {
opsValue.set(key, obj, expireTime, TimeUnit.MILLISECONDS);
nullSupportedRedisCacheTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
}
#Override
public void asynRemove(String key) {
nullSupportedRedisCacheTemplate.delete(key);
}
#Override
public boolean contain(String key) {
return nullSupportedRedisCacheTemplate.hasKey(key);
}
}
Or you may doubt that the memory is full and maxmemmory-policy delete the key automatically. However according to the ops man's feedback, the peak memory of Redis is about 500M while the max memory of Redis is set as 4G.
Any cause or analysis from you will be highly appreciated :)

How Register multiple message listner in RabbitMQ (Spring AMQP)

I am new to rabbitmq. I am using spring-rabbit 1.3.5 Release.
I want to register multiple message listner. How to do that?
I can register a single message listner.
Here is my code:
1)Interface which extends MessageListner interface
public interface MessageQueueManager extends MessageListener{
public String createQueue(String queueName);
public void sendMessage(String message, String destinationQueueName) throws Exception;
}
2) Here is the implementation:
#Service("messageQueueManager")
public class MessageQueueManagerImpl implements MessageQueueManager {
#Autowired
private AmqpAdmin admin;
#Autowired
private AmqpTemplate template;
#Autowired
private ConnectionFactory connectionFactory;
#Autowired
private SimpleMessageListenerContainer container;
#Override
public void onMessage(Message message) {
// Different message can behave differently.
}
#Override
public String createQueue(String queueName) {
// survive a server restart
boolean durable = true;
// keep it even if nobody is using it
boolean autoDelete = false;
boolean exclusive = false;
// create queue
Queue newQueue = new Queue(queueName, durable, exclusive, autoDelete);
queueName = admin.declareQueue(newQueue);
// create binding with exchange
// Producer sends to an Exchange and a Consumer receives from a Queue, the bindings that connect Queues to Exchanges are critical for connecting those producers and consumers via messaging.
/*admin.declareBinding(new Binding(queueName, DestinationType.QUEUE,
"directExchange", queueName, new HashMap<String, Object>()));*/
Binding binding = BindingBuilder.bind(newQueue).to(DirectExchange.DEFAULT).with(queueName);
admin.declareBinding(binding);
// add queue to listener
container.addQueues(newQueue);
// start listener
container.start();
return queueName;
}
#Override
public void sendMessage(String message, String destinationQueueName)
throws Exception {
template.convertAndSend("directExchange", destinationQueueName,
MessageBuilder.withBody(message.getBytes()).build());
}
}
3)Listner register in applicationContext.xml file
<!-- Listener container for setting up concurrent listeners for queues -->
<bean id="simpleMessageListenerContainer"
class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<constructor-arg index="0" ref="connectionFactory" />
<property name="missingQueuesFatal" value="false" />
<property name="concurrentConsumers" value="5" />
<property name="autoStartup" value="false" />
<property name="messageListener" ref="messageQueueManager" />
</bean>
So here SimpleMessageListenerContainer class can take only one messageListner. Do I need to declare multiple SimpleMessageListenerContainer instance to register different messageListner?
I want to register this class as a message listner.
#Service("myMessageListener")
public class MessageHandler implements MessageListener {
#Override
public void onMessage(Message message) {
log.info("Received message: " + message);
log.info("Text: " + new String(message.getBody()));
}
}
1)Register your queues:
<rabbit:queue id="spring.queue" auto-delete="false" durable="true" exclusive="false" name="spring.queue"/>
<rabbit:queue id="user.login.notification" auto-delete="false" durable="true" exclusive="false" name="user.login.notification"/>
2)Declare the bindings:
<rabbit:direct-exchange name="directExchange" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="spring.queue" key="spring.queue" />
<rabbit:binding queue="user.login.notification" key="user.login.notification MAIYAM" />
</rabbit:bindings>
</rabbit:direct-exchange>
3)Tell the container to call onMessage(Message message) method when the any of the queue publishes the message.
<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="auto" concurrency="10"
requeue-rejected="true">
<rabbit:listener ref="myMessageListener" queues="spring.queue" />
<rabbit:listener ref="messageQueueManager" queues="user.login.notification" />
</rabbit:listener-container>
4)Remove private SimpleMessageListenerContainer container; from MessageQueueManagerImpl class.
Now it should work.

Enabling connection pooling with HSQLDB and Spring embedded database

Recently, I have been trying to implement an in-memory database based on HSQLDB for one of our applications which uses Oracle DB in the production. The application uses spring framework. However, I have to implement the data-source bean programmatically as we are using the existing SQL DDL statements(Oracle queries) and so have to programmatically remove constructs like namespaces before they can run on HSQLDB.
I initialize the database using EmbeddedDatabaseBuilder(ResourceLoader).
Now my issue is that I now want to add connection pooling using say c3p0 to this.
Normally I would be using
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="HSQLDB driver path" /> (this is just for representation)
<property name="jdbcUrl" value="${xxx.jdbcUrl}" />
<property name="user" value="${xxx.username}" />
<property name="password" value="${xxx.password}" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="3" />
<property name="maxIdleTime" value="20" />
</bean>
However, I am confused as to how I can define this while using the Spring embedded database.
Disclaimer: I am really new to spring.
Following this link:
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
public static ComboPooledDataSource newDefaultDS() {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setMinPoolSize(1);
dataSource.setMaxPoolSize(1);
dataSource.setMaxIdleTime(20);
return dataSource;
}
}
import java.beans.PropertyVetoException;
import java.sql.Driver;
import org.springframework.jdbc.datasource.embedded.ConnectionProperties;
import org.springframework.jdbc.datasource.embedded.DataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class ComboPoolDataSourceFactory implements DataSourceFactory,
ConnectionProperties {
private final ComboPooledDataSource dataSource;
public ComboPoolDataSourceFactory() {
this(C3P0Utils.newDefaultDS());
}
public ComboPoolDataSourceFactory(ComboPooledDataSource dataSource) {
assert dataSource != null;
this.dataSource = dataSource;
}
public ConnectionProperties getConnectionProperties() {
return this;
}
public ComboPooledDataSource getDataSource() {
return dataSource;
}
public void setUsername(String username) {
dataSource.setUser(username);
}
public void setPassword(String password) {
dataSource.setPassword(password);
}
public void setUrl(String url) {
dataSource.setJdbcUrl(url);
}
public void setDriverClass(Class<? extends Driver> driverClass) {
try {
dataSource.setDriverClass(driverClass.getName());
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
}
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
public class EmbeddedC3P0DatabaseBuilder extends EmbeddedDatabaseBuilder {
public EmbeddedC3P0DatabaseBuilder() {
setDataSourceFactory(new ComboPoolDataSourceFactory());
}
}
And a short usage example:
EmbeddedC3P0DatabaseBuilder builder = new EmbeddedC3P0DatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.H2)
.addScript("setup-tables.sql")
.build();
JdbcTemplate template = new JdbcTemplate(db);
....
db.shutdown();

NServiceBus Simple Retry Mechanism, how do I debug (based on AsyncPages sample)

Hi
I have a website where a user signs up we need to add them to a legacy system via a soap webservice call. these webservice calls are queue'd for retry asynchronously...
I have copied the AsyncPages sample from the NServiceBus download.
However the messages seem to flit in and out of the queue without being handled (nor are they put on the error queue). (the message shows in the journal)
my website is configured like so:
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="FooComMessages" Endpoint="FooComSignupService"/>
</MessageEndpointMappings>
</UnicastBusConfig>
And I have this test code on a button click:
Global.Bus.Send(new CreateMemberContractRequest[]
{new CreateMemberContractRequest()
{birthdate = DateTime.Parse("4 oct 1975")}
}
);
My message:
namespace FooComMessages
{
[Serializable]
public class CreateMemberContractRequest : IMessage
{
public DateTime birthdate { get; set; }
//.... snip....//
}
}
My Handler Config:
<MsmqTransportConfig InputQueue="FooComSignupService" ErrorQueue="FooComSignupServiceErrors" NumberOfWorkerThreads="1" MaxRetries="20" />
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="FooComMessages" Endpoint="FooComSignupService" />
</MessageEndpointMappings>
</UnicastBusConfig>
My Handler Code:
namespace FooComSignupService
{
public class CreateMemberContractRequestHandler : IHandleMessages<CreateMemberContractRequest>
{
public IBus Bus { get; set; }
private static readonly ILog Logger = LogManager.GetLogger(typeof(CreateMemberContractRequestHandler));
public void Handle(CreateMemberContractRequest message)
{
Logger.Info("------------------------------------\nHandling CreateMemberContractRequest. id="+message.webdatabaseid);
throw new NotImplementedException();
}
}
}
EDIT:
I'm using NServiceBus.Host.exe to host the FooComSignupService
Does anyone have any idea what I could be doing wrong?
I can't hit any breakpoints in the Handle method either.
Cheers.
Murray.