Create a generic method to combine multiple .close() connection methods - java

I have these 4 methods which each close a different connection type, meaning each of those has a different input object. Each method calls the close() method on the provided input object. Is there a way to combine those methods into one, taking in a generic object? I have no way to implement an interface on the provided objects or extend them.
import java.sql.Statement;
import javax.jms.Connection;
import javax.mail.Transport;
private void close(Statement stm) {
if(stm == null) {
return;
}
try {
stm.close();
} catch (SQLException ex) {
logger.error("Error while closing statement", ex);
}
}
private void close(java.sql.Connection con) {
if(con == null) {
return;
}
try {
con.close();
} catch (SQLException ex) {
logger.error("Error while closing connection", ex);
}
}
private void close(javax.jms.Connection con) {
if(con == null) {
return;
}
try {
con.close();
} catch(JMSException ex) {
logger.error("Error while closing JMS connection", ex);
}
}
private void close(Transport transport) {
if(transport == null) {
return;
}
try {
transport.close();
} catch (MessagingException ex) {
logger.error("Error while closing mail transport", ex);
}
}
EDIT:
Thank you for your answers regarding Java 1.7. Unfortunately our servers are running Java 1.6, so is there any solution for that?

You can use reflection.
First sample give you support for try() with resources:
#Test
public void testRes() throws Exception {
try(ClosableWrapper<StringWriter> rs = new ClosableWrapper<>(new StringWriter())){
Writer wr = rs.getResource();
}
}
static class ClosableWrapper<T> implements AutoCloseable{
private T resource;
private String closeMethod = "close";
public ClosableWrapper(T resource) {
this.resource = resource;
}
public ClosableWrapper(T resource, String closeMethod) {
this.resource = resource;
this.closeMethod = closeMethod;
}
public T getResource() {
return resource;
}
#Override
public void close() throws Exception {
if(resource!=null){
Method m = resource.getClass().getMethod(closeMethod);
m.invoke(resource);
}
}
}
or just one method:
public void close(Object resource) throws Exception {
if(resource!=null){
Method m = resource.getClass().getMethod("close");
m.invoke(resource);
}
}

Assuming these are your classes, use the AutoCloseable interface and put them in a try-with-resource.

Related

