View Javadoc
1   package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.sql.SQLException;
23  import java.util.Hashtable;
24  import java.util.Iterator;
25  import java.util.Map;
26  
27  import javax.naming.Context;
28  import javax.naming.InitialContext;
29  import javax.naming.NamingException;
30  import javax.sql.DataSource;
31  
32  import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * A factory that looks up the DataSource from JNDI.  It is also able
38   * to deploy the DataSource based on properties found in the
39   * configuration.
40   *
41   * This factory tries to avoid excessive context lookups to improve speed.
42   * The time between two lookups can be configured. The default is 0 (no cache).
43   *
44   * Borrowed and adapted from Apache DB Torque
45   *
46   * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
47   * @author <a href="mailto:thomas@vandahl.org">Thomas Vandahl</a>
48   */
49  public class JndiDataSourceFactory implements DataSourceFactory
50  {
51      /** The log. */
52      private static Log log = LogFactory.getLog(JndiDataSourceFactory.class);
53  
54      /** The name of the factory. */
55      private String name;
56  
57      /** The path to get the resource from. */
58      private String path;
59  
60      /** The context to get the resource from. */
61      private Context ctx;
62  
63      /** A locally cached copy of the DataSource */
64      private DataSource ds = null;
65  
66      /** Time of last actual lookup action */
67      private long lastLookup = 0;
68  
69      /** Time between two lookups */
70      private long ttl = 0; // ms
71  
72      /**
73       * @return the name of the factory.
74       */
75      @Override
76  	public String getName()
77      {
78      	return name;
79      }
80  
81      /**
82       * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource()
83       */
84      @Override
85  	public DataSource getDataSource() throws SQLException
86      {
87          long time = System.currentTimeMillis();
88  
89          if (ds == null || time - lastLookup > ttl)
90          {
91              try
92              {
93                  synchronized (ctx)
94                  {
95                      ds = ((DataSource) ctx.lookup(path));
96                  }
97                  lastLookup = time;
98              }
99              catch (NamingException e)
100             {
101                 throw new SQLException(e);
102             }
103         }
104 
105         return ds;
106     }
107 
108     /**
109      * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes)
110      */
111     @Override
112 	public void initialize(JDBCDiskCacheAttributes config) throws SQLException
113     {
114     	this.name = config.getConnectionPoolName();
115         initJNDI(config);
116     }
117 
118     /**
119      * Initializes JNDI.
120      *
121      * @param config where to read the settings from
122      * @throws SQLException if a property set fails
123      */
124     private void initJNDI(JDBCDiskCacheAttributes config) throws SQLException
125     {
126         log.debug("Starting initJNDI");
127 
128         try
129         {
130             this.path = config.getJndiPath();
131             if (log.isDebugEnabled())
132             {
133                 log.debug("JNDI path: " + path);
134             }
135 
136             this.ttl = config.getJndiTTL();
137             if (log.isDebugEnabled())
138             {
139                 log.debug("Time between context lookups: " + ttl);
140             }
141 
142     		Hashtable<String, Object> env = new Hashtable<String, Object>();
143             ctx = new InitialContext(env);
144 
145             if (log.isDebugEnabled())
146             {
147             	log.debug("Created new InitialContext");
148             	debugCtx(ctx);
149             }
150         }
151         catch (NamingException e)
152         {
153             throw new SQLException(e);
154         }
155     }
156 
157     /**
158      * Does nothing. We do not want to close a dataSource retrieved from Jndi,
159      * because other applications might use it as well.
160      */
161     @Override
162 	public void close()
163     {
164         // do nothing
165     }
166 
167     /**
168      *
169      * @param ctx the context
170      * @throws NamingException
171      */
172     private void debugCtx(Context ctx) throws NamingException
173     {
174         log.debug("InitialContext -------------------------------");
175         Map<?, ?> env = ctx.getEnvironment();
176         Iterator<?> qw = env.entrySet().iterator();
177         log.debug("Environment properties:" + env.size());
178         while (qw.hasNext())
179         {
180             Map.Entry<?, ?> entry = (Map.Entry<?, ?>) qw.next();
181             log.debug("    " + entry.getKey() + ": " + entry.getValue());
182         }
183         log.debug("----------------------------------------------");
184     }
185 }