> Would you have three branches for the code or 3 repo's.
Please describe differences between your DEV, TEST, PROD code. Still, I'd probably recommend one repo and 3 branches.

>Would you have three projects in Atelier to communicate with the environments and GitHub?
No, there would be one Atelier project for DEV. All other code propagation should be done automatically by Continuous Integration/Continuous Delivery solution.

That may mean one of the several things:

  • You're not specifying or specifyiong incorrectly one or several request header parameters. One of the most often encountered errors is not specifying ContentType as application/json.
  • Request content is formed incorrectly

Anyway, to solve this problem you need to make a correct request to the target system, record it and compare to the Ensemble request. Here's an article on that.

Same as with modifying a rule:

Business Rule Definition is stored as XML in XData block named RuleDefinition inside rule class and can be (de)serialized as an object of Ens.Rule.Model.ruleDefinition class. Some utility methods are available there.

Here's an example of modifying Demo.ComplexMap.Rule.SemesterBatchRouting rule in ENSDEMO class. It modifies "when" condition from 1 to 0.

zn "ENSDEMO"
set ruleClass = "Demo.ComplexMap.Rule.SemesterBatchRouting"
set sc = ##class(Ens.Rule.Model.ruleDefinition).LoadFromClass(ruleClass, .rule)
set rule.ruleSets.GetAt(1).actions.GetAt(1).whens.GetAt(1).condition=0
w rule.SaveAs(ruleClass)
set sc=$system.OBJ.Compile(ruleClass,"k-d")
But instead of:
set sc = ##class(Ens.Rule.Model.ruleDefinition).LoadFromClass(ruleClass, .rule)

You need to create and fill rule object manually.

Relevant discussion.

  1. Source control
  2. Code
    • Sure, I've done something similar. Here's the code.
    • Missed that, sorry.
  3. Ensemble
    • Sure, Inside your production you have access to all BO properties, including retry-relevant:  ..RetryCount, ..%LastReportedError and many others. So first you determine if the current message is a retry (..RetryCount>0) or not and then you can decide what to do with your request based on that.

 

Code for the custom adapter that specifies Content type:

Class Production.Adapter.HTTPOutboundAdapter Extends EnsLib.HTTP.OutboundAdapter
{

Method Post(Output pHttpResponse As %Net.HttpResponse, pFormVarNames As %String, pData...) As %Status
{
    quit ..SendFormDataArray(.pHttpResponse, "POST", ..GetRequest(), .pFormVarNames, .pData)
}

ClassMethod GetRequest() As %Net.HttpRequest
{
    set request = ##class(%Net.HttpRequest).%New()
    set request.ContentType = "application/json"
    quit request
}

}

Note that this way only one-line method Post gets redefined (you'll also need to redefine Get method, but still - these are small one-line methods). ContentType may be further refactored as a setting.

Some comments

  1. Source control
    • Each class should be in a separate file. There are many source control hooks available.
    • When redefining system methods like SendFormDataArray method in DLS.HTTP.OutboundAdapter class it's better to do it in two commits - in a first one you just copy method as is and in a second you modify it. It's easier to understand "what changed?" that way (via git blame).
  2. Code
    • Do not subclass/modify system methods if it's possible. What was modified SendFormDataArray?
    • Add comments to the parts you change when you must subclass/modify system methods.
    • $CLASSNAME($THIS) is equal to $CLASSNAME()
  3. Ensemble

Business Rule Definition is stored as XML in XData block named RuleDefinition inside rule class and can be (de)serialized as an object of Ens.Rule.Model.ruleDefinition class. Some utility methods are available there.

Here's an example of modifying Demo.ComplexMap.Rule.SemesterBatchRouting rule in ENSDEMO class. It modifies "when" condition from 1 to 0.

zn "ENSDEMO"
set ruleClass = "Demo.ComplexMap.Rule.SemesterBatchRouting"
set sc = ##class(Ens.Rule.Model.ruleDefinition).LoadFromClass(ruleClass, .rule)
set rule.ruleSets.GetAt(1).actions.GetAt(1).whens.GetAt(1).condition=0
w rule.SaveAs(ruleClass)
set sc=$system.OBJ.Compile(ruleClass,"k-d")

That said, I think the better approach would be to use (in order of
increasing implementation difficulty):

  • Context Class
  • Temporary Variables
  • Rule Assist Class

So the rule by itself does not change but values supplied by Context Class/Temporary Variables/etc do.

This condition:

Super [ 'Persistent' 

Is insufficient. Consider this case:

Class Package.ClassA Extends %Library.Persistent
{
}

Class Package.ClassB Extends %XML.Adaptor
{
}

Class Package.ClassC Extends (ClassA, ClassB)
{
}

While Package.ClassC satisfies both conditions (it's a subclass of both %Library.Persistent and %XML.Adaptor), it would not be returned by the SQL query, as Super field does  not contain required superclasses directly.

 

But we can easily join 2 SubclassOf queries via SQL:

SELECT s1.name
FROM %Dictionary.ClassDefinitionQuery_SubclassOf('%Library.Persistent') s1
INNER JOIN %Dictionary.ClassDefinitionQuery_SubclassOf('%XML.Adaptor') s2 ON s2.name = s1.name