0 Replies Latest reply on May 16, 2017 2:16 PM by jfisherdev

    Remote EJB Client Channel Closed Errors

    jfisherdev

      We have been encountering the exception below seemingly at random.

       

      java.rmi.RemoteException: Error; nested exception is: 
        java.io.IOException: Channel Channel ID d1a61663 (outbound) of Remoting connection 20b68fcb to $hostname$/$hostIp$:$http.port$ has been closed
      //Invoke Remote EJB interface here
      Caused by: java.rmi.RemoteException: Error; nested exception is: 
        java.io.IOException: Channel Channel ID d1a61663 (outbound) of Remoting connection 20b68fcb to $hostname$/$hostIp$:$http.port$ has been closed
        at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:236)
        at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183)
        at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
        at com.sun.proxy.$Proxy2.invoke(Unknown Source)
        at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        ... 10 more
      Caused by: java.io.IOException: Channel Channel ID d1a61663 (outbound) of Remoting connection 20b68fcb to $hostname$/$hostIp$:$http.port$ has been closed
        at org.jboss.ejb.client.remoting.ChannelAssociation$1.handleClose(ChannelAssociation.java:123)
        at org.jboss.ejb.client.remoting.ChannelAssociation$1.handleClose(ChannelAssociation.java:115)
        at org.jboss.remoting3.spi.SpiUtils.safeHandleClose(SpiUtils.java:54)
        at org.jboss.remoting3.spi.AbstractHandleableCloseable$CloseHandlerTask.run(AbstractHandleableCloseable.java:514)
        at org.jboss.remoting3.spi.AbstractHandleableCloseable.runCloseTask(AbstractHandleableCloseable.java:419)
        at org.jboss.remoting3.spi.AbstractHandleableCloseable.closeComplete(AbstractHandleableCloseable.java:290)
        at org.jboss.remoting3.remote.RemoteConnectionChannel.closeAction(RemoteConnectionChannel.java:543)
        at org.jboss.remoting3.spi.AbstractHandleableCloseable.closeAsync(AbstractHandleableCloseable.java:372)
        at org.jboss.remoting3.remote.RemoteConnectionHandler.closeAllChannels(RemoteConnectionHandler.java:429)
        at org.jboss.remoting3.remote.RemoteConnectionHandler.sendCloseRequest(RemoteConnectionHandler.java:233)
        at org.jboss.remoting3.remote.RemoteConnectionHandler.handleConnectionClose(RemoteConnectionHandler.java:113)
        at org.jboss.remoting3.remote.RemoteReadListener$1$1.run(RemoteReadListener.java:56)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      

       

      The call is being made from a remote standalone EJB client [a Swing GUI application] to a standalone WildFly 9.0.2.final server.

       

      An approximation of the classes we use to facilitate making the remote invocation as well as the call itself are as follows.

       

      //Wraps a Context object to simplify the lookup
      public class EjbClient implements AutoCloseable {
          private final Context context;
      
          public EjbClient(Context context) {
                this.context = context;
           }
          
           //Other lookup helper operations
      
           public Object lookupEJB(String jndiName) throws NamingException {
                return context.lookup(jndiName);
           }
      
           @Override//from AutoCloseable
           public void close() throws Exception {
                context.close();
           }
      }
      

       

      //Singleton object that maintains EjbClient instances for the lifetime of the application
      public EjbClientFactory {
      
           public static EjbClientFactory getInstance(){
                ...
           }
      
           //Default client/context for this application
           private EjbClient defaultClient;
           //EjbClients/contexts for this client to communicate with other applications/servers
           private final Map<String, EjbClient> otherAppClients = new ConcurrentHashMap<>();
      
           public EjbClient getDefaultClient() throws NamingException {
                if(defaultClient == null) {
                     defaultClient = new InitialContext(createProperties());
                }
                return defaultClient;
           }
      
           public EjbClient getClientForApp(String app) {
                if(otherAppClients.containsKey(app){
                     return otherAppClients.get(app);
                }
                final Properties appClientProperties = createProperties();
                //Add/adjust app-specific properties as needed
                final EjbClient appClient = new EjbClient(new InitialContext(appClientProperties));
                otherAppClients.put(app, appClient);
                return appClient;
           }
      
           private Properties createProperties() {
           //Create properties for scoped EJB client context, relevant properties given below:
           //java.naming.factory.url.pkgs = org.jboss.ejb.client.naming
           //connect.options.org.jboss.remoting3.RemotingOptions.HEARTBEAT_INTERVAL = 60000
           //channel.options.org.jboss.remoting3.RemotingOptions.MAX_INBOUND_MESSAGES = 80
           //channel.options.org.jboss.remoting3.RemotingOptions.MAX_OUTBOUND_MESSAGES = 80
           //org.jboss.ejb.clint.scoped.context = true
           }
      }
      

       

      //The Swing client that makes the remote EJB calls.
      public class AppGuiClient {
      
           private Runnable updateAlertsRunnable = new Runnable() {
                @Override
                public void run() {
                     updateAlerts();
                }
           }
      
           void refresh() {
                //The < Java 5 way of doing the fetch on a separate thread was already there and not my idea
                final Thread updateAlertsThread = new Thread(updateAlertsRunnable);
                updateAlertsThread.setDaemon(true);
                updateAlertsThread.start();
           }     
      
           private void updateAlerts() {
                try {
                     final EjbClient ejbClient = EjbClientFactory.getInstance().getDefaultClient();
                     //Stateless session bean remote interface
                     final AlertSessionRemote remote = (AlertSessionRemote) ejbClient.lookup(...);
                     //JNDI lookup is fine, it SOMETIMES fails here when invoking the remote proxy
                     final List<Alert> alerts = remote.getAlerts();
                     //Update GUI with alert information
                     addAlerts(alerts);
                } catch (Exception e) {
                     //Show a dialog with exception details, the same happens for uncaught exceptions
                     displayException(e);
                }
           }
      }
      

       

      I don't understand how this state and exception are being reached and that this only occurs sometimes with this method. The client context is not closed between invocations [not closed until the application is finished with them], which would make sense, but isn't the case here. Also, subsequent calls with the same client/context work, which makes this more confusing.

       

      Is there client or server-side configuration that might be a problem? The only areas I could think of on the server-side would be XNIO or remoting.

       

      Any information or ideas about this would be appreciated greatly.