“Tasks List” View in workbench

Today, I write about “Tasks List” View in workbench (a.k.a. Business Central).

Most of users don’t need to worry about such internal but I just wanted to note as my work log.

Environment: BPM Suite 6.4.x (= jbpm-wb 6.5.x)

Firstly, I configured a custom UserGroupCallback to the workbench (uisng a custom UserGroupInfoProducer via beans.xml). But “Group” tab of “Tasks List” View displays tasks for login user’s groups resolved by JAAS instead of tasks for login user’s groups resolved by the custom UserGroupCallback.

I set breapoints and debugged around so I found that the custom UserGroupCallback is properly configured to TaskService in the workbench. The problem is that “Tasks List” is not using TaskService. How does it query database? Let’s drill down from client side.

As we cannot set a breakpoint in GWT client code, the first approach is to grep source codes with text label “Tasks List”. (Hmm, I’m not yet confortable with Chrome client side debug)

Finally I listed 2 candidates:

https://github.com/kiegroup/jbpm-wb/blob/6.5.x/jbpm-console-ng-human-tasks/jbpm-console-ng-human-tasks-client/src/main/java/org/jbpm/console/ng/ht/client/editors/taskslist/grid/dash/DataSetTasksListGridPresenter.java
https://github.com/kiegroup/jbpm-wb/blob/6.5.x/jbpm-console-ng-human-tasks/jbpm-console-ng-human-tasks-client/src/main/java/org/jbpm/console/ng/ht/client/editors/taskslist/grid/TasksListGridPresenter.java

I was not sure which is actually used at the stage. Then I looked into those client codes and found the backend services called.

DataSetTasksListGridPresenter -> DataSetLookupServicesImpl

https://github.com/dashbuilder/dashbuilder/blob/0.5.x/dashbuilder-backend/dashbuilder-services/src/main/java/org/dashbuilder/dataset/service/DataSetLookupServicesImpl.java

TasksListGridPresenter -> TaskQueryServiceImpl

https://github.com/kiegroup/jbpm-wb/blob/6.5.x/jbpm-console-ng-human-tasks/jbpm-console-ng-human-tasks-backend/src/main/java/org/jbpm/console/ng/ht/backend/server/TaskQueryServiceImpl.java

By setting breakpoints, I got finally sure DataSetTasksListGridPresenter -> DataSetLookupServicesImpl is actually working.

From client side, we may track the source codes like this:

https://github.com/kiegroup/kie-wb-distributions/blob/6.5.x/kie-wb/kie-wb-webapp/src/main/java/org/kie/workbench/client/KieWorkbenchEntryPoint.java#L303
-> jBPM workbech menu places “DataSet Tasks” for Task view

https://github.com/kiegroup/jbpm-wb/blob/6.5.x/jbpm-console-ng-human-tasks/jbpm-console-ng-human-tasks-client/src/main/java/org/jbpm/console/ng/ht/client/perspectives/DataSetTasksListPerspective.java#L36
-> “DataSet Tasks” is DataSetTasksListPerspective. It places “DataSet Tasks List”.

https://github.com/kiegroup/jbpm-wb/blob/6.5.x/jbpm-console-ng-human-tasks/jbpm-console-ng-human-tasks-client/src/main/java/org/jbpm/console/ng/ht/client/editors/taskslist/grid/dash/DataSetTasksListGridPresenter.java#L40
-> “DataSet Tasks List” is DataSetTasksListGridPresenter

Anyway, I prefer debugger/breakpont so that I can confirm what’s actually happening.

Now let’s see how data is queried.

By drilling down with a debugger, SQL is constructed by SQLDataSetProvider and finally executed with plain JDBC.

