001package org.apache.commons.jcs3.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.Map; 025 026import javax.naming.Context; 027import javax.naming.InitialContext; 028import javax.naming.NamingException; 029import javax.sql.DataSource; 030 031import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; 032import org.apache.commons.jcs3.log.Log; 033import org.apache.commons.jcs3.log.LogManager; 034 035/** 036 * A factory that looks up the DataSource from JNDI. It is also able 037 * to deploy the DataSource based on properties found in the 038 * configuration. 039 * 040 * This factory tries to avoid excessive context lookups to improve speed. 041 * The time between two lookups can be configured. The default is 0 (no cache). 042 * 043 * Borrowed and adapted from Apache DB Torque 044 */ 045public class JndiDataSourceFactory implements DataSourceFactory 046{ 047 /** The log. */ 048 private static final Log log = LogManager.getLog(JndiDataSourceFactory.class); 049 050 /** The name of the factory. */ 051 private String name; 052 053 /** The path to get the resource from. */ 054 private String path; 055 056 /** The context to get the resource from. */ 057 private Context ctx; 058 059 /** A locally cached copy of the DataSource */ 060 private DataSource ds; 061 062 /** Time of last actual lookup action */ 063 private long lastLookup; 064 065 /** Time between two lookups */ 066 private long ttl; // ms 067 068 /** 069 * @return the name of the factory. 070 */ 071 @Override 072 public String getName() 073 { 074 return name; 075 } 076 077 /** 078 * @see org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource() 079 */ 080 @Override 081 public DataSource getDataSource() throws SQLException 082 { 083 final long time = System.currentTimeMillis(); 084 085 if (ds == null || time - lastLookup > ttl) 086 { 087 try 088 { 089 synchronized (ctx) 090 { 091 ds = (DataSource) ctx.lookup(path); 092 } 093 lastLookup = time; 094 } 095 catch (final NamingException e) 096 { 097 throw new SQLException(e); 098 } 099 } 100 101 return ds; 102 } 103 104 /** 105 * @see org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes) 106 */ 107 @Override 108 public void initialize(final JDBCDiskCacheAttributes config) throws SQLException 109 { 110 this.name = config.getConnectionPoolName(); 111 initJNDI(config); 112 } 113 114 /** 115 * Initializes JNDI. 116 * 117 * @param config where to read the settings from 118 * @throws SQLException if a property set fails 119 */ 120 private void initJNDI(final JDBCDiskCacheAttributes config) throws SQLException 121 { 122 log.debug("Starting initJNDI"); 123 124 try 125 { 126 this.path = config.getJndiPath(); 127 log.debug("JNDI path: {0}", path); 128 129 this.ttl = config.getJndiTTL(); 130 log.debug("Time between context lookups: {0}", ttl); 131 132 final Hashtable<String, Object> env = new Hashtable<>(); 133 ctx = new InitialContext(env); 134 135 if (log.isTraceEnabled()) 136 { 137 log.trace("Created new InitialContext"); 138 debugCtx(ctx); 139 } 140 } 141 catch (final NamingException e) 142 { 143 throw new SQLException(e); 144 } 145 } 146 147 /** 148 * Does nothing. We do not want to close a dataSource retrieved from Jndi, 149 * because other applications might use it as well. 150 */ 151 @Override 152 public void close() 153 { 154 // do nothing 155 } 156 157 /** 158 * 159 * @param ctx the context 160 * @throws NamingException 161 */ 162 private static void debugCtx(final Context ctx) throws NamingException 163 { 164 log.trace("InitialContext -------------------------------"); 165 final Map<?, ?> env = ctx.getEnvironment(); 166 log.trace("Environment properties: {0}", env.size()); 167 env.forEach((key, value) -> log.trace(" {0}: {1}", key, value)); 168 log.trace("----------------------------------------------"); 169 } 170}