Why does my MessageDrivenBean JMS Session close by itself? Can/shouldn't it remain open?
gberish Nov 20, 2015 8:20 PMI'm a refugee from GlassFish learning WildFly. I need a cut-and-paste example of a standalone Java Client able to swap JMS messages with a MessageDrivenBean, but there are none, so I'm making it. So far I have a client-MDB pair that almost work.
First time I run the client, it works. The MDB onMessage() method receives the clients message. It sends a reply to another Queue to which the client listens. The client retreives it.
But second time I run the cleint, it fails on the server side. The client sends a message. The MDB onMessage() method receives it. Then the MDB throws an IllegalStateException because the session it uses was closed.
I though the idea with JMS was to re-use objects like Session. So I instantiated the session as class member in the MDB constructor which I thought would make it a permanent part of the MDB instance unless the server shut down.
I'm obviously lost. Any explanation or help is appreciated.
I put everything below. Hope it's not too much, but I though it might help anyone else new to WildFly. With two additions, cutting and pasting the code should work with an out of the box WildFly running on localhost: 1) add a new user (role: "guest"; name:" jmsuser"; pw:" jmsuser@123"), and 2) add two Queues in the standalone.xml as shown below.]
Here's what follows:
- 1. MDB Code:
- 2. Client Code:
- 3. application.xml
- 4. xml added to standalone-full.xml for Queues
- 5. Structure of jmsTest.ear file used to autodeploy MDB
- 6. Minimized extract from WildFly server.log covering a) Start up with jmsTest.ear stored in <WILDFLY_HOME>/standalone/deployments, b) client run successfully 1st time, then c)client failing on 2nd try.
- 7. Eclipse console printout for successful run.
- 8. Eclipse console printout for failed run.
1. MDB CODE:
package org.america3.gotest.server.messaging;
ALL IMPORTS
@MessageDriven(
activationConfig ={
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="maxSession",propertyValue="1"),
@ActivationConfigProperty(propertyName="destination", propertyValue="java:/jms/goSvrReceiveQueue")},
mappedName = "JmsTestMsgBean")
public class JmsTestMsgBean implements MessageListener {
private Connection connection = null;
private Session session = null;
private Queue svrSendQueue = null;
private Destination sendToDestination = null;
private MessageProducer msgProducer = null;
private final String jmsSelectorKey = "MyMessages";
// constructor
public JmsTestMsgBean () {
try {
System.out.print("\nMDB:constructor(): beg");
Context ctx = new InitialContext();
System.out.print("\n MDB:constructor(): obtained InitialContext");
System.out.print("\n : "+ ctx);
ConnectionFactory factory = (ConnectionFactory) ctx.lookup("java:/jboss/DefaultJMSConnectionFactory");
System.out.print("\n MDB:constructor(): Connection Factory looked up");
System.out.print("\n : " + factory);
this.connection = factory.createConnection("jmsuser", "jmsuser@123");
System.out.print("\n MDB:constructor(): Connection established");
System.out.print("\n : " + this.connection);
this.svrSendQueue = (Queue) ctx.lookup("jboss/exported/jms/goSvrSendQueue");
System.out.print("\n MDB:constructor(): svrSendQueue looked up");
System.out.print("\n : " + this.svrSendQueue);
this.sendToDestination = (Destination) this.svrSendQueue;
System.out.print("\n MDB:constructor(): svrSendQueue cast to Destination");
this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
System.out.print("\n MDB:constructor(): Session instantiated");
System.out.print("\n : " + this.session);
this.msgProducer = session.createProducer(sendToDestination);
System.out.print("\n MDB:constructor(): Producer instantiated");
System.out.print("\n : " + this.msgProducer);
System.out.print("\nMDB:constructor(): end");
}catch(Exception e) {
System.out.print("\n MDB:constructor(): Exception - " + e.getClass().getName());
System.out.print("\n : msg - " + e.getMessage());
System.out.print("\n MDB:constructor(): closeing any connection");
if(this.connection != null)
try {
this.connection.close();
} catch (JMSException e1) {
e1.printStackTrace();
}
System.out.print("\nMDB:constructor(): end - w/Exception");
}
}
@PostConstruct
public void myInit () {
System.out.print("\nMDB:myInit() : Construction completed. ver #10");
}
@PreDestroy
public void myDestroy () throws JMSException {
System.out.print("\nMDB:myDestroy() : called to close any connection");
if(this.connection != null) this.connection.close();
}
public void onMessage(Message msg) {
System.out.print("\nMDB:onMessage(): begin");
try {
String textReceived = (String)(((ObjectMessage)msg).getObject());
System.out.print("\n MDB:onMessage() : received message = \"" + textReceived + "\"");
String msgSelectorValue = msg.getStringProperty(this.jmsSelectorKey);
System.out.print("\n MDB:onMessage() : selector:");
System.out.print("\n : \"" + msgSelectorValue +"\"");
ObjectMessage replyMsg = session.createObjectMessage();
System.out.print("\n MDB:onMessage() : reply message created");
replyMsg.setObject(new String("Hi. Received your message ok."));
System.out.print("\n MDB:onMessage() : added String as reply Object:");
System.out.print("\n : \"Hi. Received your message ok.\"");
replyMsg.setStringProperty(this.jmsSelectorKey, msgSelectorValue);
System.out.print("\n MDB:onMessage() : setting selector property");
System.out.print("\n : Key");
System.out.print("\n : \"" + this.jmsSelectorKey + "\"");
System.out.print("\n : Value");
System.out.print("\n : \"" + msgSelectorValue + "\"");
msgProducer.send(replyMsg);
System.out.print("\n MDB:onMessage() : message sent");
System.out.print("\nMDB:onMessage() : end");
} catch (JMSException e) {
System.out.print("\n MDB:onMessage() : Exception - " + e.getClass().getName());
System.out.print("\n MDB:onMessage() : msg - " + e.getMessage());
System.out.print("\n MDB:onMessage() : close any connection");
System.out.print("\nMDB:onMessage(): end - w/Exception");
}
if(connection != null)
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
2. STANDALONE JAVA CLIENT CODE:
package org.america3.gotest.client;
ALL IMPORTS
/*************************************************************
* Required jars *
* 1. jboss-client.jar found in: *
* <JBOSS_HOME>\bin\client *
* 2. hornetq-jms-client-2.4.7.Final.jar found in *
* <JBOSS_HOME>\modules\system\layers\base\org\hornetq\main\ *
*************************************************************/
public class JmsTestClient implements MessageListener {
/**********************************************************
* these are properties for JNDI InitialContext(env) used *
* by stand alone java client run on same computer where *
* WildFly is on localhost. *
**********************************************************/
static final private Properties ENV = new Properties() {
private static final long serialVersionUID = 1L;
{
put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
put(Context.SECURITY_PRINCIPAL, "jmsuser");
put(Context.SECURITY_CREDENTIALS, "jmsuser@123");
put("jboss.naming.client.ejb.context", true);
}
};
/***********************************************************
* Not all these need to be class members. It just seemed *
* nice to put them all in one place as an overview. *
***********************************************************/
private Context ctx = null;
private HornetQJMSConnectionFactory jmsConnectionFactory = null;
private Connection jmsConnection = null;
private Session jmsSession = null;
private Queue jmsReceiveFmQueue = null;
private Queue jmsSendToQueue = null;
private MessageConsumer jmsMsgConsumer = null;
private MessageProducer jmsMsgProducer = null;
private boolean msgReturnedFlag = false;
private JmsTestClient.KillSomeTime timeKiller = null;
private final String jmsSelectorKey = "MyMessages";
private final String jmsSelectorValue = "w3Mij#l4";
private final String jmsSelector = jmsSelectorKey + "=\'" + jmsSelectorValue + "\'";
private JmsTestClient () {
try {
p(" constructor() : selector expression.");
p(" " + this.jmsSelector);
this.ctx = new InitialContext(JmsTestClient.ENV);
p(" constructor() : ctx ok");
this.jmsConnectionFactory = (HornetQJMSConnectionFactory) ctx.lookup("jms/RemoteConnectionFactory");
p(" constructor() : factory look up ok");
this.jmsReceiveFmQueue = (Queue) ctx.lookup("jms/goSvrSendQueue");
p(" constructor() : from Queue ok");
this.jmsSendToQueue = (Queue) ctx.lookup("jms/goSvrReceiveQueue");
p(" constructor() : send to Queue ok");
this.jmsConnection = jmsConnectionFactory.createConnection("jmsuser", "jmsuser@123");
p(" constructor() : connection ok");
this.jmsConnection.start();
this.jmsSession = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
p(" constructor() : session ok");
this.jmsMsgConsumer = jmsSession.createConsumer(jmsReceiveFmQueue, jmsSelector);
p(" constructor() : consumer ok");
this.timeKiller = new KillSomeTime ();
p(" constructor() : instantiated KillSomeTime Runnable ok");
this.jmsMsgConsumer.setMessageListener(this);
p(" constructor() : listener set ok");
this.jmsMsgProducer = jmsSession.createProducer(jmsSendToQueue);
p(" constructor() : producer ok");
p("constructor() : end of constructor ok");
} catch (CommunicationException e) {
p ("You forgot to start WildFly dummy!");
} catch (Exception e) {
p("constructor() : caught: " + e.getClass().getName());
p(" : " + e.getMessage());
if (this.jmsConnection != null)
try {
this.jmsConnection.close();
} catch (JMSException e1) {
e1.printStackTrace();
}
}
}
static public void main (String[] args) {
System.out.println("Begin main()");
JmsTestClient testClient = new JmsTestClient(); // to make available in catch block
try {
ObjectMessage msg = testClient.jmsSession.createObjectMessage();
msg.setObject(new String("Please Send a Reply"));
msg.setStringProperty(testClient.jmsSelectorKey, testClient.jmsSelectorValue );
testClient.jmsMsgProducer.send(msg);
testClient.p("main() : message sent");
/***************************************************************
* The rest may be overkill, but it seemed like the main thread*
* would need some time after it sent a message while it waited*
* for a reply. In actual application, client will be a java *
* GUI that stays open anyway. *
***************************************************************/
Thread t = new Thread(testClient.timeKiller);
testClient.killSomeTime (t);
if (t.isAlive()) {
testClient.p("main() : t.join() timed out. t still running. Interrupt it.");
t.interrupt();
}
Thread.sleep(1000); // give Main thread time to check for calls to onMessage();
if (testClient.msgReturnedFlag) {
testClient.p("main() : ending with message returned.");
return;
} else {
testClient.p("main() : ending with no message returned.");
}
try {
testClient.jmsConnection.close();
} catch (JMSException e) {
e.printStackTrace();
}
} catch (Exception e) {
testClient.p("main() : caught " + e.getClass().getName());
testClient.p("main() : " + e.getMessage());
}
}
public void onMessage(Message msg) {
try {
this.p("Received Message");
this.p("text: \"" + (String)((ObjectMessage)msg).getObject() + "\"");
} catch (JMSException e) {
e.printStackTrace();
}
this.msgReturnedFlag = true;
}
private void killSomeTime (Thread t) {
t.start();
try {
t.join (4000);
p("killSomeTime(): t.join() timed out.");
} catch (InterruptedException e) {
this.p("main() : caught " + e.getClass().getName());
this.p("main() : " + e.getMessage());
}
if (this.msgReturnedFlag) {
this.p("killSomeTime(): ended with message returned");
} else {
p("killSomeTime(): ended w/ no message returned");
}
}
/**************************************************
* used to kill sometime on a different Thread *
* to let the main tread wait for a reply message *
**************************************************/
class KillSomeTime implements Runnable {
public void run() {
for (int i = 0; i < 8; i++) {
try {
Thread.sleep(1000);
p("run() : Yawn #" + i + " any message yet?");
if (msgReturnedFlag) {
p("run() : yes. Ok I quit");
return;
} else {
p("run() : no. Ok back to sleep");
}
} catch (InterruptedException e) {
p("run(): Interrupted: on sleep cycle " + i);
return;
}
}
p("run(): Done killing time. Should not have gotten here.");
}
}
private void p (String s) {
String threadName = "[" + Thread.currentThread().getName() + "] ";
System.out.println(threadName + s);
}
}
3. application.xml
<?xml version="1.0" encoding="UTF-8"?>
<application
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"
version="1.4">
<description>GoTest</description>
<display-name>JmsTestMsgBean</display-name>
<module>
<ejb>jmsTest.jar</ejb>
</module>
</application>
4. LINES ADDED TO STANDALONE-FULL.XML
<jms-destinations>
<jms-queue name="goSvrReceiveQueue">
<entry name="java:/jboss/exported/jms/goSvrReceiveQueue"/>
<durable>true</durable>
</jms-queue>
<jms-queue name="goSvrSendQueue">
<entry name="java:/jboss/exported/jms/goSvrSendQueue"/>
<durable>true</durable>
</jms-queue>
</jms-destinations>
5. STRUCTURE OF jmsTest.ear FILE USED TO AUTODEPLOY MDB
jmsTest.ear
META-INF
application.xml
MANIFEST.MF
jmsTest.jar
MANIFEST.MF
org.america3.gotest.server.messagingJmsTestMsgBean.class
6. MINIMIZED EXTRACT FROM WILDFLY SERVER.LOG
####WILDFLY STARTED WITH jmsTest.ear STORED IN standalone/deployments
09:33:56,905 INFO JBoss Modules version 1.4.3.Final
09:33:57,125 INFO JBoss MSC version 1.2.6.Final
09:33:57,198 INFO WFLYSRV0049: WildFly Full 9.0.2.Final (WildFly Core 1.0.2.Final) starting
#### Java Client sends 1st message. WildFly instantiates 3 MDBs
09:34:00,285 INFO WFLYMSG0002: Bound messaging object to jndi name java:jboss/DefaultJMSConnectionFactory
09:34:00,319 INFO WFLYEJB0042: Started message driven bean 'JmsTestMsgBean' with 'hornetq-ra.rar' resource adapter
#### The following lines all printed from
#### (default-threads - 1)
09:34:00,382 INFO WFLYSRV0010: Deployed "jmsTest.ear" (runtime-name : "jmsTest.ear")
#### MDB#1
09:34:00,381 INFO MDB:constructor(): beg
09:34:00,382 INFO MDB:constructor(): obtained InitialContext
09:34:00,385 INFO : javax.naming.InitialContext@4f2ddba9
09:34:00,387 INFO MDB:constructor(): Connection Factory looked up
09:34:00,487 INFO : org.hornetq.ra.HornetQRAConnectionFactoryImpl@1adbb333
09:34:00,488 INFO MDB:constructor(): Connection established
09:34:00,491 INFO : org.hornetq.ra.HornetQRASessionFactoryImpl@13945469
09:34:00,493 INFO MDB:constructor(): svrSendQueue looked up
09:34:00,494 INFO : HornetQQueue[goSvrSendQueue]
09:34:00,497 INFO MDB:constructor(): svrSendQueue cast to Destination
09:34:00,498 INFO MDB:constructor(): Session instantiated
09:34:00,512 INFO : org.hornetq.ra.HornetQRASession@3a8003c4
09:34:00,513 INFO MDB:constructor(): Producer instantiated
09:34:00,515 INFO : org.hornetq.ra.HornetQRAMessageProducer@51c6b988
09:34:00,528 INFO MDB:constructor(): end
#### MDB #2
09:34:00,530 INFO MDB:constructor(): beg
09:34:00,531 INFO MDB:constructor(): obtained InitialContext
09:34:00,533 INFO : javax.naming.InitialContext@119e4374
09:34:00,535 INFO MDB:constructor(): Connection Factory looked up
09:34:00,540 INFO : org.hornetq.ra.HornetQRAConnectionFactoryImpl@1adbb333
09:34:00,542 INFO MDB:constructor(): Connection established
09:34:00,545 INFO : org.hornetq.ra.HornetQRASessionFactoryImpl@7fde1fad
09:34:00,547 INFO MDB:constructor(): svrSendQueue looked up
09:34:00,551 INFO : HornetQQueue[goSvrSendQueue]
09:34:00,553 INFO MDB:constructor(): svrSendQueue cast to Destination
09:34:00,555 INFO MDB:constructor(): Session instantiated
09:34:00,557 INFO : org.hornetq.ra.HornetQRASession@f699aa1
09:34:00,559 INFO MDB:constructor(): Producer instantiated
09:34:00,561 INFO : org.hornetq.ra.HornetQRAMessageProducer@28421822
#### These were printed inbetween the above output lines from MDB
09:34:00,541 INFO WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
09:34:00,543 INFO WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
09:34:00,546 INFO WFLYSRV0025: WildFly Full 9.0.2.Final (WildFly Core 1.0.2.Final) started in 4008ms - Started 337 of 523 services (244 services are lazy, passive or on-demand)
#### All the remaining lines were all printed from
####(Thread-1 (HornetQ-client-global-threads-1918894799))
09:34:19,406 INFO MDB:constructor(): end
#### MDB #3
09:34:19,407 INFO MDB:constructor(): beg
09:34:19,407 INFO MDB:constructor(): obtained InitialContext
09:34:19,408 INFO : javax.naming.InitialContext@19c988ae
09:34:19,408 INFO MDB:constructor(): Connection Factory looked up
09:34:19,421 INFO : org.hornetq.ra.HornetQRAConnectionFactoryImpl@1adbb333
09:34:19,421 INFO MDB:constructor(): Connection established
09:34:19,422 INFO : org.hornetq.ra.HornetQRASessionFactoryImpl@18ed5101
09:34:19,422 INFO MDB:constructor(): svrSendQueue looked up
09:34:19,422 INFO : HornetQQueue[goSvrSendQueue]
09:34:19,423 INFO MDB:constructor(): svrSendQueue cast to Destination
09:34:19,423 INFO MDB:constructor(): Session instantiated
09:34:19,424 INFO : org.hornetq.ra.HornetQRASession@1c919c3c
09:34:19,425 INFO MDB:constructor(): Producer instantiated
09:34:19,425 INFO : org.hornetq.ra.HornetQRAMessageProducer@db71b95
09:34:19,426 INFO MDB:constructor(): end
09:34:19,428 INFO MDB:myInit() : Construction completed. ver #10
#### 1st message processed successfully
09:34:19,429 INFO MDB:onMessage(): begin
09:34:19,430 INFO MDB:onMessage() : received message = "Please Send a Reply"
09:34:19,430 INFO MDB:onMessage() : selector:
09:34:19,431 INFO : "w3Mij#l4"
09:34:19,433 INFO MDB:onMessage() : reply message created
09:34:19,433 INFO MDB:onMessage() : added String as reply Object:
09:34:19,433 INFO : "Hi. Received your message ok."
09:34:19,434 INFO MDB:onMessage() : setting selector property
09:34:19,434 INFO : Key
09:34:19,434 INFO : "MyMessages"
09:34:19,434 INFO : Value
09:34:19,435 INFO : "w3Mij#l4"
09:34:19,435 INFO MDB:onMessage() : message sent
09:34:45,911 INFO MDB:onMessage() : end
#### Java Client sends 2nd message - fails
09:34:45,911 INFO MDB:onMessage(): begin
09:34:45,912 INFO MDB:onMessage() : received message = "Please Send a Reply"
09:34:45,912 INFO MDB:onMessage() : selector:
09:34:45,913 INFO : "w3Mij#l4"
09:34:45,913 INFO MDB:onMessage() : Exception - javax.jms.IllegalStateException
09:34:45,913 INFO MDB:onMessage() : msg - The session is closed
09:34:45,914 INFO MDB:onMessage() : close any connection
09:35:20,153 WARN HQ212037: Connection failure has been detected:
HQ119014: Did not receive data from /127.0.0.1:52282.
It is likely the client has exited or crashed without closing its connection,
or the network between the server and client has failed. You also might
have configured connection-ttl and client-failure-check-period incorrectly.
Please check user manual for more information. The connection will now be closed.
[code=CONNECTION_TIMEDOUT]
09:35:20,155 WARN HQ222061: Client connection failed, clearing up resources for session b169a693-8fbd-11e5-9e36-5f012a31de8a
09:35:20,156 WARN HQ222107: Cleared up resources for session b169a693-8fbd-11e5-9e36-5f012a31de8a
09:35:20,156 WARN HQ222061: Client connection failed, clearing up resources for session b16d9e34-8fbd-11e5-9e36-5f012a31de8a
09:35:20,157 WARN HQ222107: Cleared up resources for session b16d9e34-8fbd-11e5-9e36-5f012a31de8a
09:35:20,158 INFO HQ221021: failed to remove connection
09:43:57,526 INFO WFLYDR0009: Content WildFly\standalone\data\content\fc\64c...
is obsolete and will be removed
09:43:57,529 INFO WFLYDR0002: Content removed from location WildFly\standalone\data\content\fc\64c...
09:43:57,529 INFO WFLYDR0009: Content WildFly\standalone\data\content\19\100...
is obsolete and will be removed
09:43:57,532 INFO WFLYDR0002: Content removed from location D:\Bulletproof\bpWildFly\standalone\data\content\19\100...
- 7. ECLIPSE CONSOLE PRINTOUT FOR SUCCESSFUL RUN.
Is there a way to prevent the red printing from being added?
Begin main()
[main] constructor() : selector expression.
[main] MyMessages='w3Mij#l4'
Nov 20, 2015 2:48:29 PM org.xnio.Xnio <clinit>
INFO: XNIO version 3.3.1.Final
Nov 20, 2015 2:48:29 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.3.1.Final
Nov 20, 2015 2:48:29 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.9.Final
[main] constructor() : ctx ok
Nov 20, 2015 2:48:30 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
Nov 20, 2015 2:48:30 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@29f69090, receiver=Remoting connection EJB receiver [connection=Remoting connection <63b0b052>,channel=jboss.ejb,nodename=ace]} on channel Channel ID addf070c (outbound) of Remoting connection 691a7f8f to localhost/127.0.0.1:8080
Nov 20, 2015 2:48:30 PM org.jboss.ejb.client.EJBClient <clinit>
INFO: JBoss EJB Client version 2.1.1.Final
[main] constructor() : factory look up ok
[main] constructor() : from Queue ok
[main] constructor() : send to Queue ok
[main] constructor() : connection ok
[main] constructor() : session ok
[main] constructor() : consumer ok
[main] constructor() : instantiated KillSomeTime Runnable ok
[main] constructor() : listener set ok
[main] constructor() : producer ok
[main] constructor() : end of constructor ok
[main] main() : message sent
[Thread-0 (HornetQ-client-global-threads-1453774246)] Received Message
[Thread-0 (HornetQ-client-global-threads-1453774246)] text: "Hi. Received your message ok."
[Thread-4] run() : Yawn #0 any message yet?
[Thread-4] run() : yes. Ok I quit
[main] killSomeTime(): t.join() timed out.
[main] killSomeTime(): ended with message returned
[main] main() : ending with message returned.
- 8. ECLIPSE CONSOLE PRINTOUT FOR FAILED RUN. (RED LINES ABOVE REMOVED)
Begin main()
[main] constructor() : selector expression.
[main] MyMessages='w3Mij#l4'
[main] constructor() : ctx ok
[main] constructor() : factory look up ok
[main] constructor() : from Queue ok
[main] constructor() : send to Queue ok
[main] constructor() : connection ok
[main] constructor() : session ok
[main] constructor() : consumer ok
[main] constructor() : instantiated KillSomeTime Runnable ok
[main] constructor() : listener set ok
[main] constructor() : producer ok
[main] constructor() : end of constructor ok
[main] main() : message sent
[Thread-4] run() : Yawn #0 any message yet?
[Thread-4] run() : no. Ok back to sleep
[Thread-4] run() : Yawn #1 any message yet?
[Thread-4] run() : no. Ok back to sleep
[Thread-4] run() : Yawn #2 any message yet?
[Thread-4] run() : no. Ok back to sleep
[Thread-4] run() : Yawn #3 any message yet?
[Thread-4] run() : no. Ok back to sleep
[main] killSomeTime(): t.join() timed out.
[main] killSomeTime(): ended w/ no message returned
[main] main() : t.join() timed out. t still running. Interrupt it.
[Thread-4] run(): Interrupted: on sleep cycle 4
[main] main() : ending with no message returned.