2007年7月2日月曜日

grails でワークフロー (手で書く編3)

前述した組織モデルを前提として, jbpm を使ったワークフローを実現してみる.


では, ワークフローを定義する方法を決めましょう.



例えば Meeting というワークフローを表すクラスの名前は MeetingWorkflow ということにして, まずは controllers に置くことにします (Controller という sufiix は付きませんが).



その中身はこういう感じで, 状態機械に似ています.



import jp.co.metabolics.jbpm.grails.ProcessDefinition

import org.jbpm.graph.exe.ProcessInstance

import org.jbpm.graph.exe.Token



import jp.co.metabolics.jbpm.grails.ActionHandler

import jp.co.metabolics.jbpm.grails.AssignmentHandler

import org.jbpm.graph.exe.ProcessInstance

import org.jbpm.graph.exe.ExecutionContext

import org.jbpm.taskmgmt.exe.Assignable



/*

* convention として Workflow という名前にする.
現在は grails-app/controllers に置いているが,workflows などにするかもしれない.

*/

class MeetingWorkflow implements AssignmentHandler, ActionHandler {

// 実際には def workflow (WorkflowBuilder で作成またはリソース名を表す文字列) だけ書けばよい.

// ここでは ProcessDefinition になっている.

def workflow = {

def writer = new StringWriter()

def b = new groovy.xml.MarkupBuilder(writer)

b.'process-definition'(name:'meeting') {

swimlane(name:'promoter')

swimlane(name:'participant')

b.'start-state'(name:'start') { transition(to:'propose') }

b.'end-state'(name:'end')

b.'task-node'(name:'propose') {

task(name:'propose', swimlane:'promoter')

transition(to:'confirm')

}

b.'task-node'(name:'confirm') {

task(name:'confirm', swimlane:'participant')

transition(to:'decide')

}

b.'task-node'(name:'decide') {

task(name:'decide', swimlane:'promoter')

transition(to:'end')

}

}

ProcessDefinition.parseXmlString(writer.toString())

}



// 以下は dynamic に inject される.

private processInstance

private token



MeetingWorkflow() {

processInstance = new ProcessInstance(workflow())

token = processInstance.getRootToken()

}



void execute(ExecutionContext executionContext) {

def taskName = executionContext.getToken().getName()

def meeting = executionContext.getVariable('meeting')

// これらの情報からタスクを作って, 適切な inbox に入れる

// 例えば URL. jp.co.metabolics.inbada/meeting/propose/123/...

// アプリケーション名 (context path) /ワークフロー名/タスク名/id にリダイレクトすればよい

// grails の controller の仕組みが全部使える (はず)

// taskInstance も覚えておく必要があるが (end), そのためには jbpm の DB に直接アクセスする必要がある?

}



void assign(Assignable assignable, ExecutionContext executionContext) {



}



def start = { token.signal() }

}


書くべきことは状態機械と同様, ワークフローの定義 (workflow) のみです. 後は動的注入可能 (今はそうなっていませんが:-) です.



ユーザが自分の tasklist に入ったタスクを選択すると, それに対応する controller/action に飛ぶことになります.