I found very good example for SNMP server and SNMP client but I'm not sure how I can implement JUnit test into single test file:
public class SNMPClientTest
{
#Test
public void randomData()
{
SnmpTrap trap = new SnmpTrap("127.0.0.1",
"1.3.6.1.4.1.2789.2005.1={s}WWW Server Has Been Restarted",
2, "kschmidt", "MD5", "mysecretpass", "DES", "mypassphrase");
trap.doTrap();
}
}
public class SNMPServerTest
{
#Test
public void randomDatabaseData() throws SQLException, FileNotFoundException, IOException
{
V3TrapReceiver v3 = new V3TrapReceiver("127.0.0.1", "kschmidt", "MD5",
"mysecretpass", "DES", "mypassphrase");
v3.listen();
}
}
When I run the server I get message Waiting for traps.. and I can't continue the JUnit test. But I can run them into 2 separate files.
How I can solve this? You can find the complete source code here: http://pastebin.com/zKEtXQmq
If you wanted to have both the client and the server running within the same test you can consider starting them as separate Threads within a single Test.
I normally try to avoid this because it does add some complexity and context management to the test.
Please note:
This sample has not been tested, there may be tweaks that need to be made. The gist of the handling of the additional threads should be about right.
I did not verify anything for your tests, so all this does is run the server and then the client with no expectation of output or state.
#Rule
public ErrorCollector collector = new ErrorCollector();
#Rule
public Timeout testTimeout = new Timeout(15, TimeUnit.SECONDS);
#Test
public void testServerClientCommunication throws Exception () {
final SnmpTrap trap = new SnmpTrap("127.0.0.1",
"1.3.6.1.4.1.2789.2005.1={s}WWW Server Has Been Restarted",
2, "kschmidt", "MD5", "mysecretpass", "DES", "mypassphrase");
final V3TrapReceiver v3 = new V3TrapReceiver("127.0.0.1", "kschmidt", "MD5",
"mysecretpass", "DES", "mypassphrase");
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
v3.listen();
}
} catch (Throwable th) {
//Exceptions thrown outside of the main Junit execution won't get propagated back to fail the test
//Use the ErrorCollector to maintain awareness
collector.addError(th);
}
}};
//Create the Thread to handle the Server execution
final Thread serverExecutor = new Thread(serverTask, "SNMP Server");
/*
* Create the client task and thread.
*/
Runnable clientTask = new Runnable() {
#Override
public void run() {
try {
boolean clientIsDone = false;
while (!clientIsDone) {
trap.doTrap();
//FIXME: Determine the state that matters.
clientIsDone = true;
}
} catch (Throwable th) {
//Exceptions thrown outside of the main Junit execution won't get propagated back to fail the test
//Use the ErrorCollector to maintain awareness
collector.addError(th);
}
}};
Thread clientExecutor = new Thread(clientTask, "SNMP Client");
/*
* Start the server first
*/
//Don't hold the JVM if the server is not done.
serverExecutor.setDaemon(true);
serverExecutor.start();
/*
* Now start the client. Note that after the client traps successfully that it will interrupt the server thread.
* The intent is that the interrupt will allow the server thread to die gracefully
*/
clientExecutor.setDaemon(true);
clientExecutor.start();
//Since we off-threaded the tasks the test will consider itself 'done' unless we join with the client, which basically says
//"Hold the current thread at this point until the other thread completes."
clientExecutor.join();
}
Start the server in a method annotated with #BeforeClass. This will run before any other tests will be invoked.
Related
Is it possible in java to create a thread that will always work in the background? The problem is that the application instance sometimes crashes with an OutOfMemoryException. Therefore, several instances are launched in parallel. Each instance does some work: it saves something to the database at the request of the user. And the stream, which should work constantly, will look into the database and somehow process the information from it.
Most likely, the sheduler will not work, since the thread must be running constantly and wait for a signal to start working.
First of all, I suggest you investigate and resolve the OutOfMemoryException because it better to avoid these cases. You can instanziate a thread that wait for a request, execute a request and then return to wait for another request. The implementation is like this for thread:
/** Squares integers. */
public class Squarer {
private final BlockingQueue<Integer> in;
private final BlockingQueue<SquareResult> out;
public Squarer(BlockingQueue<Integer> requests,
BlockingQueue<SquareResult> replies) {
this.in = requests;
this.out = replies;
}
public void start() {
new Thread(new Runnable() {
public void run() {
while (true) {
try {
// block until a request arrives
int x = in.take();
// compute the answer and send it back
int y = x * x;
out.put(new SquareResult(x, y));
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}).start();
}
}
And for the caller method:
public static void main(String[] args) {
BlockingQueue<Integer> requests = new LinkedBlockingQueue<>();
BlockingQueue<SquareResult> replies = new LinkedBlockingQueue<>();
Squarer squarer = new Squarer(requests, replies);
squarer.start();
try {
// make a request
requests.put(42);
// ... maybe do something concurrently ...
// read the reply
System.out.println(replies.take());
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
To more information, you can start to read the post that I found here to provide you the example.
You basically need an infinitely running thread with some control.
I found this answer to be the simplest and it does what you need.
https://stackoverflow.com/a/2854890/11226302
I tested a multi-thread program in JUnit and main function, source code as follows:
public class TestDaemon {
#Test
public void test() {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("hello");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// default false
thread.setDaemon(false);
thread.start();
}
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("hello");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// default false
thread.setDaemon(false);
thread.start();
}
}
It didn't print hello string in the JUnit test example.
In the main function example, it could print hello in the console, but when I set the thread.setDaemon(true), it also can't print hello.
I know this is related to Daemon thred and User thread, but I don't know how to explain it.
A daemon thread is a thread that does not prevent the JVM from exiting when the program finishes but the thread is still running. An example for a daemon thread is the garbage collection.
When you run your code from main it creates both beans, thus two threads - daemon and non-daemon. As long as non-daemon thread is running, your application won't exit. So it works.
It's different when run from JUnit. As soon as JUnit test method completes (and it completes immediately after the Spring context is up), JUnit assumes your tests are done. Thus it kills all your threads and basically the whole JVM.
Remember your Waitor1 bean spawns a background thread which JUnit doesn't care about. As soon as you leave #Test method JUnit will just stop everything.
We can analyze the source code of JUnit, part of junit.textui.TestRunner as follows:
public static final int SUCCESS_EXIT = 0;
public static final int FAILURE_EXIT = 1;
public static final int EXCEPTION_EXIT = 2;
...
public static void main(String args[]) {
TestRunner aTestRunner = new TestRunner();
try {
TestResult r = aTestRunner.start(args);
if (!r.wasSuccessful()) {
System.exit(FAILURE_EXIT);
}
System.exit(SUCCESS_EXIT);
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(EXCEPTION_EXIT);
}
}
/**
* Returns whether the entire test was successful or not.
*/
public synchronized boolean wasSuccessful() {
return failureCount() == 0 && errorCount() == 0;
}
/**
* Gets the number of detected failures.
*/
public synchronized int failureCount() {
return fFailures.size();
}
/**
* Gets the number of detected errors.
*/
public synchronized int errorCount() {
return fErrors.size();
}
In this source code, we can conclude that the TestRunner excutes the Unit Test method, no need to wait it finish their tasks, then calls System.exit() method, so that terminates the program. So, it couldn't print hello in the console.
In the main function, because the new thread is not daemon thread, the main program will wait it finishing their tasks, then teminates the program. So,hellostring could be seen in the console.
I have written a multi thread code which will verify data in database and assert accordingly. But the assertions are not working in this environment.
Code to create threads
Runnable r = new WorkerThread(subasscociation);
new Thread(r).start();
new Thread(r).start();
The code for thread start function is
public class WorkerThread implements Runnable {
ArrayList<Association> alInsertedAssociations;
public WorkerThread(ArrayList<Association> alInsertedAssociations) {
this.alInsertedAssociations = alInsertedAssociations;
}
public void run() {
SecondLevelVerification slv = new SecondLevelVerification();
slv.verify(alInsertedAssociations,"add", false);
}
}
The function which asserts
public void verify(...)
{
//Code to check database
org.testng.Assert.assertNotEquals(label, 0);
}
But the code doesn't seem to work ie it doesnt assert correctly if the database doesn't have that entry.
Assertions work by throwing an exception, which in your case doesn't reach the handler installed by the testing framework. The latter monitors only the thread in which the test was started, whereas the exception is thrown from a different thread (created from within the test). See these questions for more details:
How to catch an Exception from a thread
java thread exceptions
The accepted answers therein suggest how to solve your problem. Here is a draft version of a class that will allow to propagate exceptions occurring inside your threads to the testing framework:
class MyThread extends Thread implements Thread.UncaughtExceptionHandler {
Throwable interceptedException = null;
MyThread(Runnable r) {
super(r);
this.setUncaughtExceptionHandler(this);
}
#Override
public void uncaughtException(Thread t, Throwable ex) {
interceptedException = ex;
}
public void myjoin() throws Throwable {
super.join();
if ( interceptedException != null )
throw interceptedException;
}
}
Your will have to use MyThread instead of Thread in your test code and call the myjoin() method:
Runnable r = new WorkerThread(subasscociation);
final myThread1 = new MyThread(r);
final myThread2 = new MyThread(r);
myThread1.start();
myThread2.start();
...
myThread1.myjoin();
myThread2.myjoin();
The issue is that I have a method starting a new thread for a time-consuming work. I want to test the callback result, but the child thread may still running, so as a result, what I get is not the right stub.
I think the code may explain itself:
public class JustAClass {
//it is a callback for async
public interface JustACallBack {
void callFunc(JustAResult result);
}
//this is the result interface
public interface JustAResult {
}
//this is a real class for the interface
public class JustAResultReal implements JustAResult{
public JustAResultReal(String content) {this.content = content;}
public String content;
}
//here is the key function
public void threadFunc(final JustACallBack callBack) {
BCCache.executorService.execute(new Runnable() {
#Override
public void run() {
//just to simulate a time-consuming task
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//now we callback
callBack.callFunc(new JustAResultReal("can you reach me"));
}
});
}
}
and the test function could be(I am using mockito):
#Test
public void testThreadFunc() throws Exception {
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = Mockito.mock(JustAClass.JustACallBack.class);
justAClass.threadFunc(callBack);
//add this line, we can get the expected result
Thread.sleep(1200);
Mockito.verify(callBack).callFunc(captor.capture());
System.out.println(((JustAClass.JustAResultReal)captor.getValue()).content);
}
I know we can add a sleep to wait and expect that the child thread would exit within the period, but could there be a better way? Actually how could I know how long the child thread would take? Setting a very long time can be an approach but just seems not very nice.
The general approach in #stalet's answer is close, but doesn't quite work since any assertion failures from a separate thread are not noticed by the main thread. Therefore your test will always pass, even when it shouldn't. Instead, try using ConcurrentUnit (which I authored):
#Test
public void testInvoke() throws Throwable {
Waiter waiter = new Waiter();
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = new JustAClass.JustACallBack() {
#Override
public void callFunc(final JustAClass.JustAResult result) {
waiter.assertNotNull(result);
waiter.assertTrue(result instanceof JustAClass.JustAResultReal);
waiter.resume();
}
};
justAClass.threadFunc(callBack);
waiter.await(1200, TimeUnit.SECONDS);
}
The key here is ConcurrentUnit's Waiter will properly report any assertions failures to the main test thread and the test will pass or fail as it should.
I aggree with #Gimbys comment about this is no longer a unit-test when you start testing the the threading aspect.
Nevertheless it is interesting as a way to integration-test a asynchronous invokation.
To avvoid sleep i tend to use the class CountDownLatch to wait for invokations.
In order to count down you need an actuall implementation of the callback interface - so in my example I have made a mock implementation of this.
Since there is no actual methods to fetch the data - i am just testing that it is in fact a instance of the JustAReal interface.
#Test
public void testInvoke() throws Exception {
final CountDownLatch countDownLatch = new CountDownLatch(1); //1 is how many invokes we are waiting for
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = new JustAClass.JustACallBack() {
#Override
public void callFunc(final JustAClass.JustAResult result) {
assertNotNull("Result should not be null", result);
assertTrue("Result should be instance of JustAResultReal", result instanceof JustAClass.JustAResultReal);
countDownLatch.countDown();
}
};
justAClass.threadFunc(callBack);
if(!countDownLatch.await(1200, TimeUnit.MILLISECONDS)){
fail("Timed out, see log for errors");
}
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
** See updates first as original implemenation contains some false assumptions
Backstory
I have a problem where I MUST fork the processes, the reason is that I am using the jni and the single threaded R process. Also I need a way to monitor memory and cpu, forking seems like the only real solution. You cannot implement have more than one R invocation per process, I have definitly tried to get around this limitation but am pretty sure it is not possible due to the rinside setup method.
Current implementation
I am currently trying to fork a process and connect an rmi connection to it and store these in a stacked pool. The problem is that the registry.bind() method is not blocking as it should. When binding to the registry in a main process the process will block and wait for remote method calls but when starting from a RunTime.getRuntime().exec() the process does not block and exits. This causes my endpoint daemon to close and I receive socket errors when trying to communicate with the daemon. I am using the gfork library to fork my process simply for ability to receive exceptions and such on startup of the forked process.
public class JRIDaemon implements IROperationRemoteProvider, Serializable, Runnable {
/**
* Serialization Id
*/
private static final long serialVersionUID = 2279972098306474322L;
/**
* Daemon logger
*/
private static final Logger logger = Logger.getLogger(JRIDaemon.class.getName());
/**
* This is the exeuctor service used to execute our job, the option for
* newSingleThreadExecutor is important because R is single threaded and JRI
* puts check in and will kill us if the thread is manipulated.
*/
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
/**
* This implemenation uses the exeuctor service to run the analytics
* operation. The executor service is used because R is single threaded and
* cannot be called from outside.
*/
private JRIExecutionTask callableOperation;
/**
* This is the unique id that can to fetch this daemon.
*/
private final String daemonId;
private JRIDaemon() {
this(UUID.randomUUID().toString());
}
private JRIDaemon(String daemonId) {
this.daemonId = daemonId;
}
private String getDaemonId() {
return daemonId;
}
#Override
public void run() {
logger.info("Starting the jri daemon");
System.out.println("Starting the jri daemon");
try {
IROperationRemoteProvider stub = (IROperationRemoteProvider) UnicastRemoteObject.exportObject(this, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(daemonId, stub);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Exception occurred when initializing the rmi agent ", e);
}
System.out.println("Daemon is done");
logger.fine("Exiting JRIDaemon#run");
}
/**
* Close the connection to R services.
* #throws NotBoundException
* #throws RemoteException
* #throws AccessException
*/
public void close() throws Exception {
logger.info("Calling close !!!!!!!!!");
//if (registry != null) {
// registry.unbind(daemonId);
//}
//System.exit(0);
}
/**
* #see IROperationProvider#execute(IAnalyticsOperation, List, List)
*/
#Override
public Map<String, IMetric> execute(IAnalyticsOperation operation, List<IAnalyticsOperationInput> inputs, List<? extends IDataProvider> dataProvider) throws Exception {
callableOperation = new JRIExecutionTask(inputs, operation, dataProvider);
Future<Map<String, IMetric>> execution = executorService.submit((Callable<Map<String, IMetric>>) callableOperation);
return execution.get();
}
/**
* #see IROperationProvider#interrupt()
*
* TODO come to a solution on stopping and restarting the thread in the
* Rengine implementation.
*/
#Override
public void interrupt() {
System.out.println("Calling interrupt on executor service");
executorService.shutdown();
// Can't do this yet because it causes a segfault in the task engine
// process.
// callableOperation.interrupt();
}
#Override
public Boolean isAllGood() {
return true;
}
#Override
public void activate() {
}
#Override
public void passivate() {
}
/**
* This is here only for testing purposes.
* #param args
* #throws Exception
*/
public static void main(String args[] ) throws Exception {
IROperationRemoteProvider provider = create();
Thread.sleep(10000);
System.out.println(" ALL GOOD " + provider.isAllGood());
}
/**
* This creates a daemon and initializes returns the client that can be used
* to talk to the server. The daemon is useless for the calling process as
* it is a separate process and we use the client to communicate with the
* jri daemon process.
*
* #return
*/
public static IROperationRemoteProvider create() throws Exception {
LocateRegistry.createRegistry(1099);
String daemonId = UUID.randomUUID().toString();
JRIDaemon daemon = new JRIDaemon(daemonId);
Fork<JRIDaemon, org.gfork.types.Void> forkedDaemon = new Fork<JRIDaemon, org.gfork.types.Void>(daemon);
//forkedDaemon.setJvmOptions("-Djava.security.manager -Djava.security.policy=\"taskenginesecurity.policy\"");
logger.info("Calling run task");
forkedDaemon.addListener(new Listener<JRIDaemon, org.gfork.types.Void>() {
#Override
public void onFinish(Fork<JRIDaemon, Void> fork, boolean wasKilled) throws IllegalAccessException, InterruptedException {
logger.info("Task is finished exit value -> " + fork.getExitValue() + " killed ->" + wasKilled);
}
#Override
public void onError(Fork<JRIDaemon, Void> fork) throws IllegalAccessException, InterruptedException {
logger.info("Error was " + fork.getStdErr());
}
#Override
public void onException(Fork<JRIDaemon, Void> fork) throws IllegalAccessException, InterruptedException, IOException, ClassNotFoundException {
logger.log(Level.SEVERE, " Erorro occurred in daemon ", fork.getException());
}
});
Fork.setLoggingEnabled(true);
forkedDaemon.execute();
forkedDaemon.waitFor();
logger.info("Standard out was " + forkedDaemon.getStdOut());
if (forkedDaemon.isException()) {
throw new RuntimeException("Unble to create Remote Provider ", forkedDaemon.getException());
}
//Thread.sleep(2000);
Registry registry = LocateRegistry.getRegistry();
IROperationRemoteProvider process = (IROperationRemoteProvider) registry.lookup(daemonId);
return process;
}
}
I use the create method to create a new implementation of my analytics provider, the Fork class calls run when it executes to spawn a new daemon. If I put this exact same code in a public static void main(String[] args) the process daemonizes and waits for rmi calls, but when exeting through the for operation it does not.
Here is the Gfrork execute method and you can see it uses the Runtime.exec
/**
* Starts a new java process which runs the task.
* The subprocess inherits the environment including class path an
* system properties of the current process. The JVM is launched using
* executable derived from standard system property 'java.home'.
* <p>
* Standard output (System.out) of the task can be red by {#link #getStdOut()} or
* forwarded to a file, see {#link #setStdOutWriter(Writer)}.
* The same is possible for Standard error (System.err),
* see {#link #getStdErr()} and {#link #setStdErrWriter(Writer)}.
*
* #throws Exception
*/
public synchronized void execute() throws Exception {
if (isExecuting()) {
throw new IllegalStateException(FORK_IS_ALREADY_EXECUTING);
}
exec = Runtime.getRuntime().exec(createCmdArray(), null, workingDir);
taskStdOutReader = new BufferedReader(new InputStreamReader(exec.getInputStream()));
taskErrorReader = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
readError();
readStdOut();
waitForFinishedThread = new Thread("jforkWaitForFinishedThread") {
// needed to notify listeners after execution
#Override
public void run() {
try {
waitFor();
} catch (final Exception e) {
e.printStackTrace();
stdErrText.append(String.format("ERROR jforkListenerNotifier: %s%n", e.toString()));
}
}
};
waitForFinishedThread.start();
}
I have added sleep timers to watch for the process , it does start and shortly after that it exits with no errors and a 0 status. I have verified that if there is a problem configuring rmi in the run method that it will return the exception. RMI seems to be initializing correctly but simply does not block so that the forked process does not exit. I have RTFM on Runtime.exec and have not idea what is causing this to exit. Any help would be appreciated.
Update
Thank you EJP even though your remarks were condescending they were correct. I made an incorrect assumption that the bind was blocking due to the fact that the process did not die but this is rather that it creates a separate thread to handle rmi communication. This is what keeps the process alive.
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class RunnableRMIDaemon implements Remote {
public static void main(String args[]) throws InterruptedException {
String daemonID = "123";
System.out.println("STARTING");
Registry registry;
try {
RunnableRMIDaemon daemon = new RunnableRMIDaemon();
registry = LocateRegistry.getRegistry();
final Remote stub = (Remote) UnicastRemoteObject.exportObject(daemon, 0);
registry.rebind(daemonID, stub);
Thread.sleep(1000);
} catch (RemoteException e) {
throw new RuntimeException("Remote Exception occurred while running " + e);
}
System.out.println("ENDING");
}
}
import java.io.IOException;
public class ForkRMIDaemon {
public static void main(String args[]) throws IOException, InterruptedException {
System.out.println("Starting fork");
Runtime.getRuntime().exec("java -cp . RunnableRMIDaemon");
Thread.sleep(10000);
System.out.println("Completed fork");
}
}
When the first process dies the Runtime.getRuntime().exec() process is still alive.
thanatos:testingrmifork chris$ java ForkRMIDaemon
Starting fork
Completed fork
tv-mini:testingrmifork chris$ ps -ef | grep java
501 25499 1 0 0:00.10 ttys007 0:00.72 /usr/bin/java -cp . RunnableRMIDaemon
501 25501 25413 0 0:00.00 ttys007 0:00.00 grep java
thanatos:testingrmifork chris$
My investigation is not complete yet but it appears the the simple gfork library is actually doing something to close the process on return. I have looked through the gfork code but have not seen where this can be happening.
Thanks EJP and I applogize of the incorrect information. I am guessing that gfork is doing some trickery because it allows you to call a method that is not main.
I assumed that java treated threads more like c pthreads and I have always had to create a while loop in main() otherwise my threads would be killed when main exits. My mistake
The problem is that the registry.bind() method is not blocking as it should. When binding to the registry in a main process the process will block and wait for remote method calls.
No it won't. This is fantasy. You made it up. There is nothing in the documentation that says anything of the sort. It is not a blocking call (except for the moments during which it is communicating with the Registry); and it does not 'block and wait for remote method calls'. It returns to your code. You mustn't be surprised if you make up behaviour and the system doesn't exhibit it.
This causes my endpoint daemon to close
No it doesn't. Your endpoint daemon causes itself to close, somehow. RMI starts non-daemon threads to handle incoming connections, so a JVM that has exported remote objects won't exit until those remote objects are unexported, either explicitly or via GC, or the application calls System.exit(). The way to prevent GC of your remote objects is to store static references to them.
I must say I don't understand why you are even exec-ing a sub-process, if all you are going to do in the main process is wait for it.
Came up with a semi dirty way to do it, this will block indefinitely but I will have to find a sure fire way to close the forked daemon, in a normal environment the process should get a sigkill as when I am running it form unit tests. I think I am almost there.
#Override
public void run() {
logger.info("Starting the jri daemon");
Registry registry;
try {
registry = LocateRegistry.getRegistry();
final IROperationRemoteProvider stub = (IROperationRemoteProvider) UnicastRemoteObject.exportObject(this, 0);
registry.rebind(daemonId, stub);
} catch (RemoteException e) {
throw new RuntimeException("Remote Exception occurred while running " + e);
}
final Object waitObj = new Object();
synchronized (waitObj) {
while (!closed)
try {
waitObj.wait();
} catch (InterruptedException e) {
closed = true;
}
}
logger.fine("Exiting JRIDaemon#run");
}