Java Autocloseable Test [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 months ago.
Improve this question
public class CloseableResource implements AutoCloseable {
private static boolean _closed = false;
int _n;
public CloseableResource(int n){
}
public void use() throws Exception{
throw new Exception("Exception");
}
#Override
public void close() throws Exception{
_closed = true;
}
public static boolean isClosed() {
System.out.println(_closed);
return _closed;
}
#Test
public void testAutoClose() {
boolean failed = false;
try (CloseableResource res = new CloseableResource(2)) {
assertTrue(res != null);
res.use();
} catch (Exception e) {
assertTrue(CloseableResource.isClosed());
failed = true;
}
assertTrue(failed == true);
failed = false;
try (CloseableResource res = new CloseableResource(3)) {
assertTrue(res != null);
res.use();
} catch (Exception e) {
fail("this code should not be reached");
failed = true;
} finally {
assertTrue(CloseableResource.isClosed());
}
assertTrue(failed == false);
}
I am trying to make that test work, the close method seems to work but I can't figure out why the test doesn't, it always ends up with fail("this code should not be reached"). I need some guidance please.
private static boolean _closed = false; why is this static? Making it static sets it to true or false on all instances instead of on a specific instance. I am not sure this is the desired behavior. When you create a new CloseableResource new resources will remain closed. In the constructor, you MUST set the static _close back to false. This will make your test pass, but it will make for a lousy implementation.
This is what I did to make it "work" with Java 8. With Java 8, there is no way that I know of to really test the auto-closeable attribute of your resource.
public class CloseableResource implements AutoCloseable {
private boolean _closed = false;
int _n;
public CloseableResource() {
_n = 1;
}
// public CloseableResource(int n) {
// _n = n;
// }
public void use() throws Exception {
if (_closed) {
throw new Exception("Attempting to use a closed resource");
}
}
#Override
public void close() throws Exception {
if(_closed) {
throw new Exception ("Attempting to close a closed resource");
}
_closed = true;
}
public boolean isClosed() {
System.out.println(_closed);
return _closed;
}
#Test
public void testAutoClose() {
CloseableResource res = new CloseableResource();
try {
assertTrue(res != null);
res.use();
res.close();
} catch (Exception e) {
fail("This code should not be reached");
}
try {
assertTrue(res != null);
res.use();
} catch (Exception e) {
assertTrue(e.getMessage().equals("Attempting to use a closed resource"));
}
try {
res.close();
} catch (Exception e) {
assertTrue(e.getMessage().equals("Attempting to close a closed resource"));
}
}
}
However, if using Java 9 or greater, you can declare the resource outside the try (it will be effectively final); thus allowing you to test the auto-closeable attribute of your resource effectively.
#Test
public void testAutoClose() {
CloseableResource res = new CloseableResource();
try(res) {
assertTrue(res != null);
res.use();
} catch (Exception e) {
fail("This code should not be reached");
}
try {
res.use();
} catch (Exception e) {
assertTrue(e.getMessage().equals("Attempting to use a closed resource"));
}
try {
res.close();
} catch (Exception e) {
assertTrue(e.getMessage().equals("Attempting to close a closed resource"));
}
}
This will allow you to use the same object to test all conditions in the same test.

How to disable Caching at runtime if Couchbase connection failed?

I have a similar problem as asked here - How to disable Redis Caching at run time if redis connection failed. My application is using #Cacheable at the service layer for most of the database/static resources call.
Cache is backed by Couchbase and whenever application fails to connect Couchbase node application goes down. Which is what we are not expecting, we expect data should be served from the source system whenever connection failed.
We tried implementing CacheErrorHandler but it does not work as expected because we want to execute the actual method which is making a service call and return the response rather than logging the Cache fail, basically bypassing the cache and as soon as the Couchbase node is up or connection established get the data from cache.
Any idea how we can achieve it?
Thanks #Daniel Bickler for the suggestion, below is the implementation I written referring #John Blum answer.
CouchbaseCustomCacheManager:
import java.util.Map;
import org.springframework.cache.Cache;
import com.couchbase.client.spring.cache.CacheBuilder;
import com.couchbase.client.spring.cache.CouchbaseCacheManager;
public class CouchbaseCustomCacheManager extends CouchbaseCacheManager {
public CouchbaseCustomCacheManager(
final Map<String, CacheBuilder> initialCaches) {
super(initialCaches);
}
#Override
public Cache getCache(String name) {
return new CouchbaseCacheWrapper(super.getCache(name));
}
protected static class CouchbaseCacheWrapper implements Cache {
private final Cache delegate;
public CouchbaseCacheWrapper(Cache couchbaseCache) {
this.delegate = couchbaseCache;
}
#Override
public String getName() {
try {
return delegate.getName();
} catch (Exception e) {
return null;
}
}
#Override
public Object getNativeCache() {
try {
return delegate.getNativeCache();
} catch (Exception e) {
return null;
}
}
#Override
public ValueWrapper get(Object key) {
try {
return delegate.get(key);
} catch (Exception e) {
return null;
}
}
#Override
public <T> T get(Object key, Class<T> type) {
try {
return delegate.get(key, type);
} catch (Exception e) {
return null;
}
}
#Override
public void put(Object key, Object value) {
try {
delegate.put(key, value);
} catch (Exception e) {
try {
handleErrors(e);
} catch (Exception e1) {
}
}
}
#Override
public ValueWrapper putIfAbsent(Object key, Object value) {
try {
return delegate.putIfAbsent(key, value);
} catch (Exception e) {
return null;
}
}
#Override
public void evict(Object key) {
try {
delegate.evict(key);
} catch (Exception e) {
try {
handleErrors(e);
} catch (Exception e1) {
}
}
}
#Override
public void clear() {
try {
delegate.clear();
} catch (Exception e) {
try {
handleErrors(e);
} catch (Exception e1) {
}
}
}
protected <T> T handleErrors(Exception e) throws Exception {
if (e instanceof Exception) {
return null;
} else {
throw e;
}
}
}
}
And used it as:
#Bean
public CacheManager cacheManager() {
final Map<String, CacheBuilder> cache = new HashMap<>();
for (final String appCache : "127.0.0.1,127.0.0.2,127.0.0.3".split(",")) {
cache.put(appCache, CacheBuilder.newInstance(CouchbaseCluster.create().openBucket(
"default", "")));
}
return new CouchbaseCustomCacheManager(cache);
}

Socket Closed Exception in SocketImpl Setoption

I am trying to set the SO_KEEPALIVE time of socket.
I created a class SocketBuilder to build the socket instance with SocketImpl. Source code is below,
public class SocketBuilder {
private static SocketImpl si;
public static Socket createCVPSocket() throws Exception {
if (si == null) {
init();
}
return new CSocket(si);
}
private static void init() throws SocketException {
#SuppressWarnings("rawtypes")
Constructor cons = null;
try {
cons = Class.forName("java.net.SocksSocketImpl")
.getDeclaredConstructor();
} catch (NoSuchMethodException | SecurityException
| ClassNotFoundException e) {
throw new RuntimeException(
"Not able to access socket implementation.");
}
cons.setAccessible(true);
SocketImpl si = null;
try {
si = (SocketImpl) cons.newInstance();
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Not able to create instance of socket.");
}
if (si != null) {
si.setOption(SocketImpl.SO_KEEPALIVE, new Integer(60));
}
}
private static class CSocket extends Socket {
protected CSocket(SocketImpl si) throws SocketException, Exception {
super(si);
}
}
public static void main(String[] args) {
try {
Socket sock = SocketBuilder.createCVPSocket();
System.out.println(sock);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am getting java.net.SocketException: Socket Closed exception. If I remove the line si.setOption(SocketImpl.SO_KEEPALIVE, new Integer(60)); it works fine. But I want to set the SocketImpl.SO_KEEPALIVE. How can I set the SO_KEEPALIVE of socket?
There some errors in your code:
SocketImpl si = null; this declaration overlap your class field
setOption works only when a socket open/connected
You must close socket when you finish
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.*;
public class SocketBuilder {
private static SocketImpl si;
public static Socket createCVPSocket() throws Exception {
if (si == null) {
init();
}
return new CSocket(si);
}
private static void init() throws SocketException {
#SuppressWarnings("rawtypes")
Constructor cons = null;
try {
cons = Class.forName("java.net.SocksSocketImpl")
.getDeclaredConstructor();
} catch (NoSuchMethodException | SecurityException
| ClassNotFoundException e) {
throw new RuntimeException(
"Not able to access socket implementation.");
}
cons.setAccessible(true);
si = null;
try {
si = (SocketImpl) cons.newInstance();
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Not able to create instance of socket.");
}
}
private static class CSocket extends Socket {
protected CSocket(SocketImpl si) throws SocketException, Exception {
super(si);
super.bind(new InetSocketAddress("127.0.0.1", 8888));
si.setOption(SocketImpl.SO_KEEPALIVE, Boolean.TRUE);
}
}
public static void main(String[] args) {
try {
Socket sock = SocketBuilder.createCVPSocket();
System.out.println(sock);
} catch (Exception e) {
e.printStackTrace();
}
}
}
If you look at the source code of AbstractPlainSocketImpl#setOption method,
public void setOption(int opt, Object val) throws SocketException {
if (isClosedOrPending()) {
throw new SocketException("Socket Closed");
}
// Rest of the code removed for brevity
}
You can see there is a isClosedOrPending check before setting the options.
/*
* Return true if already closed or close is pending
*/
public boolean isClosedOrPending() {
/*
* Lock on fdLock to ensure that we wait if a
* close is in progress.
*/
synchronized (fdLock) {
if (closePending || (fd == null)) {
return true;
} else {
return false;
}
}
}
In your case, since you are just creating a socket, it will not have any fd associated with it. That is why you are getting this error.

Retrieve GPS DATA on a JTextArea with 2 different class

I have a a GPS receptor. I create a class to retrieve all the GPS data on my Eclipse Console.
(This is the code of makia42)
public class COM implements Runnable{
static Thread myThread=null;
static BufferedReader br;
static BufferedWriter wr;
static InputStreamReader isr;
static OutputStreamWriter osw;
static java.io.RandomAccessFile port;
public COM(){ /**Constructeur*/
myThread=new Thread(this);
}
public void start(){
try {
port=new java.io.RandomAccessFile("COM3","rwd");
port.writeBytes("\r\n");
port.writeBytes("c,31,0,0,5\r\n");
port.writeBytes("T,1000,1\r\n");
}
catch (Exception e) {
System.out.println("start "+e.toString());
}
myThread.start();
}
public void run() {
System.out.println("lecture COM...");
for(;;){
String st = null;
try {
st=port.readLine();
} catch (IOException e) {System.out.println(e.getMessage());}
System.out.println(st);
}
}
public static void main(String[] args) {
COM temp= new COM();
temp.start();
}
}
I have another class which is a frame containing a button and a JTextArea. This class is in communication with my first class COM.
When i click the button, COM is starting and show me the data in my Eclipse Console.
But now, I'd like to show it on my JTextArea.
How can I do it ?
Best regards,
Tofuw
Take a moment to read about this pattern.
Make the Thread a Subject. Before starting register the instance of the class that contains the JTextArea as the Observer with the instance of the Thread. At the run() instead of printing on the console, use the notify(String);
public void run() {
System.out.println("lecture COM...");
for(;;){
String st = null;
try {
st=port.readLine();
} catch (IOException e) {System.out.println(e.getMessage());}
System.out.println(st);
}
}
Change to
public void run() {
System.out.println("lecture COM...");
for(;;){
String st = null;
try {
st=port.readLine();
} catch (IOException e) {System.out.println(e.getMessage());}
notifyObservers(st); //Pass the data to the observers.
}
}
EDIT:
I suppose you can rewrite the Thread to a simple class. It will render the program unresponsive while it reads, that's why you have a Thread. I suppose you can implement a cleaner way using Future<String>
public class GpsReader {
public class GenericGPSException extends Exception {
public GenericGPSException(String message, Throwable cause) {
super(message, cause);
}
}
public static void main(String[] args) {
// Example of usage
GpsReader gpsReader = new GpsReader();
String messageFromDevice;
try {
// Try read it
messageFromDevice = gpsReader.getCoordinate();
} catch (GenericGPSException e) {
// Error, what does it says?
messageFromDevice = e.getMessage();
}
JTextArea mockArea = new JTextArea();
// Show to user anything that comes to it.
mockArea.setText(messageFromDevice);
}
private boolean isReady;
private RandomAccessFile port;
public GpsReader() {
}
public String getCoordinate() throws GenericGPSException {
if (!isReady) {
try {
port = new RandomAccessFile("COM3", "rwd");
port.writeBytes("\r\n");
port.writeBytes("c,31,0,0,5\r\n");
port.writeBytes("T,1000,1\r\n");
isReady = true;
} catch (FileNotFoundException e) {
throw new GenericGPSException(
"Error at starting communication to Device ", e);
} catch (IOException e) {
throw new GenericGPSException(
"Error at starting communication to Device ", e);
}
}
try {
return port.readLine();
} catch (IOException e) {
throw new GenericGPSException("Error at reading the Device ", e);
}
}
}

Spring JDBC connection pool and InputStream results

I am writing a webservice that allows users to post files and then retrieve them at a URL (basically think of it as the RESTful Amazon S3). The issue I came across was rather then return a byte[] from my Oracle query (Spring JDBC) I am returning an InputStream and then streaming the data back to the client in chunks. This (IMO) is a much better idea since I put no size restriction on the file and I don't want 2GB byte arrays in memory.
At first it seemed to work fine, but I ran into a case during heavy load that sometimes a Connection would get reused before the previous servlet could send the file. It seems after the JDBC call that returned the InputStream, the Connection would be returned to the pool (Spring would call conn.close(), but not clear the associated ResultSet). So if no other request was given that Connection then the InputStream would still be valid and could be read from, but if the Connection was given to a new request then the InputStream would be null and the previous request would fail.
My solution was to create a subclass of InputStream that also takes a Connection as a constructor arg, and in the overridden public close() method also close the Connection. I had to ditch the Spring JDBC and just make a normal PreparedStatement call, otherwise Spring would always return the connection to the pool.
public class ConnectionInputStream extends InputStream {
private Connection conn;
private InputStream stream;
public ConnectionInputStream(InputStream s, Connection c) {
conn = c;
stream = s;
}
// all InputStream methods call the same method on the variable stream
#Override
public void close() throws IOException {
try {
stream.close();
} catch (IOException ioex) {
//do something
} finally {
try {
conn.close();
} catch (SQLException sqlex) {
//ignore
}
}
}
}
Does anyone have a more elegant solution, or see any glaring problems with my solution? Also this code wasn't cut/paste from my actual code so if there is a typo just ignore it.
Unfortunately, my imagination went wild when you asked this question. I don't know if this solution is considered more elegant. However, these classes are simple and easily re-usable so you may find a use for them if they are not satisfactory. You will see everything coming together at the end...
public class BinaryCloseable implements Closeable {
private Closeable first;
private Closeable last;
public BinaryCloseable(Closeable first, Closeable last) {
this.first = first;
this.last = last;
}
#Override
public void close() throws IOException {
try {
first.close();
} finally {
last.close();
}
}
}
BinaryCloseable is used by CompositeCloseable:
public class CompositeCloseable implements Closeable {
private Closeable target;
public CompositeCloseable(Closeable... closeables) {
target = new Closeable() { public void close(){} };
for (Closeable closeable : closeables) {
target = new BinaryCloseable(target, closeable);
}
}
#Override
public void close() throws IOException {
target.close();
}
}
The ResultSetCloser closes ResultSet objects:
public class ResultSetCloser implements Closeable {
private ResultSet resultSet;
public ResultSetCloser(ResultSet resultSet) {
this.resultSet = resultSet;
}
#Override
public void close() throws IOException {
try {
resultSet.close();
} catch (SQLException e) {
throw new IOException("Exception encountered while closing result set", e);
}
}
}
The PreparedStatementCloser closes PreparedStatement objects:
public class PreparedStatementCloser implements Closeable {
private PreparedStatement preparedStatement;
public PreparedStatementCloser(PreparedStatement preparedStatement) {
this.preparedStatement = preparedStatement;
}
#Override
public void close() throws IOException {
try {
preparedStatement.close();
} catch (SQLException e) {
throw new IOException("Exception encountered while closing prepared statement", e);
}
}
}
The ConnectionCloser closes Connection objects:
public class ConnectionCloser implements Closeable {
private Connection connection;
public ConnectionCloser(Connection connection) {
this.connection = connection;
}
#Override
public void close() throws IOException {
try {
connection.close();
} catch (SQLException e) {
throw new IOException("Exception encountered while closing connection", e);
}
}
}
We now refactor your original InputStream idea into:
public class ClosingInputStream extends InputStream {
private InputStream stream;
private Closeable closer;
public ClosingInputStream(InputStream stream, Closeable closer) {
this.stream = stream;
this.closer = closer;
}
// The other InputStream methods...
#Override
public void close() throws IOException {
closer.close();
}
}
Finally, it all comes together as:
new ClosingInputStream(
stream,
new CompositeCloseable(
stream,
new ResultSetCloser(resultSet),
new PreparedStatementCloser(statement),
new ConnectionCloser(connection)
)
);
When this ClosingInputStream's close() method is called, this is effectively what happens (with exception handling omitted for clarity's sake):
public void close() {
try {
try {
try {
try {
// This is empty due to the first line in `CompositeCloseable`'s constructor
} finally {
stream.close();
}
} finally {
resultSet.close();
}
} finally {
preparedStatement.close();
}
} finally {
connection.close();
}
}
You're now free to close as many Closeable objects as you like.
Why not read the entire InputStream/byte[]/whatever from the query before releasing the query yourself? It sounds like you are trying to return data from the query after your code has told Spring / the pool that you are done with the connection.
An alternative approach is to use a callback. Below is kind of the idea.
class MyDao
{
public boolean getData(Function<InputStream, Boolean> processData) {
// Do your SQL stuff to get a ResultSet
InputStream input = resultSet.getBinaryStream(0);
processData.apply(input);
// Do your cleanup if any
}
}

Categories

Resources