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 java.sql.Connection;
20 import java.sql.SQLException;
21
22 import javax.naming.Context;
23 import javax.naming.InitialContext;
24 import javax.naming.NamingException;
25
26 // PortableRemoteObject was introduced in JDK 1.3. We won't use it.
27 // import javax.rmi.PortableRemoteObject;
28 import javax.sql.DataSource;
29
30
31 /**
32 * The {@code JNDIConnectionSource} is an implementation of
33 * {@link ConnectionSource} that obtains a {@link javax.sql.DataSource} from a
34 * JNDI provider and uses it to obtain a {@link java.sql.Connection}. It is
35 * primarily designed to be used inside of J2EE application servers or
36 * application server clients, assuming the application server supports remote
37 * access of {@link javax.sql.DataSource}s. In this way one can take
38 * advantage of connection pooling and whatever other goodies the application
39 * server provides.
40 * <p>
41 * Sample configuration:<br>
42 * <pre>
43 * <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource">
44 * <param name="jndiLocation" value="jdbc/MySQLDS" />
45 * </connectionSource>
46 * </pre>
47 * <p>
48 * Sample configuration (with username and password):<br>
49 * <pre>
50 * <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource">
51 * <param name="jndiLocation" value="jdbc/MySQLDS" />
52 * <param name="username" value="myUser" />
53 * <param name="password" value="myPassword" />
54 * </connectionSource>
55 * </pre>
56 * <p>
57 * Note that this class will obtain an {@link javax.naming.InitialContext}
58 * using the no-argument constructor. This will usually work when executing
59 * within a J2EE environment. When outside the J2EE environment, make sure
60 * that you provide a jndi.properties file as described by your JNDI
61 * provider's documentation.
62 *
63 * @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
64 */
65 public class JNDIConnectionSource
66 extends ConnectionSourceSkeleton {
67 private String jndiLocation = null;
68 private DataSource dataSource = null;
69
70 /**
71 * @see org.apache.log4j.spi.OptionHandler#activateOptions()
72 */
73 public void activateOptions() {
74 if (jndiLocation == null) {
75 getLogger().error("No JNDI location specified for JNDIConnectionSource.");
76 }
77
78 discoverConnnectionProperties();
79
80 }
81
82 /**
83 * @see org.apache.log4j.db.ConnectionSource#getConnection()
84 */
85 public Connection getConnection()
86 throws SQLException {
87 Connection conn = null;
88 try {
89
90 if(dataSource == null) {
91 dataSource = lookupDataSource();
92 }
93 if (getUser() == null) {
94 conn = dataSource.getConnection();
95 } else {
96 conn = dataSource.getConnection(getUser(), getPassword());
97 }
98 } catch (final NamingException ne) {
99 getLogger().error("Error while getting data source", ne);
100 throw new SQLException("NamingException while looking up DataSource: " + ne.getMessage());
101 } catch (final ClassCastException cce) {
102 getLogger().error("ClassCastException while looking up DataSource.", cce);
103 throw new SQLException("ClassCastException while looking up DataSource: " + cce.getMessage());
104 }
105
106 return conn;
107 }
108
109 /**
110 * Returns the jndiLocation.
111 * @return String
112 */
113 public String getJndiLocation() {
114 return jndiLocation;
115 }
116
117
118 /**
119 * Sets the jndiLocation.
120 * @param jndiLocation The jndiLocation to set
121 */
122 public void setJndiLocation(String jndiLocation) {
123 this.jndiLocation = jndiLocation;
124 }
125
126
127 private DataSource lookupDataSource()
128 throws NamingException, SQLException {
129 DataSource ds;
130 Context ctx = new InitialContext();
131 Object obj = ctx.lookup(jndiLocation);
132
133 // PortableRemoteObject was introduced in JDK 1.3. We won't use it.
134 //ds = (DataSource)PortableRemoteObject.narrow(obj, DataSource.class);
135 ds = (DataSource) obj;
136
137 if (ds == null) {
138 throw new SQLException("Failed to obtain data source from JNDI location " + jndiLocation);
139 } else {
140 return ds;
141 }
142 }
143 }