View Javadoc

1   package org.apache.torque.dsfactory;
2   
3   /*
4    * Copyright 2001-2004 The Apache Software Foundation.
5    * 
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    * 
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.util.Hashtable;
20  import java.util.Iterator;
21  import java.util.Map;
22  import java.util.StringTokenizer;
23  
24  import javax.naming.Context;
25  import javax.naming.InitialContext;
26  import javax.naming.NameAlreadyBoundException;
27  import javax.naming.NamingException;
28  import javax.sql.DataSource;
29  
30  import org.apache.commons.configuration.Configuration;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  
35  import org.apache.torque.TorqueException;
36  
37  /***
38   * A factory that looks up the DataSource from JNDI.  It is also able
39   * to deploy the DataSource based on properties found in the
40   * configuration.
41   *
42   * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
43   * @version $Id: JndiDataSourceFactory.java,v 1.7 2004/02/22 06:18:52 jmcnally Exp $
44   */
45  public class JndiDataSourceFactory
46      extends AbstractDataSourceFactory
47      implements DataSourceFactory
48  {
49  
50      /*** The log. */
51      private static Log log = LogFactory.getLog(JndiDataSourceFactory.class);
52  
53      /*** The path to get the resource from. */
54      private String path;
55      /*** The context to get the resource from. */
56      private Context ctx;
57  
58      /***
59       * @see org.apache.torque.dsfactory.DataSourceFactory#getDataSource
60       */
61      public DataSource getDataSource() throws TorqueException
62      {
63          DataSource ds = null;
64          try
65          {
66              ds = ((DataSource) ctx.lookup(path));
67          }
68          catch (Exception e)
69          {
70              throw new TorqueException(e);
71          }
72          return ds;
73      }
74  
75      /***
76       * @see org.apache.torque.dsfactory.DataSourceFactory#initialize
77       */
78      public void initialize(Configuration configuration) throws TorqueException
79      {
80          if (configuration == null)
81          {
82              throw new TorqueException(
83                  "Torque cannot be initialized without "
84                      + "a valid configuration. Please check the log files "
85                      + "for further details.");
86          }
87          initJNDI(configuration);
88          initDataSource(configuration);
89      }
90  
91      /***
92       * Initializes JNDI.
93       *
94       * @param configuration where to read the settings from
95       * @throws TorqueException if a property set fails
96       */
97      private void initJNDI(Configuration configuration) throws TorqueException
98      {
99          log.debug("Starting initJNDI");
100         Hashtable env = null;
101         Configuration c = configuration.subset("jndi");
102         if (c == null)
103         {
104             throw new TorqueException(
105                 "JndiDataSourceFactory requires a jndi "
106                     + "path property to lookup the DataSource in JNDI.");
107         }
108         try
109         {
110             Iterator i = c.getKeys();
111             while (i.hasNext())
112             {
113                 String key = (String) i.next();
114                 if (key.equals("path"))
115                 {
116                     path = c.getString(key);
117                     log.debug("JNDI path: " + path);
118                 }
119                 else
120                 {
121                     if (env == null)
122                     {
123                         env = new Hashtable();
124                     }
125                     String value = c.getString(key);
126                     env.put(key, value);
127                     log.debug("Set jndi property: " + key + "=" + value);
128                 }
129             }
130             if (env == null)
131             {
132                 ctx = new InitialContext();
133             }
134             else
135             {
136                 ctx = new InitialContext(env);
137             }
138             log.debug("Created new InitialContext");
139             debugCtx(ctx);
140         }
141         catch (Exception e)
142         {
143             log.error("", e);
144             throw new TorqueException(e);
145         }
146     }
147 
148     /***
149      * Initializes the DataSource.
150      *
151      * @param configuration where to read the settings from
152      * @throws TorqueException if a property set fails
153      */
154     private void initDataSource(Configuration configuration)
155         throws TorqueException
156     {
157         log.debug("Starting initDataSources");
158         Configuration c = configuration.subset("datasource");
159         try
160         {
161             if (c != null)
162             {
163                 Object ds = null;
164                 Iterator i = c.getKeys();
165                 while (i.hasNext())
166                 {
167                     String key = (String) i.next();
168                     if (key.equals("classname"))
169                     {
170                         String classname = c.getString(key);
171                         log.debug("Datasource class: " + classname);
172 
173                         Class dsClass = Class.forName(classname);
174                         ds = dsClass.newInstance();
175                     }
176                     else
177                     {
178                         log.debug("Setting datasource property: " + key);
179                         setProperty(key, c, ds);
180                     }
181                 }
182 
183                 bindDStoJndi(ctx, path, ds);
184             }
185         }
186         catch (Exception e)
187         {
188             log.error("", e);
189             throw new TorqueException(e);
190         }
191     }
192 
193     /***
194      *
195      * @param ctx the context
196      * @throws NamingException
197      */
198     private void debugCtx(Context ctx) throws NamingException
199     {
200         log.debug("InitialContext -------------------------------");
201         Map env = ctx.getEnvironment();
202         Iterator qw = env.keySet().iterator();
203         log.debug("Environment properties:" + env.size());
204         while (qw.hasNext())
205         {
206             Object prop = qw.next();
207             log.debug("    " + prop + ": " + env.get(prop));
208         }
209         log.debug("----------------------------------------------");
210     }
211 
212     /***
213      *
214      * @param ctx
215      * @param path
216      * @param ds
217      * @throws Exception
218      */
219     private void bindDStoJndi(Context ctx, String path, Object ds)
220         throws Exception
221     {
222         debugCtx(ctx);
223 
224         // add subcontexts, if not added already
225         int start = path.indexOf(':') + 1;
226         if (start > 0)
227         {
228             path = path.substring(start);
229         }
230         StringTokenizer st = new StringTokenizer(path, "/");
231         while (st.hasMoreTokens())
232         {
233             String subctx = st.nextToken();
234             if (st.hasMoreTokens())
235             {
236                 try
237                 {
238                     ctx.createSubcontext(subctx);
239                     log.debug("Added sub context: " + subctx);
240                 }
241                 catch (NameAlreadyBoundException nabe)
242                 {
243                     // ignore
244                 }
245                 catch (NamingException ne)
246                 {
247                     // even though there is a specific exception
248                     // for this condition, some implementations
249                     // throw the more general one.
250                     /*
251                       if (ne.getMessage().indexOf("already bound") == -1 )
252                       {
253                       throw ne;
254                       }
255                     */
256                     // ignore
257                 }
258                 ctx = (Context) ctx.lookup(subctx);
259             }
260             else
261             {
262                 // not really a subctx, it is the ds name
263                 ctx.bind(subctx, ds);
264             }
265         }
266     }
267 }