Let me begin by saying I tried to look a lot regarding this subject and could not find any document that would help on this matter. I apologize in advance if I missed something.
I'm using Eclipse with Hibernate 5.4 and JavaFX to manage a desktop application which will ask the user to provide the database credentials interactively and use that information to override the property on the hibernate-cfg.xml file. This part is fully working. My problem comes when I want to handle the very likely scenario where the user will provide wrong credentials. It looks like hibernate does not allow me to handle any of the exceptions I'm using on my code.
Could someone please look and suggest where I should improve to be able to let handle those problems?
This is my code where I will try to build the sectionFactory with the information provided by the user. I was hoping to handle the event of wrong credentials on the task.setOnFailed, but that is never called, no matter what happens task.setOnSucceeded is always called.
//Task to connect to DB
private void taskDBConnection() {
// Create a background Task
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
actionTarget.setText("Attempt to login to database");
HibernateUtil.getSessionFactory();
return null;
}
};
// This method allows us to handle any Exceptions thrown by the task
task.setOnFailed(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent arg0) {
System.out.println("Failed LoginView.java setOnFailed");
task.getException().printStackTrace();
}
});
// If the task completed successfully, perform other updates here
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent arg0) {
System.out.println("Done LoginView.java setOnSucceeded");
loginStage.close();
}
});
// Now, start the task on a background thread
new Thread(task).start();
}
This is my sessionFactory builder class, again, the catch exception there is never called.
public static SessionFactory getSessionFactory() {
if (sessionFactory == null) {
try {
//Create the config file / legacy but still works
Configuration hibernateConfig = new Configuration().configure(new File(Paths.get("").toAbsolutePath().toString() + "\\Config\\hibernate.cfg.xml"));
hibernateConfig.setProperty("hibernate.connection.username", getUsername());
hibernateConfig.setProperty("hibernate.connection.password", getPassword());
// Creating a registry
//registry = new StandardServiceRegistryBuilder().configure(new File(Paths.get("").toAbsolutePath().toString() + "\\Config\\hibernate.cfg.xml")).build();
registry = new StandardServiceRegistryBuilder().applySettings(hibernateConfig.getProperties()).build();
// Create the MetadataSources
MetadataSources sources = new MetadataSources(registry);
sources.addAnnotatedClass(Class1.class);
sources.addAnnotatedClass(Class2.class);
// Create the Metadata
Metadata metadata = sources.getMetadataBuilder().build();
// Create SessionFactory
sessionFactory = metadata.getSessionFactoryBuilder().build();
} catch (Exception e) {
e.printStackTrace();
if (registry != null) {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
return sessionFactory;
}
Following is the error I have on Eclipse. It is quite long, so I will just post the first part. Of course I know what the exception is (I'm forcing it to happen), but I want to handle it in a way that the user will be notified they are incorrect and allows them to try again.
WARNING: com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask@87315ad -- Acquisition Attempt Failed!!! Clearing pending acquires. While trying to acquire a needed new resource, we failed to succeed more than the maximum number of allowed acquisition attempts (1). Last acquisition attempt exception:
java.sql.SQLException: ORA-01017: invalid username/password; logon denied
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:392)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:385)
at oracle.jdbc.driver.T4CTTIfun.processError(T4CTTIfun.java:1018)
at oracle.jdbc.driver.T4CTTIoauthenticate.processError(T4CTTIoauthenticate.java:501)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:522)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:257)
at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:437)
at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:954)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:639)
at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:666)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:566)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:175)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:220)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:206)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:203)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1138)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1125)
at com.mchange.v2.resourcepool.BasicResourcePool.access$700(BasicResourcePool.java:44)
at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1870)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
And the hibernate.cfg.xml
<session-factory>
<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@database:1521:schema</property>
<property name="dialect">org.hibernate.dialect.Oracle8iDialect</property>
<property name="show_sql">true</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.acquireRetryAttempts">1</property>
<property name="hibernate.c3p0.acquireRetryDelay">2500</property>
</session-factory>
In case anyone is curious, I managed to make it work more or less as I wanted by hadling any exception thrown and printing this message in a Label on my application. I will always get the root exception by iterating trought it with Optional, so when it is wrong credentials the JDBC will give this as outcome.
catch (Exception e) {
Optional<Throwable> rootCause = Stream.iterate(e, Throwable::getCause)
.filter(element -> element.getCause() == null)
.findFirst();
System.out.println(rootCause.get().getClass().getSimpleName() + " - " + rootCause.get().getMessage());}