package jifx.transactionManager;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
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.management.AttributeChangeNotification;
import javax.management.AttributeChangeNotificationFilter;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import jifx.commons.messages.IMessage;
import jifx.transactionManager.configurator.Configurator;
import jifx.transactionManager.configurator.ConfiguratorMBean;
import jifx.transactionManager.transaction.TMInformation;
import jifx.transactionManager.transaction.Transaction;
import jifx.transactionManager.transaction.TransactionInformation;
import jifx.transactionManager.transaction.TransactionTimeOut;
import org.apache.log4j.Logger;
/**
* The Transaction Manager has the responsibility of solving
* all the incoming requests from a client through an specific
* channel, and to assign the work to the corresponding entity
* in a transactional way.
*/
public class TransactionManager implements Runnable , NotificationListener {
static Logger logger = Logger.getLogger(TransactionManager.class);
private boolean activate;
private String jndi;
private TMInformation tmInformation;
private Configurator configurator;
public TransactionManager (String jndi, TMInformation tmInformation, Configurator configurator){
activate = true;
this.jndi = jndi;
this.tmInformation = tmInformation;
this.configurator = configurator;
}
/**
* Runs the TM. It will wait until a message is received. (Active waiting)
*/
public void run() {
Context jndiContext = null;
TopicConnectionFactory connectionFactory = null;
TopicConnection connection = null;
try {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.NamingContextFactory");
env.put(Context.PROVIDER_URL, jndi);
// Create a JNDI InitialConte1xt object if none exists yet.
jndiContext = new InitialContext(env);
// Look up connection factory and topic.
connectionFactory = (TopicConnectionFactory)jndiContext.lookup("TopicConnectionFactory");
Topic reqTopic = (Topic) jndiContext.lookup(tmInformation.getReqtopic());
// Establish Connection and Session
connection = connectionFactory.createTopicConnection();
TopicSession session = connection.createTopicSession (false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber topicSuscriber = session.createSubscriber(reqTopic, "owner='"+tmInformation.getIdtrn()+"'",false);
// TopicSubscriber topicSuscriber = session.createDurableSubscriber (reqTopic, this.toString(),"owner='"+tmInformation.getIdtrn()+"'",false);
connection.start();
// se queda escuchando por un mensaje
// waits for a message
while(activate) {
Message msg = topicSuscriber.receive(1000);
if (msg != null && activate) {
onMessage(msg);
}
}
if (!activate){
//session.unsubscribe(this.toString());
topicSuscriber.close();
connection.close();
}
} catch (NamingException e) {
logger.error(tmInformation.getIdtrn()+"| "+e.getMessage()+"|");
e.printStackTrace(System.out);
} catch (JMSException e) {
logger.error(tmInformation.getIdtrn()+"| "+e.getMessage()+"|");
e.printStackTrace(System.out);
} finally {
if (jndiContext != null) {
try {
jndiContext.close();
} catch (Exception e) {
logger.error(tmInformation.getIdtrn()+"|"+e.getMessage()+"|");
}
}
}
}
/**
* Method invoked when a message is received by the transaction manager.
* @param message: message received by the TM and wants to be
*/
private void onMessage(Message message) {
try {
IMessage m = (IMessage)((ObjectMessage)message).getObject();
if (logger.isDebugEnabled())
logger.debug(tmInformation.getIdtrn()+"|Mensaje recibido por el Trans.Manager|"+m.toString());
TransactionInformation ti = tmInformation.getTransactionInformation(m);
String trnName = tmInformation.getIdtrn()+"-" + new GregorianCalendar().getTimeInMillis();
Transaction trn = new Transaction(trnName, ti , message.getStringProperty("connection"));
AttributeChangeNotificationFilter nf = new AttributeChangeNotificationFilter();
nf.enableAttribute("TMState");
configurator.addNotificationListener((NotificationListener) trn, nf, this);
trn.setMessage(m);
new TransactionTimeOut(trn,ti.getTimeOut());
}catch (Exception e){
logger.error(tmInformation.getIdtrn()+"|"+e.getMessage()+"|");
}
}
/**
* Method invoked when a sendNotification event is invoked. This method should handle
* this notification. At this point of the project we are testing some functionality of this
* class.
* In future: would be important if we manage some changes at so variables or something global
* that might be notificated.
*/
public void handleNotification(Notification notification, Object handback) {
if (logger.isDebugEnabled())
logger.debug(tmInformation.getIdtrn()+"|Evento handleNotification de Transaction Manager|");
AttributeChangeNotification at = (AttributeChangeNotification)notification;
if (at.getAttributeName().equals("TMState"))
switch((ConfiguratorMBean.TMState)at.getNewValue()) {
case STOPED:
setActivate(false);
logger.info(tmInformation.getIdtrn()+"| Detenido.|");
break;
case ACTIVE:
setActivate(true);
break;
}
}
/**
* Method which returns if TM is activated.
* @return
*/
public boolean isActivate() {
return activate;
}
/**
* Method which sets the activation of the TM
* @param activate
*/
public void setActivate(boolean activate) {
this.activate = activate;
}
}