Package org.objectweb.speedo.jca

Source Code of org.objectweb.speedo.jca.SpeedoManagedConnectionFactory

/**
* perseus/connector: this is an implementation of some JCA-related technologies
* (resource adapters and managers) for the ObjectWeb consortium.
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Contact: speedo@objectweb.org
*
*/

package org.objectweb.speedo.jca;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;
import org.objectweb.util.monolog.api.Loggable;
import org.objectweb.util.monolog.Monolog;
import org.objectweb.util.monolog.wrapper.printwriter.LoggerImpl;
import org.objectweb.speedo.api.Debug;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.api.ExceptionHelper;
import org.objectweb.speedo.pm.api.POManagerItf;
import org.objectweb.speedo.pm.api.POManagerFactoryItf;

import java.io.PrintWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.File;
import java.io.InputStream;
import java.io.FileNotFoundException;
import java.util.Set;
import java.util.Properties;
import java.util.HashMap;
import java.util.Iterator;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionFactory;
import javax.security.auth.Subject;
import javax.transaction.TransactionManager;
import javax.transaction.xa.Xid;
import javax.transaction.xa.XAException;
import javax.jdo.JDOHelper;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
* @author  P. Dechamboux
*/
public abstract class SpeedoManagedConnectionFactory
        implements ManagedConnectionFactory,
        SpeedoAttributeController {

    private final static String[] DEFAULT_JNDI_NAMES = {
        "javax.transaction.UserTransaction",   //JOnAS
    "javax.transaction.TransactionManager", //WebLogic
    "java:/TransactionManager",       //JBoss
    "jta/usertransaction",               //WebSphere
        "java:comp/UserTransaction"         //Orion
    };

    /**
     * The logger into which traces about SpeedoManagedConnectionFactory are
     * produced.
     */
    private Logger logger;
    /**
     * It is assumed that only one ConnectionFactory is actually created by
     * a ManagedConnectionFactory.
     */
    protected SpeedoConnectionFactory connectionFactory;
    /**
     * For creating all loggers related to JDO and its adapter.
     */
    private LoggerFactory loggerFactory = null;
    /**
     * The factory for managing JDO transaction contexts.
     */
    public POManagerFactoryItf pmf = null;

    /**
     * The name of the property file of the PersistenceManagerFactory associated
     * with this JDO connector.
     */
    private String propertiesFileName = null;
    /**
     * The factory for managing JDO transaction contexts.
     */
    private ConnectionManager connectionManager = null;

    private PrintWriter printWriter = null;

    public boolean started = false;

    /**
     * the JNDI Name of the transaction manager
     */
    private String tmName = null;

    protected TransactionManager tm = null;

  /**
   * The hashed structure that stores JdoTransaction that have been associated
   * with a particular XID.
   */
  private HashMap xid2xac = new HashMap();

  /**
   * This abstract method is used to create a ConnectionFactory. It should be
   * implemented by the ManagedConnectionFactory associated with the actual
   * implementation of the JCA driver (either for JDO or for EJB).
   */
  protected abstract SpeedoConnectionFactory createConnectionFactory(Logger l,
      SpeedoManagedConnectionFactory fmcf,
      ConnectionManager cm,
      byte transactionMode) throws ResourceException;
 
    /**
     * Lookup in JNDI the transaction manager under the name specified in
     * parameter. The 'tm' variable is assigned if the transaction manager is
     * found.
     * @param name is the jndi name
     * @return true if an instance implementing
     * javax.transaction.TransactionManager is availlable in JNDI, otherwise
     * false.
     */
    private boolean lookupTM(String name) {
    InitialContext ictx = null;
        try {
      ictx = new InitialContext();
            Object o = ictx.lookup(name);
            if (o == null) {
                logger.log(BasicLevel.WARN,
                        "JNDI retrieves a null value for the name '" + name + "'.");
            }
            if (!(o instanceof TransactionManager)) {
                logger.log(BasicLevel.WARN,
                        "JNDI retrieves an object which is not a javax.transaction.TransactionManager (JNDI name: " + name + "): " + o);
                return false;
            }
            tm = (TransactionManager) o;
            logger.log(BasicLevel.INFO, "The TransactionManager was found in JNDI with the name '" + name + "'.");
            return true;
        } catch (Exception e) {
            logger.log(BasicLevel.WARN,
                    "Error when lookup the transaction manager in JNDI with the name '"
                    + name + "'", e);
            return false;
        } finally {
      if (ictx != null) {
        try {
          ictx.close();
        } catch (NamingException e) {
        }
      }
    }
    }

    /**
     * Starts this SpeedoManagedConnectionFactory.
     */
    public synchronized void start() throws ResourceException {
    if (started) {
      return;
    }
        //Logging initialisation
        if (loggerFactory == null) {
            if (Monolog.monologFactory == null) {
                loggerFactory = Monolog.initialize();
            } else {
                loggerFactory = Monolog.monologFactory;
            }
        }
        if (logger == null) {
            logger = loggerFactory.getLogger("org.objectweb.speedo.jca");
        }

        //Load properties file of the JDO driver
        if (pmf == null) {
            Properties p = loadProperties();
            if (p.get(SpeedoProperties.MANAGED) == null) {
                //By default the transaction demarcation is done via the JTA API
                p.put(SpeedoProperties.MANAGED, "true");
            }
            logger.log(BasicLevel.DEBUG, "Properties loaded:" + p);
            findTransactionManager(p);

      // In managed environnement the mapping structure must be created
      // before the server lauching. Indeed some data supports do not
      // accept to create data strucutre into a XA transaction.
      String str = p.getProperty(SpeedoProperties.MAPPING_STRUCTURE);
      if (str == null
          || !str.equals(SpeedoProperties.MAPPING_STRUCTURE_DN)) {
        p.put(SpeedoProperties.MAPPING_STRUCTURE,
            SpeedoProperties.MAPPING_STRUCTURE_DN);
        logger.log(BasicLevel.WARN, "The mapping structure cannot be" +
            " managed by Speedo into a managed environnement " +
            "(XA transaction): "
            + SpeedoProperties.MAPPING_STRUCTURE + " is forced to "
            + SpeedoProperties.MAPPING_STRUCTURE_DN);
      }
      //the speedo property to define the trasaction mode within a j2ee context
      byte txMode = getByteTxMode(p.getProperty(SpeedoProperties.TRANSACTION_MODE));
            connectionFactory = createConnectionFactory(logger, this, connectionManager, txMode);
            logger.log(BasicLevel.INFO, "ConnectionManager allocated");
            //fetch the real PersistenceManagerFactory
      try {
        pmf = (POManagerFactoryItf) JDOHelper.getPersistenceManagerFactory(p);
      } catch (Exception e) {
        Exception ie = ExceptionHelper.getNested(e);
        ResourceException re = new ResourceException("Impossible to instanciate Speedo: ");
        logger.log(BasicLevel.ERROR, re.getMessage(), ie);
        re.setLinkedException(ie);
        throw re;
      }
      logger.log(BasicLevel.INFO, "SpeedoManagedConnectionFactory started");
        }
        started = true;
    }


    /**
     * Loads the properties file from the classloader or from the file system.
     *
     * @param p is the Properties to fill.
     * @throws ResourceException
     */
    private Properties loadProperties() throws ResourceException {
        if (propertiesFileName == null) {
            throw new ResourceException(
                    "No name provided for the properties file of the associated PersistenceManagerFactory");
        }
        InputStream is = getClass().getClassLoader().getResourceAsStream(
                propertiesFileName);
        if (is == null) {
            File f = new File(propertiesFileName);
            try {
                if (f.exists()) {
                    is = new FileInputStream(propertiesFileName);
                    logger.log(BasicLevel.DEBUG, "Properties file '"
                            + propertiesFileName
                            + "'  found in the file system");
                }
            } catch (FileNotFoundException e) {
            } finally {
                if (is == null) {
                    throw new ResourceException(
                            "Unable to load properties file: "
                                    + propertiesFileName);
                }
            }
        } else {
            logger.log(BasicLevel.DEBUG, "Properties file '"
                    + propertiesFileName + "'  found in the classpath");
        }
        Properties p = new Properties();
        try {
            p.load(is);
        } catch (IOException e) {
            throw new ResourceException("Unable to load properties file: "
                    + propertiesFileName);
        }
        return p;
    }
   
    /**
     * Try to find the TransactionManager with:
     * - the name specified in the RA configuration xml file
     * - the name specified the properties of the JDO driver
     * - names used in some application server
     *
     * @param p is the Speedo properties
     * @return the reference to the TransactionManager
     * @throw a ResourceException is the TransactionManager cannot be found
     */
    private TransactionManager findTransactionManager(Properties p)
            throws ResourceException {
        if (tm != null) {
            return tm;
        }
        if (tmName != null && lookupTM(tmName)) {
            p.setProperty(SpeedoProperties.TM_NAME, tmName);
        } else {
            //lookup in the properties of JDO driver if the TM name is
            // specified
            String tmName2 = p.getProperty(SpeedoProperties.TM_NAME);
            if (tmName2 == null || !lookupTM(tmName2)) {
                logger.log(BasicLevel.DEBUG,
                                "Try to find the transaction manager with default JNDI names.");
                int i = 0;
                while (i < DEFAULT_JNDI_NAMES.length
                        && !lookupTM(DEFAULT_JNDI_NAMES[i])) {
                    i++;
                }
                if (i < DEFAULT_JNDI_NAMES.length) {
                    p.setProperty(SpeedoProperties.TM_NAME,
                            DEFAULT_JNDI_NAMES[i]);
                }
            }
        }

        if (tm == null) {
            throw new ResourceException(
                    "A javax.transaction.TransactionManager instance is required,"
                            + " in order to register the JDO driver as a Synchronization on transaction"
                            + (tmName == null ? "(No JNDI name specified)"
                                    : "(Bad JNDI Name)"));
        }
        logger.log(BasicLevel.DEBUG, "JDOTransactionItf manager found: " + tm);
        return tm;
    }


    protected void finalize() throws Throwable {
        stop();
        super.finalize();
    }

    /**
     * Stops this SpeedoManagedConnectionFactory.
     */
    public void stop() throws ResourceException {
        pmf = null;
    }


    /**
     * Delegates the creation of a Connection to the ConnectionFactory.
     */
    public Object createConnection() throws ResourceException {
        return connectionFactory.createConnection();
    }

  // --------------------- SpeedoXAContext Management ----------------------- //


  /**
   * Looks for a JdoTxContext associated with the particular transaction.
   * @param xid  The DTP transaction identifier.
   */
  SpeedoXAContext getXAContext(Xid xid) {
    SpeedoXAContext xac = (SpeedoXAContextxid2xac.get(xid);
    POManagerItf txc = null;
    if (xac != null) {
      txc = xac.pm;
    }
        if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG))
            logger.log(BasicLevel.DEBUG,
                    "Looking for the TxContext associated with XID (" + xid
                    + "): " + txc);
    return xac;
  }

  /**
   * Creates a JdoTxContext and associates it with the given DTP transaction.
   * @param xid  The DTP transaction identifier.
   */
  SpeedoXAContext createXAContext(Xid xid) {
    if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
      Object pm = pmf.lookup();
      if (pm != null) {
        logger.log(BasicLevel.DEBUG,
            "Unbind the PM from the current thread: "
            + "\t-current pm=" + pm
            + "\t-xid=" + xid);
      } else {
        logger.log(BasicLevel.DEBUG,
            "No PM to unbind from the current thread, xid=" + xid);
      }
    }
    pmf.unbindPM();
    SpeedoXAContext xac = new SpeedoXAContext(xid);
        if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
      logger.log(BasicLevel.DEBUG,
          "Creates an SpeedoXAContext associated with the XID: " + xid);
        }
    xid2xac.put(xid, xac);
    return xac;
  }

  /**
   * Releases a DTP transaction context and its related resources.
   * @param xid  The DTP transaction identifier.
   */
  SpeedoXAContext releaseXAContext(Xid xid, boolean mustExist) throws XAException {
    SpeedoXAContext xac = (SpeedoXAContext) xid2xac.remove(xid);
    if (xac == null) {
      if (mustExist) {
        String msg = "Impossible to release the SpeedoXAContext, xid=" + xid;
        logger.log(BasicLevel.ERROR, msg);
        throw new XAException(msg);
      }
    } else if (!xac.synchroRegistred && xac.pm != null) {
        logger.log(BasicLevel.WARN, "Closing a persistenceManager because it has not been registered as a Synchronization on the transaction (pm="
            + xac.pm + "), xid: " + xid);
        if (xac.pm.getSpeedoTransaction().isActive()) {
          xac.pm.getSpeedoTransaction().rollback();
        }
        xac.pm.closePOManager();
    } else if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
      logger.log(BasicLevel.DEBUG, "Dissociates the JdoTxContext ("
          + xac.pm + ") associated with XID: " + xid);
        }
    return xac;
  }


    // IMPLEMENTATION OF METHODS FROM THE SpeedoAttributeController INTERFACE

    /**
     * Gives access to the name of the property file for initializing the
     * underlying JDO implementation.
     * @return  The name of the property file.
     */
    public String getPropertyFile() {
        return propertiesFileName;
    }

    /**
     * Assigns to this JDO connector the name of the property file for
     * initializing the underlying JDO implementation.
     * @param pf  The name of the property file.
     */
    public void setPropertyFile(String pf) {
        propertiesFileName = pf;
    }

    public String getTransactionManagerJNDIName() {
        return tmName;
    }

    public void setTransactionManagerJNDIName(String jndiname) throws ResourceException {
        tmName = jndiname;
    }

    public void setTransactionManager(TransactionManager tm) {
        this.tm = tm;
    }

    // IMPLEMENTATION OF METHODS FROM THE (cci)ManagedConnectionFactory INTERFACE

    /**
     * Creates a JDOConnectionFactory; yields the existing one if any.
     * @param cm  The ConnectionManager to be used by the created
     *         ConnectionFactory (may be null).
     */
    public Object createConnectionFactory(ConnectionManager cm)
            throws ResourceException {
        if (!started) {
            start();
        }
        connectionFactory.setConnectionManager(cm);
        return connectionFactory;
    }

    /**
     * Creates a JDOConnectionFactory; yields the existing one if any.
     */
    public Object createConnectionFactory() throws ResourceException {
        return createConnectionFactory(null);
    }

    /**
     * Creates a new SpeedoManagedConnection.
     */
    public ManagedConnection createManagedConnection(
            Subject subject,
            ConnectionRequestInfo info) throws ResourceException {
        if (logger == null || pmf == null) {
            start();
        }
        SpeedoManagedConnection jmc = new SpeedoManagedConnection(logger, this);
    if (info != null) {
      if (info instanceof SpeedoConnectionSpec) {
        jmc.cri = (SpeedoConnectionSpec) info;
      } else {
        throw new ResourceException("Impossible to create a " +
            "ManagedConnection with this kind of ConnectionRequestInfo: "
            + info);
      }
    }
        return jmc;
    }

    /**
     * No matching rules supported. Always yields the first element of the set
     * if any.
     */
    public ManagedConnection matchManagedConnections(
            Set set,
            Subject subject,
            ConnectionRequestInfo info) throws ResourceException {
        if (set.size() == 0)
            return null;
    Iterator it = set.iterator();
    if (!it.hasNext()) {
      return null;
    }
    SpeedoManagedConnection jmc = (SpeedoManagedConnection) it.next();
    if (info != null) {
      if (info instanceof SpeedoConnectionSpec) {
        jmc.cri = (SpeedoConnectionSpec) info;
      } else {
        throw new ResourceException("Impossible to create a " +
            "ManagedConnection with this kind of ConnectionRequestInfo: "
            + info);
      }
    }
        return jmc;
    }

    /**
     * If he given PrintWrtier is a Loggable implementation then the inner
     * logger and the inner loggerFactory are used. Otherwise the a basic Logger
     * implementation is used over the specified PrintWriter.
     */
    public void setLogWriter(PrintWriter writer) throws ResourceException {
        if (logger == null) {
            if (writer instanceof Loggable) {
                logger = ((Loggable) writer).getLogger();
                loggerFactory = ((Loggable) writer).getLoggerFactory();
            } else {
                LoggerImpl li = new LoggerImpl(writer);
                logger = li;
                loggerFactory = li;
            }
        }
        printWriter = writer;
    }

    /**
     * Retrieves the printwriter used for the logging.
     */
    public PrintWriter getLogWriter() throws ResourceException {
        return printWriter;
    }
   
    //PRIVATE METHODS
    private byte getByteTxMode(String mode) {
    if (mode == null || mode.length() == 0 || mode.equals(SpeedoProperties.TRANSACTION_MODE_NORMAL)) {
      return SpeedoProperties.TRANSACTION_BMODE_NORMAL;
    }
    if (mode.equals(SpeedoProperties.TRANSACTION_MODE_REQUIRED)) {
      return SpeedoProperties.TRANSACTION_BMODE_REQUIRED;
    }
    return SpeedoProperties.TRANSACTION_BMODE_UT;
  }
}
TOP

Related Classes of org.objectweb.speedo.jca.SpeedoManagedConnectionFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.