uPortal - Java 8 Upgrade

Spring 3.2.9 Upgrade

https://github.com/Jasig/uPortal/pull/524

Spring 4.0.5 Upgrade

https://github.com/Jasig/uPortal/pull/525

Outstanding Issues

Issue with Spring 3.2.10+ and 4.0.6+

Stack Trace
ERROR [uP-PortletExec-1-guest-RENDER_HEADER-[dynamic-respondr-skin]] o.s.w.p.HeaderHandlingDispatcherPortlet 2015-02-23 14:27:05,808 - Could not complete request
java.lang.IllegalArgumentException: Object of class [org.springframework.web.portlet.context.PortletRequestAttributes] must be an instance of class org.springframework.web.context.request.ServletRequestAttributes
        at org.springframework.util.Assert.isInstanceOf(Assert.java:339) ~[spring-core-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.util.Assert.isInstanceOf(Assert.java:319) ~[spring-core-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.web.servlet.view.ContentNegotiatingViewResolver.resolveViewName(ContentNegotiatingViewResolver.java:281) ~[spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.web.portlet.DispatcherPortlet.resolveViewName(DispatcherPortlet.java:1148) ~[spring-webmvc-portlet-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.web.portlet.DispatcherPortlet.render(DispatcherPortlet.java:1090) ~[spring-webmvc-portlet-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.web.portlet.DispatcherPortlet.doRenderService(DispatcherPortlet.java:789) ~[spring-webmvc-portlet-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.web.portlet.HeaderHandlingDispatcherPortlet.doRenderService(HeaderHandlingDispatcherPortlet.java:85) [HeaderHandlingDispatcherPortlet.class:4.0.9.RELEASE]
        at org.springframework.web.portlet.FrameworkPortlet.processRequest(FrameworkPortlet.java:536) [spring-webmvc-portlet-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.web.portlet.FrameworkPortlet.doDispatch(FrameworkPortlet.java:483) [spring-webmvc-portlet-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.web.portlet.HeaderHandlingDispatcherPortlet.doHeaders(HeaderHandlingDispatcherPortlet.java:50) [HeaderHandlingDispatcherPortlet.class:4.0.9.RELEASE]
        at javax.portlet.GenericPortlet.render(GenericPortlet.java:242) [portlet-api.jar:na]
        at org.jasig.portal.portlet.container.FilterChainImpl.doFilter(FilterChainImpl.java:183) [FilterChainImpl.class:na]
        at org.jasig.portal.portlet.container.FilterChainImpl.processFilter(FilterChainImpl.java:99) [FilterChainImpl.class:na]
        at org.jasig.portal.portlet.container.FilterManagerImpl.processFilter(FilterManagerImpl.java:110) [FilterManagerImpl.class:na]
        at org.apache.pluto.container.driver.PortletServlet.dispatch(PortletServlet.java:340) [pluto-container-driver-api.jar:2.1.0-M3]
        at org.apache.pluto.container.driver.PortletServlet.doGet(PortletServlet.java:261) [pluto-container-driver-api.jar:2.1.0-M3]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) [servlet-api.jar:na]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) [servlet-api.jar:na]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) [catalina.jar:7.0.56]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.56]
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748) [catalina.jar:7.0.56]
        at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:604) [catalina.jar:7.0.56]
        at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:543) [catalina.jar:7.0.56]
        at org.apache.pluto.driver.container.DefaultPortletInvokerService.invoke(DefaultPortletInvokerService.java:233) [pluto-portal-driver-2.1.0-M3.jar:2.1.0-M3]
        at org.apache.pluto.driver.container.DefaultPortletInvokerService.render(DefaultPortletInvokerService.java:117) [pluto-portal-driver-2.1.0-M3.jar:2.1.0-M3]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_31]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_31]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_31]
        at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_31]
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.jasig.portal.portlet.dao.jpa.ThreadContextClassLoaderAspect.doThreadContextClassLoaderUpdate(ThreadContextClassLoaderAspect.java:69) [ThreadContextClassLoaderAspect.class:na]
        at sun.reflect.GeneratedMethodAccessor117.invoke(Unknown Source) ~[na:na]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_31]
        at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_31]
        at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) [spring-aop-4.0.9.RELEASE.jar:4.0.9.RELEASE]
        at com.sun.proxy.$Proxy205.render(Unknown Source) [na:na]
        at org.apache.pluto.container.impl.PortletContainerImpl.doRender(PortletContainerImpl.java:157) [pluto-container-2.1.0-M3.jar:2.1.0-M3]
        at org.jasig.portal.portlet.rendering.PortletRendererImpl.doRender(PortletRendererImpl.java:405) [PortletRendererImpl.class:na]
        at org.jasig.portal.portlet.rendering.PortletRendererImpl.doRenderHeader(PortletRendererImpl.java:218) [PortletRendererImpl.class:na]
        at org.jasig.portal.portlet.rendering.worker.PortletRenderHeaderExecutionWorker.callInternal(PortletRenderHeaderExecutionWorker.java:90) [PortletRenderHeaderExecutionWorker.class:na]
        at org.jasig.portal.portlet.rendering.worker.PortletRenderHeaderExecutionWorker.callInternal(PortletRenderHeaderExecutionWorker.java:39) [PortletRenderHeaderExecutionWorker.class:na]
        at org.jasig.portal.portlet.rendering.worker.PortletExecutionWorker$1.call(PortletExecutionWorker.java:135) [PortletExecutionWorker$1.class:na]
        at org.jasig.portal.portlet.rendering.worker.PortletExecutionWorker$ExecutionLifecycleCallable.call(PortletExecutionWorker.java:175) [PortletExecutionWorker$ExecutionLifecycleCallable.class:na]
        at org.jasig.portal.portlet.rendering.worker.PortletExecutionCallable.call(PortletExecutionCallable.java:118) [PortletExecutionCallable.class:na]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_31]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_31]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_31]
        at java.lang.Thread.run(Thread.java:745) [na:1.8.0_31]

 

