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);
}
}
}
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.