[BPMN] Service Task with REST-API (Get) Example

หลังจากงมๆมานานพอสมควรแล้วกับการใช้งาน Service Task กับ Web Service กับ Camunda BPMN Engine ครับ โดยสิ่งที่ผมใช้ คือ ตัว Camunda Connector ที่ช่วยให้เราสามารถ Config Web Service ได้ง่าย ไม่ต้องส่งงานให้ Delegate Code อย่าง BPMN Engine ของค่ายอื่นๆครับ สำหรับ

NOTE: สำหรับเรื่อง Service Task ตัว Spec ของ BPMN ไม่ได้ระบุใน Spec ชัดเจน ว่าต้องมีขั้นตอนการทำงานอย่างไร จึงเปิดให้ BPMN Engine แต่ละเจ้าสามารถเสริมเติมแต่ง Feature ได้เต็มที่ครับ

Camunda Connector

  • มี 3 รูปแบบ อ้างอิงจากเวอร์ชันที่ 7.9.0 ได้แก่
      • HTTP Connector – พวก REST API  ทั้งหลาย ใช้วิธี GET / POST และอื่นๆ แล้วเอา XML หรือ JSON มาใช้งานต่อ
    • SOAP Connector – พวก WSDL หรือ SOAP แบบเดิม
    • Custom – เขียน Code แล้วจัดการเองเลย

หลังจากเกริ่นนำได้ทดสอบ ตัว Connector แต่ละตัวกันแล้ว ตอนนี้มาดูตัวอย่างดีกว่าครับ โดยตัวอย่างที่ผมเขียนเป็นการใช้งาน HTTP Connector โดยใช้วิธี GET และผลลัพธ์ที่ได้ออกมาเป็นไฟล์ JSON ครับ เอาหละมาดูกันเลย ว่าเรา HTTP Connector แบบต้องใส่อะไรไปบ้าง

  • url => บอกว่าให้ไปเอาข้อมูลมาจาก Domain ไหน อะไร ถ้าเป็นแบบ GET ต้องยัด Parameter ลงไปในนี้ด้วยครับ
  • method => อันนี้กำหนดเป็น GET
  • header => บอกว่า Request ของเรามีอะไรบ้าง โดยกำหนดเป็น Key
    • key => Accept
    • value => application/json
  • payload => ไม่จำเป็นสำหรับ Method GET นะครับ ใส่เข้าไป จากการที่ลองไล่ Code ดูมันไม่ได้สนใจนะครับ

มาดูตัวอย่างกันบ้างดีกว่าครับ โดยผมทำเป็น Process ของการดึงข้อมูลของกระทู้ครับ

  • ข้อมูลจะถูก Mock มาจาก Open Source จาก https://jsonplaceholder.typicode.com/ อันนี้ผมเอาข้อมูล Mock จากตัว Web เลยครับ โดยใช้ URL https://jsonplaceholder.typicode.com/posts ซึ่งข้อมูลที่ได้มีผลลัพธ์ ดังนี้
  • Note: แต่เราสนใจเฉพาะ Id นะครับ ไม่ได้ ดึงมาหมด ดังนี้ URL อยู่ในรูป  https://jsonplaceholder.typicode.com/posts/<POST-ID>
  • ตัว BPMN Process – เดี๋ยวจะกล่าวในช่วงถัดไปครับ

