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 * <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource">
43 * <param name="jndiLocation" value="jdbc/MySQLDS" />
44 * </connectionSource>
45 * </pre>
46 * <p>
47 * Sample configuration (with username and password):<br>
48 * <pre>
49 * <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource">
50 * <param name="jndiLocation" value="jdbc/MySQLDS" />
51 * <param name="username" value="myUser" />
52 * <param name="password" value="myPassword" />
53 * </connectionSource>
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 }