1 package org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.sql.SQLException;
23 import java.util.Hashtable;
24 import java.util.Map;
25
26 import javax.naming.Context;
27 import javax.naming.InitialContext;
28 import javax.naming.NamingException;
29 import javax.sql.DataSource;
30
31 import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
32 import org.apache.commons.jcs3.log.Log;
33 import org.apache.commons.jcs3.log.LogManager;
34
35 /**
36 * A factory that looks up the DataSource from JNDI. It is also able
37 * to deploy the DataSource based on properties found in the
38 * configuration.
39 *
40 * This factory tries to avoid excessive context lookups to improve speed.
41 * The time between two lookups can be configured. The default is 0 (no cache).
42 *
43 * Borrowed and adapted from Apache DB Torque
44 */
45 public class JndiDataSourceFactory implements DataSourceFactory
46 {
47 /** The log. */
48 private static final Log log = LogManager.getLog(JndiDataSourceFactory.class);
49
50 /** The name of the factory. */
51 private String name;
52
53 /** The path to get the resource from. */
54 private String path;
55
56 /** The context to get the resource from. */
57 private Context ctx;
58
59 /** A locally cached copy of the DataSource */
60 private DataSource ds;
61
62 /** Time of last actual lookup action */
63 private long lastLookup;
64
65 /** Time between two lookups */
66 private long ttl; // ms
67
68 /**
69 * @return the name of the factory.
70 */
71 @Override
72 public String getName()
73 {
74 return name;
75 }
76
77 /**
78 * @see org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource()
79 */
80 @Override
81 public DataSource getDataSource() throws SQLException
82 {
83 final long time = System.currentTimeMillis();
84
85 if (ds == null || time - lastLookup > ttl)
86 {
87 try
88 {
89 synchronized (ctx)
90 {
91 ds = (DataSource) ctx.lookup(path);
92 }
93 lastLookup = time;
94 }
95 catch (final NamingException e)
96 {
97 throw new SQLException(e);
98 }
99 }
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 }