[Remoting 3] Possible bug in "org.jboss.ejb.client.EjbClientContext"
sunil_dixit Aug 26, 2013 3:22 PMjboss-ejb-client (Version 1.0.18.Final and above) has one bug (garbage collection related) in "public void unregisterEJBReceiver(final EJBReceiver receiver)" API.
This API uses "ExecutorService" to send close notification to registered listeners (if any) asynchronously.
Now if your InitialContext is eligible for garbage collection then it JVM calls RemoteContext.finalize() method which internally result into calling "org.jboss.ejb.client.EJBReceiverContext.close()" which triggers
"org.jboss.ejb.client.EJBClientContext.unregisterEJBReceiver()" .
Before "org.jboss.ejb.client.EJBClientContext.unregisterEJBReceiver() " gets executed "org.jboss.ejb.client.EJBClientContext.ejbClientContextTasksExecutorService" state is changed from RUNNING to TERMINATED i.e. ( runState is being set to 3) which result into "java.util.concurrent.RejectedExecutionException".
ThreadPoolExecutor.addIfUnderMaximumPoolSize() API will always return false as " if (poolSize < maximumPoolSize && runState == RUNNING)" prevents to create new thread.
Finally caller APIs gets following exception
java.util.concurrent.RejectedExecutionException
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
at org.jboss.ejb.client.EJBClientContext.unregisterEJBReceiver(EJBClientContext.java:432)
at org.jboss.ejb.client.EJBReceiverContext.close(EJBReceiverContext.java:59)
at org.jboss.ejb.client.remoting.ChannelAssociation.notifyBrokenChannel(ChannelAssociation.java:404)
at org.jboss.ejb.client.remoting.ChannelAssociation.access$100(ChannelAssociation.java:59)
at org.jboss.ejb.client.remoting.ChannelAssociation$1.handleClose(ChannelAssociation.java:118)
at org.jboss.ejb.client.remoting.ChannelAssociation$1.handleClose(ChannelAssociation.java:110)
at org.jboss.remoting3.spi.SpiUtils.safeHandleClose(SpiUtils.java:54)
at org.jboss.remoting3.spi.AbstractHandleableCloseable$CloseHandlerTask.run(AbstractHandleableCloseable.java:501)
at org.jboss.remoting3.spi.AbstractHandleableCloseable.runCloseTask(AbstractHandleableCloseable.java:406)
at org.jboss.remoting3.spi.AbstractHandleableCloseable.closeComplete(AbstractHandleableCloseable.java:277)
at org.jboss.remoting3.remote.RemoteConnectionChannel.closeAction(RemoteConnectionChannel.java:515)
at org.jboss.remoting3.spi.AbstractHandleableCloseable.closeAsync(AbstractHandleableCloseable.java:359)
at org.jboss.remoting3.remote.RemoteConnectionHandler.closeAllChannels(RemoteConnectionHandler.java:390)
at org.jboss.remoting3.remote.RemoteConnectionHandler.sendCloseRequest(RemoteConnectionHandler.java:231)
at org.jboss.remoting3.remote.RemoteConnectionHandler.closeAction(RemoteConnectionHandler.java:376)
at org.jboss.remoting3.spi.AbstractHandleableCloseable.closeAsync(AbstractHandleableCloseable.java:359)
at org.jboss.remoting3.ConnectionImpl.closeAction(ConnectionImpl.java:52)
at org.jboss.remoting3.spi.AbstractHandleableCloseable.closeAsync(AbstractHandleableCloseable.java:359)
at org.jboss.naming.remote.client.HaRemoteNamingStore.closeAsync(HaRemoteNamingStore.java:385)
at org.jboss.naming.remote.client.NamingStoreCache.release(NamingStoreCache.java:113)
at org.jboss.naming.remote.client.NamingStoreCache$1.close(NamingStoreCache.java:98)
at org.jboss.naming.remote.client.RemoteContext.finalize(RemoteContext.java:199)
at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
at java.lang.ref.Finalizer.runFinalizer(Unknown Source)
at java.lang.ref.Finalizer.access$100(Unknown Source)
at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
Below code in "org.jboss.ejb.client.EJBClientContext" is added into new versions and causing this problem
// we *don't* want to send these notification to listeners synchronously since the listeners can be any arbitrary
// application code and can potential block for a long time. So invoke the listeners asynchronously via our ExecutorService
final Collection<EJBClientContextListener> listeners = new ArrayList<EJBClientContextListener>(this.ejbClientContextListeners);
for (final EJBClientContextListener listener : listeners) {
this.ejbClientContextTasksExecutorService.submit(new Runnable() {
@Override
public void run() {
try {
listener.receiverUnRegistered(receiverContext);
} catch (Throwable t) {
// log and ignore
logger.debug("Exception trying to invoke EJBClientContextListener " + listener + " for EJB client context " + EJBClientContext.this + " on un-registertation of EJBReceiver " + receiver, t);
}
}
});
}
}