Thursday, July 21, 2011

In a previous post, we show how to access the initiable tasks in a main method of a simple Java class. In line with, this post demonstrates how to get the task's URL and launch the corresponding generated BPM task details form in an ADF application.

The following are the key methods and artifacts:

getTaskDisplayURL() - this method retrieves from a task object, the URL defined in the runtime Human Task configuration of a specific deployed composite, which can be found in Enterprise Manager. The URL is automatically set when you deploy a web app that contains BPM task forms with the configuration - "hwtaskflow.xml" that contains our task definition.

getTaskFlowDefinitionId() - this method returns a TaskFlowId object from the lengthy URL returned by the getTaskDisplayURL() method above.

initiateTask() - this method that returns a string is used as action attribute in the page fragment. It invokes both methods above then returns a "callTaskDetail" which launches a declarative popup.

The declarative pop-up, "modal-dialog-task-flow", is a simple task flow that we reused from the BPM Worklist components library. It doesn't do much but invoke a remote task flow. We could create our own if necessary.

wf_client_config.xml - We add this config file to remove from our code the connection details. To get a BPMServiceClientFactory instance, we just passed null parameters as follows:factory = BPMServiceClientFactory.getInstance(null, null, null);

Configure ADF Security - so we don't need to pass username and password when getting a BPMContext.

Sample Application

You can get the sample application from this link. The sample application needs to be deployed on a SOA server. On a subsequent post I will demonstrate how to run this sample on the integrated weblogic server.
In the sample, the InitiableTasksProject is deployed as an ADF library so it can easily be reused in other projects/ applications.

47 comments:

Its really good, i have created similar kind of application in my previous web development and design services provider company, but there are few things which we need to improve in that application. But its looks complete one.

Our requirement is, we want to display the BPM tasks assigned to a logged - in user in our custom ADF region..

I tried running the stand alone program(from your prev post) with a sample user, I am getting 0 initible tasks. I have a basic question here.. what is "Initiable Tasks?".. How they differ from normal Human task notifications?

All we need to do is, fetch the assigned human task notifications and display in a ADF region. Can you help me in achieving that?

Hi Subba,Initiable tasks are different from standard task list. Initiable tasks are those deployed BPM processes (applications) that can be initiated by the authenticated user. With regards to your requirement, it is relatively easier, I and will post a blog about it later but until then please check http://download.oracle.com/docs/cd/E21764_01/integration.1111/e10224/bp_worklist.htm#BABDCHEG

However, user wants the same standard BPM worklist UI look and feel with tabular layout etc... The link you have given is to just create a custom region by embedding the standard BPM task list region. Question here is, how can we customize it? to add more columns or hide some of the existing columns?

Is there a way that we can customize the look and feel of the standard BPM task list region in ADF?

You can pass "displayColumnsList" parameter to the taskList-task-flow-definition. This parameter should be a comma separated string of the columns to be displayed in the task list table.

Is there a way that we can customize the look and feel of the standard BPM task list region in ADF? If you are asking about skinning, then the answer is yes. BPM task list will inherit the look and feel of the containing page.

Please try to check also my recent post about using BPM Workspace taskflows inside a custom ADF application on this link: http://soadev.blogspot.com/2011/07/adf-uishell-application-with-oracle-bpm.html

I tried with "displayColumnsList" attribute to pass comma separated string. But looks like it accepts only the following values..

Possible values:

*

title *

number *

priority *

assignees *

state *

createdDate *

expirationDate

It is mentioned in http://download.oracle.com/docs/cd/E21764_01/integration.1111/e10224/bp_portlets.htm#BABCJJAD.

Basically, we are looking to have "instanceId" and "Application Name" in the display columns and want to enable the filter also. For easy access of the notification to the user.

In our case we have so many Human Task notifications and a user would have 100's of notifications in his Inbox. So, if we can have "Application Name" as a filter he can easily pull up a particular notification and act on it.

Customizing I mean, adding more columns to task table. Rest of teh functionality is fine for us.

I have one more question, the standard tasklist task flow region works fine, if we have ADF authentication enabled. Lets say, If we have application not enabled with ADF security then how to pass the workflow context in that case?

I see a parameter "wfCtxID" .. but i tried passing the workflow context Id for a authenticated user. But it is not working. It is giving below exceptions..

