KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > speedo > jca > JdoManagedConnectionFactory


1 /**
2  * perseus/connector: this is an implementation of some JCA-related technologies
3  * (resource adapters and managers) for the ObjectWeb consortium.
4  * Copyright (C) 2001-2004 France Telecom R&D
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * Contact: speedo@objectweb.org
21  *
22  */

23
24 package org.objectweb.speedo.jca;
25
26 import org.objectweb.util.monolog.api.BasicLevel;
27 import org.objectweb.util.monolog.api.Logger;
28 import org.objectweb.util.monolog.api.LoggerFactory;
29 import org.objectweb.util.monolog.api.Loggable;
30 import org.objectweb.util.monolog.Monolog;
31 import org.objectweb.util.monolog.wrapper.printwriter.LoggerImpl;
32 import org.objectweb.speedo.api.Debug;
33 import org.objectweb.speedo.api.SpeedoProperties;
34 import org.objectweb.speedo.api.ExceptionHelper;
35 import org.objectweb.speedo.pm.api.ProxyManagerFactory;
36 import org.objectweb.speedo.Speedo;
37
38 import java.io.PrintWriter JavaDoc;
39 import java.io.FileInputStream JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.io.File JavaDoc;
42 import java.io.InputStream JavaDoc;
43 import java.io.FileNotFoundException JavaDoc;
44 import java.util.Set JavaDoc;
45 import java.util.Properties JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.Iterator JavaDoc;
48 import javax.resource.ResourceException JavaDoc;
49 import javax.resource.spi.ConnectionManager JavaDoc;
50 import javax.resource.spi.ConnectionRequestInfo JavaDoc;
51 import javax.resource.spi.ManagedConnection JavaDoc;
52 import javax.resource.spi.ManagedConnectionFactory JavaDoc;
53 import javax.security.auth.Subject JavaDoc;
54 import javax.jdo.JDOHelper;
55 import javax.jdo.PersistenceManager;
56 import javax.transaction.TransactionManager JavaDoc;
57 import javax.transaction.xa.Xid JavaDoc;
58 import javax.transaction.xa.XAException JavaDoc;
59 import javax.naming.InitialContext JavaDoc;
60 import javax.naming.NamingException JavaDoc;
61
62 /**
63  * @author P. Dechamboux
64  */

