KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > resource > adapter > jdbc > BaseWrapperManagedConnectionFactory


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.resource.adapter.jdbc;
23
24 import java.io.PrintWriter JavaDoc;
25 import java.io.Serializable JavaDoc;
26 import java.security.AccessController JavaDoc;
27 import java.security.PrivilegedAction JavaDoc;
28 import java.sql.Connection JavaDoc;
29 import java.sql.SQLException JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.Properties JavaDoc;
33 import java.util.Set JavaDoc;
34
35 import javax.resource.ResourceException JavaDoc;
36 import javax.resource.spi.ConnectionManager JavaDoc;
37 import javax.resource.spi.ConnectionRequestInfo JavaDoc;
38 import javax.resource.spi.ManagedConnectionFactory JavaDoc;
39 import javax.resource.spi.ValidatingManagedConnectionFactory JavaDoc;
40 import javax.resource.spi.security.PasswordCredential JavaDoc;
41 import javax.security.auth.Subject JavaDoc;
42
43 import org.jboss.logging.Logger;
44 import org.jboss.resource.JBossResourceException;
45
46 /**
47  * BaseWrapperManagedConnectionFactory
48  *
49  * @author <a HREF="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
50  * @author <a HREF="mailto:adrian@jboss.com">Adrian Brock</a>
51  * @author <a HREF="mailto:weston.price@jboss.com">Weston Price</a>
52  *
53  * @version $Revision: 54925 $
54  */

