Ever forgot to Save your changes in Humantasks before pressing the Approve or Reject button?
In a SOA environment I have a humantask in a BPEL process. The humantask has an Approve and a Reject outcome.
The humantask offers the possibility to change al kinds of process related data. By default these changes are not saved when you press the Approve or Reject button. As a result It happens often that changes are not saved by making the mistake not saving changes before Approvement.
Change the default button behaviour
In this blog I will decribe how to change the behaviour behind the ‘Approve’ button. I will change it to ‘Save and Approve’. On first hand I though this would be very simple. Add a second action to the button and tha’s all. But it is not possible to directly bind multiple actions to a button. However it is still possible by binding a new action to the button that on it’s turn executes multiple actions.
This can be implemented with a Managed Bean. I will descibe how to create the Managed Bean and to bind it to the Approve and Reject button.
At first, open the humantask (jspx file). In source mode find the ‘Approve’ commandToolbarButton.
Change the values of the Action and ActionListener properties. You can do this directly in the source code or via the properties window in the bottom-right. I prefer this last option because it makes things a litle easier.
Select the left arrow behind Action. Then select ‘closeTaskFlow’. This takes care of closing the taskform after pressing the Approve button.
Now, select the right arrow behind ActionListener. Then select Edit. The following window appears.
Select ‘New’ behind Managed Bean.
Specify the Bean details as shown in the image below:
After pressing OK we will get back in the ‘Edit Property’ window. The name of the new Managed Bean is shown.
Add a method to the Bean. Press New behind Method.
Specify a Method name (e.g. saveApprove) and press OK
Press OK again.
A java class ‘MedewerkerHT.java’ is now available in the Application Source. Change/replace the source code of this class:
package amis.nl; import javax.faces.event.ActionEvent; import oracle.adf.model.BindingContext; import oracle.binding.BindingContainer; import oracle.binding.OperationBinding; public class MedewerkerHT { public MedewerkerHT() { } public void saveApprove(ActionEvent actionEvent) { // Save changes BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); OperationBinding method = bindings.getOperationBinding("update"); if (method != null) { method.execute(); } // Perform original function bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); method = bindings.getOperationBinding("APPROVE"); if (method != null) { method.execute(); } } public void saveReject(ActionEvent actionEvent) { // Save changes BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); OperationBinding method = bindings.getOperationBinding("update"); if (method != null) { method.execute(); } // Perform original function bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); method = bindings.getOperationBinding("REJECT"); if (method != null) { method.execute(); } } }
The class contains the implementation for both the Approve and the Reject Button.
In the humantask the sourcecode of the commandToolbarButton is changed into:
<af:commandToolbarButton actionListener="#{customization.saveApprove}" text="#{wf:getResourceValue('APPROVE', 'bindings.customActions')}" disabled="#{!bindings.APPROVE.enabled}" action="closeTaskFlow" partialSubmit="false" visible="#{wf:isCustomActionAvailable('APPROVE', 'bindings.customActions')}" id="ctb2"> <f:attribute name="DC_OPERATION_BINDING" value="bindings.APPROVE"/> </af:commandToolbarButton>
The actionListener is binded to the new created Managed Bean
For the reject button almost the same steps are required. Even though it is not needed to create the Bean and Method again. Now it is possible to select the existing one.
The two functions are now binded to the same button.
When i click on button, human task outcome set and closed but i am getting an error below. Do you have any idea?
oracle.adf.controller.internal.AdfcIllegalStateException: oracle.adf.controller.ControllerException: ADFC-12000: State ID in request is invalid for the current session.
at oracle.adfinternal.controller.state.ControllerState.synchronizeStatePart2(ControllerState.java:551)
at oracle.adfinternal.controller.application.SyncNavigationStateListener.afterPhase(SyncNavigationStateListener.java:79)
at oracle.adfinternal.controller.lifecycle.ADFLifecycleImpl$PagePhaseListenerWrapper.afterPhase(ADFLifecycleImpl.java:538)
at oracle.adfinternal.controller.lifecycle.LifecycleImpl.internalDispatchAfterEvent(LifecycleImpl.java:120)
at oracle.adfinternal.controller.lifecycle.LifecycleImpl.dispatchAfterPagePhaseEvent(LifecycleImpl.java:168)
at oracle.adfinternal.controller.faces.lifecycle.ADFPhaseListener$PhaseInvokerImpl.dispatchAfterPagePhaseEvent(ADFPhaseListener.java:310)
at oracle.adfinternal.controller.faces.lifecycle.ADFPhaseListener.afterPhase(ADFPhaseListener.java:87)
at oracle.adfinternal.controller.faces.lifecycle.ADFLifecyclePhaseListener.afterPhase(ADFLifecyclePhaseListener.java:53)
at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:520)
at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:207)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.help.web.rich.OHWFilter.doFilter(Unknown Source)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:205)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.adf.view.page.editor.webapp.WebCenterComposerFilter.doFilter(WebCenterComposerFilter.java:117)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:128)
at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:446)
at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:446)
at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:271)
at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:177)
at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.iam.ui.platform.servletfilter.IdentityContextFilter.doFilter(IdentityContextFilter.java:50)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.bpel.services.workflow.client.worklist.util.WorkflowFilter.doFilter(WorkflowFilter.java:175)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.bpel.services.workflow.client.worklist.util.DisableUrlSessionFilter.doFilter(DisableUrlSessionFilter.java:70)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.adf.library.webapp.LibraryFilter.doFilter(LibraryFilter.java:180)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:119)
at java.security.AccessController.doPrivileged(Native Method)
at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:324)
at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:460)
at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:103)
at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:171)
at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:71)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:163)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3748)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3714)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2283)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2182)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1491)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
Caused by: oracle.adf.controller.ControllerException: ADFC-12000: State ID in request is invalid for the current session.
at oracle.adf.controller.internal.AdfcIllegalStateException.(AdfcIllegalStateException.java:25)
… 59 more
]]