มาเจาะลึกที่ BPMN Process ครับ ประกอบด้วย Task ย่อย 3 Task ครับ

  • Task “Enter Post Id” : เป็น User Task ให้ User กรอก Id ของ Post ที่ต้องการเรียกดูครับ
  • Task “Test REST-API (GET)” : สำหรับ Task นี้ เป็น Service Task ครับ โดย Task นี้เป็นพระเอกเลยครับ เพราะใช้เชื่อมกับ Web Service ครับ
    • กำหนด Config เป็น Connector
    • ภาพรวมของข้างในของ Connector
    • มาดูที่ส่วน Input ของตัว Connector ครับ
      • Connector-Id : ต้องเป็น http-connector เท่านั้น ห้ามตั้งชื่อเองนะครับ Engine ไม่รู้จัก
      • URL – สังเกตุว่า ผมไม่ได้ Map เป็น Text ครับ ผมใช้เป็น Script แทน เพราะต้องการเอา Post Id เช่น 1  จากตัวแปรของ Process ${PostId} มาใส่ต่อท้าย URL ตามคำสั่ง ดังนี้

        ภาพรวมของ URL
      • Method
      • Header
    • การจัดการ Output ครับ – ผลลัพธ์ของ Web Service อยู่ในรูปของ JSON ซึ่งผมจะเก็บไว้ใน postResult ครับ

      • แต่เนื่องจาก ผมต้องการเอาผลลัพธ์ที่เป็น JSON มายังลงใน Variable ของ Process ครับ เพื่อเอาไปแสดงผลใน Task ถัดไปครับ เลยต้องทำเป็น Script เพื่อกำหนดค่าครับ
  • Task “View Result” : เอาผลลัพธ์ที่ได้มาแสดงผลครับ โดยมีการ Config ดังนี้
  • BPMN Model สามารถดูได้จาก GitHub เลยครับ

ทดสอบครับ

  • Task “Enter Post Id” : ดึงข้อมูลของ Post Id 2
  • Task “Test REST-API (GET)” : หน้าที่ของ Engine ทำครับ เราต้องจัดการอะไร
  • Task “View Result” :

จบไปแล้วกับการงมๆ Web Service กับ BPMN ครับ โดยผมคิดว่าคงใช้ json-server ซึ่งเป็น Standalone JSON Mock REST-API มาใช้ทำ Thesis ครับ

 

[BPMN] ลองคิดตัวอย่างของ Completion Condition กัน

พอดีช่วงนี้ได้ลองเล่น BPMN แล้ว ปัญหาที่สำคัญของ Spec ตัว BPMN เอง คือ ตัวอย่างน้อย และไม่ครอบคลุมตามคุณสมบัติที่ได้ระบุไว้ใน Spec ครับ อย่างที่ผมโคตรงง ตอนนี้ คือ Attribute ของ Multi-Instance ของ Task ครับ ลองมาคิดตัวอย่างกันดีกว่าครับ

  • Task “Monitor Shipment” – Completion Condition คือ
    • สินค้าถึงจุดหมายปลายทางแล้ว
  • Task “Approval TOR” – Completion Condition คือ
    • คณะกรรมการ 2 ใน 3 ของทั้งหมดอนุมติ
  • Task “Process Transaction” – Completion Condition คือ
    • ยอดรวมของทุกสินค้า และบริการทั้งหมดต้องเกินจาก Budget ที่ตั้งไว้ หรือ ทุก Transaction สามารถประมวลผลได้ โดยไม่มีปัญหา
    • ** ถ้าเกินจาก Budget เข้า Flow การตัดสินใจของ User
    • ** ถ้าไม่เกินส่งต่อให้ Supplier จัดการ

เดี๋ยวคิดออกอีกแล้วมาเขียนเพิ่มครับ

[BPMN] ลองใช้ Process ที่ได้เพิ่งสร้างกัน

จาก Blog ตอนก่อนหน้าที่เราได้ทำอะไรไปหลายๆอย่าง ทั้ง

มาใน Blog ตอนนี้ เรามาใช้ ลองเป็น End-User ของ Process ที่ทำครับ โดยหลังจาก Deploy Process เราต้องเข้าในส่วนของ Activiti Task กันครับ มาทวนภาพรวม Process กันก่อนครับ ดังรูป

เริ่่มลองใช้งาน Process โดยต้อง Login เป็น User ที่อยู่ใน Group Employee ครับ