https://jira.spring.io/browse/SPR-11295

https://github.com/spring-projects/spring-framework/commit/7d94b5e8536fc9084b5749b02af708296417cce5

Issue revolves around the above Spring change where ServletRequestAttributes are now being coerced to PortletRequestAttributes. uPortal leverages some Spring classes that only work with ServletRequestAttributes objects.

Deprecated / Removed JPA Classes

These classes have been deprecated and are no longer included in Spring 4.0.x. 

https://issues.jasig.org/browse/UP-4553

  • org.springframework.orm.jpa.JpaAccessor.java
    • This class is only used as a parent class for JpaPortletExecutionInterceptor
    • It is used to wrap the execution/thread of a portlet with an EntityManager
  • org.springframework.orm.jpa.JpaInterceptor.java
    • This class is instantiated as a bean in persistenceContext.xml, but is never referenced by main Java code
    • This class is only found in comments in the main Java code
    • This class is used in BaseJpaDaoTest  in test code and is used extensively
    • This class is defined as a bean in sharedJpaTestContext
    • Attempt to replace this in test with @Transactional was successful - (Maybe REQUIRED_NEW would help?)

Ideally, we need to refactor the uPortal code to no longer use these classes.  However, in the short term, these two classes have been copied into the uPortal codebase at:  uportal-war/src/main/java/org/springframework/orm/jpa

The above classes are used to add 

Resolved Issues

Unit Tests Failing with ObjectOptimisticLockingFailure

org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest#testPersistentWithPrefsNotInDb()
org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest#testPersistentNoPrefsNotInDb()