55
56 public abstract class BaseWrapperManagedConnectionFactory implements ManagedConnectionFactory JavaDoc, ValidatingManagedConnectionFactory JavaDoc, Serializable JavaDoc
57 {
58    /** @since 4.0.1 */
59    static final long serialVersionUID = -84923705377702088L;
60
61    public static final int TRACK_STATEMENTS_FALSE_INT = 0;
62    public static final int TRACK_STATEMENTS_TRUE_INT = 1;
63    public static final int TRACK_STATEMENTS_NOWARN_INT = 2;
64
65    public static final String JavaDoc TRACK_STATEMENTS_FALSE = "false";
66    public static final String JavaDoc TRACK_STATEMENTS_TRUE = "true";
67    public static final String JavaDoc TRACK_STATEMENTS_NOWARN = "nowarn";
68
69    protected final Logger log = Logger.getLogger(getClass());
70
71    protected String JavaDoc userName;
72    protected String JavaDoc password;
73
74    //This is used by Local wrapper for all properties, and is left
75
//in this class for ease of writing getConnectionProperties,
76
//which always holds the user/pw.
77
protected final Properties JavaDoc connectionProps = new Properties JavaDoc();
78
79    protected int transactionIsolation = -1;
80
81    protected int preparedStatementCacheSize = 0;
82
83    protected boolean doQueryTimeout = false;
84
85    /**
86     * The variable <code>newConnectionSQL</code> holds an SQL
87     * statement which if not null is executed when a new Connection is
88     * obtained for a new ManagedConnection.
89     */

90    protected String JavaDoc newConnectionSQL;
91
92    /**
93     * The variable <code>checkValidConnectionSQL</code> holds an sql
94     * statement that may be executed whenever a managed connection is
95     * removed from the pool, to check that it is still valid. This
96     * requires setting up an mbean to execute it when notified by the
97     * ConnectionManager.
98     */

99    protected String JavaDoc checkValidConnectionSQL;
100
101    /**
102     * The classname used to check whether a connection is valid
103     */

104    protected String JavaDoc validConnectionCheckerClassName;
105
106    /**
107     * The instance of the valid connection checker
108     */

109    protected ValidConnectionChecker connectionChecker;
110
111    /** The instance of the stale connection checker */
112    protected StaleConnectionChecker staleConnectionChecker;
113    
114    /** The staleConnectionCheckerClassName */
115    private String JavaDoc staleConnectionCheckerClassName;
116
117    private String JavaDoc exceptionSorterClassName;
118
119    private ExceptionSorter exceptionSorter;
120
121    protected int trackStatements = TRACK_STATEMENTS_NOWARN_INT;
122
123    /** Whether to share cached prepared statements */
124    protected boolean sharePS = false;
125    
126    protected boolean isTransactionQueryTimeout = false;
127    
128    protected int queryTimeout = 0;
129
130    private boolean validateOnMatch = true;
131    
132    public BaseWrapperManagedConnectionFactory ()
133    {
134
135    }
136
137    public PrintWriter JavaDoc getLogWriter() throws ResourceException JavaDoc
138    {
139       return null;
140    }
141
142    public void setLogWriter(PrintWriter JavaDoc param1) throws ResourceException JavaDoc
143    {
144    }
145
146    public Object JavaDoc createConnectionFactory(ConnectionManager JavaDoc cm) throws ResourceException JavaDoc
147    {
148       return new WrapperDataSource(this, cm);
149    }
150
151    public Object JavaDoc createConnectionFactory() throws ResourceException JavaDoc
152    {
153       throw new JBossResourceException("Resource Adapter does not currently support running in a non-managed environment.");
154    }
155
156    public String JavaDoc getUserName()
157    {
158       return userName;
159    }
160
161    public void setUserName(final String JavaDoc userName)
162    {
163       this.userName = userName;
164    }
165
166    public String JavaDoc getPassword()
167    {
168       return password;
169    }
170
171    public void setPassword(final String JavaDoc password)
172    {
173       this.password = password;
174    }
175
176    public int getPreparedStatementCacheSize()
177    {
178       return preparedStatementCacheSize;
179    }
180
181    public void setPreparedStatementCacheSize(int size)
182    {
183       preparedStatementCacheSize = size;
184    }
185
186    public boolean getSharePreparedStatements()
187    {
188       return sharePS;
189    }
190
191    public void setSharePreparedStatements(boolean sharePS)
192    {
193       this.sharePS = sharePS;
194    }
195
196    public String JavaDoc getTransactionIsolation()
197    {
198       switch (this.transactionIsolation)
199       {
200          case Connection.TRANSACTION_NONE:
201             return "TRANSACTION_NONE";
202          case Connection.TRANSACTION_READ_COMMITTED:
203             return "TRANSACTION_READ_COMMITTED";
204          case Connection.TRANSACTION_READ_UNCOMMITTED:
205             return "TRANSACTION_READ_UNCOMMITTED";
206          case Connection.TRANSACTION_REPEATABLE_READ:
207             return "TRANSACTION_REPEATABLE_READ";
208          case Connection.TRANSACTION_SERIALIZABLE:
209             return "TRANSACTION_SERIALIZABLE";
210          case -1:
211             return "DEFAULT";
212          default:
213             return Integer.toString(transactionIsolation);
214       }
215    }
216
217    public void setTransactionIsolation(String JavaDoc transactionIsolation)
218    {
219       if (transactionIsolation.equals("TRANSACTION_NONE"))
220          this.transactionIsolation = Connection.TRANSACTION_NONE;
221       else if (transactionIsolation.equals("TRANSACTION_READ_COMMITTED"))
222          this.transactionIsolation = Connection.TRANSACTION_READ_COMMITTED;
223       else if (transactionIsolation.equals("TRANSACTION_READ_UNCOMMITTED"))
224          this.transactionIsolation = Connection.TRANSACTION_READ_UNCOMMITTED;
225       else if (transactionIsolation.equals("TRANSACTION_REPEATABLE_READ"))
226          this.transactionIsolation = Connection.TRANSACTION_REPEATABLE_READ;
227       else if (transactionIsolation.equals("TRANSACTION_SERIALIZABLE"))
228          this.transactionIsolation = Connection.TRANSACTION_SERIALIZABLE;
229       else
230       {
231          try
232          {
233             this.transactionIsolation = Integer.parseInt(transactionIsolation);
234          }
235          catch (NumberFormatException JavaDoc nfe)
236          {
237             throw new IllegalArgumentException JavaDoc("Setting Isolation level to unknown state: " + transactionIsolation);
238          }
239       }
240    }
241
242    public String JavaDoc getNewConnectionSQL()
243    {
244       return newConnectionSQL;
245    }
246
247    public void setNewConnectionSQL(String JavaDoc newConnectionSQL)
248    {
249       this.newConnectionSQL = newConnectionSQL;
250    }
251
252    public String JavaDoc getCheckValidConnectionSQL()
253    {
254       return checkValidConnectionSQL;
255    }
256
257    public void setCheckValidConnectionSQL(String JavaDoc checkValidConnectionSQL)
258    {
259       this.checkValidConnectionSQL = checkValidConnectionSQL;
260    }
261
262    public void setStaleConnectionCheckerClassName(String JavaDoc value)
263    {
264       staleConnectionCheckerClassName = value;
265       
266    }
267    
268    public String JavaDoc getStaleConnectionCheckerClassName()
269    {
270       return staleConnectionCheckerClassName;
271       
272    }
273
274    public String JavaDoc getTrackStatements()
275    {
276       if (trackStatements == TRACK_STATEMENTS_FALSE_INT)
277          return TRACK_STATEMENTS_FALSE;
278       else if (trackStatements == TRACK_STATEMENTS_TRUE_INT)
279          return TRACK_STATEMENTS_TRUE;
280       return TRACK_STATEMENTS_NOWARN;
281    }
282    
283    public boolean getValidateOnMatch()
284    {
285       return this.validateOnMatch;
286    }
287
288    public void setValidateOnMatch(boolean validateOnMatch)
289    {
290       this.validateOnMatch = validateOnMatch;
291    }
292    
293    public void setTrackStatements(String JavaDoc value)
294    {
295       if (value == null)
296          throw new IllegalArgumentException JavaDoc("Null value for trackStatements");
297       String JavaDoc trimmed = value.trim();
298       if (trimmed.equalsIgnoreCase(TRACK_STATEMENTS_FALSE))
299          trackStatements = TRACK_STATEMENTS_FALSE_INT;
300       else if (trimmed.equalsIgnoreCase(TRACK_STATEMENTS_TRUE))
301          trackStatements = TRACK_STATEMENTS_TRUE_INT;
302       else
303          trackStatements = TRACK_STATEMENTS_NOWARN_INT;
304    }
305
306    public String JavaDoc getExceptionSorterClassName()
307    {
308       return exceptionSorterClassName;
309    }
310
311    public void setExceptionSorterClassName(String JavaDoc exceptionSorterClassName)
312    {
313       this.exceptionSorterClassName = exceptionSorterClassName;
314    }
315
316    public String JavaDoc getValidConnectionCheckerClassName()
317    {
318       return validConnectionCheckerClassName;
319    }
320
321    public void setValidConnectionCheckerClassName(String JavaDoc value)
322    {
323       validConnectionCheckerClassName = value;
324    }
325
326    public boolean isTransactionQueryTimeout()
327    {
328       return isTransactionQueryTimeout;
329    }
330
331    public void setTransactionQueryTimeout(boolean value)
332    {
333       isTransactionQueryTimeout = value;
334    }
335
336    public int getQueryTimeout()
337    {
338       return queryTimeout;
339    }
340
341    public void setQueryTimeout(int timeout)
342    {
343       queryTimeout = timeout;
344    }
345  
346    public Set JavaDoc getInvalidConnections(final Set JavaDoc connectionSet) throws ResourceException JavaDoc
347    {
348       final Set JavaDoc invalid = new HashSet JavaDoc();
349
350       for (Iterator JavaDoc iter = connectionSet.iterator(); iter.hasNext();)
351       {
352          final Object JavaDoc anonymous = iter.next();
353
354          if (anonymous instanceof BaseWrapperManagedConnection)
355          {
356             BaseWrapperManagedConnection mc = (BaseWrapperManagedConnection) anonymous;
357
358             if (!mc.checkValid())
359             {
360                invalid.add(mc);
361
362             }
363
364          }
365
366       }
367
368       return invalid;
369    }
370    
371    
372    /**
373     * Gets full set of connection properties, i.e. whatever is provided
374     * in config plus "user" and "password" from subject/cri.
375     *
376     * <p>Note that the set is used to match connections to datasources as well
377     * as to create new managed connections.
378     *
379     * <p>In fact, we have a problem here. Theoretically, there is a possible
380     * name collision between config properties and "user"/"password".
381     */

382    protected Properties JavaDoc getConnectionProperties(Subject JavaDoc subject, ConnectionRequestInfo JavaDoc cri)
383       throws ResourceException JavaDoc
384    {
385       if (cri != null && cri.getClass() != WrappedConnectionRequestInfo.class)
386          throw new JBossResourceException("Wrong kind of ConnectionRequestInfo: " + cri.getClass());
387
388       Properties JavaDoc props = new Properties JavaDoc();
389       props.putAll(connectionProps);
390       if (subject != null)
391       {
392          if (SubjectActions.addMatchingProperties(subject, props, this) == true)
393             return props;
394          throw new JBossResourceException("No matching credentials in Subject!");
395       }
396       WrappedConnectionRequestInfo lcri = (WrappedConnectionRequestInfo)cri;
397       if (lcri != null)
398       {
399          props.setProperty("user", (lcri.getUserName() == null)? "": lcri.getUserName());
400          props.setProperty("password", (lcri.getPassword() == null)? "": lcri.getPassword());
401          return props;
402       }
403       if (userName != null)
404       {
405          props.setProperty("user", userName);
406          props.setProperty("password", (password == null) ? "" : password);
407       }
408       return props;
409    }
410
411    boolean isExceptionFatal(SQLException JavaDoc e)
412    {
413       try
414       {
415          if (exceptionSorter != null)
416             return exceptionSorter.isExceptionFatal(e);
417
418          if (exceptionSorterClassName != null)
419          {
420             try
421             {
422                ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
423                Class JavaDoc clazz = cl.loadClass(exceptionSorterClassName);
424                exceptionSorter = (ExceptionSorter)clazz.newInstance();
425                return exceptionSorter.isExceptionFatal(e);
426             }
427             catch (Exception JavaDoc e2)
428             {
429                log.warn("exception trying to create exception sorter (disabling):", e2);
430                exceptionSorter = new NullExceptionSorter();
431             }
432          }
433       }
434       catch (Throwable JavaDoc t)
435       {
436          log.warn("Error checking exception fatality: ", t);
437       }
438       return false;
439    }
440
441    /**
442     * Checks whether a connection is valid
443     */

444    SQLException JavaDoc isValidConnection(Connection JavaDoc c)
445    {
446       // Already got a checker
447
if (connectionChecker != null)
448          return connectionChecker.isValidConnection(c);
449
450       // Class specified
451
if (validConnectionCheckerClassName != null)
452       {
453          try
454          {
455             ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
456             Class JavaDoc clazz = cl.loadClass(validConnectionCheckerClassName);
457             connectionChecker = (ValidConnectionChecker) clazz.newInstance();
458             return connectionChecker.isValidConnection(c);
459          }
460          catch (Exception JavaDoc e)
461          {
462             log.warn("Exception trying to create connection checker (disabling):", e);
463             connectionChecker = new NullValidConnectionChecker();
464          }
465       }
466
467       // SQL statement specified
468
if (checkValidConnectionSQL != null)
469       {
470          connectionChecker = new CheckValidConnectionSQL(checkValidConnectionSQL);
471          return connectionChecker.isValidConnection(c);
472       }
473
474       // No Check
475
return null;
476    }
477
478    boolean isStaleConnection(SQLException JavaDoc e)
479    {
480       boolean isStale = false;
481       
482       if(staleConnectionChecker != null)
483       {
484       
485          isStale = staleConnectionChecker.isStaleConnection(e);
486          
487       }
488       
489       if(staleConnectionCheckerClassName != null)
490       {
491          
492          try
493          {
494             
495             ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
496             Class JavaDoc clazz = cl.loadClass(staleConnectionCheckerClassName);
497             staleConnectionChecker = (StaleConnectionChecker)clazz.newInstance();
498             isStale = staleConnectionChecker.isStaleConnection(e);
499             
500          }catch (Exception JavaDoc ex2)
501          {
502             log.warn("exception trying to create stale connection checker (disabling)" + staleConnectionCheckerClassName, ex2);
503             staleConnectionChecker = new NullStaleConnectionChecker();
504          
505          }
506       
507       }
508             
509       return isStale;
510    }
511    
512
513    
514    static class SubjectActions implements PrivilegedAction JavaDoc
515    {
516       Subject JavaDoc subject;
517
518       Properties JavaDoc props;
519
520       ManagedConnectionFactory JavaDoc mcf;
521
522       SubjectActions(Subject JavaDoc subject, Properties JavaDoc props, ManagedConnectionFactory JavaDoc mcf)
523       {
524          this.subject = subject;
525          this.props = props;
526          this.mcf = mcf;
527       }
528
529       public Object JavaDoc run()
530       {
531          Iterator JavaDoc i = subject.getPrivateCredentials().iterator();
532          while (i.hasNext())
533          {
534             Object JavaDoc o = i.next();
535             if (o instanceof PasswordCredential JavaDoc)
536             {
537                PasswordCredential JavaDoc cred = (PasswordCredential JavaDoc) o;
538                if (cred.getManagedConnectionFactory().equals(mcf))
539                {
540                   props.setProperty("user", (cred.getUserName() == null) ? "" : cred.getUserName());
541                   if( cred.getPassword() != null )
542                      props.setProperty("password", new String JavaDoc(cred.getPassword()));
543                   return Boolean.TRUE;
544                }
545             }
546          }
547          return Boolean.FALSE;
548       }
549
550       static boolean addMatchingProperties(Subject JavaDoc subject, Properties JavaDoc props, ManagedConnectionFactory JavaDoc mcf)
551       {
552          SubjectActions action = new SubjectActions(subject, props, mcf);
553          Boolean JavaDoc matched = (Boolean JavaDoc) AccessController.doPrivileged(action);
554          return matched.booleanValue();
555       }
556    }
557 }
558
Popular Tags