Working with jBPM Business Process Management platform via its REST API
1.???Overview
jBPM is an open-source BPM tool. It allows developers to use a RESTful API that enables users to do the same things (complete their tasks in the process) from within a Web App UI which they can do from the jBPM Business Central web application. It is extremely easy to install and run as you can see from the steps mentioned below.
A business process allows you to model your business goals by describing the steps that need to be executed to achieve those goals, and the order of those goals is depicted using a flow chart. The core of jBPM is a light-weight, extensible workflow engine written in pure Java that allows you to execute business processes using the latest?BPMN 2.0 specification. It can run in any Java environment, embedded in your application or as a service.
2.???Installation and getting started
Time to complete this: 5 minutes
2.1 Getting started
?It is also possible to install jBPM on your machine/server Using Docker.
2.1.1????????Download jBPM
First things first, download jBPM server distribution (if not already done) to start quickly with complete environment.
Just download, unzip and run
2.1.2????????Explore your running environment
Business Central provides feature rich authoring and management environment. It consists of:
Figure 1 jBPM engine running on port 8080 on my machine
Business Central can be accessed (once the server was started) at https://localhost:8080/business-central
Figure 2 Business Central where you can access your business processes and edit/deploy them
There are set of predefined users that can be used to directly logon to Business Central:
Additional users can be created via Business Central Admin section.
2.1.3????????KIE Server Swagger documentation- jBPM RESTful API
KIE Server is the execution server that provides various capabilities
Its complete REST API documentation can be accessed at the following URI.
Figure 3 jBPM KIE Server REST API Swagger doc
2.1.4????????Try examples
You can import some pre-built examples from https://github.com/droolsjbpm/jbpm-playground.
Go to Spaces/My Space (or your own space) and click on Add project dropdown and click “import project” to import projects from the above GitHub uri.
Figure 4 Import project from GitHub
Once you get yourself familiar with the tools of the jBPM, it’s time to see something running. The easiest way is to try one of the examples shipped with the platform, it will show typical path users take to design, build and execute business logic.
2.1.4.1 Evaluation process
Evaluation process is a business process that is human centric (heavily uses human actors to perform work) that defines a complete flow of activities to perform employee evaluation.
3.???ASP.NET Core web app which works with a sample jBPM workflow using jBPM REST API
3.1 Web app architecture
Figure 5 ASP.NET Core MVC Web app architecture
3.2 The Business Process/Workflow
The following is the process/workflow we will be coding using our web app UI app invoked the jBPM REST API to execute the whole process (all its human and system tasks) through our web app UI without even going to the jBPM management console.
Figure 6 HR Evaluation business process/workflow
3.3 UI Web app
3.3.1????????Web Application Roles Mapped to BPM users and roles
You can create your own users in the ASP.NET Core web app with the database running on your local PostgreSQL instance and then edit the mapping of your users with the jBPM users and roles.
领英推荐
I am using ASP.NET Core Identity with a PostgreSQL v 12 db. This is pretty easy to set up. Just search on the web to know how you can do this.
Database script is as follows.
-
-- PostgreSQL database dump
--
-- Dumped from database version 12.3
-- Dumped by pg_dump version 13.3
-- Started on 2022-02-26 20:34:52
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- TOC entry 9 (class 2615 OID 19591)
-- Name: dbo; Type: SCHEMA; Schema: -; Owner: postgres
--
CREATE SCHEMA dbo;
ALTER SCHEMA dbo OWNER TO postgres;
--
-- TOC entry 4 (class 2615 OID 16676)
-- Name: guest; Type: SCHEMA; Schema: -; Owner: postgres
--
CREATE SCHEMA guest;
ALTER SCHEMA guest OWNER TO postgres;
--
-- TOC entry 217 (class 1255 OID 30187)
-- Name: uuid_generate_v4(); Type: FUNCTION; Schema: public; Owner: postgres
--
CREATE FUNCTION public.uuid_generate_v4() RETURNS uuid
? ? LANGUAGE c
? ? AS '$libdir/uuid-ossp', 'uuid_generate_v4';
ALTER FUNCTION public.uuid_generate_v4() OWNER TO postgres;
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- TOC entry 208 (class 1259 OID 16589)
-- Name: AspNetRoleClaims; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."AspNetRoleClaims" (
? ? "Id" integer NOT NULL,
? ? "RoleId" uuid NOT NULL,
? ? "ClaimType" text,
? ? "ClaimValue" text
);
ALTER TABLE public."AspNetRoleClaims" OWNER TO postgres;
--
-- TOC entry 207 (class 1259 OID 16587)
-- Name: AspNetRoleClaims_Id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
ALTER TABLE public."AspNetRoleClaims" ALTER COLUMN "Id" ADD GENERATED BY DEFAULT AS IDENTITY (
? ? SEQUENCE NAME public."AspNetRoleClaims_Id_seq"
? ? START WITH 1
? ? INCREMENT BY 1
? ? NO MINVALUE
? ? NO MAXVALUE
? ? CACHE 1
);
--
-- TOC entry 205 (class 1259 OID 16571)
-- Name: AspNetRoles; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."AspNetRoles" (
? ? "Id" uuid NOT NULL,
? ? "Name" character varying(256),
? ? "NormalizedName" character varying(256),
? ? "ConcurrencyStamp" text
);
ALTER TABLE public."AspNetRoles" OWNER TO postgres;
--
-- TOC entry 210 (class 1259 OID 16604)
-- Name: AspNetUserClaims; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."AspNetUserClaims" (
? ? "Id" integer NOT NULL,
? ? "UserId" uuid NOT NULL,
? ? "ClaimType" text,
? ? "ClaimValue" text
);
ALTER TABLE public."AspNetUserClaims" OWNER TO postgres;
--
-- TOC entry 209 (class 1259 OID 16602)
-- Name: AspNetUserClaims_Id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
ALTER TABLE public."AspNetUserClaims" ALTER COLUMN "Id" ADD GENERATED BY DEFAULT AS IDENTITY (
? ? SEQUENCE NAME public."AspNetUserClaims_Id_seq"
? ? START WITH 1
? ? INCREMENT BY 1
? ? NO MINVALUE
? ? NO MAXVALUE
? ? CACHE 1
);
--
-- TOC entry 211 (class 1259 OID 16617)
-- Name: AspNetUserLogins; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."AspNetUserLogins" (
? ? "LoginProvider" text NOT NULL,
? ? "ProviderKey" text NOT NULL,
? ? "ProviderDisplayName" text,
? ? "UserId" uuid NOT NULL
);
ALTER TABLE public."AspNetUserLogins" OWNER TO postgres;
--
-- TOC entry 212 (class 1259 OID 16630)
-- Name: AspNetUserRoles; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."AspNetUserRoles" (
? ? "UserId" uuid NOT NULL,
? ? "RoleId" uuid NOT NULL
);
ALTER TABLE public."AspNetUserRoles" OWNER TO postgres;
--
-- TOC entry 213 (class 1259 OID 16645)
-- Name: AspNetUserTokens; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."AspNetUserTokens" (
? ? "UserId" uuid NOT NULL,
? ? "LoginProvider" text NOT NULL,
? ? "Name" text NOT NULL,
? ? "Value" text
);
ALTER TABLE public."AspNetUserTokens" OWNER TO postgres;
--
-- TOC entry 206 (class 1259 OID 16579)
-- Name: AspNetUsers; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."AspNetUsers" (
? ? "Id" uuid NOT NULL,
? ? "UserName" character varying(256),
? ? "NormalizedUserName" character varying(256),
? ? "Email" character varying(256),
? ? "NormalizedEmail" character varying(256),
? ? "EmailConfirmed" boolean NOT NULL,
? ? "PasswordHash" text,
? ? "SecurityStamp" text,
? ? "ConcurrencyStamp" text,
? ? "PhoneNumber" text,
? ? "PhoneNumberConfirmed" boolean NOT NULL,
? ? "TwoFactorEnabled" boolean NOT NULL,
? ? "LockoutEnd" timestamp with time zone,
? ? "LockoutEnabled" boolean NOT NULL,
? ? "AccessFailedCount" integer NOT NULL
);
ALTER TABLE public."AspNetUsers" OWNER TO postgres;
--
-- TOC entry 204 (class 1259 OID 16566)
-- Name: __EFMigrationsHistory; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public."__EFMigrationsHistory" (
? ? "MigrationId" character varying(150) NOT NULL,
? ? "ProductVersion" character varying(32) NOT NULL
);
ALTER TABLE public."__EFMigrationsHistory" OWNER TO postgres;
--
-- TOC entry 2753 (class 2606 OID 16596)
-- Name: AspNetRoleClaims PK_AspNetRoleClaims; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetRoleClaims"
? ? ADD CONSTRAINT "PK_AspNetRoleClaims" PRIMARY KEY ("Id");
--
-- TOC entry 2745 (class 2606 OID 16578)
-- Name: AspNetRoles PK_AspNetRoles; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetRoles"
? ? ADD CONSTRAINT "PK_AspNetRoles" PRIMARY KEY ("Id");
--
-- TOC entry 2756 (class 2606 OID 16611)
-- Name: AspNetUserClaims PK_AspNetUserClaims; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserClaims"
? ? ADD CONSTRAINT "PK_AspNetUserClaims" PRIMARY KEY ("Id");
--
-- TOC entry 2759 (class 2606 OID 16624)
-- Name: AspNetUserLogins PK_AspNetUserLogins; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserLogins"
? ? ADD CONSTRAINT "PK_AspNetUserLogins" PRIMARY KEY ("LoginProvider", "ProviderKey");
--
-- TOC entry 2762 (class 2606 OID 16634)
-- Name: AspNetUserRoles PK_AspNetUserRoles; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserRoles"
? ? ADD CONSTRAINT "PK_AspNetUserRoles" PRIMARY KEY ("UserId", "RoleId");
--
-- TOC entry 2764 (class 2606 OID 16652)
-- Name: AspNetUserTokens PK_AspNetUserTokens; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserTokens"
? ? ADD CONSTRAINT "PK_AspNetUserTokens" PRIMARY KEY ("UserId", "LoginProvider", "Name");
--
-- TOC entry 2749 (class 2606 OID 16586)
-- Name: AspNetUsers PK_AspNetUsers; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUsers"
? ? ADD CONSTRAINT "PK_AspNetUsers" PRIMARY KEY ("Id");
--
-- TOC entry 2743 (class 2606 OID 16570)
-- Name: __EFMigrationsHistory PK___EFMigrationsHistory; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."__EFMigrationsHistory"
? ? ADD CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId");
--
-- TOC entry 2747 (class 1259 OID 16663)
-- Name: EmailIndex; Type: INDEX; Schema: public; Owner: postgres
--
CREATE INDEX "EmailIndex" ON public."AspNetUsers" USING btree ("NormalizedEmail");
--
-- TOC entry 2751 (class 1259 OID 16658)
-- Name: IX_AspNetRoleClaims_RoleId; Type: INDEX; Schema: public; Owner: postgres
--
CREATE INDEX "IX_AspNetRoleClaims_RoleId" ON public."AspNetRoleClaims" USING btree ("RoleId");
--
-- TOC entry 2754 (class 1259 OID 16660)
-- Name: IX_AspNetUserClaims_UserId; Type: INDEX; Schema: public; Owner: postgres
--
CREATE INDEX "IX_AspNetUserClaims_UserId" ON public."AspNetUserClaims" USING btree ("UserId");
--
-- TOC entry 2757 (class 1259 OID 16661)
-- Name: IX_AspNetUserLogins_UserId; Type: INDEX; Schema: public; Owner: postgres
--
CREATE INDEX "IX_AspNetUserLogins_UserId" ON public."AspNetUserLogins" USING btree ("UserId");
--
-- TOC entry 2760 (class 1259 OID 16662)
-- Name: IX_AspNetUserRoles_RoleId; Type: INDEX; Schema: public; Owner: postgres
--
CREATE INDEX "IX_AspNetUserRoles_RoleId" ON public."AspNetUserRoles" USING btree ("RoleId");
--
-- TOC entry 2746 (class 1259 OID 16659)
-- Name: RoleNameIndex; Type: INDEX; Schema: public; Owner: postgres
--
CREATE UNIQUE INDEX "RoleNameIndex" ON public."AspNetRoles" USING btree ("NormalizedName");
--
-- TOC entry 2750 (class 1259 OID 16664)
-- Name: UserNameIndex; Type: INDEX; Schema: public; Owner: postgres
--
CREATE UNIQUE INDEX "UserNameIndex" ON public."AspNetUsers" USING btree ("NormalizedUserName");
--
-- TOC entry 2769 (class 2606 OID 16597)
-- Name: AspNetRoleClaims FK_AspNetRoleClaims_AspNetRoles_RoleId; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetRoleClaims"
? ? ADD CONSTRAINT "FK_AspNetRoleClaims_AspNetRoles_RoleId" FOREIGN KEY ("RoleId") REFERENCES public."AspNetRoles"("Id") ON DELETE CASCADE;
--
-- TOC entry 2770 (class 2606 OID 16612)
-- Name: AspNetUserClaims FK_AspNetUserClaims_AspNetUsers_UserId; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserClaims"
? ? ADD CONSTRAINT "FK_AspNetUserClaims_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES public."AspNetUsers"("Id") ON DELETE CASCADE;
--
-- TOC entry 2771 (class 2606 OID 16625)
-- Name: AspNetUserLogins FK_AspNetUserLogins_AspNetUsers_UserId; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserLogins"
? ? ADD CONSTRAINT "FK_AspNetUserLogins_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES public."AspNetUsers"("Id") ON DELETE CASCADE;
--
-- TOC entry 2772 (class 2606 OID 16635)
-- Name: AspNetUserRoles FK_AspNetUserRoles_AspNetRoles_RoleId; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserRoles"
? ? ADD CONSTRAINT "FK_AspNetUserRoles_AspNetRoles_RoleId" FOREIGN KEY ("RoleId") REFERENCES public."AspNetRoles"("Id") ON DELETE CASCADE;
--
-- TOC entry 2773 (class 2606 OID 16640)
-- Name: AspNetUserRoles FK_AspNetUserRoles_AspNetUsers_UserId; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserRoles"
? ? ADD CONSTRAINT "FK_AspNetUserRoles_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES public."AspNetUsers"("Id") ON DELETE CASCADE;
--
-- TOC entry 2774 (class 2606 OID 16653)
-- Name: AspNetUserTokens FK_AspNetUserTokens_AspNetUsers_UserId; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public."AspNetUserTokens"
? ? ADD CONSTRAINT "FK_AspNetUserTokens_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES public."AspNetUsers"("Id") ON DELETE CASCADE;
-- Completed on 2022-02-26 20:34:57
--
-- PostgreSQL database dump complete
--
-
The below code snippet is an example of how Web app users are mapped to BPM users and roles.
The mapping is hardcoded below. However, you can always automate this mapping by using the web app database and querying the Web app users as well as the jBPM users. The web app users are example users and you can register users as you see fit.
public static class WebAppAndBPMUserMa
???{
???????public static List<mapping> mappings { get; }
???????static WebAppAndBPMUserMap()
???????{
???????????mappings = new List<mapping>();
???????????mappings.Clear();
?
???????????// These are example mappings. Please edit for your own
???????????// env.
???????????mappings.Add(new mapping
???????????{
???????????????UserNameOnWebApp = "[email protected]",
???????????????UserIdOnBPMEngineOrApp = "4",
???????????????UserRoleOnBPMEngineOrApp = "claim_initiator",
???????????????UserNameOnBPMEngineOrApp = "walter.bates",
???????????????PasswordOnBPMEngineOrApp = "bpm",
???????????????UserIdOnBPMEngineOrApp2 = "",
???????????????UserRoleOnBPMEngineOrApp2 = "invoice_initiator",
???????????????UserNameOnBPMEngineOrApp2 = "demo",
???????????????PasswordOnBPMEngineOrApp2 = "demo",
???????????????UserIdOnjBPMEngineOrApp = "",
???????????????UserRoleOnjBPMEngineOrApp = "employee",
???????????????UserNameOnjBPMEngineOrApp = "jack",
???????????????PasswordOnjBPMEngineOrApp = "jack",
???????????});
?
???????????mappings.Add(new mapping {
???????????????UserNameOnWebApp = "[email protected]",
???????????????UserIdOnBPMEngineOrApp = "4",
???????????????UserRoleOnBPMEngineOrApp = "claim_initiator",
???????????????UserNameOnBPMEngineOrApp = "walter.bates",
???????????????PasswordOnBPMEngineOrApp = "bpm",
???????????????UserIdOnBPMEngineOrApp2 = "",
???????????????UserRoleOnBPMEngineOrApp2 = "invoice_initiator",
???????????????UserNameOnBPMEngineOrApp2 = "demo",
???????????????PasswordOnBPMEngineOrApp2 = "demo",
???????????????UserIdOnjBPMEngineOrApp = "",
???????????????UserRoleOnjBPMEngineOrApp = "pm",
???????????????UserNameOnjBPMEngineOrApp = "john",
???????????????PasswordOnjBPMEngineOrApp = "john",
???????????});
?
???????????mappings.Add(new mapping
???????????{
???????????????UserNameOnWebApp = "[email protected]",
???????????????UserIdOnBPMEngineOrApp = "15",
???????????????UserRoleOnBPMEngineOrApp = "claim_reviewer",
???????????????UserNameOnBPMEngineOrApp = "mauro.zetticci",
???????????????PasswordOnBPMEngineOrApp = "bpm",
???????????????UserIdOnBPMEngineOrApp2 = "",
???????????????UserRoleOnBPMEngineOrApp2 = "invoice_approver",
???????????????UserNameOnBPMEngineOrApp2 = "demo",
???????????????PasswordOnBPMEngineOrApp2 = "demo",
???????????????UserIdOnjBPMEngineOrApp = "",
???????????????UserRoleOnjBPMEngineOrApp = "hr_admin",
???????????????UserNameOnjBPMEngineOrApp = "wbadmin",
???????????????PasswordOnjBPMEngineOrApp = "wbadmin",
???????????});
?
???????????
???????}
???}
p
3.3.1.1 Project Manager ([email protected]) can start new employee evaluation
3.3.1.2 Employee ([email protected]) can self-evaluate themselves
3.3.1.3 HR ([email protected]) to evaluate an employee as HR
3.3.2????????Landing page of UI
I have kept the ASP.NET Core MVC Web App UI pretty simple. You can use all kinds of styles available to make it more beautiful and trendy.
Figure 7 ASP.NET Core MVC Web application
3.4 Go to My Evaluations (sample pre-built HR evaluation workflow/business process in jBPM)
Figure 8 Click on My Evaluations Link
3.4.1????????Start a new employee evaluation as a PM
Figure 9 Start a new Employee Evaluation as a PM
Figure 10 Click the button "Start the evaluation"
The above action initiates a new jBPM process instance of the “evaluation” process.
See the image below.
Figure 11 You can see that a new jBPM process instance was triggered from the web app
Figure 12 New process instance status in jBPM console (business central)
3.4.2????????Login as [email protected] to evaluate yourself
Figure 13 Self evaluation
Figure 14 Submitting self-evaluation
3.4.3????????Login as PM ([email protected]) again to do PM evaluation
Figure 15 Submitting PM Evaluation
If you click again on one of the tasks in the My Evaluations page, you will now see a message that the next step is the HR evaluation.
Figure 16 Next step after PM evaluation is HR evaluation
3.4.4????????Login as HR ([email protected]) to evaluate an employee as HR
Figure 17 Submitting HR evaluation
Figure 18 After HR evaluation, the employee evaluation process/workflow is completed
Figure 19 New employee evaluation process completed status in jBPM business central
Thus, it is easy to prove that a jBPM example process can be completed end-to-end using jBPM REST API, which is exposed via jBPM Kie Server REST instance, from within the ASP.NET Core MVC Web application. There is no need to use the jBPM Business Central app.
4.???References
Principal software engineer (AWS | JAVA | Microservices | Hibernate | Kafka | ELK )
1 年Nice blog Prasad, can you tell me the command to run on the ip or host name, I want to access this h PM via up or host name not localhost
Technology Disclaimer: My views expressed here on LinkedIn are my own and they do not represent anyone else.
3 年I have done the same exercise (using RESTful API of a #bpm platform to run processes from ASP.NET Core MVC web app) with #bpm platforms viz. #camunda and #alfrescoactiviti (#alfrescoprocessservices). Thus, the proof-of-concept, that I wrote, works with at least 3 different #bpm platforms. Of course, almost all the open-source BPM platforms are based on #jboss, #jms, #activemq, and #drools. The simple reason behind this fact is that the JMS, Drools, ActiveMQ are the backbone of any open-source #bpm platform due to the capability they have: #asynchronous #messaging, and #businessrules #engine. Every #bpm platform would certainly have these because without them it won't work in a reliable manner.