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 }