KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > torque > dsfactory > JndiDataSourceFactory


1 package org.apache.torque.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.util.Hashtable JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.StringTokenizer JavaDoc;
26
27 import javax.naming.Context JavaDoc;
28 import javax.naming.InitialContext JavaDoc;
29 import javax.naming.NameAlreadyBoundException JavaDoc;
30 import javax.naming.NamingException JavaDoc;
31 import javax.sql.DataSource JavaDoc;
32
33 import org.apache.commons.configuration.Configuration;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 import org.apache.torque.TorqueException;
39
40 /**
41  * A factory that looks up the DataSource from JNDI. It is also able
42  * to deploy the DataSource based on properties found in the
43  * configuration.
44  *
45  * This factory tries to avoid excessive context lookups to improve speed.
46  * The time between two lookups can be configured. The default is 0 (no cache).
47  *
48  * @author <a HREF="mailto:jmcnally@apache.org">John McNally</a>
49  * @author <a HREF="mailto:thomas@vandahl.org">Thomas Vandahl</a>
50  * @version $Id: JndiDataSourceFactory.java 476550 2006-11-18 16:08:37Z tfischer $
51  */

52 public class JndiDataSourceFactory
53     extends AbstractDataSourceFactory
54 {
55     /**
56      * Key for the configuration which contains jndi properties.
57      */

58     public static final String JavaDoc JNDI_KEY = "jndi";
59
60     /**
61      * Key for the configuration property which contains the jndi path.
62      */

63     public static final String JavaDoc PATH_KEY = "path";
64
65     /**
66      * Key for the configuration property which contains the
67      * time between two jndi lookups.
68      */

69     public static final String JavaDoc TIME_BETWEEN_LOOKUPS_KEY = "ttl";
70
71     /**
72      * Key for the configuration which contains properties for a DataSource
73      * which should be bound into jndi.
74      */

75     public static final String JavaDoc DATASOURCE_KEY = "datasource";
76
77     /**
78      * Key for the configuration property which contains the class name
79      * of the datasource to be bound into jndi.
80      */

81     public static final String JavaDoc CLASSNAME_KEY = "classname";
82
83     /** The log. */
84     private static Log log = LogFactory.getLog(JndiDataSourceFactory.class);
85
86     /** The path to get the resource from. */
87     private String JavaDoc path;
88     /** The context to get the resource from. */
89     private Context JavaDoc ctx;
90
91     /** A locally cached copy of the DataSource */
92     private DataSource JavaDoc ds = null;
93
94     /** Time of last actual lookup action */
95     private long lastLookup = 0;
96
97     /** Time between two lookups */
98     private long ttl = 0; // ms
99

100     /**
101      * @see org.apache.torque.dsfactory.DataSourceFactory#getDataSource
102      */

103     public DataSource JavaDoc getDataSource() throws TorqueException
104     {
105         long time = System.currentTimeMillis();
106
107         if (ds == null || time - lastLookup > ttl)
108         {
109             try
110             {
111                 ds = ((DataSource JavaDoc) ctx.lookup(path));
112                 lastLookup = time;
113             }
114             catch (Exception JavaDoc e)
115             {
116                 throw new TorqueException(e);
117             }
118         }
119
120         return ds;
121     }
122
123     /**
124      * @see org.apache.torque.dsfactory.DataSourceFactory#initialize
125      */

126     public void initialize(Configuration configuration) throws TorqueException
127     {
128         super.initialize(configuration);
129
130         initJNDI(configuration);
131         initDataSource(configuration);
132     }
133
134     /**
135      * Initializes JNDI.
136      *
137      * @param configuration where to read the settings from
138      * @throws TorqueException if a property set fails
139      */

140     private void initJNDI(Configuration configuration) throws TorqueException
141     {
142         log.debug("Starting initJNDI");
143
144         Configuration c = configuration.subset(JNDI_KEY);
145         if (c == null || c.isEmpty())
146         {
147             throw new TorqueException(
148                 "JndiDataSourceFactory requires a jndi "
149                     + "path property to lookup the DataSource in JNDI.");
150         }
151
152         try
153         {
154             Hashtable JavaDoc env = new Hashtable JavaDoc();
155             for (Iterator JavaDoc i = c.getKeys(); i.hasNext();)
156             {
157                 String JavaDoc key = (String JavaDoc) i.next();
158                 if (key.equals(PATH_KEY))
159                 {
160                     path = c.getString(key);
161                     if (log.isDebugEnabled())
162                     {
163                         log.debug("JNDI path: " + path);
164                     }
165                 }
166                 else if (key.equals(TIME_BETWEEN_LOOKUPS_KEY))
167                 {
168                     ttl = c.getLong(key, ttl);
169                     if (log.isDebugEnabled())
170                     {
171                         log.debug("Time between context lookups: " + ttl);
172                     }
173                 }
174                 else
175                 {
176                     String JavaDoc value = c.getString(key);
177                     env.put(key, value);
178                     if (log.isDebugEnabled())
179                     {
180                         log.debug("Set jndi property: " + key + "=" + value);
181                     }
182                 }
183             }
184
185             ctx = new InitialContext JavaDoc(env);
186             log.debug("Created new InitialContext");
187             debugCtx(ctx);
188         }
189         catch (Exception JavaDoc e)
190         {
191             log.error("", e);
192             throw new TorqueException(e);
193         }
194     }
195
196     /**
197      * Initializes the DataSource.
198      *
199      * @param configuration where to read the settings from
200      * @throws TorqueException if a property set fails
201      */

202     private void initDataSource(Configuration configuration)
203         throws TorqueException
204     {
205         log.debug("Starting initDataSource");
206         try
207         {
208             Object JavaDoc dataSource = null;
209
210             Configuration c = configuration.subset(DATASOURCE_KEY);
211             if (c != null)
212             {
213                 for (Iterator JavaDoc i = c.getKeys(); i.hasNext();)
214                 {
215                     String JavaDoc key = (String JavaDoc) i.next();
216                     if (key.equals(CLASSNAME_KEY))
217                     {
218                         String JavaDoc classname = c.getString(key);
219                         if (log.isDebugEnabled())
220                         {
221                             log.debug("Datasource class: " + classname);
222                         }
223
224                         Class JavaDoc dsClass = Class.forName(classname);
225                         dataSource = dsClass.newInstance();
226                     }
227                     else
228                     {
229                         if (dataSource != null)
230                         {
231                             if (log.isDebugEnabled())
232                             {
233                                 log.debug("Setting datasource property: " + key);
234                             }
235                             setProperty(key, c, dataSource);
236                         }
237                         else
238                         {
239                             log.error("Tried to set property " + key
240                                     + " without Datasource definition!");
241                         }
242                     }
243                 }
244             }
245
246             if (dataSource != null)
247             {
248                 bindDStoJndi(ctx, path, dataSource);
249             }
250         }
251         catch (Exception JavaDoc e)
252         {
253             log.error("", e);
254             throw new TorqueException(e);
255         }
256     }
257
258     /**
259      * Does nothing. We do not want to close a dataSource retrieved from Jndi,
260      * because other applications might use it as well.
261      */

262     public void close()
263     {
264         // do nothing
265
}
266
267     /**
268      *
269      * @param ctx the context
270      * @throws NamingException
271      */

272     private void debugCtx(Context JavaDoc ctx) throws NamingException JavaDoc
273     {
274         log.debug("InitialContext -------------------------------");
275         Map JavaDoc env = ctx.getEnvironment();
276         Iterator JavaDoc qw = env.entrySet().iterator();
277         log.debug("Environment properties:" + env.size());
278         while (qw.hasNext())
279         {
280             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) qw.next();
281             log.debug(" " + entry.getKey() + ": " + entry.getValue());
282         }
283         log.debug("----------------------------------------------");
284     }
285
286     /**
287      *
288      * @param ctx
289      * @param path
290      * @param ds
291      * @throws Exception
292      */

