第十一章 创建Callout Library - 使用 J 链接类型传递标准计数字符串
使用 J 链接类型传递标准计数字符串
iris-callin.h 头文件定义了计数字符串结构 IRIS_EXSTR,表示标准 IRIS 字符串。
J 链接类型传递标准计数字符串iris-callin.h 头文件定义了计数字符串结构 IRIS_EXSTR,表示标准 IRIS 字符串。
我们继续推出有关可供 HealthShare HealthConnect 和 InterSystems IRIS 用户使用的 FHIR 适配器工具的系列文章。
在前几篇文章中,我们介绍了小型应用程序,并在此基础上建立了我们的工作,并展示了安装 FHIR 适配器后在 IRIS 实例中部署的架构。在今天的文章中,我们将看到一个示例,说明如何执行最常见的 CRUD(创建 - 读取 - 更新 - 删除)操作之一,即读取操作,我们将通过恢复资源来完成此操作。
FHIR 中的一个资源对应一种相关的临床信息,这种信息可以是病人(Patient)、对实验室的请求(ServiceRequest)或诊断(Condition)等。每种资源都定义了组成它的数据类型,以及对数据的限制和与其他类型资源的关系。每个资源都允许对其包含的信息进行扩展,从而满足 FHIR 80% 以外的需求(满足 80% 以上用户的需求)。
在本文的示例中,我们将使用最常见的资源 "Patient"。
ZFEntry 表每个 Callout 库必须定义一个 ZFEntry 表,该表允许 IRIS 加载和访问 Callout 函数。 ZFEntry 表由以 ZFBEGIN 开头、以 ZFEND 结尾的宏代码块生成。在这两个宏之间,必须为要公开的每个函数调用一次 ZFENTRY 宏。
每个 ZFENTRY 调用都采用三个参数:
ZFENTRY(zfname,linkage,entrypoint)
其中 zfname 是用于在 $ZF 调用中指定函数的字符串,linkage 是指定如何传递参数的字符串,entrypoint 是 C 函数的入口点名称。
要创建 Callout 库,代码必须包含 #define ZF_DLL 指令,该指令是一个开关,可生成用于定位库函数的内部 GetZFTable 函数。加载 Callout 库时, IRIS 调用此函数来初始化该库,以便后续查找库函数名称。
注意:ZFEntry 序列号
ZFEntry 表中条目的位置可能很重要。 $ZF(-5) 和 $ZF(-6) 接口(在“调用标注库函数”中描述)都通过指定表中的序列号(从 1 开始)来调用库函数。
在医疗行业中,处方是个非常重要的临床工作数据概念。因此,在考察用FHIR能如何构造我国所需医疗行业数据模型时,就会需要考虑如何用FHIR表达处方。
在2019年,FHIR的工作组已否认需要使用特定的资源来表达处方(不是药嘱)这个概念,见:
https://jira.hl7.org/browse/FHIR-24905

