Question
· Aug 22, 2017

How to include process context in data transformations

I have been building Business Processes in Ensemble for a few months and in a process i'd use a combination of data from the request that started the process and context variables that where filled by earlier calls in the process as input for a data transformation. I do not know how to achieve that.

What I do currently is that in my process I first call a data transformation and then make a call to an operation. For the data transformation I use as input the request that started the business process and as output the request that I will use to initiate the call to the operation. The latter I define as a context-object in my process. Thus I end up with something like this:

Process-parameters:

  • Request: MyProcess.StartProcessRequest
  • Response: Ens.Response
  • Context-fields
    • Context.CallOperationRequest = MyOperation.CallOperationRequest

Process-flow:

Step 1: Data transformation

  • Input: MyProcess.StartProcessRequest
  • Output: Context.CallOperationRequest
  • Annotation: This step prepares the request for step 2.

Step 2: Call MyOperation

  • Request of type: MyOperation.CallOperationRequest
  • Mapping:
    • Context.CallOperationRequest -> target.CallRequest
  • Annotation 2: This step calls MyOperation using the request prepared in step 1.

Insofar this works fine. But with more complex process I want to prepare operation-callrequests which use data both from MyProcess.StartProcessRequest and output from previous operations which are stored in context-variables. However I do not know how I setup properly a single data transformation that transforms data from both the request and the context to my operation-callrequest. According to the comment posted below. Something like this should be possible. Can someone explain. I.e. I am looking for something along the following lines:

Process-parameters:

  • Request: MyProcess.StartProcessRequest
  • Response: Ens.Response
  • Context-fields
    • Context.CallOperationRequest = MyOperation.CallOperationRequest
    • Context.StringOutputOperationX = %String

Process-flow:

Step X: Call operationX

  • Response mapping:
    • -> Fills Context.StringOutputOperationX

Step X+1: Data transformation

  • Input: Somehow MyProcess.StartProcessRequest + Context.StringOutputOperationX
  • Output: Context.CallOperationRequest
  • Annotation: This step prepares the request for step X+2.

Step X+2: Call Data transformation

  • Request of type: MyOperation.CallOperationRequest
  • Mapping:
    • Context.CallOperationRequest -> target.CallRequest
  • Annotation: This step calls MyOperation using the request prepared in step X+1.

I have been building Business Processes in Ensemble for a few months and I was wondering what the best design pattern is for complex multistep process. For instance, imagine you start a process with request A and in that process you call operations B, C, and D. Now operation B returns variable X which is used later as input for operations C and D. Now, the main challenge I have is that intuituively you would define a context in the process to put variable X in. However, when mappings for callrequests to operations C and D grow complex you'd like to prepare them with a data transformation (as they somehow have more elaborate functionality than the callrequest mappings), and ideally you like to put the complete mapping in a single datatransformation. However, I think that in Ensemble this is not possible if you have data from request A and from the process context as input for callrequests of subsequent operations (e.g. C and D). Thus, preparing such a call request quickly results in a multi-step process where you first run a data transformation on the initial process request A and then add in all context variables. To me this feels unnecessary cumbersome, so I have thinking about patterns that could make this a bit more clean. However, none of the patterns I have thought up are entirely satisfactory so I was really wondering what the approach was of the more experienced Ensemble process modellers.

These are the patterns I have come up with:

Multi-process pattern:

Here I design a twostep process. The first process starts with request A and calls operation B and then calls a second process which is responsible for calling operations C and D. The advantage here is that you can initiate the second process with a request A+ which contains the variable X from operation B. Consequently, you can do a single data transform from request A+ to C and a single data transform from A+ to B. The disadvantage is that this works nicely for this case but if you have  a case where operation B gives input for operation C which in turn gives input for operation D, etc. you end up with a number or processes equal to the number of operations. In my opinion this is far from clean.

Super-request pattern:

The idea here is that instead of returning inputs from operations to a context, you return them to the request that started the process. Of course, the request that started the process should be expanded to hold these variables. I hoped this should allow you to use a single data transformation to initiate each subsequent call, however, I just found out that this solution doesn't work at all because you can update the initial request with the output from an operation in that process and pass it immediately to the next step, the updated request message isn't stored in the database so when the process goes to sleep again the request "reverts back" to the original request that started the process and losses the output from operation B.

Two-step data transformation

Prior to calling an operation (e.g. C, or D) call a data transformation from request A to the request for the operation. Then use a code block to add in all context variables from previous operations in one step. This should keep preperation of all callrequests down to two steps. 

Other options

As far as I know it is not possible to use the context of a process as input for a data transformation. If I am wrong i'd like to know.

Discussion (6)1
Log in or sign up to continue

I need to spend more time thinking about what you're trying to accomplish, but this comment specifically caught my eye:

As far as I know it is not possible to use the context of a process as input for a data transformation. If I am wrong i'd like to know.

Context variables defined within the process are available to DTLs invoked within the BPL. And you can of course use context variables to reference objects and pass them to DTLs as source or target objects. Not sure that this is what you were getting at, though.

Well yes that works! I can refer to a context.MyString in any Data Transformation and when I use that Data Transformation in a business process that has a context.MyString defined it 'magically' works. I must say that I find this very unintuitive because when you test the data transformation using the test-button in the data transformation it actually errors because it doesn't know the context:

ERROR <Ens>ErrException: <UNDEFINED>zTransform+84^Calarm.Transformation.CreateCreateAccountRequest.1 *context -- logged as '-' number - @' Set zVALz=context.MyString, zVALz=$S($IsObject(zVALz):zVALz.%ConstructClone(), 1:zVALz)'

I got that error when trying to use the following input message with and without the context element:

<test>
  <context>
    <MyString>123</MyString>
  </context>
  <UserRegistrationRequest>
      <Customer>
          <Initials>P.</Initials>
          <Gender>M</Gender>
          <DateOfBirth>1983-01-01</DateOfBirth>
      </Customer>
  </UserRegistrationRequest>
</test>

So, assuming you've defined the context variables on the Context tab of the BPL, they're visible/accessible as objects with DTL called from the BPL, just like variables you define within the DTL. You can treat them just like any other variable of the defined Type:

 

Given the example from the screenshot, you can reference cvisCurrMessage as context.cvisCurrMessage within the DTL and use any methods or properties associated with its class. context.cvisCurrMessage.GetValueAt("MSH:10"), for example, returns the value of the MSH:10 field of the HL7 message referenced by context.cvisCurrMessage.

The one thing you have to be very careful about is synchronous vs. asynchronous calls to operations. You can't be guaranteed that the response object will be populated in a timely fashion when invoking the operation asynchronously, and sometimes even synchronously if you're using the BPL <call> object. You'll want to invoke the operation via the process.SendRequestSync() method in a <code> object to keep things sequenced properly.

Does that help? (if yes, please mark this response as your answer :D)

Hi guys

I'm trying something similar to this. I am call a bpl from another bpl.

When I do a trace for a context variable in the second bpl it shows up as empty.

I've also set the context super class in the 2nd bpl to be the context of the first one. I can see the context properties in the 2nd one in settings but they don't seem to be passed over.

How can I get the context of the main bpl?

Hope this makes sense...

Regards