293     private void bindDStoJndi(Context JavaDoc ctx, String JavaDoc path, Object JavaDoc ds)
294         throws Exception JavaDoc
295     {
296         debugCtx(ctx);
297
298         // add subcontexts, if not added already
299
int start = path.indexOf(':') + 1;
300         if (start > 0)
301         {
302             path = path.substring(start);
303         }
304         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(path, "/");
305         while (st.hasMoreTokens())
306         {
307             String JavaDoc subctx = st.nextToken();
308             if (st.hasMoreTokens())
309             {
310                 try
311                 {
312                     ctx.createSubcontext(subctx);
313                     log.debug("Added sub context: " + subctx);
314                 }
315                 catch (NameAlreadyBoundException JavaDoc nabe)
316                 {
317                     // ignore
318
log.debug("Sub context " + subctx + " already exists");
319                 }
320                 catch (NamingException JavaDoc ne)
321                 {
322                     log.debug("Naming exception caught "
323                                 + "when creating subcontext"
324                                 + subctx,
325                             ne);
326                     // even though there is a specific exception
327
// for this condition, some implementations
328
// throw the more general one.
329
/*
330                      * if (ne.getMessage().indexOf("already bound") == -1 )
331                      * {
332                      * throw ne;
333                      * }
334                      */

335                     // ignore
336
}
337                 ctx = (Context JavaDoc) ctx.lookup(subctx);
338             }
339             else
340             {
341                 // not really a subctx, it is the ds name
342
ctx.bind(subctx, ds);
343             }
344         }
345     }
346 }
347
Popular Tags