Daemon Thread [http-127.0.0.1:8080-5] (Suspended)	
	owns: Http11Processor  (id=214)	
	JDBCUtils.executeQuery(Connection, String) line: 77	
	Select.fetch() line: 183	
	SQLDataSetProvider$LookupProcessor.run() line: 711	
	SQLDataSetProviderCDI(SQLDataSetProvider)._lookupDataSet(SQLDataSetDef, DataSetLookup) line: 441	
	SQLDataSetProviderCDI(SQLDataSetProvider).lookupDataSet(DataSetDef, DataSetLookup) line: 235	
	SQLDataSetProviderCDI$Proxy$_$$_WeldClientProxy.lookupDataSet(DataSetDef, DataSetLookup) line: not available	
	DataSetManagerCDI(DataSetManagerImpl).lookupDataSet(DataSetLookup) line: 153	
	DataSetManagerCDI$Proxy$_$$_WeldClientProxy.lookupDataSet(DataSetLookup) line: not available	
	DataSetLookupServicesImpl.lookupDataSet(DataSetLookup) line: 79	
	DataSetLookupServicesImpl$Proxy$_$$_WeldClientProxy.lookupDataSet(DataSetLookup) line: not available	
	NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
	NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62	
	DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
	Method.invoke(Object, Object...) line: 497	
	ValueReplyRPCEndpointCallback(AbstractRPCMethodCallback).invokeMethodFromMessage(Message) line: 48	
	ValueReplyRPCEndpointCallback.callback(Message) line: 24	
	RemoteServiceCallback.callback(Message) line: 54	
	CDIExtensionPoints$2.callback(Message) line: 396	
	DeliveryPlan.deliver(Message) line: 47	
	ServerMessageBusImpl.sendGlobal(Message) line: 297	
	SimpleDispatcher.dispatchGlobal(Message) line: 46	
	ErraiServiceImpl<S>.store(Message) line: 97	
	...

https://github.com/dashbuilder/dashbuilder/blob/0.5.x/dashbuilder-backend/dashbuilder-dataset-sql/src/main/java/org/dashbuilder/dataprovider/sql/JDBCUtils.java#L77

The executed SQL is like this:

SELECT ACTIVATIONTIME "activationTime", ACTUALOWNER "actualOwner", CREATEDBY "createdBy", CREATEDON "createdOn", DEPLOYMENTID "deploymentId", DESCRIPTION "description", DUEDATE "dueDate", NAME "name", PARENTID "parentId", PRIORITY "priority", PROCESSID "processId", PROCESSINSTANCEID "processInstanceId", PROCESSSESSIONID "processSessionId", STATUS "status", TASKID "taskId", WORKITEMID "workItemId" FROM (SELECT T.ACTIVATIONTIME, T.ACTUALOWNER, T.CREATEDBY, T.CREATEDON, T.DEPLOYMENTID, T.DESCRIPTION, T.DUEDATE, T.NAME, T.PARENTID, T.PRIORITY, T.PROCESSID, T.PROCESSINSTANCEID, T.PROCESSSESSIONID, T.STATUS, T.TASKID, T.WORKITEMID, OE.ID FROM AUDITTASKIMPL T, PEOPLEASSIGNMENTS_POTOWNERS PO, ORGANIZATIONALENTITY OE WHERE T.TASKID = PO.TASK_ID AND PO.ENTITY_ID = OE.ID) "dbSQL" WHERE (STATUS = 'Ready' OR STATUS = 'Reserved' OR STATUS = 'InProgress') AND ((((ID = 'bpmsAdmin' OR ID = 'admin') OR ID = 'bpmsAdmin') AND (ACTUALOWNER = '' OR ACTUALOWNER IS NULL)) OR ACTUALOWNER = 'bpmsAdmin') GROUP BY TASKID, ACTIVATIONTIME, ACTUALOWNER, CREATEDBY, CREATEDON, DEPLOYMENTID, DESCRIPTION, DUEDATE, NAME, PARENTID, PRIORITY, PROCESSID, PROCESSINSTANCEID, PROCESSSESSIONID, STATUS, WORKITEMID ORDER BY CREATEDON ASC LIMIT 10

