Why don't EclipseLinkConnectionHandle implement the releaseConnection method? - eclipselink

In DefaultJpaDialect.releaseJdbcConnection(), the doc said that:
"This implementation does nothing, assuming that the Connection will implicitly be closed with the EntityManager.
If the JPA implementation returns a Connection handle that it expects the application to close after use, the dialect implementation needs to invoke Connection.close() (or some other method with similar effect) here."
In EclipseLinkJpaDialect.getJdbcConnection(), it returns the EclipseLinkConnectionHandle.
However there seems no implementation codes for releaseConnection in EclipseLinkConnectionHandle.
private static class EclipseLinkConnectionHandle implements ConnectionHandle {
private final EntityManager entityManager;
private Connection connection;
public EclipseLinkConnectionHandle(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public Connection getConnection() {
if (this.connection == null) {
this.connection = this.entityManager.unwrap(Connection.class);
}
return this.connection;
}
#Override
public void releaseConnection(Connection con) {
}
}
In this case, how to close the opened connections? or how connections closed?

Related

Using and extending JOOQ generated DAOs with injected DataSource?

I'm new to JOOQ... The following code seems to work in WildFly 22 but I'm not sure if that is the best way to do things. What is the preferred way to inject WF DataSource to JOOQ DAOs (my extended ones)? Is there a way to avoid doing the ".get()." in the service below and just leave #Resource(...) etc. connection related for the MyCompanyDAO to handle internally?
In other words: companyDAO.get().fetchOneById(id) vs. companyDAO.fetchOneById(id)
#Stateless
public class CompanyService extends DefaultCompanyService {
#Inject
private MyCompanyDAO companyDAO;
public Company find(Integer id) {
return companyDAO.get().fetchOneById(id);
}
}
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
private MyConnectionProvider cp;
public CompanyDAO get() { // since cannot use #Resource in dao constructor
this.configuration().set(cp).set(SQLDialect.POSTGRES);
return this;
}
// custom code here
}
public class CompanyDao extends DAOImpl<CompanyRecord, tables.pojos.Company, Integer> {
// jooq generated code here
}
#Stateless
#LocalBean
public class MyConnectionProvider implements ConnectionProvider {
#Resource(lookup = "java:/MyDS")
private DataSource dataSource;
#Override
public Connection acquire() throws DataAccessException {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new DataAccessException("Could not acquire connection.", e);
}
}
#Override
public void release(Connection connection) throws DataAccessException {
try {
connection.close();
} catch (SQLException e) {
throw new DataAccessException("Could not release connection.", e);
}
}
}
Put initialization logic of MyCompanyDAO inside a #PostConstruct method.
#PostConstruct
public void init() {
this.configuration().set(cp).set(SQLDialect.POSTGRES);
}
This way, you don't need to call get:
#Inject
private MyCompanyDAO companyDAO;
public Company find(Integer id) {
return companyDAO.fetchOneById(id);
}
How about using constructor injection instead? The generated DAO classes offer a constructor that accepts a Configuration precisely for that:
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
public MyCompanyDAO (Configuration configuration) {
super(configuration);
}
}
If for some reason you cannot inject the entire configuration (which I'd recommend), you could still inject the ConnectionProvider:
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
public MyCompanyDAO (MyConnectionProvider cp) {
super(DSL.using(cp, SQLDialect.POSTGRES));
}
}

Handling Azure Redis Cache exceptions

