0

I have a ServerEndpoint class that throws this error as soon as I attempt to connect to it from the client. I presume that some sort of dependency is missing, i.e a bundled library that is missing another jar, although it may be some other problem.

I see the following stack trace in the server log, with no additional information.

  An exception or error occurred in the container during the request processing
java.lang.NoClassDefFoundError: Could not initialize class org.example.ServerSocketEndpoint
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        at java.lang.Class.newInstance(Class.java:374)
        at org.glassfish.tyrus.core.ReflectionHelper.getInstance(ReflectionHelper.java:807)
        at org.glassfish.tyrus.core.DefaultComponentProvider.create(DefaultComponentProvider.java:60)
        at org.glassfish.tyrus.core.ComponentProviderService.getInstance(ComponentProviderService.java:232)
        at org.glassfish.tyrus.core.ComponentProviderService.getEndpointInstance(ComponentProviderService.java:293)
        at org.glassfish.tyrus.server.TyrusServerEndpointConfigurator.getEndpointInstance(TyrusServerEndpointConfigurator.java:160)
        at org.glassfish.tyrus.core.AnnotatedEndpoint$1.getEndpointInstance(AnnotatedEndpoint.java:144)
        at org.glassfish.tyrus.core.ComponentProviderService.getInstance(ComponentProviderService.java:149)
        at org.glassfish.tyrus.core.AnnotatedEndpoint.callMethod(AnnotatedEndpoint.java:452)
        at org.glassfish.tyrus.core.AnnotatedEndpoint.onError(AnnotatedEndpoint.java:507)
        at org.glassfish.tyrus.core.TyrusEndpointWrapper.onConnect(TyrusEndpointWrapper.java:657)
        at org.glassfish.tyrus.core.TyrusWebSocket.onConnect(TyrusWebSocket.java:141)
        at org.glassfish.tyrus.core.TyrusWebSocketEngine$TyrusConnection.<init>(TyrusWebSocketEngine.java:611)
        at org.glassfish.tyrus.core.TyrusWebSocketEngine$SuccessfulUpgradeInfo.createConnection(TyrusWebSocketEngine.java:556)
        at org.glassfish.tyrus.servlet.TyrusHttpUpgradeHandler.init(TyrusHttpUpgradeHandler.java:111)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:777)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
        at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
        at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
        at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
        at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
        at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
        at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
        at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
        at java.lang.Thread.run(Thread.java:745)
]]

How can I get more relevant information? I am running the server with --debug.

I also added the following to my domain configuration in order to monitor class loading:

<jvm-options>-verbose:class</jvm-options>
<jvm-options>-XX:LogFile=${com.sun.aas.instanceRoot}/logs/jvm.log</jvm-options>
<jvm-options>-XX:+LogVMOutput</jvm-options>

Is it possible to increase the verbosity further?

I am running GlassFish Server Open Source Edition 4.0 (build 89) on Linux x64 with the latest Oracle Java 7 JDK & Tyrus 1.7

Any ideas would be welcome.

The endpoint stripped to its core; I tried to leave anything that could cause issues:

@ServerEndpoint(
  value = "/main",
  encoders =  { BinaryEncoder.class },  // TextEncoder.class
  decoders =  { BinaryDecoder.class }   // TextDecoder.class
)
@Stateful
public class ServerSocketEndpoint implements IServerSocketEndpoint
{
  static {
    logger      = Debug.getLogger(ServerSocketEndpoint.class);
    ds          = DB.initDs();
    gson        = GsonPlus.create();
    sessions    = Collections.synchronizedSet(new HashSet<Session>());
    peers       = Collections.synchronizedSet(new HashSet<ISocketPeer>());
  }

  protected static final DataSource ds;
  protected static final Logger logger;
  protected static final Gson gson;
  protected static final Set<Session> sessions;
  protected static final Set<ISocketPeer> peers;

  protected TyrusSession  _session;   // TyrusSession implements JSR-356 Session
  protected long          _socketSessionId;
  protected BasicPeer     _peer;

