001: /*
002: * Licensed under the X license (see http://www.x.org/terms.htm)
003: */
004: package org.ofbiz.minerva.pool.jdbc;
005:
006: import java.io.PrintWriter;
007: import java.sql.Connection;
008: import java.util.Collection;
009: import java.util.HashMap;
010: import java.util.HashSet;
011: import java.util.Hashtable;
012: import java.util.Properties;
013:
014: import javax.naming.Context;
015: import javax.naming.InitialContext;
016: import javax.naming.Name;
017: import javax.naming.NamingException;
018: import javax.naming.RefAddr;
019: import javax.naming.Reference;
020: import javax.naming.Referenceable;
021: import javax.naming.StringRefAddr;
022: import javax.naming.spi.ObjectFactory;
023: import javax.sql.DataSource;
024:
025: import org.apache.log4j.Logger;
026: import org.ofbiz.base.util.Log4jLoggerWriter;
027: import org.ofbiz.minerva.pool.ObjectPool;
028:
029: /**
030: * DataSource for non-transactional JDBC pools. This handles configuration
031: * parameters for both the pool and the JDBC driver. It is important that you
032: * set all the configuration parameters before you initialize the DataSource,
033: * and you must initialize it before you use it. All the configuration
034: * parameters are not documented here; you are instead referred to ObjectPool
035: * and JDBCConnectionFactory.
036: * @see org.ofbiz.minerva.pool.ObjectPool
037: * @see org.ofbiz.minerva.pool.jdbc.JDBCConnectionFactory
038: *
039: * @author Aaron Mulder (ammulder@alumni.princeton.edu)
040: */
041: public class JDBCPoolDataSource implements DataSource, Referenceable,
042: ObjectFactory {
043:
044: private static Logger log = Logger
045: .getLogger(JDBCPoolDataSource.class);
046:
047: private static HashMap sources = new HashMap();
048:
049: /**
050: * Gets all the current JDBC pool data sources.
051: */
052: public static Collection getDataSources() {
053: return new HashSet(sources.values());
054: }
055:
056: /**
057: * Gets a specific JDBC pool data source by pool name.
058: */
059: public static JDBCPoolDataSource getDataSource(String poolName) {
060: return (JDBCPoolDataSource) sources.get(poolName);
061: }
062:
063: private ObjectPool pool;
064: private JDBCConnectionFactory factory;
065: private PrintWriter logWriter;
066: private int timeout;
067: private boolean initialized = false;
068: private String jndiName;
069:
070: /**
071: * Creates a new JDBC pool data source. Be sure to configure it and then
072: * call initialize before you try to use it.
073: */
074: public JDBCPoolDataSource() {
075: pool = new ObjectPool();
076: factory = new JDBCConnectionFactory();
077: PoolDriver.instance();
078: }
079:
080: // Unique properties
081: /**
082: * If you use this to set a JNDI name, this pool will be bound to that name
083: * using the default InitialContext. You can also do this manually if you
084: * have additional requirements.
085: */
086: public void setJNDIName(String name) throws NamingException {
087: InitialContext ctx = new InitialContext();
088: if (jndiName != null && !jndiName.equals(name))
089: ctx.unbind(jndiName);
090: if (name != null)
091: ctx.bind(name, this );
092: jndiName = name;
093: }
094:
095: /**
096: * Gets the JNDI name this pool is bound to. Only valid if you used
097: * setJNDIName to bind it.
098: * @see #setJNDIName
099: */
100: public String getJNDIName() {
101: return jndiName;
102: }
103:
104: // JDBC properties
105: public void setJDBCURL(String url) {
106: factory.setConnectURL(url);
107: }
108:
109: public String getJDBCURL() {
110: return factory.getConnectURL();
111: }
112:
113: public void setJDBCProperties(Properties props) {
114: factory.setConnectProperties(props);
115: }
116:
117: public void setProperties(String props) {
118: setJDBCProperties(parseProperties(props));
119: }
120:
121: public Properties getJDBCProperties() {
122: return factory.getConnectProperties();
123: }
124:
125: public void setJDBCUser(String user) {
126: factory.setUser(user);
127: }
128:
129: public String getJDBCUser() {
130: return factory.getUser();
131: }
132:
133: public void setJDBCPassword(String password) {
134: factory.setPassword(password);
135: }
136:
137: public String getJDBCPassword() {
138: return factory.getPassword();
139: }
140:
141: // Pool properties
142: public void setPoolName(String name) {
143: pool.setName(name);
144: sources.put(pool.getName(), this );
145: }
146:
147: public String getPoolName() {
148: return pool.getName();
149: }
150:
151: public void setMinSize(int size) {
152: pool.setMinSize(size);
153: }
154:
155: public int getMinSize() {
156: return pool.getMinSize();
157: }
158:
159: public void setMaxSize(int size) {
160: pool.setMaxSize(size);
161: }
162:
163: public int getMaxSize() {
164: return pool.getMaxSize();
165: }
166:
167: public void setBlocking(boolean blocking) {
168: pool.setBlocking(blocking);
169: }
170:
171: public boolean isBlocking() {
172: return pool.isBlocking();
173: }
174:
175: public void setIdleTimeoutEnabled(boolean allowShrinking) {
176: pool.setIdleTimeoutEnabled(allowShrinking);
177: }
178:
179: public boolean isIdleTimeoutEnabled() {
180: return pool.isIdleTimeoutEnabled();
181: }
182:
183: public void setGCEnabled(boolean allowGC) {
184: pool.setGCEnabled(allowGC);
185: }
186:
187: public boolean isGCEnabled() {
188: return pool.isGCEnabled();
189: }
190:
191: public void setMaxIdleTimeoutPercent(float percent) {
192: pool.setMaxIdleTimeoutPercent(percent);
193: }
194:
195: public float getMaxIdleTimeoutPercent() {
196: return pool.getMaxIdleTimeoutPercent();
197: }
198:
199: public void setIdleTimeout(long millis) {
200: pool.setIdleTimeout(millis);
201: }
202:
203: public long getIdleTimeout() {
204: return pool.getIdleTimeout();
205: }
206:
207: public void setGCMinIdleTime(long millis) {
208: pool.setGCMinIdleTime(millis);
209: }
210:
211: public long getGCMinIdleTime() {
212: return pool.getGCMinIdleTime();
213: }
214:
215: public void setGCInterval(long millis) {
216: pool.setGCInterval(millis);
217: }
218:
219: public long getGCInterval() {
220: return pool.getGCInterval();
221: }
222:
223: public void setInvalidateOnError(boolean invalidate) {
224: pool.setInvalidateOnError(invalidate);
225: }
226:
227: public boolean isInvalidateOnError() {
228: return pool.isInvalidateOnError();
229: }
230:
231: public void setTimestampUsed(boolean timestamp) {
232: pool.setTimestampUsed(timestamp);
233: }
234:
235: public boolean isTimestampUsed() {
236: return pool.isTimestampUsed();
237: }
238:
239: // Other methods
240:
241: /**
242: * Initializes the pool. You need to have configured all the pool and
243: * JDBC properties first.
244: */
245: public void initialize() {
246: initialized = true;
247: pool.setObjectFactory(factory);
248: pool.initialize();
249: }
250:
251: /**
252: * Returns a string describing the pool status (number of connections
253: * created, used, and maximum).
254: */
255: public String getPoolStatus() {
256: return pool.toString();
257: }
258:
259: /**
260: * Shuts down this data source and the underlying pool. If you used
261: * setJNDI name to bind it in JNDI, it is unbound.
262: */
263: public void close() {
264: try {
265: setJNDIName(null);
266: } catch (NamingException e) {
267: log.warn("Can't unbind from JNDI", e);
268: }
269: sources.remove(pool.getName());
270: pool.shutDown();
271: pool = null;
272: factory = null;
273: }
274:
275: /**
276: * Gets a connection from the pool.
277: */
278: public Connection getConnection() throws java.sql.SQLException {
279: if (!initialized)
280: initialize();
281:
282: return (Connection) pool.getObject();
283: }
284:
285: /**
286: * Gets a connection from the pool. If a new connection must be
287: * created, it will use the specified user name and password. If there is
288: * a connection available in the pool, it will be used, regardless of the
289: * user name and password use to created it initially.
290: */
291: public Connection getConnection(String user, String password)
292: throws java.sql.SQLException {
293: if (!initialized)
294: initialize();
295:
296: factory.setUser(user);
297: factory.setPassword(password);
298: return (Connection) pool.getObject();
299: }
300:
301: /**
302: * Gets a log writer used to record pool events.
303: */
304: public PrintWriter getLogWriter() throws java.sql.SQLException {
305: return logWriter;
306: }
307:
308: /**
309: * Sets a log writer used to record pool events.
310: */
311: public void setLogWriter(PrintWriter writer)
312: throws java.sql.SQLException {
313: if (writer == null) {
314: logWriter = null;
315: } else {
316: if (logWriter == null) {
317: logWriter = new Log4jLoggerWriter(log);
318: }
319: }
320: }
321:
322: /**
323: * This property is not used by this implementation.
324: */
325: public int getLoginTimeout() throws java.sql.SQLException {
326: return timeout;
327: }
328:
329: /**
330: * This property is not used by this implementation.
331: */
332: public void setLoginTimeout(int timeout)
333: throws java.sql.SQLException {
334: this .timeout = timeout;
335: }
336:
337: /**
338: * This method is used for parsing JDBCProperties
339: */
340: private static Properties parseProperties(String string) {
341: Properties props = new Properties();
342: if (string == null || string.length() == 0)
343: return props;
344:
345: int lastPos = -1;
346: int pos = string.indexOf(";");
347: while (pos > -1) {
348: addProperty(props, string.substring(lastPos + 1, pos));
349: lastPos = pos;
350: pos = string.indexOf(";", lastPos + 1);
351: }
352: addProperty(props, string.substring(lastPos + 1));
353: return props;
354: }
355:
356: /**
357: * This method is used for parsing JDBCProperties
358: */
359: private static void addProperty(Properties props, String property) {
360: int pos = property.indexOf("=");
361: if (pos < 0) {
362: System.err.println("Unable to parse property '" + property
363: + "' - please use 'name=value'");
364: return;
365: }
366: props.setProperty(property.substring(0, pos), property
367: .substring(pos + 1));
368: }
369:
370: // Referenceable implementation ----------------------------------
371: /**
372: * Gets a reference to this data source.
373: */
374: public Reference getReference() {
375: return new Reference(getClass().getName(), new StringRefAddr(
376: "JDBCPool", pool.getName()), getClass().getName(), null);
377: }
378:
379: // ObjectFactory implementation ----------------------------------
380: /**
381: * Decodes a reference to a specific pool data source.
382: */
383: public Object getObjectInstance(Object obj, Name name,
384: Context nameCtx, Hashtable environment) {
385: if (obj instanceof Reference) {
386: Reference ref = (Reference) obj;
387: if (ref.getClassName().equals(getClass().getName())) {
388: RefAddr addr = ref.get("JDBCPool");
389: return sources.get(addr.getContent());
390: }
391: }
392: return null;
393: }
394: }
395:
396: /*
397: vim:tabstop=3:et:shiftwidth=3
398: */
|