1 package org.apache.torque.pool;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.io.PrintWriter;
58 import java.io.Serializable;
59 import java.sql.Connection;
60 import java.sql.SQLException;
61 import java.util.HashMap;
62 import java.util.Hashtable;
63 import java.util.Map;
64 import java.util.Properties;
65 import javax.naming.BinaryRefAddr;
66 import javax.naming.Context;
67 import javax.naming.InitialContext;
68 import javax.naming.Name;
69 import javax.naming.NamingException;
70 import javax.naming.RefAddr;
71 import javax.naming.Reference;
72 import javax.naming.Referenceable;
73 import javax.naming.StringRefAddr;
74 import javax.naming.spi.ObjectFactory;
75 import javax.sql.ConnectionPoolDataSource;
76 import javax.sql.DataSource;
77 import org.apache.commons.lang.SerializationUtils;
78
79 /***
80 * Torque's default connection pool DataSource
81 *
82 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
83 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
84 * @version $Id: TorqueClassicDataSource.java,v 1.11 2003/08/18 21:48:11 mpoeschl Exp $
85 * @deprecated as of version 3.1
86 */
87 public class TorqueClassicDataSource
88 implements DataSource, Referenceable, Serializable, ObjectFactory
89 {
90 /*** Pools keyed by username. */
91 private static Map pools = new HashMap();
92
93 /*** Counter used to create an internal unique name od the Data Source */
94 private static int cpdsCounter;
95
96 /*** DataSource Name used to find the ConnectionPoolDataSource */
97 private String dataSourceName;
98
99 /*** Description */
100 private String description;
101
102 /*** Login TimeOut in seconds */
103 private int loginTimeout;
104
105 /*** Pool Data Source that is used to fetch connections */
106 private ConnectionPoolDataSource cpds;
107
108 /*** Log stream */
109 private PrintWriter logWriter;
110
111 /*** Environment that may be used to set up a jndi initial context. */
112 private Properties jndiEnvironment;
113
114 /*** Maximum Number of Connections cached in this Data Source */
115 private int defaultMaxConnections;
116
117 /***
118 * Maximum Number of Connections for a specified User in this Data
119 * Source
120 */
121 private Properties perUserMaxConnections;
122
123 /*** Maximum lifetime of a database connection */
124 private int maxExpiryTime;
125
126 /***
127 * time to wait when initiating a connection
128 * for the database to respond
129 */
130 private int connectionWaitTimeout;
131
132 /*** Interval (in seconds) that the monitor thread reports the pool state */
133 private int logInterval;
134
135 /*** Do connections from this pool are auto-committing? */
136 private boolean defaultAutoCommit;
137
138 /*** Are connections from this pool read-only? */
139 private boolean defaultReadOnly;
140
141 /***
142 * Default no-arg constructor for Serialization
143 */
144 public TorqueClassicDataSource()
145 {
146 defaultAutoCommit = true;
147 }
148
149 // Properties
150
151 /***
152 * Get the number of database connections to cache per user.
153 * This value is used for any username which is not specified
154 * in perUserMaxConnections. The default is 1.
155 *
156 * @return value of maxConnections.
157 */
158 public int getDefaultMaxConnections()
159 {
160 return defaultMaxConnections;
161 }
162
163 /***
164 * Set the number of database connections to cache per user.
165 * This value is used for any username which is not specified
166 * in perUserMaxConnections. The default is 1.
167 *
168 * @param v Value to assign to maxConnections.
169 */
170 public void setDefaultMaxConnections(int v)
171 {
172 this.defaultMaxConnections = v;
173 }
174
175 /***
176 * Get the number of database connections to cache per user. The keys
177 * are usernames and the value is the maximum connections. Any username
178 * specified here will override the value of defaultMaxConnections.
179 *
180 * @return value of perUserMaxConnections.
181 */
182 public Properties getPerUserMaxConnections()
183 {
184 return perUserMaxConnections;
185 }
186
187 /***
188 * Set the number of database connections to cache per user. The keys
189 * are usernames and the value is the maximum connections. Any username
190 * specified here will override the value of defaultMaxConnections.
191 *
192 * @param v Value to assign to perUserMaxConnections.
193 */
194 public void setPerUserMaxConnections(Properties v)
195 {
196 this.perUserMaxConnections = v;
197 }
198
199 /***
200 * Get the amount of time (in seconds) that database connections
201 * will be cached. The default is 3600 (1 hour).
202 *
203 * @return value of expiryTime.
204 */
205 public int getMaxExpiryTime()
206 {
207 return maxExpiryTime;
208 }
209
210 /***
211 * Set the amount of time (in seconds) that database connections
212 * will be cached. The default is 3600 (1 hour).
213 *
214 * @param v Value to assign to expiryTime.
215 */
216 public void setMaxExpiryTime(int v)
217 {
218 this.maxExpiryTime = v;
219 }
220
221 /***
222 * Get the amount of time (in seconds) a connection request will
223 * have to wait before a time out occurs and an error is thrown.
224 * The default is 10 seconds.
225 *
226 * @return value of connectionWaitTimeout.
227 */
228 public int getConnectionWaitTimeout()
229 {
230 return connectionWaitTimeout;
231 }
232
233 /***
234 * Eet the amount of time (in seconds) a connection request will
235 * have to wait before a time out occurs and an error is thrown.
236 * The default is 10 seconds.
237 *
238 * @param v Value to assign to connectionWaitTimeout.
239 */
240 public void setConnectionWaitTimeout(int v)
241 {
242 this.connectionWaitTimeout = v;
243 }
244
245 /***
246 * Get the interval (in seconds) between which the ConnectionPool logs
247 * the status of it's Connections. Default is 0 which indicates no
248 * logging.
249 *
250 * @return value of logInterval.
251 */
252 public int getLogInterval()
253 {
254 return logInterval;
255 }
256
257 /***
258 * Set the interval (in seconds) between which the ConnectionPool logs
259 * the status of it's Connections. Default is 0 which indicates no
260 * logging.
261 *
262 * @param v Value to assign to logInterval.
263 */
264 public void setLogInterval(int v)
265 {
266 this.logInterval = v;
267 }
268
269 /***
270 * Get the value of defaultAutoCommit, which defines the state of
271 * connections handed out from this pool. The value can be changed
272 * on the Connection using Connection.setAutoCommit(boolean).
273 * The default is true.
274 *
275 * @return value of defaultAutoCommit.
276 */
277 public boolean isDefaultAutoCommit()
278 {
279 return defaultAutoCommit;
280 }
281
282 /***
283 * Set the value of defaultAutoCommit, which defines the state of
284 * connections handed out from this pool. The value can be changed
285 * on the Connection using Connection.setAutoCommit(boolean).
286 * The default is true.
287 *
288 * @param v Value to assign to defaultAutoCommit.
289 */
290 public void setDefaultAutoCommit(boolean v)
291 {
292 this.defaultAutoCommit = v;
293 }
294
295 /***
296 * Get the value of defaultReadOnly, which defines the state of
297 * connections handed out from this pool. The value can be changed
298 * on the Connection using Connection.setReadOnly(boolean).
299 * The default is false.
300 *
301 * @return value of defaultReadOnly.
302 */
303 public boolean isDefaultReadOnly()
304 {
305 return defaultReadOnly;
306 }
307
308 /***
309 * Set the value of defaultReadOnly, which defines the state of
310 * connections handed out from this pool. The value can be changed
311 * on the Connection using Connection.setReadOnly(boolean).
312 * The default is false.
313 *
314 * @param v Value to assign to defaultReadOnly.
315 */
316 public void setDefaultReadOnly(boolean v)
317 {
318 this.defaultReadOnly = v;
319 }
320
321 /***
322 * Get the name of the ConnectionPoolDataSource which backs this pool.
323 * This name is used to look up the datasource from a jndi service
324 * provider.
325 *
326 * @return value of dataSourceName.
327 */
328 public String getDataSourceName()
329 {
330 return dataSourceName;
331 }
332
333 /***
334 * Set the name of the ConnectionPoolDataSource which backs this pool.
335 * This name is used to look up the datasource from a jndi service
336 * provider.
337 *
338 * @param v Value to assign to dataSourceName.
339 */
340 public void setDataSourceName(String v)
341 {
342 if (getConnectionPoolDataSource() != null)
343 {
344 throw new IllegalStateException("connectionPoolDataSource property"
345 + " already has a value. Both dataSourceName and "
346 + "connectionPoolDataSource properties cannot be set.");
347 }
348
349 this.dataSourceName = v;
350 }
351
352
353 /***
354 * Get the description. This property is defined by jdbc as for use with
355 * GUI (or other) tools that might deploy the datasource. It serves no
356 * internal purpose.
357 *
358 * @return value of description.
359 */
360 public String getDescription()
361 {
362 return description;
363 }
364
365 /***
366 * Set the description. This property is defined by jdbc as for use with
367 * GUI (or other) tools that might deploy the datasource. It serves no
368 * internal purpose.
369 *
370 * @param v Value to assign to description.
371 */
372 public void setDescription(String v)
373 {
374 this.description = v;
375 }
376
377
378 /***
379 * Get the value of jndiEnvironment which is used when instantiating
380 * a jndi InitialContext. This InitialContext is used to locate the
381 * backend ConnectionPoolDataSource.
382 *
383 * @param key environment key
384 * @return value of jndiEnvironment.
385 */
386 public String getJndiEnvironment(String key)
387 {
388 String value = null;
389 if (jndiEnvironment != null)
390 {
391 value = jndiEnvironment.getProperty(key);
392 }
393 return value;
394 }
395
396 /***
397 * Set the value of jndiEnvironment which is used when instantiating
398 * a jndi InitialContext. This InitialContext is used to locate the
399 * backend ConnectionPoolDataSource.
400 *
401 * @param key environment key
402 * @param value Value to assign to jndiEnvironment.
403 */
404 public void setJndiEnvironment(String key, String value)
405 {
406 if (jndiEnvironment == null)
407 {
408 jndiEnvironment = new Properties();
409 }
410 jndiEnvironment.setProperty(key, value);
411 }
412
413
414 /***
415 * Get the value of connectionPoolDataSource. This method will return
416 * null, if the backing datasource is being accessed via jndi.
417 *
418 * @return value of connectionPoolDataSource.
419 */
420 public ConnectionPoolDataSource getConnectionPoolDataSource()
421 {
422 return cpds;
423 }
424
425 /***
426 * Set the backend ConnectionPoolDataSource. This property should not be
427 * set if using jndi to access the datasource.
428 *
429 * @param v Value to assign to connectionPoolDataSource.
430 */
431 public void setConnectionPoolDataSource(ConnectionPoolDataSource v)
432 {
433 if (v == null)
434 {
435 throw new IllegalArgumentException(
436 "Null argument value is not allowed.");
437 }
438 if (getDataSourceName() != null)
439 {
440 throw new IllegalStateException("dataSourceName property"
441 + " already has a value. Both dataSourceName and "
442 + "connectionPoolDataSource properties cannot be set.");
443 }
444 this.cpds = v;
445
446 // set the dataSourceName to a unique value
447 dataSourceName = v.hashCode() + " internal cpds name " + cpdsCounter++;
448 }
449
450 /***
451 * Attempt to establish a database connection.
452 *
453 * @return A database connection.
454 * @throws SQLException
455 */
456 public Connection getConnection() throws SQLException
457 {
458 return getConnection(null, null);
459 }
460
461 /***
462 * Attempt to establish a database connection.
463 *
464 * @param username The name of the database user.
465 * @param password The password of the database user.
466 * @return A database connection.
467 * @throws SQLException
468 */
469 public synchronized Connection getConnection(String username,
470 String password)
471 throws SQLException
472 {
473 String key = getKey(username);
474 ConnectionPool pool = (ConnectionPool) pools.get(key);
475 if (pool == null)
476 {
477 try
478 {
479 registerPool(username, password);
480 pool = (ConnectionPool) pools.get(key);
481 }
482 catch (Exception e)
483 {
484 throw new SQLException(e.getMessage());
485 }
486 }
487
488 Connection con = pool.getConnection(username, password).getConnection();
489 con.setAutoCommit(defaultAutoCommit);
490 con.setReadOnly(defaultReadOnly);
491 return con;
492 }
493
494 /***
495 *
496 * @param suffix
497 * @return
498 */
499 private String getKey(String suffix)
500 {
501 String key = getDataSourceName();
502 if (key == null)
503 {
504 throw new IllegalStateException("Attempted to use DataSource "
505 + "without a backend ConnectionPoolDataSource defined.");
506 }
507
508 if (suffix != null)
509 {
510 key += suffix;
511 }
512 return key;
513 }
514
515 /***
516 *
517 * @param username The name of the database user.
518 * @param password The password of the database user.
519 * @throws javax.naming.NamingException
520 */
521 synchronized private void registerPool(String username, String password)
522 throws javax.naming.NamingException
523 {
524 String key = getKey(username);
525 if (!pools.containsKey(key))
526 {
527 ConnectionPoolDataSource cpds = this.cpds;
528 if (cpds == null)
529 {
530 Context ctx = null;
531 if (jndiEnvironment == null)
532 {
533 ctx = new InitialContext();
534 }
535 else
536 {
537 ctx = new InitialContext(jndiEnvironment);
538 }
539 cpds = (ConnectionPoolDataSource) ctx.lookup(dataSourceName);
540 }
541
542 int maxConnections = getDefaultMaxConnections();
543 if (username != null)
544 {
545 String userMaxCon =
546 (String) getPerUserMaxConnections().get(username);
547 if (userMaxCon != null)
548 {
549 maxConnections = Integer.parseInt(userMaxCon);
550 }
551 }
552
553 ConnectionPool pool = new ConnectionPool(cpds, username, password,
554 maxConnections,
555 getMaxExpiryTime(),
556 getConnectionWaitTimeout(),
557 getLogInterval());
558
559 // avoid ConcurrentModificationException
560 Map newPools = new HashMap(pools);
561 newPools.put(key, pool);
562 pools = newPools;
563 }
564 }
565
566 /***
567 * Gets the maximum time in seconds that this data source can wait
568 * while attempting to connect to a database.
569 *
570 * @return the login timeout
571 */
572 public int getLoginTimeout()
573 {
574 return loginTimeout;
575 }
576
577 /***
578 * Get the log writer for this data source.
579 *
580 * @return the log writer
581 * @deprecated Use correct debugging and logging code from Log4j
582 */
583 public PrintWriter getLogWriter()
584 {
585 if (logWriter == null)
586 {
587 logWriter = new PrintWriter(System.out);
588 }
589 return logWriter;
590 }
591
592 /***
593 * Sets the maximum time in seconds that this data source will wait
594 * while attempting to connect to a database. NOT USED.
595 *
596 * @param seconds the login timeout
597 */
598 public void setLoginTimeout(int seconds)
599 {
600 loginTimeout = seconds;
601 }
602
603 /***
604 * Set the log writer for this data source.
605 *
606 * @param out the log writer to use
607 * @deprecated Use correct debugging and logging code from Log4j
608 */
609 public void setLogWriter(java.io.PrintWriter out)
610 {
611 logWriter = out;
612 }
613
614 /***
615 * <CODE>Referenceable</CODE> implementation.
616 *
617 * @return a reference
618 * @throws NamingException
619 */
620 public Reference getReference() throws NamingException
621 {
622 String factory = getClass().getName();
623
624 Reference ref = new Reference(getClass().getName(), factory, null);
625
626 ref.add(new StringRefAddr("defaultMaxConnections",
627 String.valueOf(getDefaultMaxConnections())));
628 ref.add(new StringRefAddr("maxExpiryTime",
629 String.valueOf(getMaxExpiryTime())));
630 ref.add(new StringRefAddr("connectionWaitTimeout",
631 String.valueOf(getConnectionWaitTimeout())));
632 ref.add(new StringRefAddr("logInterval",
633 String.valueOf(getLogInterval())));
634 ref.add(new StringRefAddr("dataSourceName", getDataSourceName()));
635 ref.add(new StringRefAddr("description", getDescription()));
636
637 byte[] serJndiEnv = null;
638 // BinaryRefAddr does not allow null byte[].
639 if (jndiEnvironment != null)
640 {
641 serJndiEnv = SerializationUtils.serialize(jndiEnvironment);
642 ref.add(new BinaryRefAddr("jndiEnvironment", serJndiEnv));
643 }
644
645 byte[] serPUMC = null;
646 // BinaryRefAddr does not allow null byte[].
647 if (getPerUserMaxConnections() != null)
648 {
649 serPUMC = SerializationUtils.serialize(getPerUserMaxConnections());
650 ref.add(new BinaryRefAddr("perUserMaxConnections", serPUMC));
651 }
652
653 return ref;
654 }
655
656 /***
657 * implements ObjectFactory to create an instance of this class
658 *
659 * @param refObj
660 * @param name
661 * @param context
662 * @param env
663 * @return an instance of this class
664 * @throws Exception
665 */
666 public Object getObjectInstance(Object refObj, Name name,
667 Context context, Hashtable env)
668 throws Exception
669 {
670 Reference ref = (Reference) refObj;
671
672 if (ref.getClassName().equals(getClass().getName()))
673 {
674 setDefaultMaxConnections(Integer.parseInt(
675 (String) ref.get("defaultMaxConnections").getContent()));
676 setMaxExpiryTime(Integer.parseInt(
677 (String) ref.get("maxExpiryTime").getContent()));
678 setConnectionWaitTimeout(Integer.parseInt(
679 (String) ref.get("connectionWaitTimeout").getContent()));
680 setLogInterval(Integer.parseInt(
681 (String) ref.get("logInterval").getContent()));
682 setDataSourceName((String) ref.get("dataSourceName").getContent());
683 setDescription((String) ref.get("description").getContent());
684
685 RefAddr refAddr = ref.get("jndiEnvironment");
686 if (refAddr != null)
687 {
688 byte[] serialized = (byte[]) refAddr.getContent();
689 jndiEnvironment = (Properties)
690 SerializationUtils.deserialize(serialized);
691 }
692
693 refAddr = ref.get("perUserMaxConnections");
694 if (refAddr != null)
695 {
696 byte[] serialized = (byte[]) refAddr.getContent();
697 setPerUserMaxConnections(
698 (Properties) SerializationUtils.deserialize(serialized));
699 }
700
701 return this;
702 }
703 else
704 {
705 // We can't create an instance of the reference
706 return null;
707 }
708 }
709 }
This page was automatically generated by Maven