ERROR o.h.e.j.s.SqlExceptionHelper Connection is closed - spring

When I use DataSourceUtils.getConnection I got this error ERROR o.h.e.j.s.SqlExceptionHelper Connection is closed .
Because the previously created connection has been closed.
And before I use getConnection() it did not have the problem but it not good performance to create a new connection for every request.
I'm using multitenancy.
Datasource for write
#Primary
#Component
public class InstanceWriteDataSource implements DataSource {
#Override
public Connection getConnection() throws SQLException {
return DataSourceUtils.getConnection(getDataSource());
}
}
Datasource for read
#Component
public class InstanceReadDataSource implements DataSource {
#Override
public Connection getConnection() throws SQLException {
return DataSourceUtils.getConnection(getDataSource());
}
}
Do you have any idea about this?
Thank you.

Related

How to mock bean HikariDataSource correctly?

I wrote integration test using Mockito, but it works when connection to database was set. Actually test just check possibility access some endpoints and not related to the data access layer. So I don't need database for it yet.
Reason of failing test when database is down - HikariDatasource check connection to the database when spring instantiates context. Mocking doesn't return Connection and it lead to the fail of application. Solution that i have found is use hsql in memory database, but for me it looks like work around. Probably exists other solution providing some fake data?
Not sure that this is elegant solution, but I need to force work tests like this
mockMvc.perform(
post("/some").contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(someDto))
.header(HttpHeaders.AUTHORIZATION, AUTH_HEADER)
.accept(MediaType.APPLICATION_JSON_UTF8)
).andExpect(status().is(201));
After debugging and searching I have found solution that allowed start container without database in memory.
#TestConfiguration
#ComponentScan(basePackages = "com.test")
#ActiveProfiles("test")
public class TestConfig {
//Other Beans
#Bean
public DataSource getDatasource() {
return new MockDataSource();
}
}
class MockDataSource implements DataSource {
#Override
public Connection getConnection() throws SQLException {
return createMockConnection();
}
#Override
public Connection getConnection(String username, String password) throws SQLException {
return getConnection();
}
#Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
#Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
#Override
public void setLoginTimeout(int seconds) throws SQLException {
}
#Override
public int getLoginTimeout() throws SQLException {
return 0;
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
#Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
#Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
public static Connection createMockConnection() throws SQLException {
// Setup mock connection
final Connection mockConnection = mock(Connection.class);
// Autocommit is always true by default
when(mockConnection.getAutoCommit()).thenReturn(true);
// Handle Connection.createStatement()
Statement statement = mock(Statement.class);
when(mockConnection.createStatement()).thenReturn(statement);
when(mockConnection.createStatement(anyInt(), anyInt())).thenReturn(statement);
when(mockConnection.createStatement(anyInt(), anyInt(), anyInt())).thenReturn(statement);
when(mockConnection.isValid(anyInt())).thenReturn(true);
// Handle Connection.prepareStatement()
PreparedStatement mockPreparedStatement = mock(PreparedStatement.class);
when(mockConnection.prepareStatement(anyString())).thenReturn(mockPreparedStatement);
when(mockConnection.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStatement);
when(mockConnection.prepareStatement(anyString(), (int[]) any())).thenReturn(mockPreparedStatement);
when(mockConnection.prepareStatement(anyString(), (String[]) any())).thenReturn(mockPreparedStatement);
when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockPreparedStatement);
when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(mockPreparedStatement);
doAnswer((Answer<Void>) invocation -> null).doNothing().when(mockPreparedStatement).setInt(anyInt(), anyInt());
ResultSet mockResultSet = mock(ResultSet.class);
when(mockPreparedStatement.executeQuery()).thenReturn(mockResultSet);
when(mockResultSet.getString(anyInt())).thenReturn("aString");
when(mockResultSet.next()).thenReturn(true);
// Handle Connection.prepareCall()
CallableStatement mockCallableStatement = mock(CallableStatement.class);
when(mockConnection.prepareCall(anyString())).thenReturn(mockCallableStatement);
when(mockConnection.prepareCall(anyString(), anyInt(), anyInt())).thenReturn(mockCallableStatement);
when(mockConnection.prepareCall(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(mockCallableStatement);
ResultSet mockResultSetTypeInfo = mock(ResultSet.class);
DatabaseMetaData mockDataBaseMetadata = mock(DatabaseMetaData.class);
when(mockDataBaseMetadata.getDatabaseProductName()).thenReturn("PostgreSQL");
when(mockDataBaseMetadata.getDatabaseMajorVersion()).thenReturn(8);
when(mockDataBaseMetadata.getDatabaseMinorVersion()).thenReturn(2);
when(mockDataBaseMetadata.getConnection()).thenReturn(mockConnection);
when(mockDataBaseMetadata.getTypeInfo()).thenReturn(mockResultSetTypeInfo);
when(mockConnection.getMetaData()).thenReturn(mockDataBaseMetadata);
// Handle Connection.close()
doAnswer((Answer<Void>) invocation -> null).doThrow(new SQLException("Connection is already closed")).when(mockConnection).close();
// Handle Connection.commit()
doAnswer((Answer<Void>) invocation -> null).doThrow(new SQLException("Transaction already committed")).when(mockConnection).commit();
// Handle Connection.rollback()
doAnswer((Answer<Void>) invocation -> null).doThrow(new SQLException("Transaction already rolled back")).when(mockConnection).rollback();
return mockConnection;
}
}
Mocking DataSource allows start container and provide post call to the controller using MockMvc.

Websocket : Unexpected response code: 302

When creating a websocket connection I am getting following exception:
VM74253:149 WebSocket connection to 'wss://HerokuAppName.herokuapp.com/connect2Deploy' failed: Error during WebSocket handshake: Unexpected response code: 302
Spring boot Code for websocket:
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/connect2Deploy");
}
}
Sockethandler class only has session details because I only want session details to send server details to UI, there wont be any client to server communication.
#Component
public class SocketHandler extends TextWebSocketHandler {
public WebSocketSession sessions = null;
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//the messages will be broadcasted to all users.
sessions = session;
}
public WebSocketSession getSessions() {
return sessions;
}
}
But it always throws error during websocket handshake, am I missing something here?