JUnit Logging
     [exec] Tests run: 8, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 1.3 sec <<< FAILURE!
     [exec] testPersistentNoPrefsNotInDb(org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest)  Time elapsed: 0.218 sec  <<< ERROR!
     [exec] org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [org.jasig.portal.portlet.dao.jpa.PortletEntityImpl] with identifier [4]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.jasig.portal.portlet.dao.jpa.PortletEntityImpl#4]
     [exec] 	at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2479)
     [exec] 	at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3306)
     [exec] 	at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3506)
     [exec] 	at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:100)
     [exec] 	at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
     [exec] 	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
     [exec] 	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:280)
     [exec] 	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
     [exec] 	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
     [exec] 	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
     [exec] 	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:402)
     [exec] 	at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
     [exec] 	at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
     [exec] 	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
     [exec] 	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
     [exec] 	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
     [exec] 	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
     [exec] 	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
     [exec] 	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
     [exec] 	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
     [exec] 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     [exec] 	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
     [exec] 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     [exec] 	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
     [exec] 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     [exec] 	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
     [exec] 	at com.sun.proxy.$Proxy104.deletePortletEntity(Unknown Source)
     [exec] 	at org.jasig.portal.portlet.registry.PortletEntityRegistryImpl.deletePortletEntity(PortletEntityRegistryImpl.java:519)
     [exec] 	at org.jasig.portal.portlet.registry.PortletEntityRegistryImpl.storePortletEntity(PortletEntityRegistryImpl.java:342)
     [exec] 	at org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest$10.call(PortletEntityRegistryImplTest.java:377)
     [exec] 	at org.jasig.portal.test.BaseJpaDaoTest$MethodInvocationCallable.proceed(BaseJpaDaoTest.java:213)
     [exec] 	at org.springframework.orm.jpa.JpaInterceptor.invoke(JpaInterceptor.java:101)
     [exec] 	at org.jasig.portal.test.BaseJpaDaoTest.execute(BaseJpaDaoTest.java:125)
     [exec] 	at org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest.testPersistentNoPrefsNotInDb(PortletEntityRegistryImplTest.java:329)
     [exec] 
     [exec] testPersistentWithPrefsNotInDb(org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest)  Time elapsed: 0.115 sec  <<< ERROR!
     [exec] org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [org.jasig.portal.portlet.dao.jpa.PortletPreferencesImpl] with identifier [15]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.jasig.portal.portlet.dao.jpa.PortletPreferencesImpl#15]
     [exec] 	at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2479)
     [exec] 	at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3189)
     [exec] 	at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3087)
     [exec] 	at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3416)
     [exec] 	at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
     [exec] 	at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
     [exec] 	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
     [exec] 	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:276)
     [exec] 	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
     [exec] 	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
     [exec] 	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
     [exec] 	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:402)
     [exec] 	at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
     [exec] 	at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
     [exec] 	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
     [exec] 	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
     [exec] 	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
     [exec] 	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
     [exec] 	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
     [exec] 	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
     [exec] 	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
     [exec] 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     [exec] 	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
     [exec] 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     [exec] 	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
     [exec] 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     [exec] 	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
     [exec] 	at com.sun.proxy.$Proxy104.updatePortletEntity(Unknown Source)
     [exec] 	at org.jasig.portal.portlet.registry.PortletEntityRegistryImpl.storePortletEntity(PortletEntityRegistryImpl.java:319)
     [exec] 	at org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest$6.call(PortletEntityRegistryImplTest.java:259)
     [exec] 	at org.jasig.portal.test.BaseJpaDaoTest$MethodInvocationCallable.proceed(BaseJpaDaoTest.java:213)
     [exec] 	at org.springframework.orm.jpa.JpaInterceptor.invoke(JpaInterceptor.java:101)
     [exec] 	at org.jasig.portal.test.BaseJpaDaoTest.execute(BaseJpaDaoTest.java:125)
     [exec] 	at org.jasig.portal.portlet.registry.PortletEntityRegistryImplTest.testPersistentWithPrefsNotInDb(PortletEntityRegistryImplTest.java:209)
     [exec] 
...
     [exec] 
     [exec] Results :
     [exec] 
     [exec] Tests in error: 
     [exec]   PortletEntityRegistryImplTest.testPersistentNoPrefsNotInDb:329->BaseJpaDaoTest.execute:125 » ObjectOptimisticLockingFailure
     [exec]   PortletEntityRegistryImplTest.testPersistentWithPrefsNotInDb:209->BaseJpaDaoTest.execute:125 » ObjectOptimisticLockingFailure
     [exec] 
     [exec] Tests run: 539, Failures: 0, Errors: 2, Skipped: 5
     [exec] 

The issue here was that the unit tests specifically catch org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException, but now need to catch org.springframework.dao.OptimisticLockingFailureException.  The former is what the org.hibernate.StaleObjectStateException used to be mapped to in Spring 3.x, and the latter is what the exception gets mapped to in Spring 4.x.  

  • see org.springframework.orm.jpa.vendor.HibernateJpaDialect
  • see org.springframework.orm.hibernate3.HibernateJpaDialect (used by HibernateJpaDialect in Spring 3)
  • see org.springframework.orm.hibernate4.HibernateJpaDialect (not used by HibernateJpaDialect in Spring 4, but still included, unmodified ...to confuse matters)
  • see https://github.com/groybal/uPortal/commit/62f99e29e78340e18988b999c014801bad65d798

Resources

Â