  public static void send(final Session session, Msg msg)
  {
    RemoteEndpoint.Async remote = session.getAsyncRemote();
    if (session.isOpen())
    {
      try {
        remote.sendObject(msg);

        logger.log(Level.INFO, String.format("send() msg: %s", msg.toJson(gson)));
      }
      catch (IllegalArgumentException ex) {
        Logger.getLogger(ServerSocketEndpoint.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
  }

  public ServerSocketEndpoint()
  {
  }

  @Override
  public void close(CloseReason closeReason)
  {
    if (_session == null)
      return;

    try {
      _peer.free();
      _session.close(closeReason);
      _session = null;
    }
    catch (IOException ex) {
      methodException(ex);
    }
  }

  @OnOpen
  public void onOpen(Session session, EndpointConfig config)
  {
    _session = (TyrusSession)session;

    if (ds == null) {
      // No connection available somehow - nothing to do except log the error
    }

    InetAddress clientExtIp;
    try {
      clientExtIp = InetAddress.getByName(_session.getRemoteAddr());
    }
    catch (UnknownHostException ex) {
    }

    try (Connection dbc = ds.getConnection())
    {
      CallableStatement proc = dbc.prepareCall("{call newSocketSession(?, ?, ?, ?, ?, ?)}");
      proc.setBytes("extIp",        clientExtIp.getAddress());
      proc.setString("extHostName", clientExtIp.getHostName());
      proc.registerOutParameter("id", Types.BIGINT);
      if (proc.execute()) {
        // Process results
      }
      // Stash a reference to this DB socket session
      _socketSessionId = proc.getLong("id");
    }
    catch (SQLException ex) {
      methodException(ex);
    }
  }

  @OnError
  public void onError(Session session, Throwable ex)
  {
    methodException(ex);
  }

  @OnMessage
  public void onMessage(final Session session, Msg msg) throws IOException, EncodeException
  {
    // deal with messages
  }

  @OnClose
  public void onClose(Session session)
  {
    sessions.remove(session);
    _session = null;
    _peer = null;
  }
}

Okay so I got it to work with Pavel's help.

  1. Tyrus should not be included in the WAR as this results in duplicate files on the class path.
  2. The apache.commons.codec.binary.Base64 class was not being linked in (required for GsonPlus).

So my question becomes the following more specifically: is there a non-brute-force method of diagnosing such CNFE errors, i.e without de-constructing & re-constructing the endpoint piece by piece?

Atorian
  • 777
  • 10
  • 26
  • Can you please share endpoint mentioned in the stack trace? – Pavel Bucek Aug 10 '14 at 17:37
  • Hi Pavel. The entire endpoint is rather massive and contains proprietary code, but I can share some parts. Btw, I have learned a lot from your blog over the past few months, so thanks for that and all the work on Tyrus. – Atorian Aug 10 '14 at 19:54
  • 1
    are you sure you have "IServerSocketEndpoint" on your classpath? Can you produce simplest reproducible testcase and share it on github or somewhere? (you can mail it to me directly if you don't want to share it publicly). The CNFE is rather suspicious and weird - ah! I know what is maybe happening. I guess you have dependency on tyrus-core to be able to work with Tyrus directly, right? Can you double check that you are NOT including that jar in your war file? (It should be marked as scope "provided"). – Pavel Bucek Aug 10 '14 at 21:01
  • I checked the EAR file - IServerSocketEndpoint is definitely inside in the right place. I had suspected that tyrus-core and other files might have clashed with what is on the server, so I had removed it from the list of libraries to be packaged in the WAR. However, for whatever reason something did not get cleaned and the Tyrus files stayed in the EAR file. After your suggestion I manually cleaned all dependencies and now the EAR is 1/3 the size with no Tyrus, so thanks for that! I still get the CNFE though... I will build a testcase and send it to you asap. – Atorian Aug 10 '14 at 22:21
  • Okay so I got it to work - the apache.commons.codec.binary.Base64 class was not being linked in (required for GsonPlus). So that's solved, but surely there has to be a better way of debugging such issues? The CNFE gives no clue as to the problem - deconstructing things and building them back up piece by piece is really a last resort method of dealing with things (although clearly very effective). I can deal with such errors in development by sheer brute force, but what about the future when its deployed on multiple servers and something is missing? – Atorian Aug 11 '14 at 11:14
  • 1
    I'm pretty sure that the initial CNFE was caused by including tyrus-core.jar in your application. About the other part - you did not include any other expcetion, my guess would be that it mentioned Base64 class. I don;t think we can do anything when the classpath includes two implementations of the same class on Tyrus level. – Pavel Bucek Aug 11 '14 at 11:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59106/discussion-between-atorian-and-pavel-bucek). – Atorian Aug 11 '14 at 12:26
  • Pavel, I'd like to accept your last comment as the answer to this question. For whatever reason I get an error when trying to reach the discussion - I'll create a new question some time regarding how diagnose similar issues, but the initial CNFE was definitely because of including tyrus-core.jar. – Atorian Sep 10 '14 at 14:52

0 Answers0