Hi_im_Tony Hi_im_Tony - 3 months ago 17
Java Question

How to save received messages in separate files with messagelistener

Disk.class implementation

package server;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;

import services.CustomerData;

public class Disk implements MessageListener{

private int index;
private FileWriter f;
private BufferedWriter b;

public Disk(int i){
this.index=i;
try {
f = new FileWriter("disk"+i+".txt",true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
b = new BufferedWriter(f);
}

@Override
public void onMessage(Message m) {
try {
if(m instanceof ObjectMessage){
CustomerData c = (CustomerData) ((ObjectMessage) m).getObject();
b.write(c.getSurname()+" "+c.getName()+" "+c.getAge());
b.newLine();
b.flush();
System.out.println("disk"+index+".txt saved");
}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}


So, what happens is that every message received by every message listener is saved in the same file (the last indexed disk.txt file) but I want to save them in every single file, from 0 to N. N txt files are created but they are not modified except the last one.

EDIT: I added the FileWriter and BufferedWriter in the Disk contructor but it will create N files but modify the last one only.

Main class there Disk is created:

package server;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Hashtable;

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class StorageServer {

public static final int N = 10;

public static void main(String[] args) throws RemoteException {
Hashtable<String,String> prop = new Hashtable<String,String>();
prop.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
prop.put("java.naming.provider.url", "tcp://127.0.0.1:61616");
prop.put("topic.req", "requests");
System.setProperty("org.apache.activemq.SERIALIZABLE_PACKAGES","*");
try {
Context jndiCon = new InitialContext(prop);
TopicConnectionFactory tConnFact = (TopicConnectionFactory) jndiCon.lookup("TopicConnectionFactory");
TopicConnection tConn = tConnFact.createTopicConnection();
TopicSession tSess = tConn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = (Topic) jndiCon.lookup("req");
TopicSubscriber subscriber = tSess.createSubscriber(topic);
tConn.start();
for(int i=0; i<N; i++){
//FileWriter file = new FileWriter("disk"+i+".txt",true);
subscriber.setMessageListener(new Disk(i));
System.out.println("New disk"+i+" started");
}
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

Answer

You have a single TopicSubscriber which has a single MessageListener (hence the setMessageListener and not addMessageListener). You need to create a separate TopicSubscriber for each listener with

for(int i=0; i<N; i++){
    TopicSubscriber subscriber = tSess.createSubscriber(topic);
    subscriber.setMessageListener(new Disk(i));
    System.out.println("New disk"+i+" started");
}

I'd also recommend avoiding using the FileWriter (and FileReader) class, because it uses the platform encoding. This can cause surprises when platform (or its encoding) changes. The equivalent, but longer and safer way is:

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("whatever.txt"), "UTF-8"));

With UTF-8 being a safe encoding to use.