สวมบทบาทเป็น Employee  กันครับ

  • Login เข้าระบบด้วย User ที่อยู่ใน Group Employee ครับ
  • เข้ามาที่ เลือก Task App ครับ
  • มา Start Procrss ที่ Deploy ไว้กันเลย
  • เจอ Process ที่สร้างไว้แล้ว เลือกเลยครับ
  • ตรงนี้ เราเห็นแล้วว่า Active Process ขึ้นมาแล้วครับ

    • ถ้ากด Show Diagram เห็นว่า Task นี้ ยังอยู่ที่ Employee Request Budget ครับ
  • ถ้าต้องการทำ Task ใน Process นั้น ให้ Double Click ที่ Active ซึ่งถ้าต้องการทำ Process ต่อก็สามารถกด Claim ได้เลยครับ
  • จากนั้นกรอกข้อมูลที่จำเป็นลงไปครับ
  • พอกลับมาดูที่ Process ตอนนี้ Active Task อยู่ที่ Manager แล้วครับ

    • ถ้ากด Show Diagram เห็นว่า Task นี้ ยังอยู่ที่ Manager Review / Approve ครับ เพราะ วงเงินที่ขอไว้เกินกำหนด 1,000 บาท
  • สังเกตุดีๆครับ ตอนนี้ Assigned to nobody ครับ ให้เพิ่มคนที่อยู่ในกลุ่ม Manager ดังนี้
    • เลือก Involve someone else and start collaborating
    • จากนั้นเลือก User ในกลุ่ม Manager ครับ

Manager เข้ามา Claim Task ว่าจะอนุมัติ หรือไม่ ?

  • Login เข้าระบบด้วย User ที่อยู่ใน Group Manager ครับ
  • พอเข้ามาที่ Task App จะเจอว่ามี TaskManager Review / Approve รออยู่ครับ
  • Manager Claim Task นั้นไปครับ
  • ปรากฏว่า Manager ไม่อนุมัติ (แล้วจะทำอย่างไรต่อ !!!)
  • ตอนนี้ Process เลย วนกลับไปที่ Employee ให้ใส่ข้อมูลวงเงินมาใหม่

เมื่อ Employee แก้ข้อมูลใหม่ แล้วส่งงานกลับมาให้ Manager

  • ตอนนี้ ถ้าสังเกตุ Complete Task หลังจาก Employee ใส่ข้อมูลมาใหม่แล้ว
  • หลังจาก Manager อนุมัติแล้ว งานส่งต่อไปให้กับฝ่ายบัญชี-การเงินครับ

เมื่อฝ่ายบัญชีจัดการเสร็จแล้ว จบกระบวนการ

  • Login เข้าระบบด้วย User ที่อยู่ใน Group Accountant ครับ
  • พอมาดูที่ Task Manager ส่งงานมาให้แล้วครับ (เพราะ วงเงินที่ขออนุมัติแล้ว)
  • จากนั้น Claim Task
  • แต่เนื้องจาก Task นี้เป็น Task สุดท้ายแล้ว และก็ไม่มีิ Process อะไร นักบัญชีเลยกด Complete Task ไปครับ

จบไปแล้วกับ Blog เรื่องยาวครับ แม้ว่า Process ที่ทำเป็น Demo อาจจะไม่สมจริงเท่าไหร่นะครับ หากทุกท่านอ่านแล้วสงสัยอะไร สามารถทักมาได้ หรือทวงติงกรณีที่ผมเขียนผิดครับ ^__^

 

 

[BPMN] ลองเอา Process ที่ทำมา Deploy ขึ้นกัน

จาก Blog ก่อนหน้านี้ที่ได้ลองสร้าง Process ไปแล้ว คราวนี้ลองเอา Process ที่ทำ มาผูกให้เป็น Application โดยใช้ Activiti-App ตัว Kick Start ครับ เนื่องจาก Form ที่ทำโดยใช้ Activiti Designer ยังไม่สมบูรณ์ครับ เลยต้องเอามาปรับปรุงใน Kick Start  โดยการเพิ่ม Form ลงไป เพราะใน Process ที่ทำไว้ก่อนหน้านั้น เราได้กำหนดแค่ภาพรวม Workflow ไว้แล้ว

จริงๆมาสร้าง Workflow ในตัว Kickstart ได้เลยนะ ไม่ต้องผ่านตัว Eclipse Designer ก็ได้ครับ

เพิ่ม User และ Group ที่เกี่ยวข้อง

  • ถ้าดูจาก Process ได้สร้างขึ้นมา มีกลุ่มคนที่เกี่ยวข้องอยู่ 3 กลุ่ม ได้แก่ Accountant, Employee และ Manager ตามรูปเลย
  • สิ่งที่ต้องทำ คือ ทำให้ User และ Group เหล่านี้ มีตัวตนจริงๆ บน BPMN Engine โดยการเพิ่มเข้าไปในส่วนของ Identity management จากตัว Activiti-App เข้าทาง localhost:8080/activiti-app (ถ้ามีการเปลี่ยน Port หรือ URL ปรับแก้ให้ตรงกับที่ติดตั้งด้วย)
    • เพิ่ม User อันนี้ยัดได้ตามใจเลย
    • เพิ่ม Group ได้แก่ Accountant, Employee และ Manager
  • ถ้าทำตามนี้มี User ในแต่ละ Group ประมาณนี้