奇妙的是,IHE规范中却明确有处方(Prescription)的定义并需要引用药嘱(Medication Treatment Plan Item)。
https://www.ihe.net/uploadedFiles/Documents/Pharmacy/IHE_Pharmacy_Suppl_PRE.pdf?#page=12
FHIR官网指出这种复合式的request有三种表达方式:
• Shared requisition id
• "Based on" chain
• RequestOrchestration
https://build.fhir.org/request.html#compound
在FHIR实际应用中,则可以见到多种形态使用容器类资源表达处方并包含药嘱的表达形式,例如:
Callout library 库是一个共享库,其中包含自定义Callout函数和允许 IRIS使用它们的启用代码。本章描述如何创建Callout库并在运行时访问它。
Callout library 简介-描述如何创建和访问Callout library 。ZFEntry链接选项 - 提供了决定如何传递函数参数的链接选项的详细描述。Callout库。Callout Library运行和运行函数-描述两个可选函数,可将其设置为在加载或卸载标注库时自动运行。注:共享库和标注库的术语,共享库shared library是指动态链接的文件(Windows上的DLL文件或UNIX及相关操作系统上的SO文件)。Callout library是一个共享库,它包含到$ZF Callout接口的钩子,允许各种$ZF函数在运行时加载和访问它。
Callout库简介从ObjectScript代码访问Callout库有几种不同的方法,但一般原则是指定库名、函数名和任何必需的参数(请参阅“调用Callout库函数”)。例如,下面的代码调用一个简单的Callout库函数:
从Callout库simplecallout.
%System_Callout:USE权限$ZF(-100)需要%System_Callout:USE权限。如果安全设置高于最小值,则可能会禁用此特权。下面的过程描述了如何在%Developer角色中启用它:
%Developer角色中启用%System_Callout:USERoles页面上,单击Names列中的%Developer。Edit %Developer页面的General选项卡上,找到%System_Callout权限并单击Edit%Developer角色总是在安装 IRIS时创建,但是管理员可能不希望所有用户都可以使用它。在某些情况下,可能需要为用户提供一个角色,使$ZF(-100)可用,但不授予任何其他特权。下面的过程创建了一个只授予%System_CallOut:USE权限的新角色:
%System_Callout:USE打开Management Portal,进入System Administration > Security > Roles。
在此文章中将分享,当使用InterSystems IRIS 做后端时如何接收并保存通过POST方式发送过来的 Base64文件。
前后端之间传输文件,我认为较简单的方式是:前端将文件转为Base64格式,调用POST方法并将Base64内容附加在JSON消息中的一个参数中,在JSON消息中的另一个参数可以是文件名,比如消息定义如下:
{
"fileData": "JVBERi0xLjQKJdPr6eEKMSAwIG...",
"fileName": "example.pdf"
}在IRIS中,可以定义一个web application用于处理POST请求,同时定义一个分派类继承于%CSP.REST,在类中定义一个方法,具体保存文件。
代码示例:
ClassMethod SaveFile() As%Status
{
Try {
Do##class(%REST.Impl).%SetContentType("application/json")
If '##class(%REST.Impl).%CheckAccepts("application/json") Do##class(%REST.Impl).%ReportRESTError$ZF(-100)函数允许 IRIS 进程调用可执行程序或主机操作系统的命令。这是唯一可以在没有特殊的Callout共享库的情况下使用的$ZF函数。
$ZF(-100)的语法和功能概述。I/O。%System_Callout:USE特权—使用$ZF(-100)需要此特权。注意:$ZF(-100)取代了已弃用的函数$ZF(-1)和$ZF(-2),在所有情况下都应优先使用。
$ZF(-100)提供类似于命令行接口的功能,允许调用可执行程序或主机操作系统的命令。这个函数的语法是:
status = $ZF(-100, keywords, command, arguments )
第一个参数必须是字面量-100。其他三个参数指定以下信息:
Keywords - 包含指定各种选项的关键字的字符串。例如,字符串"/ASYNC/LOGCMD"指定程序应该异步运行,并将命令行写入日志文件。Command - 指定要调用的程序或系统命令的字符串。如果未指定可执行文件的完整路径,则操作系统将应用标准搜索路径规则。IRIS $ZF系统功能是一套相关功能的容器。$ZF套件中的大多数函数都由函数调用的第一个参数标识,该参数将是一个负数,-100或-3到-6。例如,调用操作系统命令的函数具有$ZF(-100, <oscommand>)的形式,其中<oscommand>是包含要执行的命令的字符串。当讨论这个函数时,它将被称为$ZF(-100)。以同样的方式,其他函数将被称为$ZF(-3)到$ZF(-6),只使用实际函数调用的第一个参数。也可以在不带负数参数的情况下调用$ZF()函数,在这种情况下,它调用名为iriszf的特殊Callout库中的函数。
注:Callout Libraries是动态链接的文件(Windows为DLL文件,UNIX及相关操作系统为SO文件)。Callout库是一个共享库,它包含到$ZF Callout接口的钩子,允许各种$ZF函数在运行时加载它并调用库函数。
$ZF函数集包括以下接口:
$ZF()函数(不带负数参数)主要的$ZF()函数提供了对来自名为iriszf的特殊Callout库的函数的直接访问。当定义并编译了这个自定义库后,只需指定函数名和参数(例如,$ZF("myFunction",arg1)),就可以调用它的函数。与$ZF(-3)、$ZF(-5)或$ZF(-6)不同,不需要加载库或指定库标识符。
Topic | Parameters |
|---|---|
启用 XML 映射。 | XMLENABLED 类参数 |
| 将属性映射到元素或属性。 | XMLPROJECTION property parameter ("NONE", "ATTRIBUTE", "XMLATTRIBUTE", "CONTENT", "ELEMENT", or "WRAPPED")XMLSUMMARY class parameterXMLDEFAULTREFERENCE class parameter ("SUMMARY", "COMPLETE", "ID", "OID", or "GUID")XMLREFERENCE property parameter ("SUMMARY", "COMPLETE", "ID", "OID", or "GUID") |
XML 元素名称和属性名称。 | XMLNAME class parameterXMLNAME property parameterXMLITEMNAME property parameterXMLKEYNAME property parameter默认值基于 XML 类型名称。 |
由于源 XML 文档可能包含意外的元素和属性,因此支持 XML 的类提供两个参数来指定导入此类文档时如何反应。例如,考虑以下类定义:
Class GXML.TestImportParms.Person Extends (%Persistent,%XML.Adaptor)
{
Property Name As %Name [ Required ];
Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h") [ Required ];
}
另请考虑以下 XML 文档:
<?xml version="1.0" encoding="UTF-8"?当在顶层映射 IRIS 对象(而不是作为另一个对象的属性)时,其内部 ID、OID 和全局唯一 ID 不能用作对象属性,因此不会映射这些 ID。但是,在某些情况下,可能希望使用对象 ID 作为唯一标识符。然后,例如,可以在更新存储的对象之前将传入(已更改)的对象与相应的存储对象进行匹配。
IRIS XML 支持提供了多个帮助程序类,可用于将 IRIS 对象标识符投影到 XML 文档: %XML.Id 中(对于内部 ID)、%XML.Oid(对于 ``)和 %XML.GUID(用于全局唯一 ID)。
要使用这些类,请向支持 XML 的类添加一个特殊属性,该属性的用途是包含要导出的 ID。该属性的类型必须为 %XML.Id、%XML.Oid或 %XML.GUID。确保该属性已映射,并将其标记为瞬态,以便它不包含在该类的 SQL 映射中。
当导出到 XML 时,将支持 XML 的类的对象带入内存。当对象位于内存中时,添加的特殊属性将从 IRIS 内部存储中检索请求的 ID 并包含该值(以便您可以导出它)。
例如,考虑以下类:
Class MyApp4.Obj.Person4 Extends (%Persistent,%Populate,%XML.Adaptor)
{
Property IdForExport As %XML.最近在多家现场都遇到了备机长时间宕机导致镜像日志写满磁盘的问题。在这里我将对这个问题发生的原因、发生后的处理、和如何预防这类问题发生进行一些讨论。
问题的发生一般始于一些原因导致的主机(如,01)宕机,进而触发镜像的主备切换。切换后备机(如,02)成为主机,并无缝接管业务。由于业务不受影响,如果不注意监控环境的话,很可能现场技术人员长时间都注意不到镜像的备机(01)是宕机状态。
备机长时间宕机会导致如下问题:
1. 这种情况下如果主机(02)再次遇到问题宕机,镜像将无法发挥其高可用性,无法保持业务稳定运行。
2. 主机(02)产生的镜像日志将无法同步到备机(01)。未同步的日志将一直被保存在主机(02)上不被删除。长此以往镜像日志磁盘将被写满,同样导致主机(02)宕机。
问题发现时切记不要手动从文件夹直接删除主机(02)上的镜像日志。未同步的日志一旦手动删除,镜像将无法自动同步,需要重做主备镜像。
问题发现时如果主机(02)还未宕机,此时尝试解决备机(01)问题,启动备机(01),等待镜像自动同步即可。同步完成之后镜像日志将可以被定时任务定时清除。如果遇到较为复杂的情况,现场请第一时间联系您的软件供应商,软件供应商将协同系联软件全球响应中心一起来解决您遇到的具体问题。
为了避免以上的问题发生,现场运维需要对镜像的状态和磁盘的状态配置监控。
类和属性参数
XMLNAMEXMLSEQUENCEXMLUNSWIZZLEXMLPREFIXXMLIGNOREINVALIDTAGXMLIGNOREINVALIDATTRIBUTE在 XML 中,仅包含属性的元素可以用以下任一方式表示:
<tag attribute="value" attribute="value" attribute="value"></tag>
<tag attribute="value" attribute="value" attribute="value"/>
IRIS 认为这些形式是等效的。当使用 %XML.Writer 导出对象时,可以控制关闭形式,但不能通过修改 XML 投影本身来控制。
XML 中的给定元素可以包含多个具有相同名称的元素;这些元素通过它们的顺序彼此区分。例如,以下是一个合法的 XML 文档:
<?xml version="1.0" encoding="UTF-8"?如果需要 XML 架构来显示特定的类型层次结构,则需要了解映射如何解释 IRIS 类层次结构。
类层次结构代表了有意义的数据组织等。该层次结构尽可能地反映在相应的 XML 类型定义中。
例如,假设有以下类:
Base 的类,定义了三个公共属性(Property1、Property2 和 Property3)。Addition1 的类,它扩展 Baseand 并定义一个附加公共属性 (Addition1)。Addition2 的类,它扩展 Addition1 并定义一个附加公共属性 (Addition2)。Addition2 的架构应包含什么?它必须代表所有五个属性。另外,因为这些类都是用户定义的,所以 Addition2 的架构应该显示类层次结构的详细信息;相反,如果 Base 从 IRIS 类库扩展一个类,而 IRIS 类库又从该库扩展其他类,那么这些细节就不那么有趣了。
XML 模式规范还允许定义替换组,这可以是创建选择的替代方法。语法有些不同。
根据 XML Schema 规范,复杂类型可以由类型(特别是相关类型)的选择列表组成。假设我们希望架构允许使用 <Person>, <Patient>, or <Employee> 元素,而不是 <Person> 元素。要定义这样的架构,我们会将 Person 属性的 XMLTYPECONSTRAINT 属性参数设置为等于“CHOICE”,如下所示:
Class UsingSubclasses.Example2 Extends (%Persistent, %XML.Adaptor)
{
Property Person As UsingSubclasses.Person(XMLTYPECONSTRAINT = "CHOICE");
}
默认情况下,选择列表由 Person 类的所有子类组成。
类和属性参数
XMLTYPECONSTRAINT
XMLINCLUDEINLIST
XMLINHERITANCE
当为一个类定义 XML 投影时,它的所有子类都会自动映射到单独的类型,所有这些类型都使用超类作为基类型。这意味着无论何时使用超类型,都可以使用其中一种子类型。还可以使用子类型在 XML 模式中定义选择列表或替换组。
请注意,可以为抽象类定义 XML 映射;该类在任何派生类模式中都显示为基类型,尽管它是抽象的,无法实例化。
考虑一个例子。我们从一个简单的 Person 类开始:
Class UsingSubclasses.Person Extends (%Persistent, %XML.Adaptor)
{
Property Name As %String [Required];
Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h") [Required];
}
假设我们有两个直接基于 Person 类的类。首先是 Patient 类:
Class UsingSubclasses.Patient Extends UsingSubclasses.XML 的类到 XML 类型的映射对于支持 XML 的类或基于支持 XML 的类的属性,XML 类型按如下方式确定: 如果该类具有 XMLTYPE 参数的值,则该值将用作类型名称。否则,短类名将被视为 XML 类型名。
例如,考虑以下类定义:
Class GXML.PersonWithAddress Extends (%Persistent, %XML.Adaptor)
{
Parameter XMLTYPE = "PersonType";
Property Name As %Name;
Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h");
Property HomeAddress As GXML.Address;
}
对于此类的实例,XML 类型是 PersonType,它取自 XMLTYPE 参数。
假设 GXML.Address 类不包含 XMLTYPE 参数。在本例中,对于 <HomeAddress> 元素,XML 类型是 Address,它是短类名。
XML 类型分配给命名空间,如下所示:
XSDTYPE 类参数,则该类型位于以下 W3 命名空间中:http://www.w3.本部分显示了从支持 XML 的类生成的 XML架构的一部分,该类包含定义为 %ListOfObjects 的属性。例如,考虑以下属性定义:
Property PropName As list Of %Integer(XMLITEMNAME = "MyXmlItemName");
如果此属性位于名为 Test.DemoObjList1 的启用 XML 的类中,则该类的 XML 架构包含以下内容:
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:s="http://www.w3.%ListOfDataTypes本部分显示从支持 XML 的类生成的 XML 架构的一部分,该类包含中定义为%ListOfDataTypes 的属性。例如,考虑以下属性定义:
Property PropName As %ListOfDataTypes(XMLITEMNAME = "MyXmlItemName");
如果此属性位于名为 Test.DemoList 的启用 XML 的类中,则该类的 XML 架构包含以下内容:
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:s="http://www.w3.Array of Classname本部分显示了从启用 XML 的类生成的XML 架构的一部分,此时该类包含定义为类名数组的属性。例如,考虑以下属性定义:
Property PropName As array Of %Integer(XMLITEMNAME = "MyXmlItemName", XMLKEYNAME = "MyXmlKeyName");
如果此属性位于名为 Test.DemoArray1 的启用 XML 的类中,则该类的 XML 架构包含以下内容:
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:s="http://www.w3.TCP作为OSI 7层的传输层的通信协议,其使用上不像更上层的通信协议那么方便,因为TCP操作的不是数据包,它操作的是数据流。因此有多种将TCP数据流“解释”为数据包(消息)的方法。
InterSystems IRIS提供了多种TCP适配器,用于不同的“解释”,例如EnsLib.TCP.FramedInboundAdapter使用特定的首尾字符做为分隔、EnsLib.TCP.CountedInboundAdapter使用固定的长度进行分隔...
同时,InterSystems IRIS提供了多种开箱即用的TCP业务服务和业务操作,方便接入和发送TCP数据。这里我们介绍常见的使用特定的首尾字符做为分隔的TCP业务服务和业务操作。
EnsLib.TCP.Framed.PassthroughService和EnsLib.TCP.Framed.PassthroughOperation是一组使用特定的首尾字符做为分隔TCP数据流的通用业务服务和业务操作。EnsLib.TCP.Framed.PassthroughService业务服务会将TCP数据封装在Ens.StreamContainer发送给业务流程或业务操作;而EnsLib.TCP.Framed.PassthroughOperation业务操作发送并接收Ens.
2023年11月24日19:00-20:00,InterSystems开发者社区举办了“InterSystems第二届技术征文大赛线上分享会”,邀请参赛作者进行了作品分享&点评,此次分享吸引了66位开发者参会。
未参加此次会议的社区成员,可通过以下链接了解此次Meetup详情(请注意,您需要登录后申请查看视频)
InterSystems IRIS 提供了一组通用的RESTful 业务服务和业务操作类,用户无需开发自定义的业务服务和业务操作类,就可以直接向外提供RESTful服务和调用外部的RESTful API。
| BS | EnsLib.REST.GenericService | 通用REST业务服务 |
| BS | EnsLib.REST.SAMLGenericService | 检查SAML令牌的签名和时间戳的REST业务服务 |
| BO | EnsLib.REST.GenericOperation | 通用REST业务操作 |
| BO | EnsLib.REST.GenericOperationInProc | 用于透传模式的通用REST业务操作 |
通用的RESTful 业务服务和业务操作类使用一个通用的RESTful消息类 - EnsLib.REST.GenericMessage,它是EnsLib.HTTP.GenericMessage的子类,二者数据结构都是
| HTTPHeaders | 记录http头的数组 |
| Stream | 记录http体的数据流 |
| Type | 数据流类型,例如是字符流还是二进制流。 |
目前在使用Codemirror展示cache的代码,codemirror能支持csp和js的代码高亮,但是cls的代码没有对应插件,不知具体关键字的正则表达式,是否有对应插件或解决方法,可是cls代码高亮。
✓ 十一月有 49 位新成员加入
✓ 截至目前共发布了 2,002 篇帖子
✓ 截至目前共有 1,595 位成员加入
我创建了一个类,里面有个属性OPDT 是 %Library.DateTime类型的,类继承了%XML.Adaptor,我是用 d obj.XMLExportToString(.xml) 导出为xml后,OPDT的值是 2023-11-28T13:57:26 这样的,我需要的值是 2023-11-28 13:57:26 这样的,T需要换成“ ”,有没有什么方式能设置导出的数据格式?
在日常Cache运维过程中可能会由于数据或者程序等原因造成锁的异常增长,导致数据库性能受到影响会出现程序报错或卡顿无法正常运行的问题。遇到此类问题需查看数据库当前锁列表情况,找到出现次数最多关键锁,根据关键锁对应的进程来判断处理。总结有以下三种方式查看关键锁。
|
查看方式 |
优点 |
缺点 |
|
第一种 |
易操作、方式简便 |
慢、锁数量太多无法显示 |
|
第二种 |
快、不受网页限制 |
易忘、需要输入准确命令 |
|
第三种 |
快、灵活、直接显示关键锁信息 |
需定位准确命名空间 |
下面给出自定义程序实例,程序逻辑为按命名空间循环所有锁信息,通过计数器方式记录所有锁当中出现次数最多的一个,输出其信息。入参为数据库中不同命名空间,输出结果为锁名称及锁的所有者,所有者一般为进程ID或ECP。
我们继续使用FHIR适配器的示例,在本文中,我们将回顾如何在我们的IRIS实例中进行配置以及安装的结果。
配置项目的步骤与官方文档中所示的相同,您可以直接在此处查看。好吧,让我们开始工作吧!
正如您在与本文相关的项目中看到的,我们将 IRIS 实例部署在 Docker 中,因此初始配置的主要部分将在 Dockerfile 中完成。别担心,我们不会详细介绍 Docker 配置。
要安装 FHIR 适配器,我们只需:
set status = ##class (HS.FHIRServer.Installer).InteropAdapterConfig( "/Adapter/r4" )在我们的例子中,我们定义了将接收 REST 请求的 IRIS 端点的 URL 为/Adapter/r4 。
FHIR 适配器安装完成后,我们可以查看 IRIS 实例中发生的情况。为此,我们首先查看 Web 应用程序菜单(系统管理 -> 安全 -> 应用程序 -> Web 应用程序)
.png)
正如我们所看到的,一个新的 Web 应用程序已添加到列表中,表明它对应于我们的 ADAPTER 命名空间。让我们访问它以更详细地查看其配置。
.png)