001package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.sql.SQLException; 023import java.util.Hashtable; 024import java.util.Iterator; 025import java.util.Map; 026 027import javax.naming.Context; 028import javax.naming.InitialContext; 029import javax.naming.NamingException; 030import javax.sql.DataSource; 031 032import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035 036/** 037 * A factory that looks up the DataSource from JNDI. It is also able 038 * to deploy the DataSource based on properties found in the 039 * configuration. 040 * 041 * This factory tries to avoid excessive context lookups to improve speed. 042 * The time between two lookups can be configured. The default is 0 (no cache). 043 * 044 * Borrowed and adapted from Apache DB Torque 045 * 046 * @author <a href="mailto:jmcnally@apache.org">John McNally</a> 047 * @author <a href="mailto:thomas@vandahl.org">Thomas Vandahl</a> 048 */ 049public class JndiDataSourceFactory implements DataSourceFactory 050{ 051 /** The log. */ 052 private static Log log = LogFactory.getLog(JndiDataSourceFactory.class); 053 054 /** The name of the factory. */ 055 private String name; 056 057 /** The path to get the resource from. */ 058 private String path; 059 060 /** The context to get the resource from. */ 061 private Context ctx; 062 063 /** A locally cached copy of the DataSource */ 064 private DataSource ds = null; 065 066 /** Time of last actual lookup action */ 067 private long lastLookup = 0; 068 069 /** Time between two lookups */ 070 private long ttl = 0; // ms 071 072 /** 073 * @return the name of the factory. 074 */ 075 @Override 076 public String getName() 077 { 078 return name; 079 } 080 081 /** 082 * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource() 083 */ 084 @Override 085 public DataSource getDataSource() throws SQLException 086 { 087 long time = System.currentTimeMillis(); 088 089 if (ds == null || time - lastLookup > ttl) 090 { 091 try 092 { 093 synchronized (ctx) 094 { 095 ds = ((DataSource) ctx.lookup(path)); 096 } 097 lastLookup = time; 098 } 099 catch (NamingException e) 100 { 101 throw new SQLException(e); 102 } 103 } 104 105 return ds; 106 } 107 108 /** 109 * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes) 110 */ 111 @Override 112 public void initialize(JDBCDiskCacheAttributes config) throws SQLException 113 { 114 this.name = config.getConnectionPoolName(); 115 initJNDI(config); 116 } 117 118 /** 119 * Initializes JNDI. 120 * 121 * @param config where to read the settings from 122 * @throws SQLException if a property set fails 123 */ 124 private void initJNDI(JDBCDiskCacheAttributes config) throws SQLException 125 { 126 log.debug("Starting initJNDI"); 127 128 try 129 { 130 this.path = config.getJndiPath(); 131 if (log.isDebugEnabled()) 132 { 133 log.debug("JNDI path: " + path); 134 } 135 136 this.ttl = config.getJndiTTL(); 137 if (log.isDebugEnabled()) 138 { 139 log.debug("Time between context lookups: " + ttl); 140 } 141 142 Hashtable<String, Object> env = new Hashtable<String, Object>(); 143 ctx = new InitialContext(env); 144 145 if (log.isDebugEnabled()) 146 { 147 log.debug("Created new InitialContext"); 148 debugCtx(ctx); 149 } 150 } 151 catch (NamingException e) 152 { 153 throw new SQLException(e); 154 } 155 } 156 157 /** 158 * Does nothing. We do not want to close a dataSource retrieved from Jndi, 159 * because other applications might use it as well. 160 */ 161 @Override 162 public void close() 163 { 164 // do nothing 165 } 166 167 /** 168 * 169 * @param ctx the context 170 * @throws NamingException 171 */ 172 private void debugCtx(Context ctx) throws NamingException 173 { 174 log.debug("InitialContext -------------------------------"); 175 Map<?, ?> env = ctx.getEnvironment(); 176 Iterator<?> qw = env.entrySet().iterator(); 177 log.debug("Environment properties:" + env.size()); 178 while (qw.hasNext()) 179 { 180 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) qw.next(); 181 log.debug(" " + entry.getKey() + ": " + entry.getValue()); 182 } 183 log.debug("----------------------------------------------"); 184 } 185}