Spring Boot and Spring-starter-data-jpa : Lazy loading of datasource setup

I am working on an application with Spring-starter-data-jpa and multi datasources, that need to lazy initialize datasouce connection, but i dosen't manage to work with it.
For exemple if i put a wrong password on a datasource configuration, the application startup fails.
I try to put a #Lazy annotation on the Datasource #Configuration class but the application still crash on startup.
I try to implement a LazyConnectionDataSourceProxy instead the Datasource without success.
I can't imagine that it is not possible.
Is somewone have an idea to how lazy load datasources configuration on the first jpa repository call ?
I tryed to do this with a kind of adapter/singleton mix pattern like this :
#Component
public class TestErrorDatasource implements DataSource {
private DataSource datasource;
#Autowired Environment env;
#Override
public PrintWriter getLogWriter() throws SQLException {
return getDatasource().getLogWriter();
}
#Override
public int getLoginTimeout() throws SQLException {
return getDatasource().getLoginTimeout();
}
#Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return getDatasource().getParentLogger();
}
#Override
public void setLogWriter(PrintWriter arg0) throws SQLException {
getDatasource().setLogWriter(arg0);
}
#Override
public void setLoginTimeout(int arg0) throws SQLException {
getDatasource().setLoginTimeout(arg0);
}
#Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
return getDatasource().isWrapperFor(arg0);
}
#Override
public <T> T unwrap(Class<T> arg0) throws SQLException {
return getDatasource().unwrap(arg0);
}
#Override
public Connection getConnection() throws SQLException {
return getDatasource().getConnection();
}
#Override
public Connection getConnection(String arg0, String arg1) throws SQLException {
return getDatasource().getConnection(arg0, arg1);
}
private DataSource getDatasource() {
if(datasource == null) {
this.datasource = DataSourceBuilder
.create()
.driverClassName(env.getProperty("testError.datasource.driverClassName"))
.url(env.getProperty("testError.datasource.url"))
.username(env.getProperty("testError.datasource.username"))
.password(env.getProperty("testError.datasource.password"))
.build();
}
return datasource;
}
}
But it dosen't work.
I put a break point on the getConnection() methode and i raised tha it's called on startup by
org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl
class
Is there any configuration to avoid hibernate check the getConnection() methode on starup ?
Thanks in advance
A datasource is just an interface with a 'getConnection()' method on it.
So create your own implementation that delegates to a singleton that is created only when getConnection is first called.
In other words, whilst your implementation can be a Spring bean, its singleton dependency isn't, and isn't injected, but set the first time you access getConnection.