65 public class JdoManagedConnectionFactory
66         implements ManagedConnectionFactory JavaDoc,
67         JdoAttributeController {
68
69     private final static String JavaDoc[] DEFAULT_JNDI_NAMES = {
70         "javax.transaction.UserTransaction", //JOnAS
71
"javax.transaction.TransactionManager", //WebLogic
72
"java:/TransactionManager", //JBoss
73
"jta/usertransaction", //WebSphere
74
"java:comp/UserTransaction" //Orion
75
};
76
77     /**
78      * The logger into which traces about JdoManagedConnectionFactory are
79      * produced.
80      */

81     private Logger logger;
82     /**
83      * It is assumed that only one ConnectionFactory is actually created by
84      * a ManagedConnectionFactory.
85      */

86     protected JdoConnectionFactory connectionFactory;
87     /**
88      * For creating all loggers related to JDO and its adapter.
89      */

90     private LoggerFactory loggerFactory = null;
91     /**
92      * The factory for managing JDO transaction contexts.
93      */

94     protected ProxyManagerFactory pmf = null;
95
96     /**
97      * The name of the property file of the PersistenceManagerFactory associated
98      * with this JDO connector.
99      */

100     private String JavaDoc propertiesFileName = null;
101     /**
102      * The factory for managing JDO transaction contexts.
103      */

104     private ConnectionManager JavaDoc connectionManager = null;
105
106     private PrintWriter JavaDoc printWriter = null;
107
108     protected boolean started = false;
109
110     /**
111      * the JNDI Name of the transaction manager
112      */

113     private String JavaDoc tmName = null;
114
115     protected TransactionManager JavaDoc tm = null;
116
117     /**
118      * The hashed structure that stores JdoTransaction that have been associated
119      * with a particular XID.
120      */

121     private HashMap JavaDoc xid2xac = new HashMap JavaDoc();
122
123     /**
124      * Lookup in JNDI the transaction manager under the name specified in
125      * parameter. The 'tm' variable is assigned if the transaction manager is
126      * found.
127      * @param name is the jndi name
128      * @return true if an instance implementing
129      * javax.transaction.TransactionManager is availlable in JNDI, otherwise
130      * false.
131      */

132     private boolean lookupTM(String JavaDoc name) {
133         InitialContext JavaDoc ictx = null;
134         try {
135             ictx = new InitialContext JavaDoc();
136             Object JavaDoc o = ictx.lookup(name);
137             if (o == null) {
138                 logger.log(BasicLevel.WARN,
139                         "JNDI retrieves a null value for the name '" + name + "'.");
140             }
141             if (!(o instanceof TransactionManager JavaDoc)) {
142                 logger.log(BasicLevel.WARN,
143                         "JNDI retrieves an object which is not a javax.transaction.TransactionManager (JNDI name: " + name + "): " + o);
144                 return false;
145             }
146             tm = (TransactionManager JavaDoc) o;
147             logger.log(BasicLevel.INFO, "The TransactionManager was found in JNDI with the name '" + name + "'.");
148             return true;
149         } catch (Exception JavaDoc e) {
150             logger.log(BasicLevel.WARN,
151                     "Error when lookup the transaction manager in JNDI with the name '"
152                     + name + "'", e);
153             return false;
154         } finally {
155             if (ictx != null) {
156                 try {
157                     ictx.close();
158                 } catch (NamingException JavaDoc e) {
159                 }
160             }
161         }
162     }
163
164     /**
165      * Starts this JdoManagedConnectionFactory.
166      */

167     public synchronized void start() throws ResourceException JavaDoc {
168         if (started) {
169             return;
170         }
171         //Logging initialisation
172
if (loggerFactory == null) {
173             if (Monolog.monologFactory == null) {
174                 loggerFactory = Monolog.initialize();
175             } else {
176                 loggerFactory = Monolog.monologFactory;
177             }
178         }
179         if (logger == null) {
180             logger = loggerFactory.getLogger("org.objectweb.speedo.jca");
181         }
182
183         //Load properties file of the JDO driver
184
if (pmf == null) {
185             Properties p = loadProperties();
186             if (p.get(SpeedoProperties.MANAGED) == null) {
187                 //By default the transaction demarcation is done via the JTA API
188
p.put(SpeedoProperties.MANAGED, "true");
189             }
190             logger.log(BasicLevel.DEBUG, "Properties loaded:" + p);
191             findTransactionManager(p);
192
193             // In managed environnement the mapping structure must be created
194
// before the server lauching. Indeed some data supports do not
195
// accept to create data strucutre into a XA transaction.
196
String JavaDoc str = p.getProperty(SpeedoProperties.MAPPING_STRUCTURE);
197             if (str == null
198                     || !str.equals(SpeedoProperties.MAPPING_STRUCTURE_DN)) {
199                 p.put(SpeedoProperties.MAPPING_STRUCTURE,
200                         SpeedoProperties.MAPPING_STRUCTURE_DN);
201                 logger.log(BasicLevel.WARN, "The mapping structure cannot be" +
202                         " managed by Speedo into a managed environnement " +
203                         "(XA transaction): "
204                         + SpeedoProperties.MAPPING_STRUCTURE + " is forced to "
205                         + SpeedoProperties.MAPPING_STRUCTURE_DN);
206             }
207             //the speedo property to define the trasaction mode within a j2ee context
208
byte txMode = getByteTxMode(p.getProperty(SpeedoProperties.TRANSACTION_MODE));
209             connectionFactory = new JdoConnectionFactory(logger, this, connectionManager, txMode);
210             logger.log(BasicLevel.INFO, "ConnectionManager allocated");
211             //fetch the real PersistenceManagerFactory
212
try {
213                 pmf = ((Speedo) JDOHelper.getPersistenceManagerFactory(p)).getPMFComponent();
214             } catch (Exception JavaDoc e) {
215                 Exception JavaDoc ie = ExceptionHelper.getNested(e);
216                 ResourceException JavaDoc re = new ResourceException JavaDoc("Impossible to instanciate Speedo: ");
217                 logger.log(BasicLevel.ERROR, re.getMessage(), ie);
218                 re.setLinkedException(ie);
219                 throw re;
220             }
221             logger.log(BasicLevel.INFO, "JdoManagedConnectionFactory started");
222         }
223         started = true;
224     }
225
226
227     /**
228      * Loads the properties file from the classloader or from the file system.
229      *
230      * @param p is the Properties to fill.
231      * @throws ResourceException
232      */

233     private Properties loadProperties() throws ResourceException JavaDoc {
234         if (propertiesFileName == null) {
235             throw new ResourceException JavaDoc(
236                     "No name provided for the properties file of the associated PersistenceManagerFactory");
237         }
238         InputStream JavaDoc is = getClass().getClassLoader().getResourceAsStream(
239                 propertiesFileName);
240         if (is == null) {
241             File JavaDoc f = new File JavaDoc(propertiesFileName);
242             try {
243                 if (f.exists()) {
244                     is = new FileInputStream JavaDoc(propertiesFileName);
245                     logger.log(BasicLevel.DEBUG, "Properties file '"
246                             + propertiesFileName
247                             + "' found in the file system");
248                 }
249             } catch (FileNotFoundException JavaDoc e) {
250             } finally {
251                 if (is == null) {
252                     throw new ResourceException JavaDoc(
253                             "Unable to load properties file: "
254                                     + propertiesFileName);
255                 }
256             }
257         } else {
258             logger.log(BasicLevel.DEBUG, "Properties file '"
259                     + propertiesFileName + "' found in the classpath");
260         }
261         Properties p = new Properties();
262         try {
263             p.load(is);
264         } catch (IOException JavaDoc e) {
265             throw new ResourceException JavaDoc("Unable to load properties file: "
266                     + propertiesFileName);
267         }
268         return p;
269     }
270     
271     /**
272      * Try to find the TransactionManager with:
273      * - the name specified in the RA configuration xml file
274      * - the name specified the properties of the JDO driver
275      * - names used in some application server
276      *
277      * @param p is the Speedo properties
278      * @return the reference to the TransactionManager
279      * @throw a ResourceException is the TransactionManager cannot be found
280      */

281     private TransactionManager JavaDoc findTransactionManager(Properties p)
282             throws ResourceException JavaDoc {
283         if (tm != null) {
284             return tm;
285         }
286         if (tmName != null && lookupTM(tmName)) {
287             p.setProperty(SpeedoProperties.TM_NAME, tmName);
288         } else {
289             //lookup in the properties of JDO driver if the TM name is
290
// specified
291
String JavaDoc tmName2 = p.getProperty(SpeedoProperties.TM_NAME);
292             if (tmName2 == null || !lookupTM(tmName2)) {
293                 logger.log(BasicLevel.DEBUG,
294                                 "Try to find the transaction manager with default JNDI names.");
295                 int i = 0;
296                 while (i < DEFAULT_JNDI_NAMES.length
297                         && !lookupTM(DEFAULT_JNDI_NAMES[i])) {
298                     i++;
299                 }
300                 if (i < DEFAULT_JNDI_NAMES.length) {
301                     p.setProperty(SpeedoProperties.TM_NAME,
302                             DEFAULT_JNDI_NAMES[i]);
303                 }
304             }
305         }
306
307         if (tm == null) {
308             throw new ResourceException JavaDoc(
309                     "A javax.transaction.TransactionManager instance is required,"
310                             + " in order to register the JDO driver as a Synchronization on transaction"
311                             + (tmName == null ? "(No JNDI name specified)"
312                                     : "(Bad JNDI Name)"));
313         }
314         logger.log(BasicLevel.DEBUG, "Transaction manager found: " + tm);
315         return tm;
316     }
317
318
319     protected void finalize() throws Throwable JavaDoc {
320         stop();
321         super.finalize();
322     }
323
324     /**
325      * Stops this JdoManagedConnectionFactory.
326      */

327     public void stop() throws ResourceException JavaDoc {
328         pmf = null;
329     }
330
331
332     /**
333      * Delegates the creation of a Connection to the ConnectionFactory.
334      */

335     public Object JavaDoc createConnection() throws ResourceException JavaDoc {
336         return connectionFactory.createConnection();
337     }
338
339     // --------------------- XAContext Management ----------------------- //
340

341
342     /**
343      * Looks for a JdoTxContext associated with the particular transaction.
344      * @param xid The DTP transaction identifier.
345      */

346     XAContext getXAContext(Xid JavaDoc xid) {
347         XAContext xac = (XAContext) xid2xac.get(xid);
348         PersistenceManager txc = null;
349         if (xac != null) {
350             txc = xac.pm;
351         }
352         if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG))
353             logger.log(BasicLevel.DEBUG,
354                     "Looking for the TxContext associated with XID (" + xid
355                     + "): " + txc);
356         return xac;
357     }
358
359     /**
360      * Creates a JdoTxContext and associates it with the given DTP transaction.
361      * @param xid The DTP transaction identifier.
362      */