The WHERE part “(ID = ‘bpmsAdmin’ OR ID = ‘admin’)” has to do with the JAAS resolution. Where is it introduced? Going up the stack, I found the provied DataSetLookup object already contains LogicalExprFilter:

(((id = bpmsAdmin OR id = admin OR id = bpmsAdmin) AND (actualOwner =  OR actualOwner is_null )) OR actualOwner = bpmsAdmin)

So it was passed from client side.

Then I go back to client side source codes again and go through how DataSetLookup filter is constructed. Finally, I came to AbstractTasksListGridPresenter.getUserGroupFilters() adds filters based on user/groups based on login Errai User when JAAS based.

https://github.com/kiegroup/jbpm-wb/blob/6.5.x/jbpm-console-ng-human-tasks/jbpm-console-ng-human-tasks-client/src/main/java/org/jbpm/console/ng/ht/client/editors/taskslist/grid/AbstractTasksListGridPresenter.java#L166
https://github.com/kiegroup/jbpm-wb/blob/6.5.x/jbpm-console-ng-human-tasks/jbpm-console-ng-human-tasks-client/src/main/java/org/jbpm/console/ng/ht/client/editors/taskslist/grid/AbstractTasksListGridPresenter.java#L208-L229

I’ve been talking about BPM Suite 6.4.x (= jbpm-wb 6.5.x). In jBPM 7, the implementation is different. Client side is renamed to TaskListViewImpl.

https://github.com/kiegroup/jbpm-wb/blob/7.6.x/jbpm-wb-human-tasks/jbpm-wb-human-tasks-client/src/main/java/org/jbpm/workbench/ht/client/editors/taskslist/TaskListViewImpl.java

Since jBPM 7, execution engine is consolidated to kie-server (a.k.a. Decision Server). So QueryDataResource is called as a backend service.

Thread [default task-33] (Suspended (breakpoint at line 201 in SQLDataSetProvider))	
	SQLDataSetProvider.lookupDataSet(DataSetDef, DataSetLookup) line: 201	
	DataSetManagerImpl.lookupDataSet(DataSetLookup) line: 154	
	QueryServiceImpl.query(String, QueryResultMapper<T>, QueryContext, QueryParamBuilder<?>) line: 268	
	QueryServiceImpl.query(String, QueryResultMapper<T>, QueryContext, QueryParam...) line: 210	
	QueryDataServiceBase.queryFiltered(String, String, Integer, Integer, String, String) line: 179	
	QueryDataResource.runQueryFiltered(HttpHeaders, String, String, String, Integer, Integer, String) line: 341	
	...

PotOwnerTasksPreprocessor is called instead of AbstractTaskListPresenter.getUserGroupFilters(). The behaviour looks similar.

Thread [default task-50] (Suspended)	
	PotOwnerTasksPreprocessor.preprocess(DataSetLookup) line: 57	
	DataSetManagerImpl.lookupDataSet(DataSetLookup) line: 149	
	QueryServiceImpl.query(String, QueryResultMapper<T>, QueryContext, QueryParamBuilder<?>) line: 268	
	QueryServiceImpl.query(String, QueryResultMapper<T>, QueryContext, QueryParam...) line: 210	
	QueryDataServiceBase.queryFiltered(String, String, Integer, Integer, String, String) line: 179	
	QueryDataResource.runQueryFiltered(HttpHeaders, String, String, String, Integer, Integer, String) line: 341	
	...

https://github.com/kiegroup/jbpm/blob/7.6.x/jbpm-services/jbpm-kie-services/src/main/java/org/jbpm/kie/services/impl/query/preprocessor/PotOwnerTasksPreprocessor.java#L52-L79

I filed a JIRA for this so it could be fixed/changed in the near future.

https://issues.jboss.org/browse/RHBA-401
https://issues.jboss.org/browse/RHBPMS-5126

 

Debugging kie-workbench

Debugging kie-workbench (a.k.a business-central) is a bit tricky because it’s built on top of Uberfire/Errai/GWT stack. You may notice that your remote debugger sometimes doesn’t stop at break points.

