Uploaded image for project: 'ZK'
  1. ZK
  2. ZK-4809

NPE with comet server push (servlet 3) reconnect on Tomcat

XMLWordPrintable

      Steps to Reproduce

      run the attached example using Tomcat

      place a breakpoint in org.zkoss.zkex.ui.comet.CometServerPush#activate (Line 514)

      click the buttons in the sequence:

      1. start long-op
      2. stop long-op (reaches the breakpoint)
      3. simulate comet re-connect
      4. continue the code from the breakpoint

      Current Result

      18:10:31.632 [ForkJoinPool.commonPool-worker-3] ERROR org.zkoss.zk.ui.impl.UiEngineImpl - 
      java.lang.NullPointerException: null
      	at org.apache.catalina.connector.Request.notifyAttributeRemoved(Request.java:1623)
      	at org.apache.catalina.connector.Request.removeAttribute(Request.java:1502)
      	at org.apache.catalina.connector.RequestFacade.removeAttribute(RequestFacade.java:552)
      	at org.zkoss.zk.ui.http.ExecutionImpl.removeAttribute(ExecutionImpl.java:503)
      	at LongOpComposer_12188.handleCustomEvent(LongOpComposer_12188.java:66)
      	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
      	at org.zkoss.zk.ui.select.Selectors$ComposerEventListener.onEvent(Selectors.java:673)
      	at org.zkoss.zk.ui.AbstractComponent.onEvent(AbstractComponent.java:3185)
      	at org.zkoss.zk.ui.AbstractComponent.service(AbstractComponent.java:3155)
      	at org.zkoss.zk.ui.AbstractComponent.service(AbstractComponent.java:3097)
      	at org.zkoss.zk.ui.impl.EventProcessor.process(EventProcessor.java:138)
      	at org.zkoss.zk.ui.impl.UiEngineImpl.processEvent(UiEngineImpl.java:1884)
      	at org.zkoss.zk.ui.impl.UiEngineImpl.process(UiEngineImpl.java:1656)
      	at org.zkoss.zk.ui.impl.UiEngineImpl.endUpdate(UiEngineImpl.java:1224)
      	at org.zkoss.zkex.ui.comet.CometServerPush.deactivate(CometServerPush.java:535)
      	at org.zkoss.zk.ui.impl.DesktopImpl.deactivateServerPush(DesktopImpl.java:1682)
      	at org.zkoss.zk.ui.Executions.deactivate(Executions.java:1011)
      	at LongOpComposer_12188.lambda$startLongOp$0(LongOpComposer_12188.java:52)
      	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1736)
      	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java)
      	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1728)
      	at java.base/java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:290)
      	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)
      	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
      	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
      	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
      	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
      

      Expected Result

      no exception

      Debug Information

      2 threads are accessing the CometServerpush._active attribute resulting in old Request objects stored in the current execution, when activating the serverpush

      The manual breakpoint makes the error happen 100% of the time (in a real situation that's a very rare race condition)

      cleanAsyncInfo is called from the re-connecting thread during
      org.zkoss.zkex.ui.comet.CometServerPush#processRequest (line 339)

      This method is trying to check for this.isActive() (line 434) to avoid clearing an activated request. However due to the breakpoint this will not detect the currently activated execution, and eventually call AsyncContext#complete and creating a new AsyncContext (with a new Request object)

      Once the breakpoint continues it will use an old Request object of the previous AsyncContext ... causing the exception.

      Workaround


        1. long-op.zul
          0.4 kB
          cor3000
        2. LongOpComposer_12188.java
          2 kB
          cor3000
        3. LongOpConcurrentComposer_12188.java
          3 kB
          cor3000
        4. long-op-concurrent-users.zul
          1 kB
          cor3000

            rudyhuang rudyhuang
            cor3000 cor3000
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved:

                Estimated:
                Original Estimate - 2 days Original Estimate - 2 days
                2d
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 4 days
                4d