2

I have some architecture question. I develop a wicket web-app running on glassfish appserver, there is some ejb module, etc. To create chat panel I would like to use some kind of JMS, for example Apache ActiveMQ to avoid continuous polling. I made 2 kind of handlers Sender and Receiver. Both of them has ConnectionFactory, Connecton, Session. Chat panels represents chat rooms, and each chat rooms is a Topic. (when you open a chat panel with choosen 'room', you logically subscribe the given topic.) Panels are implements MessageListener interface, so panels are listeners of consumer in Receiver object.

So panels sends messages to their topics within their Sender object, and listens them through their Receiver object. (Yeah, every panel has a Sender and a Receiver object too)

In this way there is 2 connections/panel and nobody care about close those connections at all. :(

I don't think it's a good way to use activemq. I need some advice to implement this function. Could you please give me some instruction, how experts do this? Or maybe which direction I have to go?

architecture

(ps, AMQ has running totally standalone)

Sender,

public class Sender {

    private String user = ActiveMQConnection.DEFAULT_USER;
    private String password = ActiveMQConnection.DEFAULT_PASSWORD;
    private String url = "failover://(tcp://0.0.0.0:61616)?randomize=false";

    private Destination destination;
    private Connection connection = null;
    private Session session = null;
    private ActiveMQConnectionFactory connectionFactory;
    private MessageProducer producer;

    public Sender(String topicId) {
        try {
            connectionFactory = new ActiveMQConnectionFactory(user, password, url);
            connectionFactory.setDispatchAsync(false);

            connection = connectionFactory.createTopicConnection(user, password);
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            destination = session.createTopic(topicId);

            producer = session.createProducer(destination);
        } catch (JMSException ex) {
            Logger.getLogger(Sender.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println(ex.toString());
        }
    }

    public void sendMessage(String message) {
        try {
            BytesMessage message = session.createBytesMessage();
            message.setLongProperty("text", message);
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            producer.send(destination, message);
        } catch (JMSException ex) {
            Logger.getLogger(Sender.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void close() {
        try {
            producer.close();
            session.close();
            connection.close();
        } catch (JMSException ex) {
            Logger.getLogger(Sender.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Receiver,

public class Receiver {
    private String url = "failover://(tcp://0.0.0.0:61616)?randomize=false";

    private ActiveMQConnectionFactory connectionFactory;
    private Connection connection;
    private Session session = null;
    private Topic destination = null;
    private TopicSubscriber consumer;
    private IdGenerator clientIdGenerator = new IdGenerator();

    public Receiver(String topicId, MessageListener listener) {
        try {
            connectionFactory = new ActiveMQConnectionFactory(url);
            connectionFactory.setDispatchAsync(false);

            connection = connectionFactory.createTopicConnection();
            connection.setClientID(clientIdGenerator.generateId());
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            destination = session.createTopic(topicId);
            consumer = session.createDurableSubscriber(destination, "subscriber");
            consumer.setMessageListener(listener);
        } catch (JMSException ex) {
            Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void close() {
        try {
            consumer.close();
            session.close();
            connection.close();
        } catch (JMSException ex) {
            onException(ex);
            Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
Joe F
  • 4,174
  • 1
  • 14
  • 13
Victor
  • 325
  • 4
  • 12

1 Answers1

0

To create chat panel i would like to use some kind of JMS, for example Apache ActiveMQ to avoid continuous polling.

The setup you describe would still need continuous polling! Your ChatPanels are server-side Wicket components. You would still have to get the chat data from those server-side Wicket components to the client (browser), which needs continuous polling via Javascript. You could implement your own Wicket behavior that does exactly that, but it's polling nonetheless.

If you want to avoid continuous polling altogether you would have to go for WebSockets. Wicket has an experimental module for websocket support (https://cwiki.apache.org/confluence/display/WICKET/Wicket+Native+WebSockets). However, websocket doesn't work on older browsers.

Tom
  • 3,913
  • 19
  • 28
  • so i just can leave AMQ and use new AbstractAjaxTimerBehavior(Duration.milliseconds(300)){ @Override protected void onTimer(AjaxRequestTarget art){}}); to check new messages? – Victor Jun 28 '13 at 18:54
  • I thought if TopicSubscriber has MessageListener, it get notification when new messages has arrived and that's all communication. My onMessage(Message message) (method of MessageListener) got messages from Topic when one was sent. – Victor Jun 28 '13 at 19:02
  • Yes, your subscriber will be notified when new messages arrive. But you have no way of sending this message from your ChatPanel to the users browsers. The way with AbstractAjaxTimerBehavior in your comment would definitely work! But you have to be aware that the browsers will poll your server. – Tom Jun 28 '13 at 19:04
  • I store messages in datastore, and activeMQ message contains only id of DBMessage, so in onMessage(Message message) i can find DBMessage by id from database, and somehow i can refresh wicket page by AjaxReqeuestTarget – Victor Jun 28 '13 at 19:08
  • To sum up, do you suggest just leave AMQ and use TimerBehavior? why i have to be aware that the browsers will poll my server? What is the best way to solve this situation ? – Victor Jun 28 '13 at 19:09
  • Yes, that's my advice. You won't be able to "somehow refresh the wicket page by AjaxRequestTarget" without having a browser sending a request to you Wicket application. – Tom Jun 28 '13 at 19:22
  • what if 1500 user with 10 chatroom (chatpanel) (so 15.000 AbstractAjaxTimerBehavior) sends request to server in every 300 milliseconds (3 times in a second) i'm afraid it's too much doesn't it ? – Victor Jun 28 '13 at 19:32
  • well, it's maybe not answer my question, but could be solution of my problem. – Victor Jun 29 '13 at 09:40