go to post Kevin Kindschuh · Aug 27 Nice work! The Docker version ran perfect. I then tried to install and run it on my local IRIS instance with ZPM and I get the execution error: ERROR <Ens>ErrException: <THROW>CreateFolder+9^dc.samba.SambaBusinessOperation.1 *%Exception.PythonException <PYTHON EXCEPTION> 246 <class 'ModuleNotFoundError'>: No module named 'smbclient' -- logged as '-' number - @' Set sc = ##class(dc.samba.SambaService).CreateFolder(server, port, share, username, password, folder)' I had run irispip to load smbprotocol, which seemed to run fine: ..\bin\irispip install --target \InterSystems\IRISHealth\python smbprotocol but the smbclient module still seems to be missing. What am I missing? Thanks!!
go to post Kevin Kindschuh · Aug 13 Looking for a sample Ensemble BusinessService that uses the adapter to download data. Initially I'd like to just build a passthrough service, but I would also like to create an inbound HL7 service and a Record Mapper service. /// https://docs.intersystems.com/irisforhealth20231/csp/docbook/Doc.View.cls?KEY=EGIN_options_connectivity\ /// https://docs.intersystems.com/irisforhealth20231/csp/docbook/DocBook.UI.Page.cls?KEY=ECLOUD_inbound /// https://docs.intersystems.com/irisforhealth20231/csp/documatic/%25CSP.Documatic.cls?LIBRARY=ENSLIB&CLASSNAME=EnsLib.CloudStorage.InboundAdapter Class ARTIS.Adapter.CloudStorage.PassthroughService Extends Ens.BusinessService { Parameter ADAPTER = "EnsLib.CloudStorage.InboundAdapter"; /// Configuration item(s) to which to send file stream messages Property TargetConfigNames As %String(MAXLEN = 1000); Parameter SETTINGS = "TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}"; Parameter CONTAINERCLASS = "Ens.StreamContainer"; /// Wrap the input stream object in a StreamContainer message object and send it. <p> /// https://docs.intersystems.com/irisforhealth20231/csp/docbook/DocBook.UI.Page.cls?KEY=ECLOUD_inbound#ECLOUD_inbound_bs /// based on EnsLib.File.PassthroughService but [at least initially] without archive and work folders.<p> /// We assume our InboundAdapter has the DeleteAfterDownload to prevent pulling the same over and over. Method OnProcessInput(pInput As EnsLib.CloudStorage.InboundInput, Output pOutput As %RegisteredObject) As %Status { // https://docs.intersystems.com/irisforhealth20231/csp/docbook/DocBook.UI.Page.cls?KEY=ECLOUD_inbound#ECLOUD_inbound_bs #dim tContent As %GlobalBinaryStream = pInput.Content //a stream that contains the data from cloud storage #dim tMeta As %String = pInput.Meta // metadata associated with the cloud storage blob #dim tName As %String = pInput.Name // the name of cloud storage blob #dim tSC,tSC1 As %Status = $$$OK #dim tSource, iTarget, tOneTarget As %String #dim tSyncCommit As %Integer Set tSource=$G(tName) _ $C(10)_$G(tMeta) // Do I need to convert tContent from binary stream to character stream first?? https://docs.intersystems.com/irisforhealth20242/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fzconvert#RCOS_fzconvert_handle Set pInput=$classmethod(..#CONTAINERCLASS,"%New",tContent) $$$SyncCommitSet(tSyncCommit) For iTarget=1:1:$L(..TargetConfigNames, ",") { Set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W") Continue:""=tOneTarget $$$sysTRACE("Sending input Stream "_pInput.Stream_"("_pInput.Stream.Size_")"_" from '"_tSource_"' to '"_tOneTarget_"'") Set tSC1=..SendRequestAsync(tOneTarget,pInput) Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1) } $$$SyncCommitClear(tSyncCommit) Quit tSC } /// Return an array of connections for drawing lines on the config diagram ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item) { Do ##super(.pArray,pItem) If pItem.GetModifiedSetting("TargetConfigNames",.tValue) { For i=1:1:$L(tValue,",") { Set tOne=$ZStrip($P(tValue,",",i),"<>W") Continue:""=tOne Set pArray(tOne)="" } } } }
go to post Kevin Kindschuh · Apr 17 To make it easy to get the SessionId from DTL, BPL, or rules, where the $$$JobCurrentHeaderId macro is not defined, add methods like these to your extended function class that Extends Ens.Rule.FunctionSet: /// Return the current Ens.MessageHeader IdClassMethod XCurrentMessageHeaderId() As %String [ CodeMode = expression ]{$GET($$$JobCurrentHeaderId)} /// Return the current SessionIdClassMethod XSessionId() As %String [ CodeMode = expression ]{$GET($$$JobSessionId)} /// Return the current SuperSessionClassMethod XSuperSession() As %String [ CodeMode = expression ]{$GET($$$JobSuperSession)}
go to post Kevin Kindschuh · Apr 15 When you created the SP in with SQL DDL, did you have to implement Query/Exec/Fetch/Close methods to return the filtered dataset, or did you use some other cleaner method? When you create the SP in SQL it inherits from class %SQLQuery, which implements Query/Exec/Fetch/Close, but if you create the SP with ObjectScript it inherits from %Query with does not -- making it easy to return a single value but messy to return a resultset. Am I missing a trick?
go to post Kevin Kindschuh · Apr 11 Use $GET($$$JobSuperSession) A SuperSession ID is generated in a Business Service when the Generate SuperSession ID setting is checked, thereby giving an identity for messages streams that made up of multiple production namespace-based sessions. Subsequent Business Processes and Operations are expected to propagate it on (without overriding it with a new one). The SuperSessionID identifies the originating instance and namespace, plus the original Session ID, and looks something like this: MYSERVER.COM^IRISHEALTH^PRODNAMESPACE^12345. The EnsLib.HTTP.OutboundAdapter will include the SuperSessionID in an HTTP Header if the Send Supersession setting is set. The Enslib.HTTP.InboundAdapter will copy the SuperSessionID from the HTTP Header into the new Ensemble message, if present (and the Generate SuperSession setting is not set to override it by generating a new one). That is, if only the first Business Server in the first instance in the message stream has Generate SuperSession ID set, and all of the Business Operations that send them on have Send SuperSession setting set, the SuperSessionID identity is propagated unchanged among instances in the message stream.
go to post Kevin Kindschuh · May 27, 2021 Try creating a new role that is a full copy of %EnsRole_Operator, except removing the %Ens_ProductionRun resource. Then create a new user with the new role plus roles for %DB_%DEFAULT or whatever databases contain productions they will manage. This new user should allow normal access to start and stop hosts, but without the production start/stop buttons. I verified that worked for me. If you want to further restrict such a user, peel off resources from your custom role, testing each time to make sure you are getting the desired result. In general, start by using standard roles that work, and then remove resources you don't want, testing as you go, rather than trying to build them up.That way you won't be struggling with obscure behavior due to dependencies. Good luck!
go to post Kevin Kindschuh · May 17, 2021 If you want to walk through a list of all the configuration settings for an item, not just those that have been set, you can find an example in the GetSettingsSubTree() method of the EnsPortal.DefaultSettings class. If $IsObject(pItem) { Set tSC = pItem.GetStaticSettings(.pList) if $$$ISOK(tSC) { Do pItem.PopulateVirtualSettings() Set n0 = $O(pList(""),-1) Set n = pItem.VirtualSettings.Count() For I = 1:1:n { Set pList(n0+i) = pItem.VirtualSettings.GetAt(i) } } Each of the setting items in pList are a $LIST that contains: Type = $LIST(setting,1) // "host"Name = $LIST(setting,2) //"FilePath"Value = $LIST(setting,3)Description = $LIST(setting,7)DataType = $LIST(setting,8) // "%Library.String"LocalizedName = $LIST(setting,15) // "File Path"Setting Category = $LIST(setting,16) // "Basic"Localized Category = $LIST(setting,17) // "Basic Setting"Editor = $LIST(setting,18) // "directorySelector"
go to post Kevin Kindschuh · May 12, 2021 Yes. those that show green or blue will not show with the query since they are stored in System Default Settings or defaults in the class. Only those that are black are the ones in the XData. You can still create a new Settings entry and save it (they should then show as black, since it will then be a setting in the XData settings.)
go to post Kevin Kindschuh · May 11, 2021 Your problem is the FindSettingsByName method, above, does not find settings you see in the production settings tab for some items, right? They are shown in black (not green from the class definition or blue from System Default Settings)? If you do: SELECT ID, Production, Name, Settings FROM Ens_Config.Item do you see them in the Settings column? Do you see the settings in the production class XData block? Do you have examples where a given setting shows with one items but not others?
go to post Kevin Kindschuh · May 6, 2020 Yes, these document already appear in the Clinical Viewer, however, they do not appear for document consumers that fetch through XDS.b, not the viewer. So the question is how to make them visible for those consumers as well. My customer considered replicating the documents in the registry, which is the cleanest approach used by another of my customers. But there are an extremely large number of these accumulated over a decade so they prefer an approach that avoids duplicating them in requisitioned expansion of storage. Your insight has already been valuable. Many thanks!
go to post Kevin Kindschuh · Apr 17, 2020 This is very helpful. So if I received a progress note in HL7 v2, I could add registration of it as a document with a repositoryID that indicates the edge gateway where it is being stored in SDA This would add the progress note to the list returned by an XDS.b document search response by an external consumer It looks as if the standard HS.IHE.XDSb.Consumer.Operations in the Registry would pass a request for retrieval of the to the particular edge in which it is stored without any customization, right? In the Edge that may have the progress note document stored in the steamlet, add the HS.IHE.XDSbRepositoryServices and HS.IHE.XDSb.Repository.Process components and set the RepositoryOperations setting to a custom version of HS.IHE.XDSb.Repository.Operations that overrides the RetrieveDocument() method grab the document body from the streamlet instead of the ECR. This would allow document search and retrieval to operate just as if the entire document was stored with with a PnR Am I close? Thanks!!Kevin
go to post Kevin Kindschuh · Jun 29, 2016 I suspect the Message Schema Category setting specified in your Business Service is NOT specifying category 2.2. This setting overrides whatever version number is in MSH:12 (since the MSH value is notoriously unreliable). You may be specifying another version or a custom schema. When the message hits your rule, the docCategory constraint value is compared to what the Business Service assigned, not MSH:12. Look at a message that failed in the Message Viewer Body tab, to see the MessageTypeCategory value (which is compared to docCategory) and Name value (which is compared to docName). One of them does not match, otherwise the message would be sent.The WHEN conditional expression in Rule 1 does absolutely nothing. The pair of AND conditions duplicates the docName filter in the Constraint so also has no effect. And therefore adding OR 1=1 further has no effect. So the Constraint has to be your problem.If you added the same constraints to Rule 2, it would also break, since your problem is with the constraints.