GWT transforms some Java sources into Javascript/HTML so that they can work in browser side. In other words, some Java sources are not actually executed in JVM. Specifically, *.client.* packages (and *.model.* packages when they are accessed by client classes).

Environment: Drools 6.3.0.Final

There are 2 approaches to debug GWT client side:

1. SuperDevMode

If you experienced classic “DevMode” some years ago, you may be surprised that current Google-Chrome / FireFox don’t support the GWT plugin any longer. You cannot debug the GWT client java code in your Eclipse 😦

Now it’s “SuperDevMode”. What “Super” is … you can debug the client Java code in your browser!

You can find more details in Mike’s blog post.

http://blog.athico.com/2014/05/running-drools-wb-with-gwts-superdevmode.html

The blog post explains how to use SuperDevMode via GWT launcher. It’s useful if you are developing kie-workbench but you need to configure the kie-drools-wb-webapp project with GWT Eclipse plugin (sorry, I don’t know about IDEA). There is an easier way if you want to just debug the code.

1. Clone kie-wb-distributions from github (https://github.com/droolsjbpm/kie-wb-distributions) and checkout an expected tag (e.g. 6.3.0.Final).
2. cd kie-drools-wb/kie-drools-wb-webapp
3. mvn clean install -DskipTests Probably, not required, just in case.
4. If you are setting an env variable “JBOSS_HOME”, clear it. (e.g. export JBOSS_HOME=)
5. mvn gwt:debug

Since GWT 2.7.0, SuperDevMode is default. You will see the message:

[INFO] Super Dev Mode starting up
[INFO]    workDir: /tmp/gwt-codeserver-4694758264243958369.tmp
[INFO]    Loading Java files in org.kie.workbench.drools.FastCompiledKIEDroolsWebapp.
[INFO] INFO  [org.jboss.modules] JBoss Modules version 1.3.3.Final
...
[INFO] Listening for transport dt_socket at address: 8000

6. Attach Eclipse remote debugger to the port 8000
7. GWT Development Mode Window pops up.
8. Wait until the GWT Development Mode Window displays “Copy to Clipboard” button. (It takes sometime. Examining the window may help the GUI to refresh)

GWT Development Mode_094

9. Press “Copy to Clipboard” button and paste the URL to Google Chrome.
10. Login as admin/admin

KIE Drools Workbench - Google Chrome_093

11. Logging in triggers GWT compile. You need to wait some time again.
12. Now you can access kie-workbench
13. Open JavaScript Console in Chrome [More Tools]->[JavaScript Console]
14. For example, Put “GuidedRuleEditorPresenter” in search box. Clicking the search result, GuidedRuleEditorPresenter.java is opened. Set a break point inside loadContent() method. Then open a Guided Rule.

Developer Tools - http:--127.0.0.1:8888-kie-drools-wb.html_092

You can debug Java in browser 🙂

15. If you set a break point in a class of *.backend.* packages (e.g. GuidedRuleEditorServiceImpl), it stops in Eclipse as usual.

For more information, take a look at documents in gwtproject:

http://www.gwtproject.org/doc/latest/DevGuideCompilingAndDebugging.html
http://www.gwtproject.org/articles/superdevmode.html

2. classic DevMode

To be honest, I still prefer the old classic DevMode because I can debug client codes and backend codes in Eclipse seamlessly. But certainly the classic DevMode is outdated now so I need to get familiar with SuperDevMode.

If you still want to use classic DevMode, you have a loophole. You can dowload the old Firefox (say, 26.0) and install GWT plugin. Please note that using old version means you have lots of security issues. Make sure to use it only for local debugging.

You can enable classic DevMode with the option. I’m not sure if the option will be available in future versions. Just confirmed with GWT 2.7.0.

mvn gwt:debug -Dgwt.superDevMode=false

Following the same steps of SuperDevMode but now you can set break points in Eclipse side even for client codes.

Enjoy!