I'm using Azure Redis Cache for development and wanted to verify the way I'm handling the exceptions. According to the best practices, it's possible to face RedisConnectionExceptions and to resolve this, we have to dispose the old ConnectionMultiplexer and create a new one. If abortConnect is set to false, then the multiplexer will silently retry connecting without throwing the error. So if the exception is thrown, it will only be after some attempts to reconect and still failing. Is my understanding of this correct?
This is my connection string -
cachename.redis.cache.windows.net:6380,password=Password,ssl=True,abortConnect=False
I believe the connection exception will only occus when you try to call GetConnection() on the multiplexer. Find my Code below -
static Lazy<ConnectionMultiplexer> multiplexer = CreateMultiplexer();
public static ConnectionMultiplexer GetConnection() => multiplexer.Value;
private static Lazy<ConnectionMultiplexer> CreateMultiplexer()
{
return new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionString));
}
private static void CloseMultiplexer(Lazy<ConnectionMultiplexer> oldMultiplexer)
{
if (oldMultiplexer != null)
{
oldMultiplexer.Value.Close();
}
}
public static void Reconnect()
{
var oldMultiplexer = multiplexer;
CloseMultiplexer(multiplexer);
multiplexer = CreateMultiplexer();
}
And I'm Consuming this below in another class -
public class RedisCacheManager
{
private static IDatabase _cache;
private TimeSpan expiry = new TimeSpan(hours: 6, minutes: 0, seconds: 0);
public RedisCacheManager()
{
try
{
_cache = RedisCacheHelper.GetConnection().GetDatabase();
}
catch(RedisConnectionException)
{
RedisCacheHelper.Reconnect();
new RedisCacheManager();
}
}
public async Task<RedisValue[]> GetFromCacheAsync(List<string> keys)
{
var cacheValues = await _cache.StringGetAsync(keys.Select(k => (RedisKey)k).ToArray());
return cacheValues;
}
public async Task SaveInCacheAsync<TValue>(Dictionary<string, TValue> kvps)
{
var tasks = new List<Task>();
foreach(var kvp in kvps)
{
tasks.Add(_cache.StringSetAsync(kvp.Key, JsonConvert.SerializeObject(kvp), expiry));
}
await Task.WhenAll(tasks);
}
}
I'm not sure id calling the constructor in the catch block is a good practice. And are there any other exceptions that I would need to handle while calling StringGetAsync and StringSetAsync?
The CacheManager can look like this:
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public sealed class RedisCacheManager : IDisposable
{
private readonly TimeSpan _expiry;
private readonly Lazy<ConnectionMultiplexer> _lazyConnection;
private ConnectionMultiplexer Connection { get => _lazyConnection.Value; }
public RedisCacheManager(string connectionString, TimeSpan expiry)
{
_expiry = expiry;
_lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionString));
}
public async Task<RedisValue[]> GetFromCacheAsync(IEnumerable<string> keys)
{
var cacheValues = await Connection.GetDatabase()
.StringGetAsync(keys.Select(key => (RedisKey)key).ToArray()).ConfigureAwait(false);
return cacheValues;
}
public async Task SaveInCacheAsync<TValue>(Dictionary<string, TValue> kvps)
{
var tasks = kvps
.Select(kvp => Connection.GetDatabase().StringSetAsync(kvp.Key, JsonConvert.SerializeObject(kvp), _expiry))
.ToArray();
await Task.WhenAll(tasks).ConfigureAwait(false);
}
public void Dispose()
{
if (_lazyConnection.IsValueCreated)
{
_lazyConnection.Value.Dispose();
}
}
}
Using:
public readonly static RedisCacheManager RedisCacheManager = new RedisCacheManager("connection string", TimeSpan.FromHours(6));
Remarks:
it is intended that abortConnect=false (which means that the call succeeds even if a connection to the Azure Cache for Redis is not established) and from constructor shouldn't be thrown any Redis-exceptions
The object returned from GetDatabase is a cheap pass-thru object, and does not need to be stored.
GetFromCacheAsync / SaveInCacheAsync-methods can throw an exception to outside and it is OK. You can apply Retry-policy to resolve transient faults.
If you have any IoC-container then it should create RedisCacheManager with a single instance scope (for example, Autofac registration)

How to use Jedis in flink map()

My code like this:
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(500);
DataStream<String> stream = env.addSource(getConsumer(TOPIC_1));
Jedis jedis = new Jedis("master1");
stream.map(new RichMapFunction<String, String>() {
#Override
public String map(String value) throws Exception {
String result = jedis.hget("rtc", value);
return result;
}
});
I want to get some data from Redis in map(), but it cannot run,because Jedis.class is not serializable.
How to use not serializable class in map(),such as ZkClient,Jedis?
All rich functions like the RichMapFunction have an open(Configuration) and close call which you can override. These lifecycle methods are called once the function has been deployed to a TaskManager where it is executed.
class MyMapFunction extends RichMapFunction<String, String> {
private transient Jedis jedis;
#Override
public void open(Configuration parameters) {
// open connection to Redis, for example
jedis = new Jedis("master1");
}
#Override
public void close() {
// close connection to Redis
jedis.close();
}
}

