Proxies and AOP make clustering Spring applications arcane ----------------------------------------------------------
Key: CDV-834 URL: https://jira.terracotta.org/jira//browse/CDV-834 Project: Community Development Issue Type: Bug Components: X-Sample Apps, X-SpringRuntime Affects Versions: 2.7.0-stable0 Reporter: Geert Bevin Assignee: Issue Review Board Consider this class: public class UserDetailsWrapper implements UserDetails { private final StandardAuthoritiesService service; private final User delegate; public UserDetailsWrapper(final StandardAuthoritiesService service, final User delegate) { this.service = service; this.delegate = delegate; } // ... } When this enters a clustered graph, the service field is clustered by default. However, you might not want to cluster it if the Spring bean for the service isn't clustered. Terracotta will spit out a TCNonPortableObjectError like the one below if an instance of UserDetailsWrapper is for example stored in a clustered session. Nothing whatshowever in this output refers to the class above, hence making it virtually impossible for the user to know what to do. They will just add JdkDynamicAopProxy to the included classes and start to pull in any possible class that is used by the service and Spring AOP. This actually happened to me and it took me hours of searching and backing up to figure out where to cut the shared graph. [INFO] [cargo0] com.tc.exception.TCNonPortableObjectError: [INFO] [cargo0] ******************************************************************************* [INFO] [cargo0] Attempt to share an instance of a non-portable class referenced by a portable class. This [INFO] [cargo0] unshareable class has not been included for sharing in the configuration. [INFO] [cargo0] [INFO] [cargo0] For more information on this issue, please visit our Troubleshooting Guide at: [INFO] [cargo0] http://terracotta.org/kit/troubleshooting [INFO] [cargo0] [INFO] [cargo0] Referring class : $Proxy20 [INFO] [cargo0] Thread : http-8080-1 [INFO] [cargo0] JVM ID : VM(1) [INFO] [cargo0] Non-included class: org.springframework.aop.framework.JdkDynamicAopProxy [INFO] [cargo0] [INFO] [cargo0] Action to take: [INFO] [cargo0] [INFO] [cargo0] 1) Reconfigure to include the unshareable classes [INFO] [cargo0] * edit your tc-config.xml file [INFO] [cargo0] * locate the <dso> element [INFO] [cargo0] * add this snippet inside the <dso> element [INFO] [cargo0] [INFO] [cargo0] <instrumented-classes> [INFO] [cargo0] <include> [INFO] [cargo0] <class-expression>org.springframework.aop.framework.JdkDynamicAopProxy</class-expression> [INFO] [cargo0] </include> [INFO] [cargo0] </instrumented-classes> [INFO] [cargo0] [INFO] [cargo0] * if there is already an <instrumented-classes> element present, simply add [INFO] [cargo0] the new includes inside it [INFO] [cargo0] [INFO] [cargo0] It is possible that some or all of the classes above are truly non-portable, the solution [INFO] [cargo0] is then to mark the referring field as transient. [INFO] [cargo0] [INFO] [cargo0] [INFO] [cargo0] ******************************************************************************* [INFO] [cargo0] [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl.throwNonPortableException(ClientObjectManagerImpl.java:826) [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl.checkPortabilityOfTraversedReference(ClientObjectManagerImpl.java:718) [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl.access$900(ClientObjectManagerImpl.java:82) [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl$NewObjectTraverseTest.checkPortability(ClientObjectManagerImpl.java:1059) [INFO] [cargo0] at com.tc.object.Traverser.addReferencedObjects(Traverser.java:48) [INFO] [cargo0] at com.tc.object.Traverser.traverse(Traverser.java:89) [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl.addToManagedFromRoot(ClientObjectManagerImpl.java:982) [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl.create(ClientObjectManagerImpl.java:338) [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl.lookupOrCreateIfNecesary(ClientObjectManagerImpl.java:402) [INFO] [cargo0] at com.tc.object.ClientObjectManagerImpl.lookupOrCreate(ClientObjectManagerImpl.java:375) [INFO] [cargo0] at com.tc.object.tx.ClientTransactionManagerImpl.logicalInvoke(ClientTransactionManagerImpl.java:756) [INFO] [cargo0] at com.tc.object.TCObjectLogical.logicalInvoke(TCObjectLogical.java:20) [INFO] [cargo0] at com.tc.object.bytecode.ManagerImpl.logicalInvoke(ManagerImpl.java:235) [INFO] [cargo0] at com.tc.object.bytecode.ManagerUtil.logicalInvoke(ManagerUtil.java:287) [INFO] [cargo0] at java.util.HashMap.put(HashMap.java) [INFO] [cargo0] at com.terracotta.session.SessionData.bindAttribute(SessionData.java:345) [INFO] [cargo0] at com.terracotta.session.SessionData.setAttributeReturnOld(SessionData.java:241) [INFO] [cargo0] at com.terracotta.session.SessionData.setAttribute(SessionData.java:233) [INFO] [cargo0] at org.springframework.security.context.HttpSessionContextIntegrationFilter.storeSecurityContextInSession(HttpSessionContextIntegrationFilter.java:392) [INFO] [cargo0] at org.springframework.security.context.HttpSessionContextIntegrationFilter.access$000(HttpSessionContextIntegrationFilter.java:100) [INFO] [cargo0] at org.springframework.security.context.HttpSessionContextIntegrationFilter$OnRedirectUpdateSessionResponseWrapper.doSessionUpdate(HttpSessionContextIntegrationFilter.java:518) [INFO] [cargo0] at org.springframework.security.context.HttpSessionContextIntegrationFilter$OnRedirectUpdateSessionResponseWrapper.sendRedirect(HttpSessionContextIntegrationFilter.java:506) [INFO] [cargo0] at org.springframework.security.util.RedirectUtils.sendRedirect(RedirectUtils.java:60) [INFO] [cargo0] at org.springframework.security.ui.AbstractProcessingFilter.sendRedirect(AbstractProcessingFilter.java:345) [INFO] [cargo0] at org.springframework.security.ui.AbstractProcessingFilter.successfulAuthentication(AbstractProcessingFilter.java:379) [INFO] [cargo0] at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:266) [INFO] [cargo0] at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) [INFO] [cargo0] at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) [INFO] [cargo0] at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89) [INFO] [cargo0] at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) [INFO] [cargo0] at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) [INFO] [cargo0] at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235) [INFO] [cargo0] at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) [INFO] [cargo0] at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) [INFO] [cargo0] at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:174) [INFO] [cargo0] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236) [INFO] [cargo0] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167) [INFO] [cargo0] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) [INFO] [cargo0] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [INFO] [cargo0] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) [INFO] [cargo0] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [INFO] [cargo0] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128) [INFO] [cargo0] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [INFO] [cargo0] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:568) [INFO] [cargo0] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [INFO] [cargo0] at com.tc.tomcat55.session.SessionValve55.tcInvoke(SessionValve55.java:63) [INFO] [cargo0] at com.tc.tomcat55.session.SessionValve55.invoke(SessionValve55.java:50) [INFO] [cargo0] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286) [INFO] [cargo0] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845) [INFO] [cargo0] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583) [INFO] [cargo0] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) [INFO] [cargo0] at java.lang.Thread.run(Thread.java:613) -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: https://jira.terracotta.org/jira//secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira _______________________________________________ tc-dev mailing list tc-dev@lists.terracotta.org http://lists.terracotta.org/mailman/listinfo/tc-dev