Hi Subba,"Customizing I mean, adding more columns to task table. Rest of teh functionality is fine for us."-You can take advantage of custom views plus the flex-field mapping capability of the standard BPM worklist application. You can create separate views per application and add additional columns coming from the payload into the table using public flex-field.Rommel

I would like to know if you can help me on this because I need to reuse some bpm functionallity, like you do here...

I have a relatively simple process: one task and then some routes that will be executed depending of the outcome of the task. At the final of each route I will call a subprocess.

When a user is on a task, there is an action menu where the user selects an action. If he clicks on the reassign action, he will choose for whom the task should be reassignes. As far as I know, when the user reassign a task, my process will not continue (because the task is not accomplish yet), right?

The problem is that I need the funcionality of searching users like the reassign action give out of the box, but I just want it to get the users/groups selected. With that I will later call a subprocess that will be route to the former users/groups. So I need the page but I dont want to reassign the task.

To achieve this I put a button on the form, and Im calling the same popup the reassign is calling. The popup works, but it seems something is not initailized because the search doesnt give results. Strangly, if I open the popup using the reasign button, close it, and then open the same poup using my button, the search will work... So basically something is missing here..

After that, I need to get the selected users/groups (in my managed bean for the popup/dialog and then set a process variable (by code) and finally submit the form.

I add this adf button in design time to the task form with a showPopupBehavior:

Im just pointing to the automatically created reassign popup. I didn´t changed nothing in the reassign popup!

When I click on the button in run time, the popup will work: I see the popup with the indentity browser on it. However, the search inside the identity browser doesnt return results (maybe is throwing an error, dont know).

If I go to the automatically built action menu and choose reassign, the popup will open and the search works...

If I then go to my button again, the search will work... So there is something that the action button is initalizing or something like that that dont happen when I open the popup using my button.

I dont even talk about the fact that I really dont want to execute the reassign beahvior (just want the searh functionality). So my goal, after be able to search with the identityBrowser, is to delete the action listener (so the reassign will not be executed), and execute my own bean.

Can you first try to launch the popup programmatically in a managed bean instead of the showPopupBehaviour.http://soadev.blogspot.com/2010/02/adf-faces-rc-simple-but-robust.html

To prevent the user from reassignning the task, I believe you need to create another popup component which could be pointing to the same identityBrowser, but different action listener on the dialog buttons.

my intenttion is to use another popup with another listner, indeed. So you are saying that my problem is maybe due to the showpopupbehaviour? I will try that other way than.

But just to let you know, if that works, I will have another big problem: to get the selected users from the identityBrowser control. Any ideas to accomplish this? Is it possible to get a reference to the shuttle in the identityBrowser?

To get the selectedUsers access the IdentityBrowser model which is in pageFlowScope. Below is how you can access it programmatically:IdentityBrowserView identityBrowserView = (IdentityBrowserView)getPageFlowScope().get("identityBrowserView");List selectedIdentities = identityBrowserView.getSelectedIdentities();

Of course you can use EL like #{pageFlowScope.identityBrowserView.selectedIdentities}

Hi webuser,The acctgEntryEditForm in my case is a backing bean that is specific to my page. You should create another one which is applicable you like for example TaskDetailsBean.java and declare it as managed bean in the task-flow where your taskDetails.jspx view is located.

I was able to invoke the popup with your code. Unfortunattly, the identitybrowser still doesnt return values on the search... I just put the identity component in the new popup, but it still doesnt return values....

finally I was able to make the popup work. the problem when I copied your code was that for some reason the proprieties of each object didnt get refreshed. So I explicitly set the properties in each box and now the popup works.

- How do you know the identityBrowser control has this method: getSelectedIdentities(). Where can I see the other methods?

- I need to set the assignees of other task (in a subprocess) with the selected users in the identityBrowser. For that I was thinking in putting the users I get with your code to a variable and then set this variable to the assignees in the subprocess. However, I dont know how this variable sgould be composed. For instances: with each user/group followed by a semmicolon?

- Also, after set the value to this variable, I need to submit the task (so my process will continue). for that im usign this code (after the previous code to ger the users form identityBrowser:

Hi webuser- How do you know the identityBrowser control has this method: getSelectedIdentities(). Where can I see the other methods?

>You can find it in you task flow definition. The managed beans including this identityBrowserView are defined there. If you view the source of the task flow, you can control+click on the class name so that JDev will create a stub class that shows the exposed methods of the class.

- I need to set the assignees of other task (in a subprocess) ...>Then you need to put the value you retrieved in the identityBrowserView.getSelectedIdentities() to a variable in your task payload.

--- Also, after set the value to this variable, I need to submit the task..> it seems that you are too far from what you are trying to achieve. The sample code you present doesn't help either. I suggest that you read the developer guides, which are all present JDeveloper help.

Im sorry for atill asking you questions, and thank you for your help so far.

you said:"Then you need to put the value you retrieved in the identityBrowserView.getSelectedIdentities() to a variable in your task payload."

If I drag and drop the variable from the payload to the form I get this binding:#{bindings.user.inputValue}

"user" is my string

Can you give me an example of how I can set this value in adf/java code?

Relating to the code I post here, I got it dragging and dropping the submit and update action to the form. Then in the backendbean I get the code.

So I think that I just would need to put this code in my button. Actually, if my button doesnt have any popup/dialog, it seems to work. The problem is that when I open the dialog (using the same button) I then get the error:

"target unreachable, "identityBrowserView" returned null.

I dont have any clue why this is happening because, after clicking OK in the dialog, I dont need the identitybrowser anymore (I already copy the data to my variable), so why there is something trying to find it? Is it the scope where it is declared?

Hi webuser,"Can you give me an example of how I can set this value in adf/java code?"-Please see the following from the developers guide: http://download.oracle.com/docs/cd/E14571_01/web.1111/b31974/web_adv.htm#CACIDGAD

So in your case, you may have:JUCtrlAttrsBinding user= (JUCtrlAttrsBinding)bindings.findNamedObject("user");user.setAttribute("user", "your_user_values_here_from_identity_browser");

But there are already ulitity methods to simplify the code above. Try searching for ADFUtils in the forum. As a sample usage of this ADFUtils, see the following code from Andrejus blog: http://4.bp.blogspot.com/_OSq71i5oy0c/TMk1rMVFg9I/AAAAAAAAEbM/9-ibTD9ycHA/s1600/21.pnglocated in: http://andrejusb.blogspot.com/2010/10/initializing-oracle-bpm-11g-process.html

"? Is it the scope where it is declared?"--As I said, it is declared in the task flow where your taskDetails page is contained.

The last message displays the value I set to the variable. So, this code should be working.

However, when I go to Enterprise manager and look at the instance of the task that left the activity, my values are not being passed on the xml :(

Do you have any idea of what can be wrong?

I dont understand why if I drag the field to my form and write something on it (it will have this bind: #{bindings.user.inputValue}) the value is being passed, but if I make that code, even seeing that the value was actually changed), the value is lost somewhere.... like if it is not committed.

Im really sorry to post so much messages, but, I realize that if I put that code in a bean in a button that is in the task form, the variable is set. However, in a bean related to a dialog, the variable get set but for any reason it is lost after. So this must be a scope situation, right?

But in that way I still dont know how to be able to acomplish this in the event of a dialog/popup method.

Hi webuser,This is not a scope issue because the binding container has its own internal scope. The problem is the operation being made after the value was set that should trigger an update to the task.Are you sure that it woks on a regular button and not on a dialog button? Please confirm by having another test. If indeed it works, post here the whole action listener code (you call bean code).Pino

Hi webuser,Since your sure that it works using normal button, then I suggest you try putting code inside a dialogListener like as follows:public void handleIdentityBrowserDialogReturn(DialogEvent ev) {

if(ev.getOutcome().equals(DialogEvent.Outcome.ok)) { //put relavent code here... }}Remove the buttons in your dialog and set the dialogListener property of the af:dialog to point to the method above like as follows:<af:dialog id="d3" type="okCancel" dialogListener="#{your_bean.handleIdentityBrowserDialogReturn}"> <wlc:identityBrowser .../></af:dialog>

My first approach (the one Im trying to accomplish) is build exactly with a dialoglistner. In the dialogListner property Im pointing to a bean where Im executing that same code. And then doesnt work...

I just dont understand what you mean about "remove the buttons in your dialog", because without buttons how the code will be executed?

just let me explain one more thing. The button where the code works is not in the dialog. That button is in the task form itself. That is the difference Im talking about. Everything else is exactly the same.

So, for any reason, if I run that code in a bean associated with an object in the form, that works, but running that code in dialogs, doesnt work.

Hi webuser,"because without buttons how the code will be executed?" - The code will be executed in the DialogListener (not ActionListener). The "YesNo" dialog type will have two buttons even if you remove your custom buttons.

"if I run that code in a bean associated with an object in the form, that works, but running that code in dialogs, doesnt work." -- Sorry, but I cant really comment on this one.

thank you for sharing this article: i found it very useful. Please, let me ask you a couple of questions about it. Thanks to your suggestions and other material i found on the web, I successed in realizing a traditional Fusion Web App able to remotely open BPM human task forms in an inline-frame (or pop-up or whatever...). Basically i successed in doing something very similar to what the picture in your article shows (open a dialog with inside a BPM human task form). Anyway, i'm encountering the following problem: wherever i close any of the task forms approving or rejecting the task, the task is pushed forward in the BPM process, but the task form remains opened in the browser and i get the following error:

Caused By: java.lang.NullPointerException at oracle.bpel.services.workflow.worklist.adf.ADFWorklistBeanUtil.getURLTORedirect(ADFWorklistBeanUtil.java:416) at oracle.bpel.services.workflow.worklist.adf.InvokeActionBean.getParentURL(InvokeActionBean.java:1048) at oracle.bpel.services.workflow.worklist.adf.InvokeActionBean.invokeScript(InvokeActionBean.java:1063)

By investigating the matter, i discovered the problem was i didn't provide the "parentURL" parameter to the task flow in the hash map passed to the getTaskDisplayURL method, but even if i provide that parameter the human task form doesn't close itself which is quite annoying. I even tried to pass the "bpmBrowserWindowStatus" parameter with value "close" or "keep", and in that case i get no error but the browser shows an error pop-up with no message and the task form keeps to stay open: arrrrrghhh!!!Do you have any clue on this behavior?

i am trying to run above code in my jDeveloper & i'm getting following java exception stack trace:Exception in thread "main" java.lang.NoClassDefFoundError: oracle/bpm/casemgmt/client/ICaseManagementServiceClient at com.wft.uep.Fixture.getBPMServiceClientFactory(Fixture.java:29) at com.wft.uep.Fixture.getBPMServiceClient(Fixture.java:45) at com.wft.uep.GetProcessInstances.testGetProcessInstances(GetProcessInstances.java:26) at com.wft.uep.GetProcessInstances.main(GetProcessInstances.java:21)Caused by: java.lang.ClassNotFoundException: oracle.bpm.casemgmt.client.ICaseManagementServiceClient at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ... 4 more

i don't know where to find oracle.bpm.casemgmt.client.ICaseManagementServiceClient class can you please help me on this.

I have already implemented a customized worklist and I used a sample code -like what you did present here- in my worklist. it shows the list of applications for the user and initiates applications well.

But I have still an unsolved task which is opening assigned task's form.I am just able to get detailed information of the task, but I am not able to generate appropriate link to open humantask's form.

I used your "getTaskDisplayURL(task)" method to generate a link to open assigned task, but it did not generate a valid url to open the humanTask's form.this is a sample one: "http://rfh-ptc-uat-ws:7003/workflow/Project1/faces/adf.task-flow?_document=WEB-INF%2FHumantask1_TaskFlow.xml&parentURL=http%3A%2F%2FRFH-PTC-UAT-WS%3A7003%2Fworklist&bpmWorklistContext=f44adbb2-b0f6-475f-bcf2-4a2b448d62df%3B%3BVZROoLhY4hm1mZZ%2FJwCHmxMkivxpBYlB7V98jmo4UVDSnGoV%2FXYp8x5%2FVGrVVL0mud2jA4APbIKgA6br37NB%2FhjAhFQhpJUTTJu%2BwPjfspLNVq1QPgRnY6gfVJFlY%2BS5QohskySbooH9U8DOAsfWKQqDnShq10D6OnHaNCMAoNhGXswRa8GxlynokOVS9ZiuS4znIsV3730wUOq55x1SemFAUK8VMFjUXDYcnGkyWcmqVQ%2Fl1lB4Ofga47a99qCb&bpmWorklistTaskId=TestEnglish&_id=Humantask1_TaskFlow&_afrLoop=1303713189363704&_afrWindowMode=0&_afrWindowId=bp_workflow"

HI, PinoThere is a problem bothering me, how to get the task operation page/url in workspaceI'm not sure whether this method can, WorklistUtil getTaskDisplayURL (factory. GetWorkflowServiceClient (), getIBPMContext (), task, null, "worklist", the parameters).You only instruction how to init a task of process,I want to more,Thanks!