มาปรับ Process ให้ตามขั้นตอน ดังนี้

  • เพิ่ม GUI Form
    • ใน Activity Employee Request Budget สำหรับ Employee ในกรอกจำนวนเงินที่ต้องการขอเบิก
      • เลือก Activity ก่อน มาดูในส่วนของ Panel ข้างล่าง เลือก Reference Form
      • เลือก New Form
      • จากนั้นลาก Number Control
      • และกำหนด Property ตามรูป
      • **ข้อควรระวัง: ให้กำหนด Id ของ Control ให้ตรงกับ Condition ที่เขียนไว้ ซึ่งที่ส่วนที่นำไปใช้ต่อ คือ Sequence Flow ที่มี Conditional Expression ดังนี้
      • จากนั้นกด Save
    • ใน Activity  Manager Review / Approve สำหรับให้ Manager ตรวจทาน และอนุม้ติ ผลการร้องขอเบิกเงิน
      • เลือก Activity ก่อน มาดูในส่วนของ Panel ข้างล่าง เลือก Reference Form
      • เลือก New Form
      • จากนั้นลาก Drop Down Control
      • และกำหนด Property ตามรูป
      • อย่าลืมใส่ Option Value เพื่อเอาไปใช้งานกับ Sequence Flow ต่อไป
      • จากนั้นกด Save
  • ปรับเรื่อง Owner ในแต่ละ Actvity ให้ลงตาม Group – ในที่นี้ยกตัวอย่างของ Activity  Accountant Acknowledge โดยต้องให้ User ที่อยู่ในกลุ่ม Accountant เข้ามาจัดการครับ ส่วนที่ Group เหลือ Employee และ Manager ลองปรับตามได้
    • เลือก Activity  Accountant Acknowledge  ก่อน มาดูในส่วนของ Panel ข้างล่าง เลือก Assignments
    • โดยเจ้า Assignments เลือกได้ 2 แบบ
      • Fixed Values – กำหนดค่าลงไปเลย
      • Identity Store – ใช้ User & Group ที่ได้สร้างในตัว  Identity management โดยในที่นี้ใช้วิธีการนี้
    • กำหนด Candinate Group
    • เลือก Group ที่ต้องการในที่นี้ กลุ่ม Accountant

แปลง Process เป็น App เพื่อ Deploy

  • ใน Activiti-App ในส่วน KickStart ให้เลือก App จากนั้นเลือก Create App
  • กำหนดข้อมูลทั่วไปของ App จากนั้นกด Create ดังรูป
  • กำหนดสี และรูป
  • รวมถึง Process Definiton ที่ต้องการใช้
  • กด Save มีให้แก้ข้อมูลของ App รวมถึงการกด Publish เพื่อประกาศใช้งาน

หลังจาก Deploy (Publish Process ขึ้นไปแล้ว) ต่อไปจะเป็น Blog ที่ลอง Execute Process ที่ได้สร้างขึ้นมาครับ

 

[BPMN] Activiti สร้าง Unit Test

หลงจาก Blog ตอนที่แล้ว ที่ได้สร้าง Process ของการขอเบิกเงินไปแล้ว ตอนนี้เราต้องมา Proof ก่อนว่า Process ที่ทำนั้น มันใช้งานได้จริงๆ พร้อมที่นำไป Deploy ขึ้น Activiti Server ครับ โดยมีขั้นตอน ดังนี้

Step 1 : กำหนดโครงสร้างไฟล์ที่เกี่ยวข้องกันก่อน

