001    /*
002     * Copyright 2002-2008 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.springframework.transaction.jta;
018    
019    import javax.naming.NamingException;
020    import javax.transaction.SystemException;
021    
022    import org.objectweb.jotm.Current;
023    import org.objectweb.jotm.Jotm;
024    
025    import org.springframework.beans.factory.DisposableBean;
026    import org.springframework.beans.factory.FactoryBean;
027    
028    /**
029     * {@link FactoryBean} that retrieves the JTA UserTransaction/TransactionManager
030     * for ObjectWeb's <a href="http://jotm.objectweb.org">JOTM</a>. Will retrieve
031     * an already active JOTM instance if found (e.g. if running in JOnAS),
032     * else create a new local JOTM instance.
033     *
034     * <p>With JOTM, the same object implements both the
035     * {@link javax.transaction.UserTransaction} and the
036     * {@link javax.transaction.TransactionManager} interface,
037     * as returned by this FactoryBean.
038     *
039     * <p>A local JOTM instance is well-suited for working in conjunction with
040     * ObjectWeb's <a href="http://xapool.experlog.com">XAPool</a>, e.g. with bean
041     * definitions like the following:
042     *
043     * <pre class="code">
044     * &lt;bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/&gt;
045     *
046     * &lt;bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"&gt;
047     *   &lt;property name="userTransaction" ref="jotm"/&gt;
048     * &lt;/bean&gt;
049     *
050     * &lt;bean id="innerDataSource" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"&gt;
051     *   &lt;property name="transactionManager" ref="jotm"/&gt;
052     *   &lt;property name="driverName" value="..."/&gt;
053     *   &lt;property name="url" value="..."/&gt;
054     *   &lt;property name="user" value="..."/&gt;
055     *   &lt;property name="password" value="..."/&gt;
056     * &lt;/bean&gt;
057     *
058     * &lt;bean id="dataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"&gt;
059     *   &lt;property name="dataSource" ref="innerDataSource"/&gt;
060     *   &lt;property name="user" value="..."/&gt;
061     *   &lt;property name="password" value="..."/&gt;
062     *   &lt;property name="maxSize" value="..."/&gt;
063     * &lt;/bean&gt;</pre>
064     *
065     * Note that Spring's {@link JtaTransactionManager} will automatically detect
066     * that the passed-in UserTransaction reference also implements the
067     * TransactionManager interface. Hence, it is not necessary to specify a
068     * separate reference for JtaTransactionManager's "transactionManager" property.
069     *
070     * <p>Implementation note: This FactoryBean uses JOTM's static access method
071     * to obtain the JOTM {@link org.objectweb.jotm.Current} object, which
072     * implements both the UserTransaction and the TransactionManager interface,
073     * as mentioned above.
074     *
075     * @author Juergen Hoeller
076     * @since 21.01.2004
077     * @see JtaTransactionManager#setUserTransaction
078     * @see JtaTransactionManager#setTransactionManager
079     * @see org.objectweb.jotm.Current
080     */
081    public class JotmFactoryBean implements FactoryBean, DisposableBean {
082    
083            private Current jotmCurrent;
084    
085            private Jotm jotm;
086    
087    
088            public JotmFactoryBean() throws NamingException {
089                    // Check for already active JOTM instance.
090                    this.jotmCurrent = Current.getCurrent();
091    
092                    // If none found, create new local JOTM instance.
093                    if (this.jotmCurrent == null) {
094                            // Only for use within the current Spring context:
095                            // local, not bound to registry.
096                            this.jotm = new Jotm(true, false);
097                            this.jotmCurrent = Current.getCurrent();
098                    }
099            }
100    
101            /**
102             * Set the default transaction timeout for the JOTM instance.
103             * <p>Should only be called for a local JOTM instance,
104             * not when accessing an existing (shared) JOTM instance.
105             */
106            public void setDefaultTimeout(int defaultTimeout) {
107                    this.jotmCurrent.setDefaultTimeout(defaultTimeout);
108                    // The following is a JOTM oddity: should be used for demarcation transaction only,
109                    // but is required here in order to actually get rid of JOTM's default (60 seconds).
110                    try {
111                            this.jotmCurrent.setTransactionTimeout(defaultTimeout);
112                    }
113                    catch (SystemException ex) {
114                            // should never happen
115                    }
116            }
117    
118    
119            /**
120             * Return the JOTM instance created by this factory bean, if any.
121             * Will be <code>null</code> if an already active JOTM instance is used.
122             * <p>Application code should never need to access this.
123             */
124            public Jotm getJotm() {
125                    return this.jotm;
126            }
127    
128            public Object getObject() {
129                    return this.jotmCurrent;
130            }
131    
132            public Class getObjectType() {
133                    return this.jotmCurrent.getClass();
134            }
135    
136            public boolean isSingleton() {
137                    return true;
138            }
139    
140    
141            /**
142             * Stop the local JOTM instance, if created by this FactoryBean.
143             */
144            public void destroy() {
145                    if (this.jotm != null) {
146                            this.jotm.stop();
147                    }
148            }
149    
150    }