I'm currently working on a java application. It's a standalone client with Spring
and Hibernate
. Also C3P0
.
In the previous version we used a standard user(hardcoded in the configuration file) for the database connection but now we changed it so that every user has to provide his own credentials.
The beans with the code for the database are basically created on-demand.
I changed the XML-files and added a postprocessor which sets the credentials as well as some connection settings. It looks similar to this now:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
configurer = new PropertyPlaceholderConfigurer();
// properties are retrieved from a private method
configurer.setProperties(getProperties());
context.addBeanFactoryPostProcessor(configurer);
context.setConfigLocations(new String[] { "first.xml","second.xml" });
context.refresh();
return context.getBean("myClass", MyClass.class);
This all works as expected but now we reach the part where I'm currently stuck.
I want to provide a test functionality for the connection, so that the user can click a button and then is told if his credentials were accepted or not.
My first idea was to do a simple select on the database. Sifting through the logs however, I noticed that Spring tries to connect to the database during the refresh()
(or rather the instantiation of the bean) anyway. I can see exceptions in the logs, for example:
java.sql.SQLException: Connections could not be acquired from the underlying database!
Unfortunately, Spring doesn't seem to actually care. The exceptions are logged away but refresh()
finishes and is not throwing any exceptions because of this. I had hoped that I could simply catch the exception and then I would know that the connection failed.
I could just do the select as planned, but I want to limit the connection attempts as much as possible, because the database server will block the user after several attempts. Even permanently if there are to many attempts(already had some fun with that, before I changed the settings for the connection pool).
My searches regarding this problem came up with practically nothing. Is there a way to get the exception somehow? Or does Spring provide an API of sorts that would tell me about the connection error during the instantiation/refresh?
Failing that, any ideas for an alternative approach? Preferably one that needs only a single attempt to determine if a connection is possible.
Edit: For anyone interested: I went with the suggestion from Santosh and implemented a connection test in JDBC
.
Unfortunately there seems to be no easy way to make use of the database errors/exceptions encountered during the bean instantiation.
Quoting @Bozo from his answer here.
What you can do is extend
LocalSessionFactoryBean
and override thegetObject()
method, and make it return a proxy (viajava.lang.reflect.Proxy
or CGLIB / javassist), in case the sessionFactory is null. That way aSessionFactory
will be injected. The proxy should hold a reference to a bareSessionFactory
, which would initially be null. Whenever the proxy is asked to connect, if the sessionFacotry is still null, you call thebuildSessionFactory()
(of theLocalSessionFactoryBean
) and delegate to it. Otherwise throw an exception. (Then of course map your new factory bean instead of the current)
There is also a simple and rudimentary approach wherein before creating ClassPathXmlApplicationContext
, simply try to obtain a connection using raw JDBC calls. If that succeed then proceed or else give use appropriate message.