363     XAContext createXAContext(Xid JavaDoc xid) {
364         if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
365             Object JavaDoc pm = pmf.lookup();
366             if (pm != null) {
367                 logger.log(BasicLevel.DEBUG,
368                         "Unbind the PM from the current thread: "
369                         + "\t-current pm=" + pm
370                         + "\t-xid=" + xid);
371             } else {
372                 logger.log(BasicLevel.DEBUG,
373                         "No PM to unbind from the current thread, xid=" + xid);
374             }
375         }
376         pmf.unbindPM();
377         XAContext xac = new XAContext(xid);
378         if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
379             logger.log(BasicLevel.DEBUG,
380                     "Creates an XAContext associated with the XID: " + xid);
381         }
382         xid2xac.put(xid, xac);
383         return xac;
384     }
385
386     /**
387      * Releases a DTP transaction context and its related resources.
388      * @param xid The DTP transaction identifier.
389      */

390     XAContext releaseXAContext(Xid JavaDoc xid, boolean mustExist) throws XAException JavaDoc {
391         XAContext xac = (XAContext) xid2xac.remove(xid);
392         if (xac == null) {
393             if (mustExist) {
394                 String JavaDoc msg = "Impossible to release the XAContext, xid=" + xid;
395                 logger.log(BasicLevel.ERROR, msg);
396                 throw new XAException JavaDoc(msg);
397             }
398         } else if (!xac.synchroRegistred && xac.pm != null) {
399                 logger.log(BasicLevel.WARN, "Closing a persistenceManager because it has not been registered as a Synchronization on the transaction (pm="
400                         + xac.pm + "), xid: " + xid);
401                 if (xac.pm.currentTransaction().isActive()) {
402                     xac.pm.currentTransaction().rollback();
403                 }
404                 xac.pm.close();
405         } else if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
406             logger.log(BasicLevel.DEBUG, "Dissociates the JdoTxContext ("
407                     + xac.pm + ") associated with XID: " + xid);
408         }
409         return xac;
410     }
411
412
413     // IMPLEMENTATION OF METHODS FROM THE JdoAttributeController INTERFACE
414

