try-with-resources is nice and all that, but it seems to me that it is still not sufficient for effective resource management when creating classes that wrap multiple AutoCloseable objects. For example, consider
import java.io.*;
class AutocloseableWrapper implements AutoCloseable {
private FileReader r1;
private FileReader r2;
public AutocloseableWrapper(String path1, String path2) throws IOException {
r1 = new FileReader(path1);
r2 = new FileReader(path2);
}
#Override
public void close() throws IOException {
r1.close();
r2.close();
}
public static void main(String[] args) throws IOException {
try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
System.out.format("doing something\n");
throw new IOException("doing something in main");
}
}
}
There are at least two issues with this wrapper:
If "bad-path" is invalid and causes the assignment to r2 to throw, then r1 is not closed.
If wrapper construction succeeds but then r1.close throws, then r2 is not closed.
All those issues can be addressed, but then writing the wrapper becomes quite non-trivial and error-prone, even if wrapping only two resources:
import java.io.*;
class AutocloseableWrapper implements AutoCloseable {
private FileReader r1;
private FileReader r2;
public AutocloseableWrapper(String path1, String path2) throws IOException {
r1 = new FileReader(path1);
try {
r2 = new FileReader(path2);
}
catch (IOException e) {
try {
r1.close();
}
catch (IOException e2) {
e.addSuppressed(e2);
}
throw e;
}
}
#Override
public void close() throws IOException {
IOException e = null;
try {
r1.close();
}
catch (IOException e1) {
e = e1;
}
try {
r2.close();
}
catch (IOException e2) {
if (e == null)
throw e2;
else {
e.addSuppressed(e2);
throw e;
}
}
}
public static void main(String[] args) throws IOException {
try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
System.out.format("doing something\n");
throw new IOException("doing something in main");
}
}
}
Is there some helper class or any other way to make writing wrappers easier?
You should enable the syntactic code unwrapped by the compiler....You can find the Oracle article over here :-
http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html
Coming to the question,if you have a wrapper you can do something like this
#Override
public void close() throws IOException {
Throwable t = null;
try {
r1.close();
} catch (Throwable t1) {
t = t1;
throw t1;
} finally {
if (t != null) {
try {
r2.close();
} catch (Throwable t2) {
t.addSuppressed(t2);
}
} else {
r2.close();
}
}
}
Note:This will work because of precise rethrow feature in Java 7
You could use a generic resource wrapper such as:
public class CloseableChain implements AutoCloseable {
private AutoCloseable r1;
private CloseableChain r2;
public void attach(AutoCloseable r) {
if (r1 == null) {
r1 = r;
} else {
if (r2 == null) {
r2 = new CloseableChain();
}
r2.attach(r);
}
}
public void close() throws Exception {
if (r1 == null) {
return;
}
Throwable t = null;
try {
r1.close();
} catch (Throwable t1) {
t = t1;
throw t1;
} finally {
if (r2 != null) {
if (t != null) {
try {
r2.close();
} catch (Throwable t2) {
t.addSuppressed(t2);
}
} else {
r2.close();
}
}}}}
Then you could refactor your code to:
import java.io.*;
class AutocloseableWrapper implements AutoCloseable {
private CloseableChain chain;
private FileReader r1;
private FileReader r2;
private FileReader r3;
public AutocloseableWrapper(String path1, String path2) throws IOException {
chain = new CloseableChain();
r1 = new FileReader(path1);
chain.attach(r1);
r2 = new FileReader(path2);
chain.attach(r2);
// and even more...
r3 = new FileReader("whatever");
chain.attach(r3);
}
#Override
public void close() throws IOException {
chain.close();
}
public static void main(String[] args) throws IOException {
try (AutocloseableWrapper w = new AutocloseableWrapper("good", "bad")) {
System.out.format("doing something\n");
throw new IOException("doing something in main");
}
}
}
Related
On running the below code
class MyResource1 implements AutoCloseable {
public void close() throws IOException {
System.out.print("1 ");
}
}
class MyResource2 implements Closeable {
public void close() throws IOException {
throw new IOException();
}
}
public class MapAndFlatMap {
public static void main(String[] args) {
try (
MyResource1 r1 = new MyResource1();
MyResource2 r2 = new MyResource2();
) {
System.out.print("T ");
} catch (IOException ioe) {
System.out.print("IOE ");
} finally {
System.out.print("F ");
}
}
}
I am getting the below output
T IOE 1 F
But I was expecting
T 1 IOE F
Even after changing the order of resources in try like the following
MyResource2 r2 = new MyResource2();
MyResource1 r1 = new MyResource1();
There is no change in output .In my understanding the resources will be closed in opposite direction of their declaration . Is it correct ?
It is a documented behavior: "close methods of resources are called in the opposite order of their creation"
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.
While it is qute clear how to configure multi-threaded jBehave run,
it is not qute clear for me how to deal with logging mess.
What are the options here?
Rederect application's output to std out (JBehave's one is already there). Notice follow=true
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.follow=true
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %-64.64C %4L | %m%n
log4j.rootLogger=error, stdout
log4j.logger.com.company.app.interesting.module=debug
...
Per thread file output
#SuppressWarnings("resource")
public class ThreadFileOutput extends PrintStream {
private static ThreadLocal<FileOutputStream> threadOutput = new ThreadLocal<>();
private static PrintStream stdout = System.out;
private static PrintStream stderr = System.err;
static {
System.setOut(new ThreadFileOutput(stdout));
System.setErr(new ThreadFileOutput(stderr));
}
public ThreadFileOutput(OutputStream out) {
super(out);
}
public static void startThreadOutputRedirect(FileOutputStream stream) {
threadOutput.set(stream);
}
public static void stopThreadOutputRedirect() {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
threadOutput.set(null);
try {
stream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void forceOut(String line) {
stdout.println(line);
}
public static void forceErr(String line) {
stderr.println(line);
}
#Override
public void write(byte[] b) throws IOException {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.write(b);
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.write(b);
}
}
#Override
public void write(int b) {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.write(b);
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.write(b);
}
}
#Override
public void write(byte[] buf, int off, int len) {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.write(buf, off, len);
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.write(buf, off, len);
}
}
#Override
public void flush() {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.flush();
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.flush();
}
}
}
Start redirecting thread output to the file befor the test and stop it after the test
startThreadOutputRedirect(new FileOutputStream(new File(workDirRelative(story.getPath()))));
stopThreadOutputRedirect();
in
/**
* JBehave to TC integration.
*/
public class TeamCityReporter extends NullStoryReporter {
private static final LookupTranslator ESCAPE_TABLE = new LookupTranslator(new String[][] {
{ "'", "|'" },
{ "\n", "|n" },
{ "\r", "|r" },
{ "\\u", "|0x" },
{ "|", "||" },
{ "[", "|[" },
{ "]", "|]" }
});
private ThreadLocal<Story> story = new ThreadLocal<>();
private ThreadLocal<String> scenario = new ThreadLocal<>();
#Override
#SuppressWarnings("resource")
public void beforeStory(Story story, boolean givenStory) {
this.story.set(story);
this.scenario.set(null);
try {
startThreadOutputRedirect(new FileOutputStream(new File(workDirRelative(story.getPath()))));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
forceOut(format("##teamcity[testSuiteStarted name='%s']", escape(story.getPath())));
out.println(story.getPath());
super.beforeStory(story, givenStory);
}
#Override
public void afterStory(boolean givenStory) {
forceOut(format("##teamcity[testSuiteFinished name='%s']", escape(story.get().getPath())));
stopThreadOutputRedirect();
super.afterStory(givenStory);
}
#Override
public void beforeScenario(String scenario) {
this.scenario.set(scenario);
forceOut(format("##teamcity[testStarted name='%s']", escape(scenario)));
out.println(scenario);
super.beforeScenario(scenario);
}
#Override
public void afterScenario() {
forceOut(format("##teamcity[testFinished name='%s']", escape(scenario.get())));
this.scenario.set(null);
super.afterScenario();
}
#Override
public void beforeStep(String step) {
out.println(format("\n%s\n", step));
super.beforeStep(step);
}
#Override
public void storyNotAllowed(Story story, String filter) {
forceOut(format("##teamcity[message text='story not allowed %s' status='WARNING']", escape(story.getName())));
out.println(format("\n(Not allowed) %s\n", story.getPath()));
super.storyNotAllowed(story, filter);
}
#Override
public void failed(String step, Throwable cause) {
forceOut(format("##teamcity[testFailed name='%s' message='%s' details='%s']", new String[] { escape(scenario.get()), escape(getRootCauseMessage(cause)), escape(getStackTrace(cause)) }));
out.println(format("\n(Failed) %s\n", step));
cause.printStackTrace();
super.failed(step, cause);
}
#Override
public void pending(String step) {
forceOut(format("##teamcity[testFailed name='%s' message='Step in PENDING state: %s']", escape(scenario.get()), escape(step)));
out.println(format("\n(Pending) %s\n", step));
super.pending(step);
}
#Override
public void notPerformed(String step) {
out.println(format("\n(Not performed) %s\n", step));
super.notPerformed(step);
}
private static String escape(String string) {
return ESCAPE_TABLE.translate(string);
}
}
Turn on parallel JBehave execution
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
...
})
public class Stories extends JUnitStories {
#Before
public void setUp() throws Exception {
configuredEmbedder()
// turn on parallel test execution
.useExecutorService(newFixedThreadPool(30, new ThreadFactoryBuilder()
.setDaemon(true)
.build()));
configuredEmbedder()
.embedderControls()
...
// don't use it this way not to produce multiThreading = true and delayed StoryReporter callbacks
// and you will see your application logging 'for each jbehave step'
// .useThreads(30);
}
#Override
public Configuration configuration() {
return new MostUsefulConfiguration()
...
.useStoryReporterBuilder(new StoryReporterBuilder()
...
.withFormats(HTML)
.withReporters(teamCityReporter));
}
}
As a result, there will be a log file for each parallel test having both test output and application output (only the code being executed by test runner thread).
Bonus - TeamCityReporter (JBehave to TC integration) will successfully count running parallel tests in real time and report any test failures on TC GUI. Configure test output directory as TC artifact path to access each test output.
I'm trying to create a method f1(x) that throws an exception when x equals 5. After that I will try to call that method from another method f2() to invoke that exception. Then I have to have f2() recover by calling f1(x+1). I tried coding something, but I'm stuck. Here is the code:
public class FiveException extends Exception {
public void f1(int x) throws FiveException {
if (x == 5) {
throw new FiveException();
}
}
public void f2() {
int x = 5;
try {
f1(x);
}catch (FiveException e) {
System.out.println("x is 5");
}
}
public static void main(String[] args) {
FiveException x5 = new FiveException();
x5.f2();
}
}
The print statement works, but I'm not sure how to call f(x+1). Any help on how to fix this and any techniques to write exceptions is appreciated.
Because f1 throws FiveException, wherever you call f1 you must either catch the exception or throw it to the method calling the method that raises the exception. For example:
public static void main(String[] args) throws FiveException {
FiveException x5 = new FiveException();
x5.f1(1);
}
Or:
public static void main(String[] args) {
FiveException x5 = new FiveException();
try {
x5.f1(1);
} catch (FiveException e) {
e.printStackTrace();
}
}
But your code is confusing... normally, it isn't the exception class that throws itself, you have other classes that throw the exception class.
If it's being invoked inside a catch statement, you must surround it with another try-catch, 'cause the code inside catch isn't protected, like this:
public void f2() {
int x = 5;
try {
f1(x);
}catch (FiveException e) {
System.out.println("x is 5");
try {
f1(x + 1);
} catch (FiveException e) {
e.printStackTrace();
}
}
}
But this code is ugly, you can write the following:
public void f2() {
int x = 5;
fProtected(x);
fProtected(x + 1);
}
private void fProtected(int x) {
try {
f1(x);
}catch (FiveException e) {
System.out.println("x is 5");
}
}
There're some library classes that although implement Serializable, fail to serialize correctly. I can't fix them, but I can extend ObjectOutputStream and ObjectInputStream for some workaround.
I want my ObjectOutputStream to write additional data for each instance of class A and ObjectInputStream to read and apply that data after A is deserialized.
Currently I have a mid-workaround that requires explicit additional calls to writeObject() and readObject(). I'd prefer to manage without these calls.
Uncomment /* */ blocks to see how it works.
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import org.junit.Test;
import static org.junit.Assert.*;
public class CloneSerializableTest2 {
// library classes
public static class A implements Serializable {
public transient String s1;
}
public static class MyA extends A {
public String s2;
}
/*
private static class AHolder implements Serializable {
private static final Field s1Fld;
static {
try {
s1Fld = A.class.getDeclaredField("s1");
s1Fld.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unexpected error", e);
}
}
private String s1;
private A a;
public AHolder(A m) {
this.a = m;
try {
s1 = (String)s1Fld.get(m);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
public void restoreA() {
try {
s1Fld.set(a, s1);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
}
*/
#SuppressWarnings("unchecked")
public static <T> T cloneSerializable(T o) {
try {
/*
final List<AHolder> accumSrc = new ArrayList<AHolder>();
*/
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout)
/*
{
{
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException
{
if (obj instanceof A) {
accumSrc.add(new AHolder((A)obj));
}
return super.replaceObject(obj);
}
}
*/
;
out.writeObject(o);
/*
out.writeObject(accumSrc);
*/
out.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object copy = in.readObject();
/*
List<AHolder> accumDst = (List<AHolder>)in.readObject();
for (AHolder r : accumDst) {
r.restoreA();
}
*/
in.close();
return (T)copy;
} catch (IOException e) {
throw new RuntimeException("Unexpected error", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unexpected error", e);
}
}
#Test
public void testIt() throws Exception {
try {
MyA m1 = new MyA();
m1.s1 = "a";
m1.s2 = "b";
m1 = cloneSerializable(m1);
assertEquals("a", m1.s1);
assertEquals("b", m1.s2);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
Answering to myself
import java.io.*;
import java.lang.reflect.Field;
import org.junit.Test;
import static org.junit.Assert.*;
public class CloneSerializableTest2 {
// library classes
public static class A implements Serializable {
public transient String s1;
}
public static class MyA extends A {
public String s2;
}
private static class AHolder implements Serializable, Externalizable {
private static final Field s1Fld;
static {
try {
s1Fld = A.class.getDeclaredField("s1");
s1Fld.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unexpected error", e);
}
}
private String s1;
private A a;
#SuppressWarnings("unused")
public AHolder() {
}
public AHolder(A m) {
this.a = m;
try {
s1 = (String)s1Fld.get(m);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
private Object readResolve() {
try {
s1Fld.set(a, s1);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
return a;
}
#Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(s1);
ObjectOutputStream out2 = ((ObjectOutputStream)out);
out2.writeUnshared(a);
}
#Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
s1 = (String)in.readObject();
a = (A)in.readObject();
}
}
#SuppressWarnings("unchecked")
public static <T> T cloneSerializable(T o) {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout)
{
{
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException
{
if (obj instanceof A) {
obj = new AHolder((A) obj);
} else if (obj instanceof AHolder) {
obj = ((AHolder)obj).a;
}
return super.replaceObject(obj);
}
};
out.writeObject(o);
out.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object copy = in.readObject();
in.close();
return (T)copy;
} catch (IOException e) {
throw new RuntimeException("Unexpected error", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unexpected error", e);
}
}
#Test
public void testIt() throws Exception {
try {
MyA m1 = new MyA();
m1.s1 = "a";
m1.s2 = "b";
m1 = cloneSerializable(m1);
assertEquals("a", m1.s1);
assertEquals("b", m1.s2);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}