Question
· Jun 18, 2023

What are The Business Operation's Messages Types?

Hi devs!

How one can understand the classnames of request and response messages of a given operation?

E.g. when I build the data transformation, how do I know which message will come to the operation?

And which message type will be returned from operation without looking into the source code of the class?

Product version: IRIS 2023.1
Discussion (15)2
Log in or sign up to continue

Hi Evgeny,

Historic message type flows can be seen with:

SELECT %NOLOCK DISTINCT SourceConfigName,TargetConfigName,MessageBodyClassName
FROM Ens.MessageHeader
ORDER BY SourceConfigName,TargetConfigName,MessageBodyClassName

For a running production with Testing enabled, the Test Action launches a dialog with drop-down list of test message types handled by an operation.

See: Class EnsPortal.Dialog.TestingService with classmethod GetValidRequestTypeList

A pattern I have noticed implemented for processing generic XML Streams is for a property to be exposed in the business operation that configures a list of expected ClassNames ( supporting %XML.Adapter ) to correlate.

An interesting question for 3rd-party providers of interoperability components.

Maybe this is suggesting a "New Transform" Wizard could be aware of the production in focus.

In some implementations due to the visibility of notes in the management portal, these may be directed more at a "support role" than a "developer role" for which the organizations may be different. So some empathy with removing the dev teeth from descriptions where they might be confusing, outside an operational support context. Possibly would be beneficial to have different types of production visible notes.

Hi Evgeny,

If the operation class is using the mechanism in Ens.BusinessOperation to route incoming requests to the OnMessage() method, you can use the XData content to get a list of supported request (just as the Portal testing dialog does). If the operation class implements it’s own custom OnMessage(), there is no simple way to tell what request classes are supported. The XData is described in the documentation.

For responses, there is a RESPONSECLASSNAME parameter defined in classes extending Ens.Request. I believe this used by the BPL editor. This is somewhat limited however, since the operation can as well respond with any %RegisteredObject object and accept any kind of request (via OnMessage), e.g. any class extending %RegisteredObject if it is marked as "in process".

Anyways, as Robert C. points out, documenting what the operation intent is and it's interface, especially if they are not trivial, helps a lot and IMHO is best practice.

Thanks, Robert!

Anyway I think every operation should expose these classes: request class and response class. They are like interfaces of a given service or operation.

And once I start building a transformation where it is known where the router gets the message(response) from and where it directs it the data transformation builder could show these message classes on the source and target parts of the transformation. This will safe a significant amount of developers' time.

If we think how this could be implemented, what about extending Operations with MessageClasses class, that will add two properties RequestClass and ResponseClass, that could be overridden with a proper class types by Operation developer?

This is crucial if we have a lot of 3rd party Operation and Services builders.

I agree that developers need this information presented in a better way, but I'm thinking the approach would be to have the UI read the Message Map rather than adding properties to the Operation class.  Here's my reasoning.

One concern with this idea is that a Business Operation can accept many kinds of request messages. In a sense the Business Operation doesn't actually have a request message at all.  It's the individual methods within the Operation that do, and the Message Map specifies how they align.

I suppose the Operation class could have a property for each method-level request class, but that doesn't seem to be very helpful.  To make it useful there'd need to be a way to match the properties with their respective methods, such as by naming convention.

Even then, it would just be a form of documentation because the Operation code has no technical need for properties of that kind.

We could certainly rework things so it does use them, but that seems forced and I think it would make things more complicated rather than simpler. For one thing, it would mean that the calling framework needs to set the correct property of the Operation object based on what method it's about to call.  Then it needs to clear the reference after the method returns.  If you didn't clear the reference it would persist until the next call to that method, in the meantime preventing the request object from being garbage collected.  That could cause any number of problems related to resources like locks, network connections, file handles, etc. not being released.  You'd have similar bookkeeping for the response message if you moved that to a property.

OK. Lets just do this already !!

This example uses Properties and Settings to expose the Request and Response Types so they are viewable from the Management Portal:

This is achieved with the following code:

Class Test.Operation Extends Ens.BusinessOperation
{
Parameter ADAPTER = "EnsLib.HTTP.OutboundAdapter";
Property Adapter As EnsLib.HTTP.OutboundAdapter;
Parameter INVOCATION = "Queue";
Property RequestTypes As %String(MAXLEN = 4000) [ InitialExpression = {..GetRequestTypes()}, Transient ];
Property ResponseTypes As %String(MAXLEN = 4000) [ InitialExpression = {..GetResponseTypes()}, Transient ];
Parameter SETTINGS = "RequestTypes:Info,ResponseTypes:Info";

ClassMethod GetRequestTypes()
{
  set ret=""
  set messageTypes=..GetMessageList()
  quit:messageTypes="" ret
  for i=1:1:$LL(messageTypes) {
    set ret=ret_$C(13,10)_$LI(messageTypes,i)
  }
  quit ret
}

ClassMethod GetResponseTypes()
{
  set ret=""
  set messageTypes=..GetResponseClassList()
  quit:messageTypes="" ret
  for i=1:1:$LL(messageTypes) {
    set ret=ret_$C(13,10)_$LI(messageTypes,i)
  }
  quit ret
}

XData MessageMap
{
<MapItems>
  <MapItem MessageType="Ens.StringRequest"> 
    <Method>DoOne</Method>
  </MapItem>
  <MapItem MessageType="EnsLib.HL7.Message"> 
    <Method>DoTwo</Method>
  </MapItem>
</MapItems>
}

Method DoOne(request As Ens.StringRequest, response As Ens.StringResponse)
{
}

Method DoTwo(request As EnsLib.HL7.Message, response As EnsLib.HL7.Message)
{
}
}

How it works.

The Getter methods populate the Properties ( RequestTypes, ResponseTypes ) via InitialExpression

These Properties are exposed to the User Interface via the SETTINGS parameter

Note also I have set the MAXLEN of the properties over 2000K characters. This forces the Management Portal to render a TextArea instead of a single line Text input control.

The reuse pattern is to have this code in a class.

Then can add behavior via extends to inherit this behavior.

Class Test.NewOperation2 Extends (Ens.BusinessOperation, Test.Operation)
{
Parameter INVOCATION = "Queue";
}

IRIS is so flexible :)