415     /**
416      * Gives access to the name of the property file for initializing the
417      * underlying JDO implementation.
418      * @return The name of the property file.
419      */

420     public String JavaDoc getPropertyFile() {
421         return propertiesFileName;
422     }
423
424     /**
425      * Assigns to this JDO connector the name of the property file for
426      * initializing the underlying JDO implementation.
427      * @param pf The name of the property file.
428      */

429     public void setPropertyFile(String JavaDoc pf) {
430         propertiesFileName = pf;
431     }
432
433     public String JavaDoc getTransactionManagerJNDIName() {
434         return tmName;
435     }
436
437     public void setTransactionManagerJNDIName(String JavaDoc jndiname) throws ResourceException JavaDoc {
438         tmName = jndiname;
439     }
440
441     public void setTransactionManager(TransactionManager JavaDoc tm) {
442         this.tm = tm;
443     }
444
445     // IMPLEMENTATION OF METHODS FROM THE (cci)ManagedConnectionFactory INTERFACE
446

447     /**
448      * Creates a JdoConnectionFactory; yields the existing one if any.
449      * @param cm The ConnectionManager to be used by the created
450      * ConnectionFactory (may be null).
451      */

452     public Object JavaDoc createConnectionFactory(ConnectionManager JavaDoc cm)
453             throws ResourceException JavaDoc {
454         if (!started) {
455             start();
456         }
457         connectionFactory.setConnectionManager(cm);
458         return connectionFactory;
459     }
460
461     /**
462      * Creates a JdoConnectionFactory; yields the existing one if any.
463      */

