You can use simply:
..RetryInterval
Instead of
%Ensemble("%Process").RetryIntervalSince current object is %Ensemble("%Process").
- Log in to post comments
You can use simply:
..RetryInterval
Instead of
%Ensemble("%Process").RetryIntervalSince current object is %Ensemble("%Process").
set obj = {"RecordIDs":[{"ID":"1234","Type":"INTERNAL"},{"ID":"1234","Type":"EXTERNAL"}],"ContactIDs":null,"Items":[{"ItemNumber":"320","Value":null,"Lines":[{"LineNumber":0,"Value":"1","Sublines":null},{"LineNumber":1,"Value":"100063287","Sublines":null}]}]}
w obj.Items.%Get(0).Lines.%Get(0).LineNumber
>0
w obj.Items.%Get(0).Lines.%Get(1).LineNumber
>1To iterate over arbitrary number of array elements use iterator:
set iterator = obj.Items.%Get(0).Lines.%GetIterator()
while iterator.%GetNext(.key,.line) { w line.LineNumber,! }
>0
>1It's a global that stores information about processed files. It can be accessed via $$$DoneFileTable macro - it's defined in EnsLib.File.InboundAdapter.
You'll need to subclass EnsLib.File.InboundAdapter and modify this line in OnTask method to do what you need:
$$$LOGINFO("Skipping previously processed file '"_tOneFilename_"'")Alternatively you can monitor done file table and send alerts when you find new records.
Both options seem lacking.
Provided your patient MRN doesn't contain whitespaces, you can use $justify to pad string to required length and $translate to convert whitespaces into zeros.
w $tr($j("a", 10), " ", 0)
>000000000aMaybe you're sending HTML emails?
WriteLine works only for plaintext emails.
Use <br/> for new line in HTML emails.
To send HTML emails specify these settings:
set mail.ContentType = "text/html" set mail.IsHTML = 1 set mail.Charset = "utf-8"
ID value contains all pieces of the primary key separated by ||. In the case of %Dictionary.StorageSQLMapDefinition it's:
Class||Storage||SQLMapName
So to open %Dictionary.StorageSQLMapDefinition you need to either construct an ID like this:
Set Class = "%CSP.Util.Performance" Set Storage = "CspPerformance" Set SQLMapName = "Map1" Set Id = $LTS($LB(Class, Storage, SQLMapName), "||") Set Obj = ##class(%Dictionary.StorageSQLMapDefinition).%OpenId(Id)
Alternatively you can use Open method for IDKEY index (more on auto-generated methods for indices, properties etc.):
Set Obj = ##class(%Dictionary.StorageSQLMapDefinition).IDKEYOpen(Class, Storage, SQLMapName)
There are several ways to handle this:
Code sample for 1 - utility method to search for setting in a production object.
/// Find BH in a current production by a setting value
ClassMethod findConfigItemBySettingValue(settingName As %String, settingValue As %String, businessType As %String = "", enabledOnly As %Boolean = 0) As Ens.Config.Item
{
#dim sc As %Status
// Get current production object
#dim prod As Ens.Config.Production = ..getCurrentProduction()
if '$isObject(prod) quit ""
// Cycle over production elements
#dim item As Ens.Config.Item
#dim result As Ens.Config.Item = ""
for i = prod.Items.Count():-1:1
{
set item = prod.Items.GetAt(i)
// Search only for specified type
if ((businessType '= "") && (item.BusinessType() '= businessType)) || (enabledOnly && 'item.Enabled) continue
// Cycle over settings
do item.PopulateModifiedSettings()
set ind = ""
for
{
set setting = item.ModifiedSettings.GetNext(.ind)
if (ind = "") quit
// Found it?
if (setting.Name = settingName)
{
if ($ZStrip(setting.Value, "<>W") = $ZStrip(settingValue, "<>W")) set result = item
quit
}
}
if $isObject(result) quit
}
quit result
}
/// Get current running production object
ClassMethod getCurrentProduction() As Ens.Config.Production
{
#dim sc As %Status
#dim prodName As %String
#dim prodState As %Integer
// Find the name and status of current production
set sc = ##class(Ens.Director).GetProductionStatus(.prodName, .prodState)
if $$$ISERR(sc)
{
$$$LOGERROR($System.Status.GetErrorText(sc))
quit ""
}
//Status should be "Running"
if (prodState '= $$$eProductionStateRunning) quit ""
// Open object by name
#dim prod As Ens.Config.Production = ##class(Ens.Config.Production).%OpenId(prodName, , .sc)
if $$$ISERR(sc)
{
$$$LOGERROR($System.Status.GetErrorText(sc))
quit ""
}
quit prod
}
Check out SystemMethodsRemover - it does automatic regexp replace on the codebase. It's configured for system methods replacing, but you can easily repurpose it.
Why return binary data in JSON? I think it preferable to make a separate request for it.
SQL join or is there something more elaborate?
SELECT cd.name FROM %Dictionary.ClassDefinition cd JOIN subclassofquery sq ON sq.Name = cd.Name WHERE cd.System IS NULL
Let's say you have this production definition:
Class Passthrough.Production Extends Ens.Production
{
XData ProductionDefinition
{
<Production Name="TEST" LogGeneralTraceEvents="false">
<Description></Description>
<ActorPoolSize>2</ActorPoolSize>
<Item Name="PassthroughOperation" Category="" ClassName="EnsLib.SOAP.GenericOperation" PoolSize="1" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
<Setting Target="Adapter" Name="HTTPServer">www.webservicex.net</Setting>
<Setting Target="Adapter" Name="URL">|</Setting>
</Item>
<Item Name="PassthroughService" Category="" ClassName="Passthrough.PassthroughService" PoolSize="0" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
<Setting Target="Host" Name="TargetConfigName">PassthroughProcess</Setting>
<Setting Target="Adapter" Name="EnableStandardRequests">1</Setting>
<Setting Target="Adapter" Name="Port"></Setting>
<Setting Target="Host" Name="OneWay">1</Setting>
</Item>
<Item Name="PassthroughProcess" Category="" ClassName="Passthrough.PassthroughProcess" PoolSize="1" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
<Setting Target="Host" Name="TargetConfigName">PassthroughOperation</Setting>
</Item>
</Production>
}You can change
After recompile, new name should be displayed in SMP.
Assuming you have %request object what happens when you call:
S array=[].$fromJSON(%request.Content)
on small and big requests?
Can you provide a minimal sample of class A that refers to class B and vice versa?
Seems like ability to parse files directly was introduced after 2016.1 (I tested in 2017.1 and it works. Your initial code works after replacing %From with $from:
S filename="/tmp/pictures.json"
S stream=##class(%Stream.FileCharacter).%New()
S sc=stream.LinkToFile(filename)
I ('sc) W "Error on linking file "_filename,! W
try {
set obj= [].$fromJSON(stream)
} catch ex {
w "Error. Unable to parse file "_filename,!
w "Error type "_ex.Name,!
w "Error code "_ex.Code,!
w "Error location "_ex.Location,!
set obj=""
}
q obj
Q I would recommend upgrading from 2016.1 to 2017.1.
It's $fromJSON on 16.1:
Set filename = "/tmp/pictures.json" Set array = [].$fromJSON(filename)
Sure:
Set filename = "/tmp/pictures.json" Set array = [].%FromJSON(filename)
Missed it. Rebuild from management portal is equal to ##class(Package.Class).%BuildIndices(), except management portal rebuild is done asynchronously, so you need to go to SMP - Menu - Background Tasks to check that it's done. ##class(Package.Class).%BuildIndices() is done synchronously so you know immediately that indices are rebuilt.
Adding an index doesn't built it for existing data. Only data added after the index is created is indexed automatically. You need to rebuild the index:
w ##class(Package.Class).%BuildIndices()
1. How do you want to use this partial index?
2. NULL values are indexed, same as any other value (with one difference that any number of NULL values are allowed in a Unique index). Consider the following example:
Class Sample.Person Extends %Persistent
{
Property Name As %String;
Index NameIndex On Name;
/// do ##class(Sample.Person).Test()
ClassMethod Test()
{
kill ^Sample.PersonD, ^Sample.PersonI
do ..AddPerson("ed")
do ..AddPerson("ed")
do ..AddPerson("bob")
do ..AddPerson()
do ..AddPerson()
zw ^Sample.PersonD, ^Sample.PersonI
}
ClassMethod AddPerson(Name)
{
set p = ..%New()
set:$d(Name) p.Name = Name
do p.%Save()
}Whn I run the text method:
do ##class(Sample.Person).Test()
I get the following data global:
^Sample.PersonD=5
^Sample.PersonD(1)=$lb("","ed")
^Sample.PersonD(2)=$lb("","ed")
^Sample.PersonD(3)=$lb("","bob")
^Sample.PersonD(4)=$lb("","")
^Sample.PersonD(5)=$lb("","")And the following index global:
^Sample.PersonI("NameIndex"," ",4)=""
^Sample.PersonI("NameIndex"," ",5)=""
^Sample.PersonI("NameIndex"," BOB",3)=""
^Sample.PersonI("NameIndex"," ED",1)=""
^Sample.PersonI("NameIndex"," ED",2)=""As you see NULL values are indexed same as any other value.
Index global has the following structure:
^ClassIndexGlobal(IndexName, IndexValue, Id) = DataStoredInIndex
Where:
Also for this SQL:
SELECT ID FROM Sample.Person WHERE Name IS NULL
The following plan that uses our index gets generated:
If you have a method that only returns dynamic object or array you can use [codemode = expression]:
ClassMethod TestGETMixedDynamicObject(class As Frontier.UnitTest.Fixtures.Class) As %DynamicObject(PUBLIC=1) [codemode=expression]
{
{
"class": (class)
}
}What does
(PUBLIC=1)
means for a return type?
Please provide your SSL config.
Use old json provider:
set st = ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(json, class,.obj, $$$YES)
Instead of class argument, the json can contain _class property.
Settings are not really meant to be used like that.
If you want to report usage volume the best option would be creting a DeepSee cube over Ens.MessageHeader class. For a limited subset of analytic operations SQL may be enough.
Here's what I came up with.
Business service (works in SYNC or ASYNC mode depending on OneWay setting):
Class Passthrough.PassthroughService Extends EnsLib.SOAP.GenericService
{
Property DefaultResponce As %String(MAXLEN = "") [ InitialExpression = "<soap:Envelope><soap:Body></soap:Body></soap:Envelope>" ];
Parameter SETTINGS = "OneWay:Basic";
/// Pass through to OnProcessInput()
Method ProcessBody(pAction As %String, pRequestBody As %CharacterStream, pResponseBody As %CharacterStream) As %Boolean
{
Set tSC=..ProcessInput(pRequestBody, .pResponseBody, pAction)
Set:pResponseBody="" pResponseBody = ..DefaultResponce
Quit $$$OK
}
}And a BP for ASYNC logging (you need to set it as a target for BS only if you want ASYNC mode and logging, otherwise just call BO directly):
Class Passthrough.PassthroughProcess Extends Ens.BusinessProcess [ ClassType = persistent ]
{
/// Configuration item to which to send messages
Property TargetConfigName As Ens.DataType.ConfigName;
Parameter SETTINGS = "TargetConfigName:Basic:selector?multiSelect=0&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}";
Method OnRequest(pRequest As EnsLib.SOAP.GenericMessage, Output pResponse As EnsLib.SOAP.GenericMessage) As %Status
{
Quit ..SendRequestSync(..TargetConfigName, pRequest, .pResponse)
}
}
Default EnsLib.SOAP.GenericOperation can be used for BO.
Have you thought about writing an article on External Service Registry best practices? It seems like a very interesting topic.