1 /**
2  *  Copyright Terracotta, Inc.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */

16 package net.sf.ehcache.transaction.manager;
17
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Properties;
23 import java.util.Set;
24 import java.util.concurrent.locks.Lock;
25 import java.util.concurrent.locks.ReentrantLock;
26
27 import javax.transaction.TransactionManager;
28
29 import net.sf.ehcache.CacheException;
30 import net.sf.ehcache.transaction.manager.selector.AtomikosSelector;
31 import net.sf.ehcache.transaction.manager.selector.BitronixSelector;
32 import net.sf.ehcache.transaction.manager.selector.GenericJndiSelector;
33 import net.sf.ehcache.transaction.manager.selector.GlassfishSelector;
34 import net.sf.ehcache.transaction.manager.selector.JndiSelector;
35 import net.sf.ehcache.transaction.manager.selector.NullSelector;
36 import net.sf.ehcache.transaction.manager.selector.Selector;
37 import net.sf.ehcache.transaction.manager.selector.WeblogicSelector;
38 import net.sf.ehcache.transaction.xa.EhcacheXAResource;
39
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * Default {@link TransactionManagerLookup} implementation, that will be used by an {@link net.sf.ehcache.Cache#initialise() initializing}
45  * Cache should the user have not specified otherwise.
46  * <p>
47  * This implementation will:
48  * <ol>
49  * <li>lookup a TransactionManager under java:/TransactionManager, this location can be overridden;
50  * <li>if it failed, lookup for a Glassfish transaction manager;
51  * <li>if it failed, lookup for a Weblogic transaction manager;
52  * <li>if it failed, look for a Bitronix TransactionManager;
53  * <li>and if it failed, finally an Atomikos one.
54  * </ol>
55  *
56  * To specify under what specific name the TransactionManager is to be found, you can provide a jndiName property using
57  * {@link #setProperties(java.util.Properties)}. That can be set in the CacheManager's configuration file.
58  *
59  * The first TransactionManager instance is then kept and returned on each {@link #getTransactionManager()} call
60  *
61  * @author Alex Snaps
62  */

63 public class DefaultTransactionManagerLookup implements TransactionManagerLookup {
64
65     private static final Logger LOG = LoggerFactory.getLogger(DefaultTransactionManagerLookup.class.getName());
66
67     private final Lock lock = new ReentrantLock();
68     private final List<EhcacheXAResource> uninitializedEhcacheXAResources = new ArrayList<EhcacheXAResource>();
69     private volatile boolean initialized = false;
70     private volatile Selector selector;
71
72     private final JndiSelector defaultJndiSelector = new GenericJndiSelector();
73
74     private final Selector[] transactionManagerSelectors = new Selector[] {defaultJndiSelector,
75         new GlassfishSelector(),
76         new WeblogicSelector(),
77         new BitronixSelector(),
78         new AtomikosSelector()
79     };
80
81     /**
82      * {@inheritDoc}
83      */

84     public void init() {
85         if (!initialized) {
86             lock.lock();
87             try {
88                 Iterator<EhcacheXAResource> iterator = uninitializedEhcacheXAResources.iterator();
89                 while (iterator.hasNext()) {
90                     if (getTransactionManager() == null) {
91                         throw new CacheException("No Transaction Manager could be located, cannot initialize DefaultTransactionManagerLookup." +
92                                                  " Caches which registered an XAResource: " + getUninitializedXAResourceCacheNames());
93                     }
94                     EhcacheXAResource resource = iterator.next();
95                     selector.registerResource(resource, true);
96                     iterator.remove();
97                 }
98             } finally {
99                 lock.unlock();
100             }
101             initialized = true;
102         }
103     }
104
105     private Set<String> getUninitializedXAResourceCacheNames() {
106         Set<String> names = new HashSet<String>();
107         for (EhcacheXAResource xar : uninitializedEhcacheXAResources) {
108             names.add(xar.getCacheName());
109         }
110         return names;
111     }
112
113     /**
114      * Lookup available txnManagers
115      *
116      * @return TransactionManager
117      */

118     public TransactionManager getTransactionManager() {
119         if (selector == null) {
120             lock.lock();
121             try {
122                 if (selector == null) {
123                     lookupTransactionManager();
124                 }
125             } finally {
126                 lock.unlock();
127             }
128         }
129         return selector.getTransactionManager();
130     }
131
132     private void lookupTransactionManager() {
133         for (Selector s : transactionManagerSelectors) {
134             TransactionManager transactionManager = s.getTransactionManager();
135             if (transactionManager != null) {
136                 this.selector = s;
137                 LOG.debug("Found TransactionManager for {}", s.getVendor());
138                 return;
139             }
140         }
141         this.selector = new NullSelector();
142         LOG.debug("Found no TransactionManager");
143     }
144
145     /**
146      * {@inheritDoc}
147      */

148     public void register(EhcacheXAResource resource, boolean forRecovery) {
149         if (initialized) {
150             selector.registerResource(resource, forRecovery);
151         } else {
152             lock.lock();
153             try {
154                 uninitializedEhcacheXAResources.add(resource);
155             } finally {
156                 lock.unlock();
157             }
158         }
159     }
160
161     /**
162      * {@inheritDoc}
163      */

164     public void unregister(EhcacheXAResource resource, boolean forRecovery) {
165         if (initialized) {
166             selector.unregisterResource(resource, forRecovery);
167         } else {
168             lock.lock();
169             try {
170                 Iterator<EhcacheXAResource> iterator = uninitializedEhcacheXAResources.iterator();
171                 while (iterator.hasNext()) {
172                     EhcacheXAResource uninitializedEhcacheXAResource = iterator.next();
173                     if (uninitializedEhcacheXAResource == resource) {
174                         iterator.remove();
175                         break;
176                     }
177                 }
178             } finally {
179                 lock.unlock();
180             }
181         }
182     }
183
184     /**
185      * {@inheritDoc}
186      */

187     public void setProperties(Properties properties) {
188         if (properties != null) {
189             String jndiName = properties.getProperty("jndiName");
190             if (jndiName != null) {
191                 defaultJndiSelector.setJndiName(jndiName);
192             }
193         }
194     }
195
196 }
197