I'm interested in doing some work on the PostgreSQL JDBC driver to help with the implementation of Statement.setQueryTimeout(...) , one of the most problematic specification matching holes in the driver. To do this, I need a portable way to get a timer or set up an emergency / callback that works on all Java EE application servers, servlet containers, and Java SE environments.
It seems that it is not as simple as it should be, and I am fixated enough to pounce on your mercy. How the hell am I making a simple timer callback that works in Java SE, Java EE, and servlet containers?
If necessary, I may withstand the execution of separate versions of -ee and -se, but this is highly undesirable. Issues for each container are completely impractical, although automatically selected adapters for each container may be acceptable if they are highly unacceptable.
The PgJDBC driver should run on hard old application servers in ancient versions of JVM, but I donโt care if checkout timeouts are available only in the JDBC4 driver version for modern containers and JVM. There is already a conditional compilation infrastructure that allows you to release JDBC3 / JDK 1.4 and JDBC4 / JDK 1.5, so code that only works with 1.5 or even 1.6 is not a problem.
(edit): An added complication is that the JDBC driver can be deployed by users:
- As a container module or built-in component launched when the container starts;
- As a standalone deployment object that you can deploy and redistribute at run time; or
- Embeds inside a
war or ear application
... and we need to support all of these scenarios, preferably without the need to configure custom applications! If we cannot support all of these scenarios, it should at least work without support for the operator timeout and gracefully fail when command execution delays are not supported.
Oh, write once, run ...
I can't just use java.util.Timer or java.util.concurrent :
I see widespread claims that using java.util.Timer or Java SE concurrency (JSR-166) utility in java.util.Timer package is not recommended in Java EE, but rarely any details. JSR 236 Proposition states that:
java.util.Timer, java.lang.Thread, and the Java SE concurrency (JSR-166) utilities in the java.util.concurrency (sic) package should never be used in managed environments because they create threads outside the scope of the container.
A little more information shows that calls from uncontrolled flows will not receive container services, so all kinds of things in the application can burst in exciting and unexpected ways. Given that calling a timer can cause the exception to be thrown by PgJDBC and propagated in the user application code, this is important.
(edit): The JDBC driver itself does not require any container services, so I donโt care if they work in the timer thread (s) until these threads never run any user code. This problem reliably ensures that they do not.
JSR 236 timer abstraction level is nonexistent
JSR 236 does not work, and I do not see a replacement that satisfies the same requirements for portable timers.
I cannot find a reference to a container portable way to get a timer with a container. If I could grab a timer from JNDI on containers and go back to direct instantiation when getting one of the JNDIs failed, that would be fine ... but I can't even find a way to do this.
EJB timers unsuitable
There are EJB timers, but they are not suitable for low-level materials, such as the JDBC driver implementation, because they:
- Constantly restarting the container or machine.
- high overhead
- can be implemented using a database to save time
- time-oriented non-machine time
- not available in regular servlet containers
- not available in "web profile" EE application servers
Thus, EJB timers can be completely removed from the list.
I cannot upset my own timer thread
The same problems that prevent the use of java.util.Timer and friends do not allow me to start my own timer thread and manage my timers. This is not a starter.
The Java EE specification says:
A bean should not attempt to manage flows. A bean should not attempt to start, stop, pause, or resume a stream or change the priority or name of a stream. A bean should not attempt to manage thread groups.
and EE Tutorial :
Resource adapters that improperly use threads can jeopardize the entire application server environment. For example, a resource adapter may create too many threads or may not properly issue the threads it creates. Poor thread handling interferes with application server shutdown and affects application server performance, as creating and destroying threads is expensive.
WorkManager does not execute timers
There javax.resource.spi.work.WorkManager , but (a) it is not intended for use on the side of the service provider in the application (b) it is not intended for timers. Perhaps the timer can be hacked using the Work element, which sleeps with a timeout, but is ugly at best and will probably be quite ineffective.
It doesn't look like it will work on Java SE either.
Java Connector Architecture (JCA)
As indicated in the Java EE tutorial , a connector architecture may be a viable option for EE containers. However, again, servlet containers such as Tomcat or Jetty may not support it.
I am also concerned about the consequences associated with this route.
So i'm stuck
How do I accomplish this simple task?
Do I need to write a new ThreadPoolExecutor that receives threads from a container via JNDI, and then use this as a base for the new ScheduledThreadPoolExecutor ? If so, is there even a portable way to get streams from a container, or do I need JNDI code to search in the container and adapter code?
Am I missing something stupid and dazzlingly obvious?
How do other libraries that need asynchronous operation, timers, or callbacks transfer portability between Java EE and Java SE?