0

I built a 3-tier application with MySQL 5.5, Glassfish 3.1.2 and a stand-alone Swing client (JRE 6_u32). I plan a GUI update service running on the Glassfish server, so that any user currently connected to the application server gets informed when another user creates, modifies or removes an @Entity annotated object.

For that purpose, I plan a session bean that acts as JMS topic producer as soon as any callback method (@PostPersist, @PostUpdate, @PostRemove) is invoked by the entity listener. The stand-alone Swing clients act thereby as JMS message consumers of the topic.

My application consists of 3 projects. First the EJB project witch runs within the server container and holds the facade session beans, a class-library project which holds the @Entity annotated classes and remote facade interfaces (this one is shared by the EJB project and stand-alone swing client for inter-communication purposes) and finally a stand-alone swing client that manages the GUIs. The @Singleton class is part of the classlib project and thus I cannot use dependency injection there. Moreover I think this is exactly the problem, the @Singleton class is NOT container-managed since it's packed in its own jar-lib and being referenced by the EJB project (have to use JNDI lookup).

What kind of Session Bean would you recommend to implement the topic message producer on the application server ? Singleton, Stateful, Stateless, Message-Driven ?

Here's my singelton session bean as it is right now. The problem is, that the @PostConstruct annotated initConnection method is somehow not invoked. The fields 'session' and 'publisher' are null when publishCreated() is being invoked...

Any ideas how to solve this issue ? Many thanks in advance!

@Singleton
public class UpdateService {

    private Destination topic;
    private ConnectionFactory factory;
    private Connection connection;
    private Session session;
    private MessageProducer producer;

    public UpdateService() { }

    @PostConstruct void initConnection() {
        try {
            InitialContext ctx = ServerContext.getInitialContext();
            factory = (TopicConnectionFactory)ctx.lookup("jms/TopicFactory");
            topic = (Topic)ctx.lookup("jms/TopicUpdate");
            connection = factory.createConnection();
            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            producer = session.createProducer(topic);
        } catch (NamingException ex) {
            Logger.getLogger(UpdateService.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        } catch (JMSException ex) {
            Logger.getLogger(UpdateService.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        }
    }

    @PreDestroy void closeConnection() {
        try {
            session.close();
            connection.close();
        } catch (JMSException ex) {
            Logger.getLogger(UpdateService.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        }
    }

    @PostPersist void publishCreated(IUpdateableEntity entity) throws JMSException {
        if(session!=null && producer!=null) {
            ObjectMessage message = session.createObjectMessage(new UpdateMessage(entity, UpdateType.CREATED));
            producer.send(message);
        }
    }

    @PostUpdate void publishUpdated(IUpdateableEntity entity) throws JMSException {
        if(session!=null && producer!=null) {
            ObjectMessage message = session.createObjectMessage(new UpdateMessage(entity, UpdateType.MODIFIED));
            producer.send(message);
        }
    }

    @PostRemove void publishRemoved(IUpdateableEntity entity) throws JMSException {
        if(session!=null && producer!=null) {
            ObjectMessage message = session.createObjectMessage(new UpdateMessage(entity, UpdateType.REMOVED));
            producer.send(message);
        }
    }

}
salocinx
  • 3,715
  • 8
  • 61
  • 110
  • Have you tried adding `@Startup` annotation to your singleton bean. – Nayan Wadekar May 31 '12 at 10:42
  • hi nayan. thanks for your suggestion. I already tried with @Startup, but then an exception is thrown that the connection to the topic cannot be established. Probably because the container tries to instantiate the singleton before the JMS system is started... Any other ideas how to solve the issue? – salocinx May 31 '12 at 15:30

1 Answers1

1

Its server's responsibility to inject the dependencies while initializing the bean. You can try by using annotations to inject these JMS resources.

@Startup
@Singleton
public class UpdateService {

    @Resource(mappedName = "jms/TopicFactory")
    private ConnectionFactory connectionFactory;

    @Resource(mappedName = "jms/TopicUpdate")
    private Topic replyToTestQueue;

    @PostConstruct
    void initConnection() {

          //-- Messaging Configuration 
    }
}

Make sure these resources are properly configured through administration console. I am not used to Glassfish, but I have tried & its working fine.

But, by default all singleton methods are transactional & thread-safe, you can manage concurrency by locking explicitly. Else, you can use stateless bean if it fits well.

Nayan Wadekar
  • 11,444
  • 4
  • 50
  • 73
  • thanks nayan. I forgot to mention an important fact. My application consists of 3 projects. First the EJB project witch runs within the server container, a class-library which holds the entity classes and remote facade interfaces (this one is shared by the EJB & client for inter-communication) and finally a stand-alone swing client. The @ Singleton class is part of the classlib project and thus I cannot use dependency injection there. Moreover I think this is exactly the problem, the @Singleton class is NOT container-managed. Is there another possibility to achieve an automated initialization? – salocinx Jun 03 '12 at 09:58
  • @salocinx As it isn't part of EJB project & not running with any application server, these annotations won't work. I presume classlib is plain java project here. Can't you move singleton to EJB project & classlib acts as mediator between GUI & EJB project. Also I think entity listener is part of EJB project, so from there you can produce message, singleton will also be in same application. – Nayan Wadekar Jun 03 '12 at 16:34
  • @ Nayan. Unfortunately the entity listener is also part of the classlib project, since the @ Entity annotated classes stay in the classlib project for inter-communication purposes between the EJB project and the stand-alone swing client. moving @ Singleton message producer to EJB, leaving entity listener and @ Entity classes in classlib, then calling a business method on the singleton when entity listener triggers an event? or how would you design a mediator in this case? – salocinx Jun 04 '12 at 08:36
  • @salocinx You can send messages from classlib project when events occur, these are consumed by MDB in EJB project which further invokes singleton bean for processing which is in the same application. – Nayan Wadekar Jun 07 '12 at 08:19