View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.db;
18  
19  import javax.naming.Context;
20  import javax.naming.InitialContext;
21  import javax.naming.NamingException;
22  import javax.sql.DataSource;
23  import java.sql.Connection;
24  import java.sql.SQLException;
25  
26  // PortableRemoteObject was introduced in JDK 1.3. We won't use it.
27  // import javax.rmi.PortableRemoteObject;
28  
29  
30  /**
31   * The {@code JNDIConnectionSource} is an implementation of
32   * {@link ConnectionSource} that obtains a {@link javax.sql.DataSource} from a
33   * JNDI provider and uses it to obtain a {@link java.sql.Connection}.  It is
34   * primarily designed to be used inside of J2EE application servers or
35   * application server clients, assuming the application server supports remote
36   * access of {@link javax.sql.DataSource}s.  In this way one can take
37   * advantage of  connection pooling and whatever other goodies the application
38   * server provides.
39   * <p>
40   * Sample configuration:<br>
41   * <pre>
42   *    &lt;connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource"&gt;
43   *        &lt;param name="jndiLocation" value="jdbc/MySQLDS" /&gt;
44   *    &lt;/connectionSource&gt;
45   *  </pre>
46   * <p>
47   * Sample configuration (with username and password):<br>
48   * <pre>
49   *    &lt;connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource"&gt;
50   *        &lt;param name="jndiLocation" value="jdbc/MySQLDS" /&gt;
51   *        &lt;param name="username" value="myUser" /&gt;
52   *        &lt;param name="password" value="myPassword" /&gt;
53   *    &lt;/connectionSource&gt;
54   *  </pre>
55   * <p>
56   * Note that this class will obtain an {@link javax.naming.InitialContext}
57   * using the no-argument constructor.  This will usually work when executing
58   * within a J2EE environment.  When outside the J2EE environment, make sure
59   * that you provide a jndi.properties file as described by your JNDI
60   * provider's documentation.
61   *
62   * @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
63   */
64  public class JNDIConnectionSource
65      extends ConnectionSourceSkeleton {
66      private String jndiLocation = null;
67      private DataSource dataSource = null;
68  
69      /**
70       * @see org.apache.log4j.spi.OptionHandler#activateOptions()
71       */
72      public void activateOptions() {
73          if (jndiLocation == null) {
74              getLogger().error("No JNDI location specified for JNDIConnectionSource.");
75          }
76  
77          discoverConnnectionProperties();
78  
79      }
80  
81      /**
82       * @see org.apache.log4j.db.ConnectionSource#getConnection()
83       */
84      public Connection getConnection()
85          throws SQLException {
86          Connection conn;
87          try {
88  
89              if (dataSource == null) {
90                  dataSource = lookupDataSource();
91              }
92              if (getUser() == null) {
93                  conn = dataSource.getConnection();
94              } else {
95                  conn = dataSource.getConnection(getUser(), getPassword());
96              }
97          } catch (final NamingException ne) {
98              getLogger().error("Error while getting data source", ne);
99              throw new SQLException("NamingException while looking up DataSource: " + ne.getMessage());
100         } catch (final ClassCastException cce) {
101             getLogger().error("ClassCastException while looking up DataSource.", cce);
102             throw new SQLException("ClassCastException while looking up DataSource: " + cce.getMessage());
103         }
104 
105         return conn;
106     }
107 
108     /**
109      * Returns the jndiLocation.
110      *
111      * @return String
112      */
113     public String getJndiLocation() {
114         return jndiLocation;
115     }
116 
117 
118     /**
119      * Sets the jndiLocation.
120      *
121      * @param jndiLocation The jndiLocation to set
122      */
123     public void setJndiLocation(String jndiLocation) {
124         this.jndiLocation = jndiLocation;
125     }
126 
127 
128     private DataSource lookupDataSource()
129         throws NamingException, SQLException {
130         DataSource ds;
131         Context ctx = new InitialContext();
132         Object obj = ctx.lookup(jndiLocation);
133 
134         // PortableRemoteObject was introduced in JDK 1.3. We won't use it.
135         //ds = (DataSource)PortableRemoteObject.narrow(obj, DataSource.class);
136         ds = (DataSource) obj;
137 
138         if (ds == null) {
139             throw new SQLException("Failed to obtain data source from JNDI location " + jndiLocation);
140         } else {
141             return ds;
142         }
143     }
144 }