464     public Object JavaDoc createConnectionFactory() throws ResourceException JavaDoc {
465         return createConnectionFactory(null);
466     }
467
468     /**
469      * Creates a new JdoManagedConnection.
470      */

471     public ManagedConnection JavaDoc createManagedConnection(
472             Subject JavaDoc subject,
473             ConnectionRequestInfo JavaDoc info) throws ResourceException JavaDoc {
474         if (logger == null || pmf == null) {
475             start();
476         }
477         JdoManagedConnection jmc = new JdoManagedConnection(logger, this);
478         if (info != null) {
479             if (info instanceof JDOConnectionSpec) {
480                 jmc.cri = (JDOConnectionSpec) info;
481             } else {
482                 throw new ResourceException JavaDoc("Impossible to create a " +
483                         "ManagedConnection with this kind of ConnectionRequestInfo: "
484                         + info);
485             }
486         }
487         return jmc;
488     }
489
490     /**
491      * No matching rules supported. Always yields the first element of the set
492      * if any.
493      */

494     public ManagedConnection JavaDoc matchManagedConnections(
495             Set JavaDoc set,
496             Subject JavaDoc subject,
497             ConnectionRequestInfo JavaDoc info) throws ResourceException JavaDoc {
498         if (set.size() == 0)
499             return null;
500         Iterator JavaDoc it = set.iterator();
501         if (!it.hasNext()) {
502             return null;
503         }
504         JdoManagedConnection jmc = (JdoManagedConnection) it.next();
505         if (info != null) {
506             if (info instanceof JDOConnectionSpec) {
507                 jmc.cri = (JDOConnectionSpec) info;
508             } else {
509                 throw new ResourceException JavaDoc("Impossible to create a " +
510                         "ManagedConnection with this kind of ConnectionRequestInfo: "
511                         + info);
512             }
513         }
514         return jmc;
515     }
516
517     /**
518      * If he given PrintWrtier is a Loggable implementation then the inner
519      * logger and the inner loggerFactory are used. Otherwise the a basic Logger
520      * implementation is used over the specified PrintWriter.
521      */

522     public void setLogWriter(PrintWriter JavaDoc writer) throws ResourceException JavaDoc {
523         if (logger == null) {
524             if (writer instanceof Loggable) {
525                 logger = ((Loggable) writer).getLogger();
526                 loggerFactory = ((Loggable) writer).getLoggerFactory();
527             } else {
528                 LoggerImpl li = new LoggerImpl(writer);
529                 logger = li;
530                 loggerFactory = li;
531             }
532         }
533         printWriter = writer;
534     }
535
536     /**
537      * Retrieves the printwriter used for the logging.
538      */

539     public PrintWriter JavaDoc getLogWriter() throws ResourceException JavaDoc {
540         return printWriter;
541     }
542     
543     //PRIVATE METHODS
544
private byte getByteTxMode(String JavaDoc mode) {
545         if (mode == null || mode.length() == 0 || mode.equals(SpeedoProperties.TRANSACTION_MODE_NORMAL)) {
546             return SpeedoProperties.TRANSACTION_BMODE_NORMAL;
547         }
548         if (mode.equals(SpeedoProperties.TRANSACTION_MODE_REQUIRED)) {
549             return SpeedoProperties.TRANSACTION_BMODE_REQUIRED;
550         }
551         return SpeedoProperties.TRANSACTION_BMODE_UT;
552     }
553 }
Popular Tags