go to post Eduard Lebedyuk · Aug 31, 2017 Does it work like this? ClassMethod WriteCapture(vstrCommand As %String) As %String { set tOldIORedirected = ##class(%Device).ReDirectIO() set tOldMnemonic = ##class(%Device).GetMnemonicRoutine() set tOldIO = $io try { set str="" //Redirect IO to the current routine - makes use of the labels defined below use $io::("^"_$ZNAME) //Enable redirection do ##class(%Device).ReDirectIO(1) XECUTE (vstrCommand) } catch ex { set str = "" } //Return to original redirection/mnemonic routine settings if (tOldMnemonic '= "") { use tOldIO::("^"_tOldMnemonic) } else { use tOldIO } do ##class(%Device).ReDirectIO(tOldIORedirected) quit str //Labels that allow for IO redirection //Read Character - we don't care about reading rchr(c) quit //Read a string - we don't care about reading rstr(sz,to) quit //Write a character - call the output label wchr(s) do output($char(s)) quit //Write a form feed - call the output label wff() do output($char(12)) quit //Write a newline - call the output label wnl() do output($char(13,10)) quit //Write a string - call the output label wstr(s) do output(s) quit //Write a tab - call the output label wtab(s) do output($char(9)) quit //Output label - this is where you would handle what you actually want to do. // in our case, we want to write to str output(s) set str=str_s quit }
go to post Eduard Lebedyuk · Aug 31, 2017 You can use simply: ..RetryInterval Instead of %Ensemble("%Process").RetryInterval Since current object is %Ensemble("%Process").
go to post Eduard Lebedyuk · Aug 30, 2017 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 >1 To 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 >1
go to post Eduard Lebedyuk · Aug 29, 2017 It's a global that stores information about processed files. It can be accessed via $$$DoneFileTable macro - it's defined in EnsLib.File.InboundAdapter.
go to post Eduard Lebedyuk · Aug 28, 2017 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.
go to post Eduard Lebedyuk · Aug 28, 2017 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) >000000000a
go to post Eduard Lebedyuk · Aug 28, 2017 Maybe 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"
go to post Eduard Lebedyuk · Aug 28, 2017 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)
go to post Eduard Lebedyuk · Aug 28, 2017 There are several ways to handle this: Dynamically adjust BP settings (your suggestion). To do that you need to modify object(s) of Ens.Config.Item class and update the production. Check GetItemSettingValue method in Ens.Director class for an example of getting setting value. After that update the production and that's it. The problem with that approach are:Updated settings take effect for all new incoming/outgoing messagesUpdating production is a time-consuming operation, it should be used as rarely as possibleProxy process. Add proxy process that calls your target process. The proxy process should only contain logic related to error processing. And the target process should return the message immediately without any error checks.Modify the process so it does not return an error each time, but rather sleeps and calls the operation again depending on an error. 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 }
go to post Eduard Lebedyuk · Aug 28, 2017 Check out SystemMethodsRemover - it does automatic regexp replace on the codebase. It's configured for system methods replacing, but you can easily repurpose it.
go to post Eduard Lebedyuk · Aug 28, 2017 Why return binary data in JSON? I think it preferable to make a separate request for it.
go to post Eduard Lebedyuk · Aug 15, 2017 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
go to post Eduard Lebedyuk · Aug 15, 2017 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 <Production Name="TEST" To any other name. After recompile, new name should be displayed in SMP.
go to post Eduard Lebedyuk · Aug 14, 2017 Assuming you have %request object what happens when you call: S array=[].$fromJSON(%request.Content) on small and big requests?
go to post Eduard Lebedyuk · Aug 14, 2017 Can you provide a minimal sample of class A that refers to class B and vice versa?
go to post Eduard Lebedyuk · Aug 14, 2017 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.
go to post Eduard Lebedyuk · Aug 14, 2017 It's $fromJSON on 16.1: Set filename = "/tmp/pictures.json" Set array = [].$fromJSON(filename)
go to post Eduard Lebedyuk · Aug 14, 2017 Sure: Set filename = "/tmp/pictures.json" Set array = [].%FromJSON(filename)
go to post Eduard Lebedyuk · Aug 14, 2017 The problem is not with WSDL itself, but rather with the generated classes. There seems to be a loop dependency. Try recompiling.Strategic placement of DependsOn keyword may help.