Step 2 : สร้างไฟล์ Config ที่เกี่ยวข้อง

  • สร้างไฟล์แปลง Activiti Project ให้เป็น Maven Project ซึ่งมีไฟล์ pom.xml เพื่อเก็บ Dependency ต่างๆไว้ โดยสำหรับการ Test BPMN ต้องใช้ Dependency ที่จำเป็น ดังนี้
    • activiti-engine : สำหรับ Execute BPMN
    • JUnit : สำหรับทำ Unit Test
    • MySQL Connector/J : ใช้เชื่อมต่อ Database ของ activiti-engine
    • spring framework [Optional] : ในกรณีที่ต้องการใช้ Activiti กับ Spring
    • และสุดท้าย หน้าตาของไฟล์ pom.xml มี Dependency ดังนี้ครับ
  • สร้างไฟล์ activiti.cfg.xml โดยมีการกำหนดค่า ดังนี้

Step 3 : เอาไฟล์ Process มาใส่

  • เอาไฟล์ Process ที่ทำไว้ จาก Blog ตอนที่แล้วจะเป็นไฟล์ Test.bpmn เอามาวางไว้ที่ Path .../src/test/resources/ ดังรูป
  • หรืออาจจะอ้างไปที่ Path ของ project เลยก็ได้ครับ เช่น

Step 4 : สร้าง Unit Test ขึ้นครับ

  • ตั้งโครงใหม่ ให้มันเข้ากับ Activiti 6.0 และ JUnit 5 กันก่อนครับ

โดยใช้ Test แบ่งเป็นช่วงๆ ดังนี้

  • ส่วน @BeforeAll – ทำงานตอน Execute Test ครั้งแรก โดยสร้าง ActivitiRule ขึ้นมา เพื่อเตรียม Activiti-Engine ให้พร้อม
  • ส่วน @BeforeEach และ @AfterEach เป็นส่วนที่ทำงานก่อน และหลัง Test Case แต่ละอัน
    • @BeforeEach – ในที่นี้เป็นการ Deploy Process ที่เพิ่งสร้าง ให้ Activiti-Engine รู้จัก
    • @AfterEach – ในที่นี้เป็นการ ลบ หรือ Clear Process ที่เพิ่ง Deploy ออกจาก Activiti-Engine รู้จัก
  • ส่วน @Test เป็น Test Case ที่เตรียมไว้ ซึ่งมี 5 Test Case ดังนี้
    • TC1 test1ProcessIsStart – บอกว่า Process ที่ Deploy ไปพร้อมใช้งาน หรือไม่ ?
    • TC2 test2AssignValueInVariableBudgetAmount – ตอนที่สร้าง Process ขึ้นมา เราได้ยัดค่าตัวแปร BudgetAmount ลงไป โดยใน Test Case ดูจะดูว่า มันสามารถดึงค่าที่ได้ Pass เข้าไปได้ หรือไม่
    • TC3 test3AssignValueInVariableApproved – ตอนที่สร้าง Process ขึ้นมา เราได้ยัดค่าตัวแปร Approved ลงไป โดยใน Test Case ดูจะดูว่า มันสามารถดึงค่าที่ได้ Pass เข้าไปได้ หรือไม่
    • TC4 test4WhenEmployeeNeedBudgetMoreThan1K – ทดสอบตาม Scenario ที่ได้กำหนดไว้ ดังรูป
      โดย Code สำหรับทดสอบสามารถเขียนได้ ดังนี้
    • TC5 test5WhenEmployeeNeedBudgetLessThanOrEqual1K – ทดสอบตาม Scenario ที่ได้กำหนดไว้ ดังรูป
      โดย Code สำหรับทดสอบสามารถเขียนได้ ดังนี้

Step 5 : ทดสอบ Run Unit Test

  • คลิกขวาที่ UnitTest เลย ชื้อไฟล์ จากนั้น Run As >> JUnit ซึ่งทำเขียน Test ถูกต้อง ได้ผลลัพธ์ ดังนี้

ปัญหาที่เกิด

  • ทดสอบ Run Test แล้วเจอ Error java.lang.NoClassDefFoundError สามารถแก้ไขโดยเพิ่ม JUnit ที่ Java Build Path ดังรูป
  • ตอนนี้ตัว Activiti Framework ยังไม่รองรับ JUnit 5 นะครับ วิธีที่ผมแก้ มันแก้แบบลูกทุ่งไปก่อน เพราะ ตัว Class AcitiviRule มันช่วยทำให้ Test ได้ง่ายขึ้น
  • ลำดับของการ Execute Test ของ JUnit มันมั่วมากครับ