[KULRICE-10916] Sorting is broken for tables using server side paging Created: 09/Oct/13  Updated: 23/Mar/14  Resolved: 14/Oct/13

Status: Closed
Project: Kuali Rice Development
Component/s: Development
Affects Version/s: 2.4
Fix Version/s: 2.4
Security Level: Public (Public: Anyone can view)

Type: Bug Fix Priority: Critical
Reporter: Peter Giles (Inactive) Assignee: Mark Fyffe (Inactive)
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: 1 day
Time Spent: 4 hours
Original Estimate: 1 day, 4 hours

Rice Module:
KRAD
KRAD Feature Area:
UIF Component
Sprint: 2.4.0-m2 KRAD Sprint 4
KAI Review Status: Not Required
KTI Review Status: Not Required
Code Review Status: Not Required
Include in Release Notes?:
Yes

 Description   

Sorting is broken when server paging is enabled. To reproduce in the KRAD sample app:

  • Navigate to Library -> Collections -> Server Paging
  • Click on the header for any sortable column

You'll get a JS alert similar to "DataTables warning (table id = 'u100101'): DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error."

In the server log you'll get a stack trace:

java.lang.IllegalStateException: View context is not active
	at org.kuali.rice.krad.uif.component.ComponentBase.copy(ComponentBase.java:2192)
	at org.kuali.rice.krad.uif.util.MultiColumnComparator.buildPrototypeRow(MultiColumnComparator.java:406)
	at org.kuali.rice.krad.uif.util.MultiColumnComparator.<init>(MultiColumnComparator.java:103)
	at org.kuali.rice.krad.web.controller.helper.DataTablesPagingHelper.applyTableJsonSort(DataTablesPagingHelper.java:223)
	at org.kuali.rice.krad.web.controller.helper.DataTablesPagingHelper.processPagingRequest(DataTablesPagingHelper.java:80)
	at org.kuali.rice.krad.web.controller.UifControllerBase.tableJsonRetrieval(UifControllerBase.java:1243)
	at org.kuali.rice.krad.web.controller.UifControllerBase$$FastClassByCGLIB$$7929303a.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
	at org.kuali.rice.krad.demo.uif.controller.ServerPagingTestController$$EnhancerByCGLIB$$28bb2b06.tableJsonRetrieval(<generated>)
	at sun.reflect.GeneratedMethodAccessor771.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.kuali.rice.krad.web.filter.CharsetFilter.doFilter(CharsetFilter.java:58)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.kuali.rice.krad.web.filter.UserLoginFilter.doFilter(UserLoginFilter.java:89)
	at org.kuali.rice.krad.web.filter.UserLoginFilter.doFilter(UserLoginFilter.java:77)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.kuali.rice.krad.web.filter.BootstrapFilterChain.doFilter(BootstrapFilter.java:327)
	at org.kuali.rice.krad.web.filter.DummyLoginFilter.doFilter(DummyLoginFilter.java:82)
	at org.kuali.rice.krad.web.filter.DummyLoginFilter.doFilter(DummyLoginFilter.java:62)
	at org.kuali.rice.krad.web.filter.BootstrapFilterChain.doFilter(BootstrapFilter.java:320)
	at org.kuali.rice.krad.web.filter.BootstrapFilter.doFilter(BootstrapFilter.java:199)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.kuali.rice.krad.web.filter.UifSessionTimeoutFilter.doFilter(UifSessionTimeoutFilter.java:106)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.kuali.rice.core.web.Log4JContextClearingFilter.doFilterInternal(Log4JContextClearingFilter.java:37)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.kuali.rice.krad.web.filter.HideWebInfFilter.doFilter(HideWebInfFilter.java:68)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:213)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:182)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)


 Comments   
Comment by Peter Giles (Inactive) [ 11/Oct/13 ]

Hi Mark, the sort for server paging broke somewhere in this cluster of commits last friday: r41980, r41981, r41982. The MultiColumnComparator is (on line 406) copying components for use as prototypes, and this is happening when the view state is not active. I'm not sure why it's forbidden to copy components at that time. Can you please take a look? Thanks

Comment by Mark Fyffe (Inactive) [ 11/Oct/13 ]

Hi Peter - I'll look into this over the weekend. It should be relatively straightforward to address. I'll follow up with details tomorrow or Sunday.

Comment by Mark Fyffe (Inactive) [ 14/Oct/13 ]

Committed a fix.

Since MultiColumnComparator creates copies of selected components from the posted view, it needs to be encapsulated in a lifecycle or initialization call to enable modification. Since the sorting isn't really part of the lifecycle, I wrapped the MultiColumnComparator constructor in an encapsulateInitialization call() and am no longer seeing this issue.

@@ -224,7 +225,13 @@
                 sortIndices[i] = i;
             }

-            Arrays.sort(sortIndices, new MultiColumnComparator(modelCollection, collectionGroup, newColumnSorts, view));
+            MultiColumnComparator comparator = ViewLifecycle
+                    .encapsulateInitialization(new Callable<MultiColumnComparator>(){
+                @Override
+                public MultiColumnComparator call() throws Exception {
+                    return new MultiColumnComparator(modelCollection, collectionGroup, newColumnSorts, view);
+                }});
+            Arrays.sort(sortIndices, comparator);

             // apply the sort to the modelCollection
             Object[] sorted = new Object[sortIndices.length];
Comment by Adam Campbell (Inactive) [ 21/Oct/13 ]

validated on env14
closing as fixed

Generated at Mon Sep 28 10:04:42 CDT 2020 using JIRA 7.0.11#70121-sha1:19d24976997c1d95f06f3e327e087be0b71f28d4.