github.com/unirita/cuto@v0.9.8-0.20160830082821-aa6652f877b7/flowgen/converter/bpmn.go (about)

     1  package converter
     2  
     3  import "encoding/xml"
     4  
     5  // Definitions element in BPMN.
     6  type Definitions struct {
     7  	XMLName xml.Name `xml:"definitions"`
     8  	Process *Process `xml:"process"`
     9  }
    10  
    11  // NewDefinitions create empty Definitions object.
    12  func NewDefinitions() *Definitions {
    13  	d := new(Definitions)
    14  	d.Process = NewProcess()
    15  	return d
    16  }
    17  
    18  // AppendServiceTask appends ServiceTask object to Definitions#Process.
    19  func (d *Definitions) AppendServiceTask(task *ServiceTask) {
    20  	d.Process.Tasks = append(d.Process.Tasks, task)
    21  }
    22  
    23  // AppendParallelGateway appends ParallelGateway object to Definitions#Process.
    24  func (d *Definitions) AppendParallelGateway(gateway *ParallelGateway) {
    25  	d.Process.Gateways = append(d.Process.Gateways, gateway)
    26  }
    27  
    28  // AppendSequenceFlow appends SequenceFlow object to Definitions#Process.
    29  func (d *Definitions) AppendSequenceFlow(flow *SequenceFlow) {
    30  	d.Process.Flows = append(d.Process.Flows, flow)
    31  }
    32  
    33  // AppendJob appends job element to Definitions object.
    34  // This function returns job ID to create connection with next element.
    35  func (d *Definitions) AppendJob(job *Job, pre string) string {
    36  	s := NewServiceTask(job)
    37  	d.AppendServiceTask(s)
    38  	d.AppendSequenceFlow(NewSequenceFlow(pre, s.ID))
    39  	return s.ID
    40  }
    41  
    42  // AppendGateway appends gateway element to Definitions object.
    43  // This function returns close gateway ID to create connection with next element.
    44  func (d *Definitions) AppendGateway(gw *Gateway, pre string) string {
    45  	openGW, closeGW := NewParallelGatewayPair(gw)
    46  	d.AppendParallelGateway(openGW)
    47  	d.AppendParallelGateway(closeGW)
    48  	d.AppendSequenceFlow(NewSequenceFlow(pre, openGW.ID))
    49  
    50  	// Append inner paths.
    51  	for _, pathHead := range gw.PathHeads {
    52  		preInPath := openGW.ID
    53  		current := pathHead
    54  		for {
    55  			d.AppendJob(current, preInPath)
    56  			preInPath = current.ID()
    57  			var ok bool
    58  
    59  			next := current.Next()
    60  			if next == nil {
    61  				break
    62  			}
    63  
    64  			current, ok = next.(*Job)
    65  			if !ok {
    66  				panic("Nest of gateway detected.")
    67  			}
    68  		}
    69  		d.AppendSequenceFlow(NewSequenceFlow(preInPath, closeGW.ID))
    70  	}
    71  	return closeGW.ID
    72  }
    73  
    74  // Process element in BPMN.
    75  type Process struct {
    76  	Start    *StartEvent        `xml:"startEvent"`
    77  	End      *EndEvent          `xml:"endEvent"`
    78  	Tasks    []*ServiceTask     `xml:"serviceTask"`
    79  	Gateways []*ParallelGateway `xml:"parallelGateway"`
    80  	Flows    []*SequenceFlow    `xml:"sequenceFlow"`
    81  }
    82  
    83  // Create empty Process object.
    84  func NewProcess() *Process {
    85  	p := new(Process)
    86  	p.Start = NewStartEvent()
    87  	p.End = NewEndEvent()
    88  	p.Tasks = make([]*ServiceTask, 0)
    89  	p.Gateways = make([]*ParallelGateway, 0)
    90  	p.Flows = make([]*SequenceFlow, 0)
    91  	return p
    92  }
    93  
    94  // StartEvent element in BPMN.
    95  type StartEvent struct {
    96  	ID string `xml:"id,attr"`
    97  }
    98  
    99  // Create StartEvent object with unique ID.
   100  func NewStartEvent() *StartEvent {
   101  	s := new(StartEvent)
   102  	s.ID = ":start"
   103  	return s
   104  }
   105  
   106  // EndEvent element in BPMN.
   107  type EndEvent struct {
   108  	ID string `xml:"id,attr"`
   109  }
   110  
   111  // Create EndEvent object with unique ID.
   112  func NewEndEvent() *EndEvent {
   113  	e := new(EndEvent)
   114  	e.ID = ":end"
   115  	return e
   116  }
   117  
   118  // ServiceTask element in BPMN.
   119  type ServiceTask struct {
   120  	ID   string `xml:"id,attr"`
   121  	Name string `xml:"name,attr"`
   122  }
   123  
   124  // Create ServiceTask object from job element.
   125  func NewServiceTask(job *Job) *ServiceTask {
   126  	s := new(ServiceTask)
   127  	s.ID = job.ID()
   128  	s.Name = job.Name()
   129  	return s
   130  }
   131  
   132  // ParallelGateway element in BPMN.
   133  type ParallelGateway struct {
   134  	ID string `xml:"id,attr"`
   135  }
   136  
   137  // Create pair of ParallelGateway to open and close parallel paths.
   138  // This function has two return values.
   139  // First one is gateway for open, second one is gateway for close.
   140  func NewParallelGatewayPair(gw *Gateway) (*ParallelGateway, *ParallelGateway) {
   141  	const (
   142  		openSuffix  = "_open"
   143  		closeSuffix = "_close"
   144  	)
   145  
   146  	openGW := new(ParallelGateway)
   147  	openGW.ID = gw.ID() + openSuffix
   148  	closeGW := new(ParallelGateway)
   149  	closeGW.ID = gw.ID() + closeSuffix
   150  	return openGW, closeGW
   151  }
   152  
   153  // SequenceFlow element in BPMN.
   154  type SequenceFlow struct {
   155  	From string `xml:"sourceRef,attr"`
   156  	To   string `xml:"targetRef,attr"`
   157  }
   158  
   159  // Create SequenceFlow
   160  func NewSequenceFlow(from, to string) *SequenceFlow {
   161  	s := new(SequenceFlow)
   162  	s.From = from
   163  	s.To = to
   164  	return s
   165  }