JSPWiki
  1. JSPWiki
  2. JSPWIKI-659

NotSerializableException on Tomcat restart , UserManager not Serializable

    Details

    • Type: Bug Bug
    • Status: Reopened
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 2.8.3, 2.9.1
    • Fix Version/s: None
    • Component/s: Core & storage
    • Labels:
      None
    • Environment:

      apache-tomcat-6.0.16

      Description

      If you stop Tomcat using ctrl-C and restart it again, there is a NotSerializableException on the console. Looks like this has no consequences, but still it should not be.

      SCHWERWIEGEND: IOException while loading persisted sessions: java.io.WriteAbortedException: writing
      aborted; java.io.NotSerializableException: com.ecyrd.jspwiki.auth.UserManager$JSONUserModule
      java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.ecyrd.jspwiki.
      auth.UserManager$JSONUserModule
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1333)
      at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
      <<< SKIPPED >>>
      Starting up background thread: WatchDog for 'JSPWiki'.
      17.03.2008 11:40:43 org.apache.coyote.http11.Http11Protocol start
      INFO: Starting Coyote HTTP/1.1 on http-8080
      17.03.2008 11:40:43 org.apache.jk.common.ChannelSocket init
      INFO: JK: ajp13 listening on /0.0.0.0:8009
      17.03.2008 11:40:43 org.apache.jk.server.JkMain start
      INFO: Jk running ID=0 time=0/31 config=null
      17.03.2008 11:40:43 org.apache.catalina.startup.Catalina start
      INFO: Server startup in 4239 ms

      1. JSPWIKI-659.patch
        7 kB
        Harry Metske
      2. ff.patch
        2 kB
        Harry Metske

        Issue Links

          Activity

          Hide
          Vasilij Pupkin added a comment -

          Some Years Later ...

          • tomcat 6.0
          • JSPWiki v2.8.3
          • tomcat installed as a Windows 2003 Server service.

          ------- ERROR ------

          09.08.2010 10:29:11 org.apache.catalina.session.StandardSession writeObject
          WARNUNG: Cannot serialize session attribute JSONRPCBridge for session 5A168ED273CD31CE07F9003981FB6669
          java.io.NotSerializableException: com.ecyrd.jspwiki.auth.UserManager
          at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
          at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
          at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
          at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
          at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
          at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
          at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
          at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
          at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
          at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
          at java.util.HashMap.writeObject(HashMap.java:1001)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:597)
          at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
          at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1461)
          at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
          at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
          at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
          at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
          at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
          at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
          at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
          at org.apache.catalina.session.StandardSession.writeObject(StandardSession.java:1517)
          at org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:959)
          at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:517)
          at org.apache.catalina.session.StandardManager.unload(StandardManager.java:463)
          at org.apache.catalina.session.StandardManager.stop(StandardManager.java:667)
          at org.apache.catalina.core.StandardContext.stop(StandardContext.java:4519)
          at org.apache.catalina.core.ContainerBase.removeChild(ContainerBase.java:924)
          at org.apache.catalina.startup.HostConfig.undeployApps(HostConfig.java:1191)
          at org.apache.catalina.startup.HostConfig.stop(HostConfig.java:1162)
          at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:313)
          at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
          at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1086)
          at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1098)
          at org.apache.catalina.core.StandardEngine.stop(StandardEngine.java:448)
          at org.apache.catalina.core.StandardService.stop(StandardService.java:584)
          at org.apache.catalina.core.StandardServer.stop(StandardServer.java:744)
          at org.apache.catalina.startup.Catalina.stop(Catalina.java:628)
          at org.apache.catalina.startup.Catalina.start(Catalina.java:603)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:597)
          at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
          at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)

          Show
          Vasilij Pupkin added a comment - Some Years Later ... tomcat 6.0 JSPWiki v2.8.3 tomcat installed as a Windows 2003 Server service. ------- ERROR ------ 09.08.2010 10:29:11 org.apache.catalina.session.StandardSession writeObject WARNUNG: Cannot serialize session attribute JSONRPCBridge for session 5A168ED273CD31CE07F9003981FB6669 java.io.NotSerializableException: com.ecyrd.jspwiki.auth.UserManager at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326) at java.util.HashMap.writeObject(HashMap.java:1001) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1461) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326) at org.apache.catalina.session.StandardSession.writeObject(StandardSession.java:1517) at org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:959) at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:517) at org.apache.catalina.session.StandardManager.unload(StandardManager.java:463) at org.apache.catalina.session.StandardManager.stop(StandardManager.java:667) at org.apache.catalina.core.StandardContext.stop(StandardContext.java:4519) at org.apache.catalina.core.ContainerBase.removeChild(ContainerBase.java:924) at org.apache.catalina.startup.HostConfig.undeployApps(HostConfig.java:1191) at org.apache.catalina.startup.HostConfig.stop(HostConfig.java:1162) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:313) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117) at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1086) at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1098) at org.apache.catalina.core.StandardEngine.stop(StandardEngine.java:448) at org.apache.catalina.core.StandardService.stop(StandardService.java:584) at org.apache.catalina.core.StandardServer.stop(StandardServer.java:744) at org.apache.catalina.startup.Catalina.stop(Catalina.java:628) at org.apache.catalina.startup.Catalina.start(Catalina.java:603) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
          Hide
          Harry Metske added a comment -

          Yes we know this problem .
          Still in 3.0 it exists (apparently also for class org.apache.wiki.auth.UserManager).

          There is a workaround by changing tomcat's conf/context.xml :

           
          
              <!-- Uncomment this to disable session persistence across Tomcat restarts
              
              <Manager pathname="" />
               -->
          

          But you won't have session persistence off course.

          Show
          Harry Metske added a comment - Yes we know this problem . Still in 3.0 it exists (apparently also for class org.apache.wiki.auth.UserManager). There is a workaround by changing tomcat's conf/context.xml : <!-- Uncomment this to disable session persistence across Tomcat restarts <Manager pathname="" /> --> But you won't have session persistence off course.
          Hide
          Bruce Wen added a comment -

          This issue also occurred in Tomcat 5.5.29.

          Harry, do you mean comment <Manager pathname="" />? In Tomcat 5.5.29, it is defaultly commented.

          Show
          Bruce Wen added a comment - This issue also occurred in Tomcat 5.5.29. Harry, do you mean comment <Manager pathname="" />? In Tomcat 5.5.29, it is defaultly commented.
          Hide
          Bruce Wen added a comment -

          Unomment <Manager pathname="" />, the exception disappear. But as Harry said, you won't have session persistence anymore.

          Show
          Bruce Wen added a comment - Unomment <Manager pathname="" />, the exception disappear. But as Harry said, you won't have session persistence anymore.
          Hide
          Harry Metske added a comment -

          Now here is my analysis after digging for a couple of hours:

          The problem occurs because we put com.metaparadigm.jsonrpc.JSONRPCBridge in the HttpSession.
          First, I do not understand why we put this in the session, I'd be glad if someone could explain.

          This class is put in the session at
          org.apache.wiki.rpc.json.JSONRPCManager.sessionCreated(JSONRPCManager.java:277) .

          JSONRPCBridge has a ref to org.apache.wiki.auth.UserManager$JSONUserModule (seen in a heapdump).

          JSONUserModule has a ref to UserManager, and although it is declared as volatile, it still causes a NotSerializableException.

          UserManager is not Serializable and should not go in the session (it holds refs to things like UserDatabase, you sure don't want that one in the session).

          We now have Sessions of about 4k in size (tomcat's SESSIONS.ser file).

          If we do not put JSONRPCBridge in the session (see attached patch), the session size goes down with a factor 3 (1k).

          Any thoughts ?
          If not, I'd like to apply the attached patch. (all tests and webtests pass, and manual testing also does not reveal bugs with this patch).

          regards,
          Harry

          Show
          Harry Metske added a comment - Now here is my analysis after digging for a couple of hours: The problem occurs because we put com.metaparadigm.jsonrpc.JSONRPCBridge in the HttpSession. First, I do not understand why we put this in the session, I'd be glad if someone could explain. This class is put in the session at org.apache.wiki.rpc.json.JSONRPCManager.sessionCreated(JSONRPCManager.java:277) . JSONRPCBridge has a ref to org.apache.wiki.auth.UserManager$JSONUserModule (seen in a heapdump). JSONUserModule has a ref to UserManager, and although it is declared as volatile, it still causes a NotSerializableException. UserManager is not Serializable and should not go in the session (it holds refs to things like UserDatabase, you sure don't want that one in the session). We now have Sessions of about 4k in size (tomcat's SESSIONS.ser file). If we do not put JSONRPCBridge in the session (see attached patch), the session size goes down with a factor 3 (1k). Any thoughts ? If not, I'd like to apply the attached patch. (all tests and webtests pass, and manual testing also does not reveal bugs with this patch). regards, Harry
          Hide
          Juan Pablo Santos Rodríguez added a comment -

          Hi,

          JSONRPCBridge needs to be in session to enable javascript access to all classes implementing org.apache.wiki.rpc.RPCCallable (cfr. related link to jsonrpc). In this case, seems to me that JSONUserModule#getUserInfo() gets called at ./src/webdocs/templates/default/admin/UserManagement.jsp, line 44.

          Aside from JSONUserModule there are 3 more classes implementing RPCCallable, with functionalities related to search, file upload and a sample plugin with AJAX support.

          Declaring UserManager transient inside JSONUserModule seems to be insufficient to make it Serializable (cfr. http://stackoverflow.com/q/7144912). Haven't tested yet, but promoting JSONUserModule to a first level class instead of being an inner class would take away the exception. If that's the case, I think we could do this in 2.9.1, doesn't seem to me like a class used for extending JSPWiki...

          br,
          juan pablo

          Show
          Juan Pablo Santos Rodríguez added a comment - Hi, JSONRPCBridge needs to be in session to enable javascript access to all classes implementing org.apache.wiki.rpc.RPCCallable (cfr. related link to jsonrpc ). In this case, seems to me that JSONUserModule#getUserInfo() gets called at ./src/webdocs/templates/default/admin/UserManagement.jsp, line 44. Aside from JSONUserModule there are 3 more classes implementing RPCCallable, with functionalities related to search, file upload and a sample plugin with AJAX support. Declaring UserManager transient inside JSONUserModule seems to be insufficient to make it Serializable (cfr. http://stackoverflow.com/q/7144912 ). Haven't tested yet, but promoting JSONUserModule to a first level class instead of being an inner class would take away the exception. If that's the case, I think we could do this in 2.9.1, doesn't seem to me like a class used for extending JSPWiki... br, juan pablo
          Hide
          Harry Metske added a comment -

          Just tested, promoting JSONUserModule to a first level class instead of being an inner class does not fix the issue .

          Show
          Harry Metske added a comment - Just tested, promoting JSONUserModule to a first level class instead of being an inner class does not fix the issue .
          Hide
          Glen Mazza added a comment -

          Does this problem occur if you shut down Tomcat properly instead of using Ctrl-C? (i.e., by running $CATALINA_HOME/bin/shutdown.sh?) If no, then I'm not sure this is really a problem. We can't and shouldn't be guaranteeing proper working of webapps, either on startup or shutdown, if you shut down the servlet container improperly. Proper shutdown is what allows webapps to properly release their resources before closing.

          Show
          Glen Mazza added a comment - Does this problem occur if you shut down Tomcat properly instead of using Ctrl-C? (i.e., by running $CATALINA_HOME/bin/shutdown.sh?) If no, then I'm not sure this is really a problem. We can't and shouldn't be guaranteeing proper working of webapps, either on startup or shutdown, if you shut down the servlet container improperly. Proper shutdown is what allows webapps to properly release their resources before closing.
          Hide
          Harry Metske added a comment -

          No no, I use the shutdown.sh command to stop tomcat.
          And if I would Crtl-C it, or kill it (TERM signal, not KILL signal) that still should not make a difference since tomcat has a JVM shutdownHook.
          Shutting down tomcat with a TERM signal is considered normal operation.

          Show
          Harry Metske added a comment - No no, I use the shutdown.sh command to stop tomcat. And if I would Crtl-C it, or kill it (TERM signal, not KILL signal) that still should not make a difference since tomcat has a JVM shutdownHook. Shutting down tomcat with a TERM signal is considered normal operation.
          Hide
          Harry Metske added a comment -

          Digging a bit deeper in JSONRPCBridge, I read that it is not necessary to put it in the session. You can use the Global Bridge in that case.
          The JavaDoc says :

          * The JSONRPCServlet looks for a session specific bridge object
          * under the attribute <code>"JSONRPCBridge"</code> in the HttpSession
          * associated with the request (without creating a session if one does
          * not already exist). If it can't find a session specific bridge instance,
          * it will default to invoking against the global bridge.
          * <p />
          * Using a session specific bridge allows you to export certain object 
          * instances or classes only to specific users, and of course these instances
          * could be stateful and contain data specific to the user's session.
          

          That is also what JSPWiki does if it cannot get it from the session (line 120 in JSONRPCManager):

                  if( bridge == null) bridge = JSONRPCBridge.getGlobalBridge();
          
          

          As JP mentioned, there are two more RPCCallable classes (JSONSearch, JSONTracker), but they are registered with the Global Bridge, so they do not have the Serialization issue.
          The JSONUserModule BTW is also registered with the Global Bridge, see line 120 in UserManager

                  JSONRPCManager.registerGlobalObject( "users", new JSONUserModule(this), new AllPermission(null) );
          

          I will attach a new patch again to complete disable session scope JSONBridge , and only use the Global Bridge.

          Am I missing something ?

          Show
          Harry Metske added a comment - Digging a bit deeper in JSONRPCBridge, I read that it is not necessary to put it in the session. You can use the Global Bridge in that case. The JavaDoc says : * The JSONRPCServlet looks for a session specific bridge object * under the attribute <code>"JSONRPCBridge"</code> in the HttpSession * associated with the request (without creating a session if one does * not already exist). If it can't find a session specific bridge instance, * it will default to invoking against the global bridge. * <p /> * Using a session specific bridge allows you to export certain object * instances or classes only to specific users, and of course these instances * could be stateful and contain data specific to the user's session. That is also what JSPWiki does if it cannot get it from the session (line 120 in JSONRPCManager): if( bridge == null) bridge = JSONRPCBridge.getGlobalBridge(); As JP mentioned, there are two more RPCCallable classes (JSONSearch, JSONTracker), but they are registered with the Global Bridge, so they do not have the Serialization issue. The JSONUserModule BTW is also registered with the Global Bridge, see line 120 in UserManager JSONRPCManager.registerGlobalObject( "users", new JSONUserModule(this), new AllPermission(null) ); I will attach a new patch again to complete disable session scope JSONBridge , and only use the Global Bridge. Am I missing something ?
          Hide
          Harry Metske added a comment -

          proposed patch

          Show
          Harry Metske added a comment - proposed patch
          Hide
          Juan Pablo Santos Rodríguez added a comment -

          +1 to JSPWIKI-659.patch

          Show
          Juan Pablo Santos Rodríguez added a comment - +1 to JSPWIKI-659 .patch
          Hide
          Janne Jalkanen added a comment -

          I recall that originally I did use GlobalBridge, but there were some really good reasons why I chose not to use it - probably related to thread safety or security. Unfortunately I cannot recall what those reasons were.

          If the jsonrpc or jabsorb are not being maintained, it's probably safest to rip them out and replace with something like Jackson.

          Show
          Janne Jalkanen added a comment - I recall that originally I did use GlobalBridge, but there were some really good reasons why I chose not to use it - probably related to thread safety or security. Unfortunately I cannot recall what those reasons were. If the jsonrpc or jabsorb are not being maintained, it's probably safest to rip them out and replace with something like Jackson.
          Hide
          Harry Metske added a comment -

          You are probably referring to what is in the method comment ? :

              /**
               *  Is called whenever a session is created.  This method creates a new JSONRPCBridge
               *  and adds it to the user session.  This is done because the global JSONRPCBridge
               *  InvocationCallbacks are not called; only session locals.  This may be a bug
               *  in JSON-RPC, or it may be a design feature...
               *  <p>
               *  The JSONRPCBridge object will go away once the session expires.
               *  
               *  @param session The HttpSession which was created.
               */
          

          Anyways, let's fix it now, and go for Jackson as the long-term solution.

          Show
          Harry Metske added a comment - You are probably referring to what is in the method comment ? : /** * Is called whenever a session is created. This method creates a new JSONRPCBridge * and adds it to the user session. This is done because the global JSONRPCBridge * InvocationCallbacks are not called; only session locals. This may be a bug * in JSON-RPC, or it may be a design feature... * <p> * The JSONRPCBridge object will go away once the session expires. * * @param session The HttpSession which was created. */ Anyways, let's fix it now, and go for Jackson as the long-term solution.
          Hide
          Janne Jalkanen added a comment -

          Yup. So I am assuming that the JSON api will stop to work if you switch to GlobalBridge.

          Show
          Janne Jalkanen added a comment - Yup. So I am assuming that the JSON api will stop to work if you switch to GlobalBridge.
          Hide
          Harry Metske added a comment -

          hmmm, I just tested http://localhost:8080/admin/Admin.jsp (including the Users tab), and I don't see a difference in behaviour with or without the patch. Also no error messages in the logs.

          Show
          Harry Metske added a comment - hmmm, I just tested http://localhost:8080/admin/Admin.jsp (including the Users tab), and I don't see a difference in behaviour with or without the patch. Also no error messages in the logs.
          Hide
          Harry Metske added a comment -

          fixed in 2.9.1-svn-17

          Show
          Harry Metske added a comment - fixed in 2.9.1-svn-17
          Hide
          Harry Metske added a comment -

          Unfortunately I did not test the quick search when trying to fix this. It is indeed broken.

          Show
          Harry Metske added a comment - Unfortunately I did not test the quick search when trying to fix this. It is indeed broken.
          Hide
          Harry Metske added a comment -

          I will revert the patch for this, so at least quick search works again.

          Show
          Harry Metske added a comment - I will revert the patch for this, so at least quick search works again.

            People

            • Assignee:
              Harry Metske
              Reporter:
              Vasilij Pupkin
            • Votes:
              3 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:

                Development