/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.cache;

import org.jboss.logging.Logger;
import org.jboss.cache.transaction.DummyTransactionManager;

import javax.transaction.TransactionManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.lang.reflect.Method;

/**
 * A generic class that chooses the best-fit TransactionManager. Tries a number of well-known appservers
 *
 * @author Markus Plesser
 * @version $Id: GenericTransactionManagerLookup.java,v 1.1.4.5 2005/12/01 19:48:40 dimitris Exp $
 */
public class GenericTransactionManagerLookup implements TransactionManagerLookup {

   /**
    * our logger
    */
   private static Logger log=Logger.getLogger(GenericTransactionManagerLookup.class);

   /**
    * lookups performed?
    */
   private static boolean lookupDone=false;

   /**
    * no lookup available?
    */
   private static boolean lookupFailed=false;

   /**
    * the (final) used TransactionManager
    */
   private static TransactionManager tm=null;

   /**
    * JNDI locations for TransactionManagers we know of
    */
   private static String[][] knownJNDIManagers={
      {"java:/TransactionManager", "JBoss, JRun4"},
      {"java:comp/UserTransaction", "Resin, Orion, JOnAS (JOTM)"},
      {"javax.transaction.TransactionManager", "BEA WebLogic"}
   };

   /**
    * WebSphere 5.1 TransactionManagerFactory
    */
   private static final String WS_FACTORY_CLASS_5_1="com.ibm.ws.Transaction.TransactionManagerFactory";

   /**
    * WebSphere 5.0 TransactionManagerFactory
    */
   private static final String WS_FACTORY_CLASS_5_0="com.ibm.ejs.jts.jta.TransactionManagerFactory";

   /**
    * WebSphere 4.0 TransactionManagerFactory
    */
   private static final String WS_FACTORY_CLASS_4="com.ibm.ejs.jts.jta.JTSXA";

   /**
    * Get the systemwide used TransactionManager
    *
    * @return TransactionManager
    */
   public TransactionManager getTransactionManager() {
      if(!lookupDone)
         doLookups();
      if(tm != null)
         return tm;
      if(lookupFailed) {
         //fall back to a dummy from JBossCache
         tm=DummyTransactionManager.getInstance();
         log.warn("Falling back to DummyTransactionManager from JBossCache");
      }
      return tm;
   }


   /**
    * Try to figure out which TransactionManager to use
    */
   private static void doLookups() {
      if(lookupFailed)
         return;
      InitialContext ctx;
      try {
         ctx=new InitialContext();
      }
      catch(NamingException e) {
         log.error("Could not create an initial JNDI context!", e);
         lookupFailed=true;
         return;
      }
      //probe jndi lookups first
      Object jndiObject=null;
      for(int i=0; i < knownJNDIManagers.length; i++) {
         try {
            if(log.isDebugEnabled()) log.debug("Trying to lookup TransactionManager for " + knownJNDIManagers[i][1]);
            jndiObject=ctx.lookup(knownJNDIManagers[i][0]);
         }
         catch(NamingException e) {
            log.info("Failed to perform a lookup for [" + knownJNDIManagers[i][0] + " (" + knownJNDIManagers[i][1] + ")]");
         }
         if(jndiObject instanceof TransactionManager) {
            tm=(TransactionManager)jndiObject;
            log.info("Found TransactionManager for " + knownJNDIManagers[i][1]);
            return;
         }
      }
      //try to find websphere lookups since we came here
      Class clazz;
      try {
         log.debug("Trying WebSphere 5.1: " + WS_FACTORY_CLASS_5_1);
         clazz=Class.forName(WS_FACTORY_CLASS_5_1);
         log.info("Found WebSphere 5.1: " + WS_FACTORY_CLASS_5_1);
      }
      catch(ClassNotFoundException ex) {
         try {
            log.debug("Trying WebSphere 5.0: " + WS_FACTORY_CLASS_5_0);
            clazz=Class.forName(WS_FACTORY_CLASS_5_0);
            log.info("Found WebSphere 5.0: " + WS_FACTORY_CLASS_5_0);
         }
         catch(ClassNotFoundException ex2) {
            try {
               log.debug("Trying WebSphere 4: " + WS_FACTORY_CLASS_4);
               clazz=Class.forName(WS_FACTORY_CLASS_4);
               log.info("Found WebSphere 4: " + WS_FACTORY_CLASS_4);
            }
            catch(ClassNotFoundException ex3) {
               log.info("Couldn't find any WebSphere TransactionManager factory class, neither for WebSphere version 5.1 nor 5.0 nor 4");
               lookupFailed=true;
               return;
            }
         }
      }
      try {
         Method method=clazz.getMethod("getTransactionManager", null);
         tm=(TransactionManager)method.invoke(null, null);
      }
      catch(Exception ex) {
         log.error("Found WebSphere TransactionManager factory class [" + clazz.getName() +
                   "], but couldn't invoke its static 'getTransactionManager' method", ex);
      }
   }

}