Define hive-jdbc JNDI data source on WebSphere

I am trying to setup a JNDI Data Source on WebSphere 8.5.5.11, using hive-jdbc.jar.
When using the console in WebSphere, and using the form to create a new JDBC provider, there is a field for the implementation class name. WebSphere requires that the class implements javax.sql.XADataSource or javax.sql.ConnectionPoolDataSource. However, the hive-jdbc driver implements non of those, it implements only java.sql.DataSource.
For this reason, it doesn't work, WebSphere reports an error when trying to save the form.
Any idea what can I do about this?
You can write a trivial implementation of javax.sql.ConnectionPoolDataSource that delegates to the javax.sql.DataSource implementation. Here is an example,
package example.datasource;
import java.sql.*;
import javax.sql.*;
public class HiveConnectionPoolDataSource extends org.apache.hive.jdbc.HiveDataSource implements ConnectionPoolDataSource {
public PooledConnection getPooledConnection() throws SQLException {
return new HivePooledConnection(null, null);
}
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return new HivePooledConnection(user, password);
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return ConnectionPoolDataSource.class.equals(iface) || super.isWrapperFor(iface);
}
public <T> T unwrap(Class<T> iface) throws SQLException {
return ConnectionPoolDataSource.class.equals(iface) ? (T) this : super.unwrap(iface);
}
class HivePooledConnection implements PooledConnection {
private Connection con;
private final String user;
private final String password;
HivePooledConnection(String user, String password) {
this.user = user;
this.password = password;
}
public void addConnectionEventListener(ConnectionEventListener listener) {}
public void addStatementEventListener(StatementEventListener listener) {}
public void close() throws SQLException {
if (con != null) {
con.close();
con = null;
}
}
public Connection getConnection() throws SQLException {
if (con == null || con.isClosed()) {
con = user == null
? HiveConnectionPoolDataSource.this.getConnection()
: HiveConnectionPoolDataSource.this.getConnection(user, password);
return con;
} else
throw new IllegalStateException();
}
public void removeConnectionEventListener(ConnectionEventListener listener) {}
public void removeStatementEventListener(StatementEventListener listener) {}
}
}
Package your compiled class in a JAR alongside the JDBC driver JAR(s), and configure your custom JDBC provider in WebSphere Application Server to point at this JAR as though it were a part of the JDBC driver. Specify the implementation class name as example.datasource.HiveConnectionPoolDataSource or whatever package/name you chose for your own implementation. You should then be able to use the JDBC driver.
Also adding a link to the WebSphere Application Server request for enhancements page if anyone wants to request that support for javax.sql.DataSource be added.

MultiTenantConnectionProvider implementation has null autowired datasource

I'm trying to support a multi-tenant by schema in my spring boot (1.4) application. I have the following in my config:
hibernate:
format_sql: true
default_schema: corrto
multiTenancy: SCHEMA
tenant_identifier_resolver: com.config.HeaderTenantIdentifierResolver
multi_tenant_connection_provider: com.config.SchemaPerTenantConnectionProvider
My MultiTenantConnectionProvider implementation is as follows:
public class SchemaPerTenantConnectionProvider implements MultiTenantConnectionProvider {
#Autowired
private DataSource dataSource;
#Override
public Connection getAnyConnection() throws SQLException {
return this.dataSource.getConnection();
}
#Override
public void releaseAnyConnection(Connection connection) throws SQLException {
connection.close();
}
#Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = this.getAnyConnection();
// need to do stuff here
return connection;
}
#Override
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
}
#Override
public boolean supportsAggressiveRelease() {
return true;
}
#Override
public boolean isUnwrappableAs(Class unwrapType) {
return false;
}
#Override
public <T> T unwrap(Class<T> unwrapType) {
return null;
}
}
It is failing because dataSource is null. I'm assuming it hasn't been created yet but I'm having a hard time finding solutions via Google.
I met the same problem.It seems that in the yml ,HeaderTenantIdentifierResolver and SchemaPerTenantConnectionProvider is managed by hibernate.See here.

Resources