001    package org.apache.ojb.broker.transaction.tm;
002    
003    /* Copyright 2004-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    import javax.transaction.TransactionManager;
019    
020    import org.apache.commons.lang.SystemUtils;
021    import org.apache.ojb.broker.core.NamingLocator;
022    import org.apache.ojb.broker.util.ClassHelper;
023    import org.apache.ojb.broker.util.logging.Logger;
024    import org.apache.ojb.broker.util.logging.LoggerFactory;
025    
026    /**
027     * Abstract base class implementation of the {@link TransactionManagerFactory} interface, all
028     * derived classes have to implement method {@link #getLookupInfo()}.
029     *
030     * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
031     * @version $Id: AbstractTransactionManagerFactory.java,v 1.1 2007-08-24 22:17:41 ewestfal Exp $
032     */
033    
034    public abstract class AbstractTransactionManagerFactory implements TransactionManagerFactory
035    {
036        private static Logger log = LoggerFactory.getLogger(AbstractTransactionManagerFactory.class);
037    
038        /**
039         * Returns "getTransactionManager";
040         */
041        public static String TM_DEFAULT_METHOD_NAME = "getTransactionManager";
042    
043    
044        private static TransactionManager tm = null;
045    
046        /**
047         * Returns an array of possible JNDI lookup / class names for
048         * the {@link javax.transaction.TransactionManager} instance. An array was used
049         * because for different application server versions the
050         * JNDI/class name may change.
051         * <p/>
052         * Expect an [n][3] string array. Following arguments are available:
053         * <ul>
054         *    <li>info[i][0] = short description of used TM, e.g. appServer name</li>
055         *    <li>info[i][2] = JNDI name to lookup TM or the method name to retrieve TM instance</li>
056         *    <li>info[i][3] = if 'null' an JNDI lookup was made with JNDI name set above, if not null
057         * the class name of the TM factory was assumed and the method name set above will be invoked</li>
058         * </ul>
059         * Example:
060         * <p>
061         * {{"JBoss", "java:/TransactionManager", null}};<br/>
062         * In JBoss we lookup the TM via JNDI, so we don't need a TM factory class.
063         * </p>
064         *
065         * <p>
066         * {{"Websphere 4", TM_DEFAULT_METHOD_NAME, "com.ibm.ejs.jts.jta.JTSXA"},<br/>
067         *    {"Websphere 5", TM_DEFAULT_METHOD_NAME, "com.ibm.ejs.jts.jta.TransactionManagerFactory"},<br/>
068         *    {"Websphere >5", TM_DEFAULT_METHOD_NAME, "com.ibm.ws.Transaction.TransactionManagerFactory"}};<br/>
069         * In Websphere we have to use a TM factory class and obtain the TM via a <em>getTransactionManager()</em>
070         * method call. The TM factory class is varied in different versions.
071         * </p>
072         */
073        public abstract String[][] getLookupInfo();
074    
075        /**
076         * @see org.apache.ojb.broker.transaction.tm.TransactionManagerFactory
077         */
078        public synchronized TransactionManager getTransactionManager() throws TransactionManagerFactoryException
079        {
080            if (tm == null)
081            {
082                StringBuffer msg = new StringBuffer();
083                String[][] lookupInfo = getLookupInfo();
084                String EOL = SystemUtils.LINE_SEPARATOR;
085    
086                for (int i = 0; i < lookupInfo.length; i++)
087                {
088                    String description = lookupInfo[i][0];
089                    String methodName = lookupInfo[i][1];
090                    String className = lookupInfo[i][2];
091                    try
092                    {
093                        if (className == null)
094                        {
095                            tm = jndiLookup(description, methodName);
096                        }
097                        else
098                        {
099                            tm = instantiateClass(description, className, methodName);
100                        }
101                        msg.append("Successfully requested TM for " + description + EOL);
102                    }
103                    catch (Exception e)
104                    {
105                        if (className == null)
106                            msg.append("Error on TM request for " + description +
107                                    ", using jndi-lookup '" + methodName + "'" + EOL + e.getMessage() + EOL);
108                        else
109                            msg.append("Error on TM request for " + description + ", using method '" +
110                                    methodName + "' for class '" + className + "'" + EOL + e.getMessage() + EOL);
111                    }
112                    if (tm != null) break;
113                }
114                // if we don't get an TM instance throw exception
115                if (tm == null)
116                {
117                    throw new TransactionManagerFactoryException("Can't lookup transaction manager:" + EOL + msg);
118                }
119            }
120            return tm;
121        }
122    
123        protected TransactionManager jndiLookup(String description, String methodName)
124        {
125            log.info(description + ", lookup TransactionManager: '" + methodName + "'");
126            return (TransactionManager) NamingLocator.lookup(methodName);
127        }
128    
129        protected TransactionManager instantiateClass(String description, String className, String methodName) throws Exception
130        {
131            log.info(description + ", invoke method '"
132                    + methodName + "()' on class " + className);
133            Class tmClass = ClassHelper.getClass(className);
134            return (TransactionManager) tmClass.getMethod(methodName, null).invoke(null, null);
135        }
136    }