Reliable Messaging with RabbitMQ

I have an application that sends AMQP messages via RabbitMQ. message sending is triggered on an http request. Recently I have noticed that some messages appear to be getting lost (as in never delivered). I also noticed that the list of channels being managed by the server is steadily increasing. The first thing I have corrected is to close channels after they are no longer required. However, I am still not sure my code is correctly structured to ensure delivery. Two sections of code are below; the first is a section of a singleton that manages the connection (does not recreate on every call), the second is the sending code. Any advice / guidance would be appreciated.
#Service
public class PersistentConnection {
private static Connection myConnection = null;
private Boolean blocked = false;
#Autowired ApplicationConfiguration applicationConfiguration;
#Autowired ConfigurationService configurationService;
#PostConstruct
private void init() {
}
#PreDestroy
private void destroy() {
try {
myConnection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public Connection getConnection( ) {
if (myConnection == null) {
start();
}
else if (!myConnection.isOpen()) {
log.warn("AMQP Connection closed. Attempting to start.");
start();
}
return myConnection;
}
private void start() {
log.debug("Building AMQP Connection");
ConnectionFactory factory = new ConnectionFactory();
String ipAddress = applicationConfiguration.getAMQPHost();
String password = applicationConfiguration.getAMQPUser();
String user = applicationConfiguration.getAMQPPassword();
String virtualHost = applicationConfiguration.getAMQPVirtualHost();
String port = applicationConfiguration.getAMQPPort();
try {
factory.setUsername(user);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setPort(Integer.parseInt(port));
factory.setHost(ipAddress);
myConnection = factory.newConnection();
}
catch (Exception e) {
e.printStackTrace();
}
myConnection.addBlockedListener(new BlockedListener() {
public void handleBlocked(String reason) throws IOException {
// Connection is now blocked
blocked = true;
}
public void handleUnblocked() throws IOException {
// Connection is now unblocked
blocked = false;
}
});
}
public Boolean isBlocked() {
return blocked;
}
}
/*
* Sends ADT message to AMQP server.
*/
private void send(String routingKey, String message) throws Exception {
String exchange = applicationConfiguration.getAMQPExchange();
String exchangeType = applicationConfiguration.getAMQPExchangeType();
Connection connection = myConnection.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(exchange, exchangeType);
channel.basicPublish(exchange, routingKey, null, message.getBytes());
// Close the channel if it is no longer needed in this thread
channel.close();
}
Try this code:
#Service
public class PersistentConnection {
private Connection myConnection = null;
private Boolean blocked = false;
#Autowired ApplicationConfiguration applicationConfiguration;
#Autowired ConfigurationService configurationService;
#PostConstruct
private void init() {
start(); /// In this way you can initthe connection and you are sure it is called only one time.
}
#PreDestroy
private void destroy() {
try {
myConnection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public Connection getConnection( ) {
return myConnection;
}
private void start() {
log.debug("Building AMQP Connection");
ConnectionFactory factory = new ConnectionFactory();
String ipAddress = applicationConfiguration.getAMQPHost();
String password = applicationConfiguration.getAMQPUser();
String user = applicationConfiguration.getAMQPPassword();
String virtualHost = applicationConfiguration.getAMQPVirtualHost();
String port = applicationConfiguration.getAMQPPort();
try {
factory.setUsername(user);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setPort(Integer.parseInt(port));
factory.setHost(ipAddress);
myConnection = factory.newConnection();
}
catch (Exception e) {
e.printStackTrace();
}
myConnection.addBlockedListener(new BlockedListener() {
public void handleBlocked(String reason) throws IOException {
// Connection is now blocked
blocked = true;
}
public void handleUnblocked() throws IOException {
// Connection is now unblocked
blocked = false;
}
});
}
public Boolean isBlocked() {
return blocked;
}
}
/*
* Sends ADT message to AMQP server.
*/
private void send(String routingKey, String message) throws Exception {
String exchange = applicationConfiguration.getAMQPExchange();
String exchangeType = applicationConfiguration.getAMQPExchangeType();
Connection connection = myConnection.getConnection();
if (connection!=null){
Channel channel = connection.createChannel();
try{
channel.exchangeDeclare(exchange, exchangeType);
channel.basicPublish(exchange, routingKey, null, message.getBytes());
} finally{
// Close the channel if it is no longer needed in this thread
channel.close();
}
}
}
This could be enough, you have an connection with rabbitmq when the system starts.
If you an lazy singleton, the code is just a bit different.
I suggest to not use isOpen() method, please read here:
isOpen
boolean isOpen() Determine whether the component is currently open.
Will return false if we are currently closing. Checking this method
should be only for information, because of the race conditions - state
can change after the call. Instead just execute and try to catch
ShutdownSignalException and IOException Returns: true when component
is open, false otherwise
EDIT**
Question 1:
What are you looking for is the HA client.
RabbitMQ java client by default doesn't support this features, since the version 3.3.0 supports only the reconnect,read this:
...allows Java-based clients to reconnect automatically after network
failure. If you want be sure about your messages you have to create an
robust client able to resists to all fails.
Generally you should consider the fails, for example:
what happen if there is an error during the message publish?
In your case you simply lose the message,You should re-queue the message manually.
Question 2:
I don’t know your code, but connection == null shouldn’t happen, because this procedure is called for first:
#PostConstruct
private void init() {
start(); /// In this way you can initthe connection and you are sure it is called only one time.
}
Anyway you can raise an exception, the question is:
What do I have to do with the message that I was trying to send?
See the question 1
I’d like to suggest to read more about the HA, for example this:
http://www.rabbitmq.com/ha.html
https://www.rabbitmq.com/reliability.html
And this for the client:
https://github.com/jhalterman/lyra (I never used it)
Create a reliable system with rabbitmq is not complex, but you should know some basic concept.
Anyway .. Let me know!

Why is NHibernate AdoTransaction's finalizer called?

I'm profiling out unit & integration tests, and I find the a lot of the time is spent on the finalizer of NHibernate.Transaction.AdoTransaction - this means it is not getting disposed properly.
I am not using AdoTransaction directly in the code, so it's probably used by some other object inside NHibernate. Any idea what I'm forgetting to Dispose?
Here is my text fixture:
public abstract class AbstractInMemoryFixture
{
protected ISessionFactory sessionFactory;
protected ILogger Logger { get; private set; }
static readonly Configuration config;
private static readonly ISessionFactory internalSessionFactory;
static AbstractInMemoryFixture()
{
config = new NHibernateConfigurator().Configure(NHibernateConfigurators.SQLiteInMemory());
internalSessionFactory = config.BuildSessionFactory();
}
[SetUp]
public void SetUp()
{
const string sqliteInMemoryConnectionString = "Data Source=:memory:;Version=3;Pooling=False;Max Pool Size=1;";
var con = new SQLiteConnection(sqliteInMemoryConnectionString);
con.Open();
new SchemaExport(config).Execute(false, true, false, true, con, System.Console.Out);
var proxyGenerator = new ProxyGenerator();
sessionFactory = proxyGenerator.CreateInterfaceProxyWithTarget(internalSessionFactory, new UseExistingConnectionInterceptor(con));
Logger = new NullLogger();
ExtraSetup();
}
[TearDown]
public void TearDown()
{
var con = sessionFactory.OpenSession().Connection;
if (con != null)
{
if (con.State == ConnectionState.Open)
con.Close();
con.Dispose();
}
}
private class UseExistingConnectionInterceptor :IInterceptor
{
private readonly SQLiteConnection connection;
public UseExistingConnectionInterceptor(SQLiteConnection connection)
{
this.connection = connection;
}
public void Intercept(IInvocation invocation)
{
if (invocation.Method.Name != "OpenSession" || invocation.Method.GetParameters().Length > 0)
{
invocation.Proceed();
return;
}
var factory = (ISessionFactory) invocation.InvocationTarget;
invocation.ReturnValue = factory.OpenSession(connection);
}
}
protected virtual void ExtraSetup() { }
}
I have the same problem while accessing a Sybase database. I don't know why, nor if it's really the reason of the issue, but it appears that some of the code in \NHibernate\Transaction\AdoTransaction.cs (lines 307 to 311) related to closing/disposing the object have been disabled for a while. Unfortunately, the blame feature of SVN does not give too much info :(