View Javadoc

1   package org.apache.torque.dsfactory;
2   
3   /* ====================================================================
4    * The Apache Software License, Version 1.1
5    *
6    * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
7    * reserved.
8    *
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   *
13   * 1. Redistributions of source code must retain the above copyright
14   *    notice, this list of conditions and the following disclaimer.
15   *
16   * 2. Redistributions in binary form must reproduce the above copyright
17   *    notice, this list of conditions and the following disclaimer in
18   *    the documentation and/or other materials provided with the
19   *    distribution.
20   *
21   * 3. The end-user documentation included with the redistribution,
22   *    if any, must include the following acknowledgment:
23   *       "This product includes software developed by the
24   *        Apache Software Foundation (http://www.apache.org/)."
25   *    Alternately, this acknowledgment may appear in the software itself,
26   *    if and wherever such third-party acknowledgments normally appear.
27   *
28   * 4. The names "Apache" and "Apache Software Foundation" and
29   *    "Apache Turbine" must not be used to endorse or promote products
30   *    derived from this software without prior written permission. For
31   *    written permission, please contact apache@apache.org.
32   *
33   * 5. Products derived from this software may not be called "Apache",
34   *    "Apache Turbine", nor may "Apache" appear in their name, without
35   *    prior written permission of the Apache Software Foundation.
36   *
37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48   * SUCH DAMAGE.
49   * ====================================================================
50   *
51   * This software consists of voluntary contributions made by many
52   * individuals on behalf of the Apache Software Foundation.  For more
53   * information on the Apache Software Foundation, please see
54   * <http://www.apache.org/>.
55   */
56  
57  import java.util.Hashtable;
58  import java.util.Iterator;
59  import java.util.Map;
60  import java.util.StringTokenizer;
61  
62  import javax.naming.Context;
63  import javax.naming.InitialContext;
64  import javax.naming.NameAlreadyBoundException;
65  import javax.naming.NamingException;
66  import javax.sql.DataSource;
67  
68  import org.apache.commons.configuration.Configuration;
69  
70  import org.apache.commons.logging.Log;
71  import org.apache.commons.logging.LogFactory;
72  
73  import org.apache.torque.TorqueException;
74  
75  /***
76   * A factory that looks up the DataSource from JNDI.  It is also able
77   * to deploy the DataSource based on properties found in the
78   * configuration.
79   *
80   * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
81   * @version $Id: JndiDataSourceFactory.java,v 1.6 2003/05/14 19:38:04 mpoeschl Exp $
82   */
83  public class JndiDataSourceFactory
84      extends AbstractDataSourceFactory
85      implements DataSourceFactory
86  {
87  
88      /*** The log. */
89      private static Log log = LogFactory.getLog(JndiDataSourceFactory.class);
90  
91      /*** The path to get the resource from. */
92      private String path;
93      /*** The context to get the resource from. */
94      private Context ctx;
95  
96      /***
97       * @see org.apache.torque.dsfactory.DataSourceFactory#getDataSource
98       */
99      public DataSource getDataSource() throws TorqueException
100     {
101         DataSource ds = null;
102         try
103         {
104             ds = ((DataSource) ctx.lookup(path));
105         }
106         catch (Exception e)
107         {
108             throw new TorqueException(e);
109         }
110         return ds;
111     }
112 
113     /***
114      * @see org.apache.torque.dsfactory.DataSourceFactory#initialize
115      */
116     public void initialize(Configuration configuration) throws TorqueException
117     {
118         if (configuration == null)
119         {
120             throw new TorqueException(
121                 "Torque cannot be initialized without "
122                     + "a valid configuration. Please check the log files "
123                     + "for further details.");
124         }
125         initJNDI(configuration);
126         initDataSource(configuration);
127     }
128 
129     /***
130      * Initializes JNDI.
131      *
132      * @param configuration where to read the settings from
133      * @throws TorqueException if a property set fails
134      */
135     private void initJNDI(Configuration configuration) throws TorqueException
136     {
137         log.debug("Starting initJNDI");
138         Hashtable env = null;
139         Configuration c = configuration.subset("jndi");
140         if (c == null)
141         {
142             throw new TorqueException(
143                 "JndiDataSourceFactory requires a jndi "
144                     + "path property to lookup the DataSource in JNDI.");
145         }
146         try
147         {
148             Iterator i = c.getKeys();
149             while (i.hasNext())
150             {
151                 String key = (String) i.next();
152                 if (key.equals("path"))
153                 {
154                     path = c.getString(key);
155                     log.debug("JNDI path: " + path);
156                 }
157                 else
158                 {
159                     if (env == null)
160                     {
161                         env = new Hashtable();
162                     }
163                     String value = c.getString(key);
164                     env.put(key, value);
165                     log.debug("Set jndi property: " + key + "=" + value);
166                 }
167             }
168             if (env == null)
169             {
170                 ctx = new InitialContext();
171             }
172             else
173             {
174                 ctx = new InitialContext(env);
175             }
176             log.debug("Created new InitialContext");
177             debugCtx(ctx);
178         }
179         catch (Exception e)
180         {
181             log.error("", e);
182             throw new TorqueException(e);
183         }
184     }
185 
186     /***
187      * Initializes the DataSource.
188      *
189      * @param configuration where to read the settings from
190      * @throws TorqueException if a property set fails
191      */
192     private void initDataSource(Configuration configuration)
193         throws TorqueException
194     {
195         log.debug("Starting initDataSources");
196         Configuration c = configuration.subset("datasource");
197         try
198         {
199             if (c != null)
200             {
201                 Object ds = null;
202                 Iterator i = c.getKeys();
203                 while (i.hasNext())
204                 {
205                     String key = (String) i.next();
206                     if (key.equals("classname"))
207                     {
208                         String classname = c.getString(key);
209                         log.debug("Datasource class: " + classname);
210 
211                         Class dsClass = Class.forName(classname);
212                         ds = dsClass.newInstance();
213                     }
214                     else
215                     {
216                         log.debug("Setting datasource property: " + key);
217                         setProperty(key, c, ds);
218                     }
219                 }
220 
221                 bindDStoJndi(ctx, path, ds);
222             }
223         }
224         catch (Exception e)
225         {
226             log.error("", e);
227             throw new TorqueException(e);
228         }
229     }
230 
231     /***
232      *
233      * @param ctx the context
234      * @throws NamingException
235      */
236     private void debugCtx(Context ctx) throws NamingException
237     {
238         log.debug("InitialContext -------------------------------");
239         Map env = ctx.getEnvironment();
240         Iterator qw = env.keySet().iterator();
241         log.debug("Environment properties:" + env.size());
242         while (qw.hasNext())
243         {
244             Object prop = qw.next();
245             log.debug("    " + prop + ": " + env.get(prop));
246         }
247         log.debug("----------------------------------------------");
248     }
249 
250     /***
251      *
252      * @param ctx
253      * @param path
254      * @param ds
255      * @throws Exception
256      */
257     private void bindDStoJndi(Context ctx, String path, Object ds)
258         throws Exception
259     {
260         debugCtx(ctx);
261 
262         // add subcontexts, if not added already
263         int start = path.indexOf(':') + 1;
264         if (start > 0)
265         {
266             path = path.substring(start);
267         }
268         StringTokenizer st = new StringTokenizer(path, "/");
269         while (st.hasMoreTokens())
270         {
271             String subctx = st.nextToken();
272             if (st.hasMoreTokens())
273             {
274                 try
275                 {
276                     ctx.createSubcontext(subctx);
277                     log.debug("Added sub context: " + subctx);
278                 }
279                 catch (NameAlreadyBoundException nabe)
280                 {
281                     // ignore
282                 }
283                 catch (NamingException ne)
284                 {
285                     // even though there is a specific exception
286                     // for this condition, some implementations
287                     // throw the more general one.
288                     /*
289                       if (ne.getMessage().indexOf("already bound") == -1 )
290                       {
291                       throw ne;
292                       }
293                     */
294                     // ignore
295                 }
296                 ctx = (Context) ctx.lookup(subctx);
297             }
298             else
299             {
300                 // not really a subctx, it is the ds name
301                 ctx.bind(subctx, ds);
302             }
303         }
304     }
305 }