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 }