搜索​​​​

清除过滤器
文章
Claire Zheng · 五月 18, 2023

【视频】对话:“数据二十条”与FHIR标准

“数据二十条”体现了怎样的制度创新和政策智慧?FHIR将如何发挥作用?来看InterSystems亚太区总经理老卢(Luciano Brustia)与CHIMA主任委员王才有的精彩探讨!
公告
Claire Zheng · 十一月 9, 2023

InterSystems开发者社区中文版第二届技术征文大赛专家评审团亮相!

大家好! 2023年9月19日-11月24日(北京时间),🏆InterSystems开发者社区中文版第二届技术征文大赛🏆正在进行中(←点击链接进入参赛页面,浏览所有参赛文章)!作为此次大赛重要奖项“专家提名奖”评比的重要部分,我们的专家评审团已组建成团! 以下为我们的专家团成员,来自我们的销售工程师团队与WRC支持团队。 @Yunfei.Lei @Peng.Qiao @Lin.Zhu @jieliang.liu7848 @Ida.Yang @Louis.Lu @Hao.Ma @Jingwei.Wang @Tete.Zhang @Tengzhou.Zhuang 我们期待专家评审团对参赛作品的公平审阅与打分。 作为社区成员,您的个人贡献也会对每一篇参赛文章产生影响,每一次浏览和点赞都将助力您喜欢的文章赢得“开发者社区奖”。 欢迎大家积极投稿、点赞、分享、学习! 欢迎积极参加InterSystems开发者社区中文版第二届技术征文大赛
文章
Michael Lei · 六月 14, 2023

使用LangChain 修复 SQL

本文是 SqlDatabaseChain 的简单快速入门(我所做的)。 希望大家会感兴趣。 非常感谢: sqlalchemy-iris 作者@Dmitry Maslennikov 您的项目使我的试验变得可能。 文章脚本使用 openai API,因此请注意不要在外部共享您不打算共享的表信息和记录。 如果需要,可以插入本地模型。 创建一个新的虚拟环境 mkdir chainsql cd chainsql python -m venv . scripts\activate pip install langchain pip install wget # Need to connect to IRIS so installing a fresh python driver python -c "import wget;url='https://raw.githubusercontent.com/intersystems-community/iris-driver-distribution/main/DB-API/intersystems_irispython-3.2.0-py3-none-any.whl';wget.download(url)" # And for more magic pip install sqlalchemy-iris pip install openai set OPENAI_API_KEY=[ Your OpenAI Key ] python 初始测试 from langchain import OpenAI, SQLDatabase, SQLDatabaseChain db = SQLDatabase.from_uri("iris://superuser:******@localhost:51775/USER") llm = OpenAI(temperature=0, verbose=True) db_chain = SQLDatabaseChain.from_llm(llm, db, verbose=True) db_chain.run("How many Tables are there") 错误结果 sqlalchemy.exc.DatabaseError: (intersystems_iris.dbapi._DBAPI.DatabaseError) [SQLCODE: <-25>:<Input encountered after end of query>] [Location: <Prepare>] [%msg: < Input (;) encountered after end of query^SELECT COUNT ( * ) FROM information_schema . tables WHERE table_schema = :%qpar(1) ;>] [SQL: SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';] (Background on this error at: https://sqlalche.me/e/20/4xp6) ←[32;1m←[1;3mSELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';←[0m>>> 开发者之间的对话 IRIS 不喜欢以分号结尾的 SQL 查询。 现在做什么? ? 想法:我告诉 LangChain 帮我修理SQL如何 太酷了,我们开工吧 !! 测试二 from langchain import OpenAI, SQLDatabase, SQLDatabaseChain from langchain.prompts.prompt import PromptTemplate _DEFAULT_TEMPLATE = """Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. Use the following format: Question: "Question here" SQLQuery: "SQL Query to run" SQLResult: "Result of the SQLQuery" Answer: "Final answer here" The SQL query should NOT end with semi-colon Question: {input}""" PROMPT = PromptTemplate( input_variables=["input", "dialect"], template=_DEFAULT_TEMPLATE ) db = SQLDatabase.from_uri("iris://superuser:******@localhost:51775/USER") llm = OpenAI(temperature=0, verbose=True) llm = OpenAI(temperature=0, verbose=True) db_chain = SQLDatabaseChain(llm=llm, database=db, prompt=PROMPT, verbose=True) db_chain.run("How many Tables are there") 结果二 SQLQuery:←[32;1m←[1;3mSELECT COUNT(*) FROM information_schema.tables←[0m SQLResult: ←[33;1m←[1;3m[(499,)]←[0m Answer:←[32;1m←[1;3mThere are 499 tables.←[0m ←[1m> Finished chain.←[0m 'There are 499 tables.' 我就说很快吧 参考资料: https://walkingtree.tech/natural-language-to-query-your-sql-database-using-langchain-powered-by-llms/ https://python.langchain.com/en/latest/modules/chains/examples/sqlite.html#sqldatabasesequentialchain https://python.langchain.com/en/latest/modules/agents/plan_and_execute.html
公告
Claire Zheng · 六月 14, 2023

2023 年 6 月 13 日 - 公告:进程内存使用量增加

InterSystems 已纠正导致进程内存使用量增加的缺陷。 具体来说,在对局部变量执行$Order 、 $Query 或 Merge时,会出现本地进程分区内存消耗增加的问题。虽然这对大多数运行环境没有不利影响,但支持大量进程或严格限制每个进程最大内存使用的环境可能会受到影响。某些进程可能会遇到<STORE> 错误。 该缺陷存在于2023.1.0.229.0中,但它被重新发布为2023.1.0.235.1,并包含了修复程序,以加快修正,而无需客户等待维护版本。 此缺陷的更正标识为 DP-423127 和 DP-423237。这些将包含在所有未来版本中。 该缺陷出现在 InterSystems IRIS ® 、InterSystems IRIS for Health ™ 和HealthShare ® Health Connect 的版本 2022.2、2022.3 和 2023.1(内部版本 229)中。如果您运行的是这些版本之一,我们建议升级到 2023.1(内部版本 235)。 此修复也可通过 Ad hoc 分发获得。 如果您对此警报有任何疑问,请联系全球响应中心。
公告
Michael Lei · 一月 10

全球创新:2023 年欧洲医疗健康黑克松Hackathon InterSystems FHIR 挑战赛获胜数字健康项目

嗨,大家好, 我们想重点介绍 2023 年布拉格欧洲欧洲医疗健康黑克松Hackathon期间创建的一些杰出项目。IKEM 和阿斯利康向参与者提出了九个现实世界的医疗保健挑战。 InterSystems 向参与者介绍了使用 FHIR 存储库并通过在 AWS 上提供 FHIR 云服务来在其解决方案中执行 FHIR 可用性的机会。 来认识一下我们挑战的获胜者: 第一名Čarodějové (PathoSync) “PathoSync 软件是复杂病理学家平台的坚实基础。通过使用自定义映射,任何实验室都可以将其数据投影到 FHIR7 标准,该标准很快将在全球范围内强制执行。这使得数字化过程更加顺利。与 InterSystems 的连接确保了质量并实现了很多医疗保健功能。此外,使用位于欧洲的FHIR服务器严格遵循GDPR规范,因此软件的使用遵循欧洲标准。 项目详情|视频演示| GitHub链接 1链接 2 第二名ICU SPYEYES(生命视力Vital Vision) “ICU 需要一个系统来自动记录视频循环,捕捉患者和人员移动等关键活动。该系统将允许人进行回顾性注释、预先注释和识别人员,并可选择模糊患者面部。它的目的是收集数据以用于开发未来医院中的患者监控算法。 我们为 ICU 开发了一个系统,该系统利用运动检测、LLM 和标准 CV 技术进行视频分析。它构建了一个带注释的视频数据库,对于专注于患者监护的训练算法至关重要。我们的解决方案生成通过 FHIR 共享的结构化报告和视频,确保高效的数据处理。通过开源平台 CVAT 进行手动审核,质量得到提高,优化了我们用于监测患者康复情况的实时警报系统。” 项目详情|视频演示| GitHub 第三名 VariantCall (PathoX) “端到端解决方案 PathoX 是一个可轻松进行数据摄取、特征提取和映射的平台,可增强病理学家的工作流程。导入器工作流程支持列映射并通知用户缺失的信息。我们使用 FHIR 来保证未来的互操作性和合规性与未来的立法。病理学家还可以像平常的工作流程一样突出显示数据并留下评论,并查看所有文件的分析。” 项目详情|视频演示| GitHub 大家都很棒,恭喜!希望能对大家有所启发,我们也期待看到您的项目如何发展成为创新且有影响力的初创企业!
文章
Hao Ma · 六月 19, 2023

IRIS通过SNMP发送警告通知的操作

上篇文章[IRIS, Caché监控指导 - 警告和告警](https://cn.community.intersystems.com/post/iris-cach%C3%A9%E7%9B%91%E6%8E%A7%E6%8C%87%E5%AF%BC-%E8%AD%A6%E5%91%8A%E5%92%8C%E5%91%8A%E8%AD%A6) 发出后收到要求介绍一下发送SNMP通知的具体操作,这里介绍一下。 我省去了SNMP的原理,这个有需要的可以网上查找。这里只做一个配置的操作:测试怎么从一个Windows上安装的IRIS实例发送IRIS Alert给另一台Linux服务器。 ## 第一步: 配置 Windows SNMP 因为安全原因,Windows 10不再默认安装中启动SNMP,用户需要手工安装SNMP启动服务。以下两个文章是古老的Window 2003和新的Windows 10中配置SNMP的安装,给各位做个参考。 - [HOW TO: Configure the SNMP Service in Windows Server 2003](https://support.microsoft.com/en-us/help/324263/how-to-configure-the-simple-network-management-protocol-snmp-service-i) - [How to Install and Configure SNMP Service on Windows 10](https://theitbros.com/snmp-service-on-windows-10/) 简单的总结一下:Windows系统中有两个服务: - SNMP Service:使简单网络管理协议(SNMP)请求能够在此计算机上被处理。如果此服务停止,计算机将不能处理 SNMP 请求。如果此服务被禁用,所有明确依赖它的服务都将不能启动。 - SNMP Trap:接收本地或远程简单网络管理协议 (SNMP) 代理程序生成的陷阱消息并将消息转发到此计算机上运行的 SNMP 管理程序。如果此服务被停用,此计算机上基于 SNMP 的程序将不会接收 SNMP trap 消息。如果此服务被禁用,任何依赖它的服务将无法启动。 当前我需要从本机向远端发送SNMP, 所以只需要开启SNMP Service即可。然后需要配置SNMP Service的: - Community名称 - 发送Trap的目的地址 - Community的权限(在”安全”子页面配置,权限为读写,应该选中“发送身份验证Trap”) 如下图,Commnity是”public”, 发送trap到172.16.58.1和172.16.58.101, 分别是两台远端的服务器。 ## 第二步: 配置IRIS SNMP 在Windows系统注册iscsnmp.dll Windows系统中,如果IRIS安装在SNMP服务安装之前, 需要手工执行以下命令来注册iscsnmp.dll到Windows Registry。命令成功执行后要重启操作系统的SNMP Service。 打开IRIS Terminal工具,在%SYS命名空间执行: ``` SYS>set myStatus=$$Register^SNMP() Cache SNMP Extension Agent DLL successfully added to Registry ``` 上述命令行必须是在Administrator的角色执行,否则会有权限问题, 提示错误 “Unable to open Registry key 'SOFTWARE\Microsoft\Windows\CurrentVersion\CommonFilesDir” 开启 %SNMP_Monitor服务 到System>Security Management >Services, 启动%Service_Monitor服务。%Service_Monitor服务负责Caché和本地操作系统的SNMP Agent的通信,如果关闭,本地和远程的SNMP通信都将中断。 到“系统>配置>监视器配置- 配置设置。选中” 开启SNMP服务随系统启动而启动”,英文”Start SNMP Agent at System Startup”。(Cache'中本页面还包括BMC PORTAL监控软件或者WMI选项,如果不使用,可以不用关心)。 最后,为了启用修改后的配置,需要重启Caché实例。如果是测试环境, 也可以不重启,而是在Caché Terminal执行:`Do start^SNMP()` 或者`Do start^SNMP(705,20) `来应用修改, 其中705是ensemble SNPM作为subagent的默认TCP端口号, 20是超时时间。 命令`do stop^SNMP()`命令可以在IRIS停止SNMP工作。 ## 第三步: 向远端服务器发送SNMP Trap 这里,远端服务器我使用net-snamp工具。 net-snmp是linux, unix, mac os上第一选择的snmp服务和工具。简单的介绍centos 7 的net-snmp安装命令 ```bash # 安装net-snmp [root@serverb ~]# yum install net-snmp net-snmp-utils -y # 查看版本 [root@serverb ~]# snmpd -v # 启动 [root@serverb ~]# systemctl start snmpd [root@serverb ~]# systemctl status snmpd ``` (如果接收警告的SNMP Server是Windows系统,您可以选择一些图形化的工具做SNMP Trap的接收,比如[iReasoning](https://www.ireasoning.com/). ) ### 设置snmp trap deamon ```bash hma@CNMBPHMA ~ % snmptrapd -df -Lo NET-SNMP version 5.6.2.1 ``` ### 在IRIS发送Alert 简单的制造一个alert的最简单的方法是用下面的命令,它向messages.log写一个级别为2的记录,这个记录会再写到alert.log里,通过SNMP发送给SNMP服务器。 ``` %SYS>do ##class(%SYS.System).WriteToConsoleLog("Winter is coming",,2) ``` ### 检查SNMP服务器收到警告 这时去刚才的snmptrapd终端,可以看到收到了警告。 ```bash hma@CNMBPHMA ~ % snmptrapd -df -Lo Received 137 byte packet from UDP: [172.16.58.200]:55212->[0.0.0.0]:0 0000: 30 81 86 02 01 00 04 06 70 75 62 6C 69 63 A4 79 0.......public�y 0016: 06 0A 2B 06 01 04 01 81 81 33 04 02 40 04 AC 10 ..+......3..@.�. 0032: 3A C8 02 01 06 02 01 0E 43 03 5E E4 CB 30 5A 30 :�......C.^��0Z0 0048: 1E 06 14 2B 06 01 04 01 81 81 33 04 01 01 01 01 ...+......3..... 0064: 06 48 43 44 45 4D 4F 04 06 48 43 44 45 4D 4F 30 .HCDEMO..HCDEMO0 0080: 38 06 14 2B 06 01 04 01 81 81 33 04 01 01 01 08 8..+......3..... 0096: 06 48 43 44 45 4D 4F 04 20 5B 55 74 69 6C 69 74 .HCDEMO. [Utilit 0112: 79 2E 45 76 65 6E 74 5D 20 57 69 6E 74 65 72 20 y.Event] Winter 0128: 69 73 20 63 6F 6D 69 6E 67 is coming ``` 到这里,IRIS的警告通过SNMP发送已经成功,接下来,您可以做进一步的测试,比如, 如果您对镜像的警告很重视, 您可以测试做如下的测试: 接收镜像相关的警告 - **Becoming primary mirror server** 本镜像成员成为主机 - **Arbiter connection lost** 丢失和arbiter的连接。 - **MirrorServer: Connection to xxxx(backup) terminated** ​ 丢失和backup的连接。 以上3个警告都会写入alert,并发送给snmp服务器。 最后,如果您熟悉其他的监控工具,这时候您可以配置您的工具来接收警告了。 我后面会贴一个zabbix上监控IRIS的介绍,其中的警告用SNMP Trap实现,有兴趣的同学可关注本作者。
文章
Louis Lu · 八月 30, 2023

使用代码获取数据库剩余空间

大家可以通过InterSystems IRIS 管理门户SMP查看当前数据库剩余空间,路径是 Management Portal: System Operation > Database 当然大家也可以通过下面的代码查看数据库的可用磁盘空间: /// ZISJ.mac Set stmt=##class(%SQL.Statement).%New() Set status=stmt.%PrepareClassQuery("SYS.Database","FreeSpace") Set rs=stmt.%Execute() While rs.%Next() { Write ! For i=1:1:9 { Write rs.%GetData(i),"," } }
文章
姚 鑫 · 七月 25, 2023

第二章 HL7 架构和可用工具

# 第二章 HL7 架构和可用工具 - HL7 模式和消息概述 ## HL7 模式和消息概述 `InterSystems` 产品可以处理和传递 `HL7` 消息,而无需使用架构来解析它,但将架构与消息关联允许执行以下操作: - 解析消息并访问以下字段值: - 数据转换 - 路由规则 - 自定义 `ObjectScript` 代码 - 验证消息是否符合架构。 每个 `HL7` 消息均由消息类型标识,该消息类型在 `MSH` 段 `MessageType` 字段 (`MSH:9`) 中指定。一些消息类型共享相同的消息结构。例如,在`HL7`版本`2.3.1`中,用于预先接纳患者的`ADT_A05`消息具有与`ADT_A01`接纳消息相同的结构。该架构指定 `ADT_A05` 消息具有结构类型 `ADT_A01`。 为了解析 `HL7` 消息,需要两条信息: - 架构类别 — 这是 `HL7` 版本号,例如 `2.3.1` 或 `2.7`,或者它可能是 `InterSystems` 产品中定义的自定义架构的类别。`production` 从业务服务消息模式类别设置或从数据转换设置获取模式类别。尽管 `HL7` 消息在 `MSH` 段 `VersionID` 字段中包含模式版本号 (`MSH:12`),但 `InterSystems` 不使用此值,因为许多应用程序并未一致地设置此字段。 - 结构类型 - `production` 从 `MSH:9` 字段获取消息类型,然后检查架构定义以获取该消息的结构类型。 在某些情况下,使用 `MSH:9.3` 子字段来限定消息类型。 `MSH:9:`3 子字段在 `HL7` 消息中以两种方式使用:1) 作为消息类型的修饰符,或 2) 指定结构类型。如果 MSH:9:3 修改消息类型(通常为数字),InterSystems 产品会将其作为消息类型的一部分。如果 MSH:9:3 指定结构类型(例如 `ADT_A01`),则 `InterSystems` 在确定消息类型和设置 `Name` 属性时都会忽略它。 `InterSystems` 产品不需要 `MSH:9.3` 子字段来确定结构类型,因为它们从架构中获取结构类型。 当业务服务或数据转换创建 `EnsLib.HL7.Message` 对象来存储 `HL7` 消息时,它会组合架构类别和结构类型,并使用以下语法将其存储在 `DocType` 属性中: ``` category:structureType ``` 例如,类别 `2.3.1` 的有效 `DocType` 值包括 `2.3.1:ACK`、`2.3.1:ADT_A17`、`2.3.1:BAR_P01` 和 `2.3.1:PEX_P07`。消息类型可以与结构类型不同,存储在 `Name` 属性中。 如果在 `ObjectScript` 代码中创建 `EnsLib.HL7.Message` 对象,则应根据 `MSH:9` 字段中的值设置 `DocType` 和 `Name` 属性。 `HL7` 标准允许本地扩展,例如尾部 `Z` 段。这些段未在基本架构类别中定义。如果要访问数据转换、路由规则或 `ObjectScript` 中自定义 `Z` 段中的字段,则需要定义指定扩展消息的自定义架构类别。 可以将自定义 `HL7` 架构置于源代码管理之下。启用源代码控制后,源代码控制选项(例如签出和签入)可从主 `HL7` 模式页面使用,但在用于处理自定义模式的其他页面(例如 `HL7` 模式消息类型页面)上不可用。在使用其他页面编辑架构之前,必须从 `HL7` 架构页面检查整个架构。 `HL7` 模式主页面提供了源代码控制输出窗口,该窗口捕获所有相关 `HL7` 模式页面的源代码控制活动。有关设置源代码控制的信息,请参阅将 `IRIS` 与源代码控制系统集成。 这个应该只是讲的HL7 v2 的消息吧?
问题
li liao · 八月 30, 2023

Caché 2016.1 CDC

参考 https://blog.csdn.net/InterSystems/article/details/115350635 搭建 mirror ,获取数据变更,示例给出了获取数据变更的代码: Class ZCustom.MirrorDejournal Extends SYS.MirrorDejournal{ Method RunFilter( MirrorDBName As %String, GlobalReference As %String, RecordType As %String, Address As %Integer) As %Integer{ Set ^CDCLog( $I($^CDCLog))=$lb(MirrorDBName,GlobalReference,RecordType,Address) Quit 1} 示例代码将变更存储在 global 对象 CDCLog 中,想请问下获取变更前后数据,发送到外部系统,有哪些方式? 可以参考我们的CDC系列文章https://cn.community.intersystems.com/node/491941,谢谢!
公告
Claire Zheng · 十月 17, 2023

重要公告:征文大赛将延期至11月24日!欢迎继续投稿,参加InterSystems开发者社区中文版第二届技术征文大赛!

嗨,开发者们! 我们决定将🏆InterSystems开发者社区中文版第二届技术征文大赛 🏆的参赛时间延长至11月24日,请参赛者关注重要时间节点的变化。 📝 2023年9月19日-11月23日(北京时间),文章发布与点赞收集!在社区发布文章后即可开始为您的文章收集点赞。越早发布文章,就越有时间收集更多点赞(这是您获得“开发者社区奖”的关键)。 📝 2023年11月23日(北京时间),专家打分截止(专家提名奖)。 🎉 2023年11月24日(北京时间),公布获奖名单。 欢迎大家继续积极投稿,赢取大奖! 了解参赛规则及文章样例:点击此处 了解奖品详情:点击此处 欢迎投稿参赛! 快乐分享技术,期待您的大作!✨ 🏆InterSystems开发者社区中文版第二届技术征文大赛 🏆(←点击链接进入参赛页面,浏览所有参赛文章)
文章
Lilian Huang · 八月 1, 2023

FHIR 应用系列--虚拟实验室: 基于VR和AI的重症监护室模拟培训

VR ICU® 是 InterSystems FHIR 创新孵化器 Caelestinus 的参与者。这篇文章将向您介绍我们利用 InterSystems FHIR Server 为医疗保健提供的 VR 解决方案。 我们是一家技术初创企业虚拟实验室,利用先进的 VR/AR 技术开发解决方案。VR ICU® 是一个针对重症监护室医务人员的培训平台,是在 Covid 时代为满足医院需求而创建的。 与InterSystems合作的优势 我们的 VR ICU® 解决方案符合实践需求,是与医院合作开发的。 除了技术解决方案和技能学习本身,记录培训课程、培训进度和成功率对于医院或麻醉学和重症监护部门的有效管理也至关重要。医务长可以通过了解谁在何时接受了培训,清楚地掌握能够在重症监护室使用设备的人员数量,从而有效地对他们进行培训,以保持技能、有控制地规划人员技能储备并提高他们的能力。 在这方面,与 InterSystems 的合作对我们来说至关重要,它使我们能够在应用程序中存储每次培训期间的数据。目前,我们会记录参与者的姓名、培训日期和时长、培训类型、设备类型、错误数量和类型,必要时还会记录培训成功完成的信息。 如何使用?用户登录应用程序并选择一个账户。 根据 HL7 标准,该账户作为从业人员存在于数据库的资源下。培训课程开始时,会在应用程序中创建一个新的 "任务"--在这里输入培训课程的开始时间和培训课程的类型,课程结束时,再次输入培训课程的结束时间。错误会写入输出表。培训完成后,任务中的数据将序列化为 JSON 格式,并使用 FHIR API 发送到云端。为了使 VR 应用程序之外的数据可视化,我们开发了一款平板电脑应用程序。该应用程序与存储在云端的数据相连,并显示特定用户的个人训练课程。 人力资源部门通过培训数据了解受训人员完成培训的总体情况和水平,从而有效地规划他们的进一步培训,并跟踪了解员工的能力及其在重症监护室护理过程中的替换性。您可以点击这里:https://www.youtube.com/watch?v=3oO0uuHy0kg&t=8s 如今,医院、大学和模拟中心都在使用 VR ICU®。 虚拟现实技术将教育和培训提升到了一个新的水平。通过体验学习,可以提高培训效果和记忆力。 在 VR ICU® 中使用 InterSystems 的 FHIR 云服务器作为存储培训进度数据的工具,并使用 FHIR API 进行通信,这也对我们进军国外市场产生了积极影响,尤其是在德国,FHIR 标准是一种广为接受的解决方案,用于与人力资源部门传输信息,并与第三方调度系统进行通信。 麻醉学和重症监护审查参考:https://www.youtube.com/embed/Qve5xEm89cU?feature=oembed 它是如何开始的? 2020 年,一场大流行病袭击了我国。医院人满为患,人手短缺,尤其是重症监护室。麻醉、复苏和重症医学科主任在晚间新闻中解释说,如果更多的医生被隔离或生病,他就没有足够的合格人员来操作肺部呼吸机。其他医院也证实了同样的情况。我们萌生了制作一个专门用于培训的肺部呼吸机数字拷贝,帮助医院培训其他科室医生的想法。 我们找到了麻醉复苏部(ARO)的负责人、模拟中心的专家。医生们支持我们的想法,有些人还参与了开发工作。我们还得到了医疗设备制造商的支持,他们看到了虚拟现实培训的附加值。 我们是如何开展项目的,解决方案的重要性何在? 1. 我们评估了重症监护室的现状: - 在没有真实病人和/或医疗设备的情况下,50% 以上的重症监护室程序无法进行培训。 - 医疗设备制造商难以将医务人员集中到一处进行培训(只有 30% 的受训人员能坚持到培训结束) - 过去两年中,麻醉学和重症监护部门的人员流动率约为 20%。 2. 问题的解决方案: - 虚拟现实自动培训平台 - 模拟重症监护室的手术过程,无需真实病人,也无需使用真实医疗设备 - 节省技术和医疗用品 - 也可用于远程培训,从不同地点/工作场所进入同一个虚拟空间 - 在安全的环境中进行风险情况演练 - 将人为错误的风险降至最低 3. 潜力: - 利用人工智能(AI)模拟和练习危急情况,确定正确的程序 - 人工智能可模拟病人-设备-病人之间的互动 - 制造商的设备集中在一个虚拟空间,使医院的培训更加容易 愿景 VR ICU® 的目标是作为一个平台,让医院从实际使用的设备目录中选择 3D 设备,并从中创建培训环境。 我们向医疗设备制造商提出的愿景最初得到了 BBraun、费森尤斯和 Linet 的支持。随后,其他公司也纷纷效仿这些大胆的先行者。我们还根据所进入的市场扩大我们的设备组合。目前,我们在美国、亚洲和南美都有合作伙伴,他们正在补充信息并与制造商进行谈判。 我们正在全球会议上展示 VR ICU®,我们很高兴能成为 Caelestinus 孵化器的一部分。由于我们与 InterSystems 的合作,我们有机会参加在西雅图举行的 InterSystems 2022 年全球峰会,现在我们正在拉斯维加斯参加 HLTH 2022。 VR ICU® 已经赢得了许多奖项,最近在奥地利林茨,我们凭借该解决方案赢得了最佳初创企业奖。 这些成功的展示吸引了投资者的关注。我们欢迎那些希望进一步开发我们产品的人向我们推荐他们。我们计划在 2023 年向捷克、斯洛伐克和德国的医院出售许可证。我们欢迎商业合作伙伴以及能够加快 VR ICU® 实际应用--市场进入进程或希望为人工智能/VR 版本的开发做出贡献的合作伙伴。 原文来自这里:https://community.intersystems.com/node/529381
文章
Michael Lei · 八月 10, 2023

如何比较两个数据库中的多个Global和Routines

InterSystems 常见问题解答 ※如果您想比较使用Mirror、Shadow或其他机制复制的数据库,请使用此方法。 您可以使用 DATACHECK 实用程序来比较Global。请参阅下面的文档。DataCheck 概述 [IRIS] *** Routines比较使用系统例程 %RCMP 或管理门户。 以下是如何在管理门户中使用它。 例如,假设以下Routine位于 USER 命名空间中。 test() public{ quit "hello" } 假设以下Routine位于 USER2 命名空间中。 test() public{ quit "Hello" } 下面是在连接到 USER 命名空间的终端中运行 %RCOM 的结果。 * 在Compare : 中写入Routine名称以及要与: 进行比较的Routine名称要指定另一个命名空间中的Routine,请指定|“命名空间名称”|例程名称.MAC。 用户>执行 ^%RCMP比较:comptest.mac 与:|"USER2"|comptest.macCompare: // [备注] 如果没有可比较的内容,请按 Enter忽略评论差异?否 => 否忽略前导空格?否 => 否显示结果于Device: c:\temp\comp.txt // [备注] 指定文件名时的文件输出 参数? (“WNS”)=>comptest.MAC |“USER2”|comptest.MAC****************************************************** ******************************用户> 对比结果如下。 常规比较 2021 年 2 月 2 日 2:31 PM来自目录:c:\intersystems\iris\mgr\user\ comptest.MAC |“USER2”|comptest.MAC****************************************************** ******************************竞争测试.MAC+2 退出“你好”......................|“USER2”|comptest.MAC+2 退出“你好”****************************************************** **************************
文章
Weiwei Gu · 九月 14, 2023

VS Code 无法连接到服务器的原因之一

昨天,我在一个客户网站提供从 Studio 迁移到 VS Code 的定制咨询时,就遇到了这种情况。 该站点的服务器已配置为使用delegated authentication,但尚未针对 /api/atelier Web 应用程序设置“delegated”复选框,而 InterSystems ObjectScript 扩展包的成员正是使用该复选框进行连接的。 一旦我们的应用程序设置了其复选框并单击了服务器管理器刷新按钮,就可以在服务器上枚举命名空间。
文章
Weiwei Gu · 八月 14, 2023

调试管理门户加载图片失败的原因

在提交的 WRC case中(Intersystems 全球技术支持响应中心),我们经常看到客户提出有关新 Web 网关设置的问题,其中管理门户加载一半,但不显示图像。本文将解释为什么会出现此错误,以及如何修复它。本说明主要针对服务 InterSystems IRIS 实例的 Web 网关,但相同的说明也应适用于服务 Caché 实例的 CSP 网关。 问题: 您刚刚在独立的 Web 服务器上安装了 Web Gateway。当你去加载管理门户时,你发现它无法显示或加载图像,如下所示: 为什么会发生这种情况: 问题是,为了完整加载管理门户,InterSystems IRIS 必须加载许多 .js、.css 和 .png 文件(静态文件)。如果您看到像上面这样的管理门户页面,请随时打开浏览器的开发人员工具小程序,导航到“网络”选项卡,并确认未提供各种 .js、.css 和 .png 组件: 最初安装 Web Gateway 时,我们仅为以下扩展设置映射: .csp .cls .zen .cxw 这些是客户在自己的自定义应用程序中最常使用的文件扩展名类型,以及用于为 Web Gateway 管理门户提供服务的 .cxw 扩展名。如果您想要加载其他管理门户组件,则必须注册其他文件类型以由 Web 网关提供服务。 如何解决该问题: 要使管理门户完全显示,您必须配置 Web 网关以提供其他文件类型。对于 IIS,您可以为 .js、.png、.css 等扩展名添加单独的映射,也可以添加通配符映射。可以在此处找到有关注册 IIS 的其他文件类型的文档:https: //docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls ?KEY=GCGI_win#GCGI_registering 如果您在 Unix / Linux 系统上的 Apache 之上运行 Web Gateway,您有几个选择。您可以通过添加其他文件扩展名(如 IIS 上的情况)来配置此功能,也可以添加 CSP 位置指令。请参阅此处的文档了解完整详细信息: https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls ?KEY=GCGI_ux,位于“使用 CSP 注册其他文件类型”下
文章
Qiao Peng · 一月 31

用Java开发互操作产品 - PEX

InterSystems IRIS、Health Connect和上一代的Ensemble提供了优秀的互操作架构,但即便有低代码开发能力,很多开发者还是希望能用自己的技术栈语言在InterSystems的产品上开发互操作产品。 考虑到互操作产品本身的开放性要求和各个技术栈背后庞大的生态价值,InterSystems IRIS和Health Connect提供了Production EXtension (PEX)架构,让开发者使用自己的技术栈语言来开发互操作解决方案。目前PEX支持Java、.net、Python。 这里我们介绍使用Java利用PEX进行互操作产品的开发。 一 InterSystems IRIS上使用Java开发的基础 在进入PEX主题前,需要简单介绍一下Java在InterSystems IRIS上开发的各种技术选项,因为PEX也是以这些技术选项为基础的。 如果仅把InterSystems IRIS作为一个数据库看待,可以使用JDBC对它进行SQL访问,这是最传统的开发方式; Java是一个面向对象的开发语言,而InterSystems IRIS也是支持面向对象的数据平台。InterSystems IRIS的外部语言服务器技术,提供了一套Java原生SDK,让Java和InterSystems IRIS可以互相访问对方的对象,甚至Java可以通过它直接访问InterSystems IRIS后台的持久化多维数组。外部语言服务器提供了非常灵活、高效的开发方式; 如果是想把Java对象直接持久化到InterSystems IRIS,除了Hibernate,InterSystems IRIS提供一种更高性能的方法 - XEP(Express Event Persistence表达事件持久化); 最后,Java可以通过PEX开发InterSystems IRIS的互操作产品组件。PEX基于Java原生SDK。 作为多种Java访问方式的基础,InterSystems IRIS的Java外部语言服务器的架构如下: InterSystems IRIS和Java通过动态代理对象的方式操作对方对象,动态代理无需在对方代码变更时重新生成代理类。 InterSystems IRIS提供了intersystems-jdbc-<版本号>.jar,不仅用于JDBC连接、也用于Java外部语言服务器连接,提供Java原生SDK。 在Java端通过jdbc.IRIS管理InterSystems IRIS连接,使用jdbc.IRISObject反向操作IRIS对象。 InterSystems IRIS端提供并管理包括Java语言服务器在内的一系列外部语言服务器。注意,一般情况下,使用系统开箱的这些外部服务器就够了,不需要额外建立额外的Java语言服务器。而且,也无需事先启动,外部语言服务器会在调用时自动启动。 Java连接到InterSystems IRIS,并创建IRIS外部服务器的示例: String connStr = "jdbc:IRIS://127.0.0.1:1972/USER"; String user = "superuser"; String pwd = "SYS"; // 使用DriverManager 创建IRIS连接 // IRISConnection conn = (IRISConnection)java.sql.DriverManager.getConnection(connStr,user,pwd); // 或使用IRISDataSource 创建IRIS连接 IRISDataSource ds = new IRISDataSource(); ds.setURL(connStr); ds.setUser(user); ds.setPassword(pwd); IRISConnection conn = (IRISConnection) ds.getConnection(); // 创建IRIS外部服务器 IRIS irisjv = IRIS.createIRIS(conn); // 调用IRIS类%PopulateUtils的类方法Name,产生随机姓名 String tempTrader = irisjv.classMethodString("%PopulateUtils", "Name"); 二 PEX 开发 PEX针对于互操作产品的开发,通过PEX使用外部语言开发互操作产品所需的组件,甚至可以通过PEX开发互操作产品的所有组件。 2.1 InterSystems IRIS互操作产品架构 典型的InterSystems IRIS互操作产品架构如下,它的典型工作机制是: 业务服务通过入站适配器监听外部系统,例如TCP和文件系统,将数据组织成消息发送给业务流程 业务流程根据流程需要在特定流程节点将消息发送给业务操作 业务操作通过出站适配器访问外部应用,发送数据并获取响应,并将响应数据组织成消息反馈给业务流程 在互操作产品内部流转的都是消息,消息默认自动持久化并可以通过SQL等方式结构化查询 互操作产品涉及3类组件: 业务组件:包括业务服务、业务流程、业务操作 适配器:包括入站适配器和出站适配器 消息 这3类组件都可以通过PEX进行开发。 2.2 PEX 类和类包 InterSystems IRIS 提供了一个intersystems-utils-<版本号>.jar包,提供com.intersystems.enslib.pex类包,用于基于Java开发互操作产品组件。 在Java代码里还要调用IRIS Object Script开发的组件和代码,因此,还需要intersystems-jdbc-<版本号>.jar。 2.3 示例业务场景介绍 下面我们根据一个示例业务场景介绍如何使用Java PEX进行互操作产品的开发。 业务场景是一个银行间汇款的流程: 业务服务(Finance.FromFileTransaction)监听特定文件夹,并从新汇款申请文件中解析出汇款请求,发送给业务流程(Finance.ProcessPaymentRequest); 业务流程先将请求发送给汇出行的业务操作(Finance.ToPayFromBank),获取汇出行的审核结果; 如果汇出行审核批准,则业务流程继续将请求发送给接收行的业务操作(Finance.ToPayToBank) 这里汇出行的业务操作和接收行的业务操作都会将数据写入特定文件夹的文件中。 这个场景中,我们完全使用Java开发全部的组件,包括:请求、响应消息;入站、出站文件适配器;业务操作;业务流程和业务服务。 下面我们就开始吧。 2.4 消息开发 Java消息类是com.intersystems.enslib.pex.Message的子类,消息中的属性,需要定义为public。它会在互操作业务组件间传递时自动持久化。 在IRIS端,Java消息自动映射到EnsLib.PEX.Message,它是一个持久化的IRIS类,包含以下属性: %classname属性:Java消息类名 %json属性:Java消息的JSON类型(IRIS动态对象) 在InterSystems IRIS端,例如消息可视化追踪页面和消息表,你看到的Java消息都是EnsLib.PEX.Message类型。 PEX消息用到的共同账号信息类的示例代码: package Finance; // 封装银行账号信息的类. public class PaymentProfile extends com.intersystems.enslib.pex.Message { public int AccountNumber; public int RoutingNumber; public String UserName; } 请求消息的示例代码: package Finance; import Finance.PaymentProfile; // PEX开发的转账请求消息. public class TransactionRequest extends com.intersystems.enslib.pex.Message { public double TransactionAmount; // 转账金额 public PaymentProfile PayFrom; // 付方银行账号信息 public PaymentProfile PayTo; // 收方银行账号信息 public String FromCurrency; // 付方货币 public String ToCurrency; // 收方货币 // 实例化银行账号属性. public TransactionRequest(){ PayFrom = new PaymentProfile(); PayTo = new PaymentProfile(); } } 响应消息的示例代码: package Finance; // PEX开发的转账响应消息. public class TransactionResponse extends com.intersystems.enslib.pex.Message { public boolean approved; } 2.5 业务组件和适配器的运行时变量 在互操作产品的管理配置页面,可以设置各个业务组件和适配器的配置项,例如文件适配器的文件路径,方便实施和管理。 对于Java开发的业务组件和适配器,同样我们需要这样的配置项。这些配置项,我们称之为运行时变量,这样进行定义: 运行时变量是Java业务组件类和适配器类的public类型的属性 对这些属性使用Java annotation进行元数据描述,例如: @FieldMetadata(IsRequired=true,Description="文件路径") public String FilePath; 后面的Java业务组件和适配器会用到运行时变量的声明方法。 2.6 入站适配器开发 如果要开发Java入站适配器,需要定义一个com.intersystems.enslib.pex.InboundAdapter的Java子类。并在类中实现以下方法: 方法 参数 说明 OnTask 无 适配器根据调用间隔设置,周期性地调用该方法对数据源进行查询;将数据调用BusinessHost.ProcessInput()将数据发送给业务服务;BusinessHost是业务服务的固定的变量名 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 例如入站文件适配器示例代码如下: package Finance; import java.io.File; // 导入File类. import java.io.FileNotFoundException; // 导入此类以处理错误. import com.intersystems.enslib.pex.FieldMetadata; // 导入PEX运行时变量类 // 这是一个PEX的入站适配器,检测定义在InboundFilePath的文件夹路径。如果文件夹下有文件,遍历这些文件,使用ProcessInput()将文件路径发送给业务服务 public class PEXInboundAdapter extends com.intersystems.enslib.pex.InboundAdapter { @FieldMetadata(IsRequired=true,Description="输入文件路径") public String InboundFilePath; // 文件夹路径配置项. public void OnTearDown() {} public void OnInit() {} public void OnTask() throws Exception { // 检查文件夹路径,并遍历文件. File folder = new File(InboundFilePath); File[] list = folder.listFiles(); if (list.length > 0) { for (File file : list) { // 忽略.keep后缀文件. // 其它文件路径发送给业务组件BusinessHost. if (file.getName().equals(".keep")) {continue;} BusinessHost.ProcessInput(file.getAbsolutePath()); } } } } 2.7 Java开发组件的注册与更新 开发好的Java组件,需要在InterSystems IRIS端进行注册,让互操作产品可以直接使用这些组件。 注册的方法在Production扩展页面,点击注册新组件: 在远程类名称中填写Java组件类名 在代理名称中填写IRIS生成的代理类名称,可以和Java类名不同。这个类名是在互操作产品中看到和使用的名字。 选择外部语言服务器为%Java Server 将封装有Java组件类的jar文件路径和其它依赖jar文件路径添加到网关额外CLASSPATHS下 注册后就可以在列表中看到注册的组件和组件类型,并在互操作产品中可以直接使用了。 如果后来修改了Java代码,则需要选中已经组册的组件,对其进行更新: * 记得下面这些Java开发的组件也需要注册后使用。 2.8 出站适配器开发 同样,可以通过继承com.intersystems.enslib.pex.OutboundAdapter来开发Java出站适配器类。 它需要实现以下方法: 方法 参数 说明 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 其它方法 根据需要 执行具体的适配器操作 例如出站文件适配器示例代码如下,它提供写文件的方法: package Finance; import java.io.File; // 导入File类. import java.io.FileNotFoundException; // 导入此类以处理错误. import java.lang.StringBuffer; // 导入string buffer类. import java.io.FileWriter; // 写文件的包. import java.util.Date; // 处理日期的包. import com.intersystems.enslib.pex.FieldMetadata; // 导入PEX运行时变量类. import java.text.SimpleDateFormat; // 格式化日期字符串的包. // 这是一个PEX的出站适配器,通常被业务操作使用,连接到外部系统. 这里适配器提供WriteToFile()方法,供业务操作调用. public class PEXOutboundAdapter extends com.intersystems.enslib.pex.OutboundAdapter { @FieldMetadata(IsRequired=true,Description="输出文件路径") public String FilePath; // 输出文件路径. public void OnTearDown() {} public void OnInit() {} //写文件的方法,输入参数input是向文件中写入的内容 public Object WriteToFile(java.lang.Object input) throws Exception { // 转换为字符串 String OutputMessage = (String)input; // 允许用户输入的路径有或没有尾部路径分隔符. if (FilePath.substring(FilePath.length() - 1) != File.separator) { FilePath = FilePath + File.separator; } // 用当前日期时间产生文件名. Date today = new Date(); SimpleDateFormat Formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); String DateString = Formatter.format(today); // 产生完整文件路径. String OutputPath = FilePath + DateString; // 创建文件. File OutputFile = new File (OutputPath); // 实例化FileWriter对象. FileWriter writer = new FileWriter(OutputFile); // 将内容写入文件 writer.write(OutputMessage); writer.close(); return null; } } 2.9 业务操作开发 Java业务操作类,是com.intersystems.enslib.BusinessOperation的子类。需要实现以下功能: 方法 参数 说明 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 OnMessage 无 个方法会在业务操作收到其它业务组件传递过来的消息时被调用 在该方法内部,可以调用适配器的方法 - Adapter.invoke("适配器方法名", 方法参数) Adapter是适配器对象,已经实例化,无需执行自己的实例化代码。Adapter是固定变量名 getAdapterType 无 返回使用的适配器类名 如果是PEX开发的适配器,返回的是它注册到InterSystems IRIS的代理类名 如果使用默认适配器,返回 Ens.InboundAdapter 如果不使用适配器,返回空字符串 例如我们的示例中,有以下2个业务操作: 1. 与汇出银行接口的业务操作类: package Finance; import Finance.TransactionRequest; import Finance.PaymentProfile; import Finance.TransactionResponse; import java.lang.StringBuffer; // PEX业务操作类,和支付银行接口. // 它从业务流程接收请求消息Finance.ProcessPaymentRequest, 将消息内容写入文件并返回内容为'approval' 的响应消息(Finance.TransactionResponse). public class ToPayFromBank extends com.intersystems.enslib.pex.BusinessOperation { public void OnTearDown() {} public void OnInit(){} // 确定适配器 public String getAdapterType() { return "Finance.PEXOutboundAdapter"; } // 响应请求消息 public java.lang.Object OnMessage(java.lang.Object object) throws java.lang.Exception { // 将输入对象转换为对应的类实例. TransactionRequest request = (TransactionRequest)object; // 初始化StringBuffer对象,构造输出文件内容. StringBuffer outputMessage = new StringBuffer(); // 将数据写入StringBuffer. outputMessage.append("Debit request:" + System.lineSeparator()); outputMessage.append("Route:" + request.PayFrom.RoutingNumber + System.lineSeparator()); outputMessage.append("Account: " + request.PayFrom.AccountNumber + System.lineSeparator()); outputMessage.append("Amount: " + request.TransactionAmount); // 调用出站适配器的方法,将数据写入文件. Adapter.invoke("WriteToFile", outputMessage.toString()); // 实例化响应消息,并对响应消息赋值后返回给业务流程. TransactionResponse response = new TransactionResponse(); response.approved = true; return response; } } 2. 与接收银行接口的业务操作类: package Finance; import Finance.TransactionRequest; import Finance.PaymentProfile; import java.lang.StringBuffer; // PEX业务操作类,和收款银行接口. // 从业务流程接收请求消息,并将消息内容写入文件. public class ToPayToBank extends com.intersystems.enslib.pex.BusinessOperation { public void OnTearDown() {} public void OnInit(){} // 确定适配器 public String getAdapterType() { return "Finance.PEXOutboundAdapter"; } // 响应请求消息 public java.lang.Object OnMessage(java.lang.Object object) throws java.lang.Exception { // 将输入对象转换为对应的消息类实例. TransactionRequest request = (TransactionRequest)object; // 实例化StringBuffer对象以构造文件内容. StringBuffer outputMessage = new StringBuffer(); // 将数据写入StringBuffer. outputMessage.append("credit request:" + System.lineSeparator()); outputMessage.append("SourceRouting:" + request.PayFrom.RoutingNumber + System.lineSeparator()); outputMessage.append("SourceAccount: " + request.PayFrom.AccountNumber + System.lineSeparator()); outputMessage.append("ToAccount: " + request.PayTo.AccountNumber + System.lineSeparator()); outputMessage.append("Amount: " + request.TransactionAmount); // 调用出站适配器方法将数据写入文件 Adapter.invoke("WriteToFile", outputMessage.toString()); // 无需响应消息. return null; } } 2.10 业务流程开发 使用Java开发业务流程,则完全是代码开发模式,而非基于BPL的低代码模式。 Java业务流程类是com.intersystems.enslib.pex.BusinessProcess 的子类,需要实现以下方法: 方法 参数 说明 OnInit 无 适配器初始化的方法 OnTearDown 无 适配器退出清理的方法 OnRequest request 请求消息 处理发送给业务流程的请求消息,这个请求消息启动业务流程 OnResponse request 请求消息, response 响应消息, callRequest - 本次异步调用发起的请求消息, callResponse - 本次异步调用收到的响应消息, completionKey - 异步调用发起时传入的completionKey 处理异步调用返回的响应消息-callResponse OnComplete request 请求消息, response 响应消息 整个业务流程完成时,被调用的方法 另外,类里还可以声明需要在业务流程期间保存的持久化数据,和在BPL中要到的上下文(context)数据一样,例如记录汇出行的审核结果。声明时,需要加@Persistent这个Java annotation: @Persistent // 定义名为runningTotal的持久化的属性 public integer runningTotal = 0; 本用例的业务流程示例代码如下: package Finance; import Finance.TransactionRequest; //导入请求消息类 import Finance.TransactionResponse; //导入响应消息类 // 这是一个PEX业务流程类,它从业务服务(Finance.FromFileService)接收请求消息. // 先将汇款请求消息发送给汇出行业务操作(Finance.ToPayFromBank) 并等待审核结果. 如果批准, 将请求消息发送给接收行业务操作(Finance.ToPayToBank). public class ProcessPaymentRequest extends com.intersystems.enslib.pex.BusinessProcess { public Object OnComplete(Object object,Object object2) {return null;} public void OnTearDown(){} public void OnInit(){} // 无需返回响应消息给调用者 public java.lang.Object OnResponse(java.lang.Object request, java.lang.Object response, java.lang.Object callRequest, java.lang.Object callResponse, java.lang.String completionKey) throws java.lang.Exception { return null; } // 处理请求消息 public java.lang.Object OnRequest(java.lang.Object object) throws java.lang.Exception { // 将输入对象转换为对应的消息类实例. TransactionRequest request = (Finance.TransactionRequest) object; // 将支付请求消息以同步请求的方式发送给汇出行. Object response = SendRequestSync("Finance.ToPayFromBank", request); // 将收到的响应消息对象转换为对应的消息类实例. TransactionResponse bankResponse = (TransactionResponse)response; // 记录汇出行审核结果,用于调试 LOGINFO("汇出行审核结果是:"+bankResponse.approved); // 检查汇出行审核结果,如果是批准,则将汇款请求发送给接收行. if (bankResponse.approved) { // 使用异步调用方式通知接收行,无需等待返回. SendRequestAsync("Finance.ToPayToBank", request); } return null; } } 2.11 业务服务开发 Java业务服务类是com.intersystems.enslib.pex.BusinessService 的子类。它有一个父类定义的属性 – TargetComponentNames, 用于设置发送消息目标的下游业务组件名列表。可以同时发送消息给多个下游业务组件,组件名之间通过逗号分隔。 业务服务可以使用适配器,这时它会根据适配器的设置定期轮询外部系统,例如SQL适配器轮询外部SQL表、文件适配器轮询外部文件夹。但业务服务也可以不使用适配器,而直接被外部系统调用,例如发布为SOAP、RESTful服务的业务服务就不使用适配器。 适配器 执行过程 需要实现的方法 使用专业适配器 适配器的OnTask()方法定期执行获得数据,将数据发送给业务服务的ProcessInput() OnProcessInput() 使用默认适配器 Ens.InboundAdapter 适配器的OnTask()方法定期执行,并调用业务服务的ProcessInput(); 业务服务的OnProcessInput()执行数据获取 OnProcessInput() 不使用适配器 不定期执行,用户代码在需要时通过Director.CreateBusinessService() 创建业务服务,并执行其方法 OnProcessInput() 或其它需要的方法 本示例中的业务服务使用前面Java开发的文件入站适配器,其代码如下: package Finance; import java.io.File; // 导入File类. import java.io.FileNotFoundException; // 导入此类以处理错误. import java.util.Scanner; // 导入Scanner类读取文本文件. import Finance.TransactionRequest; // 导入请求消息类. // 这是一个PEX的业务服务类,从文件读取汇款请求. 将文件内容转换为Finance.TransactionRequest消息对象,并检查运行时变量TargetComponentNames,确定需要把请求消息发送给哪些业务组件. public class FromFileTransaction extends com.intersystems.enslib.pex.BusinessService { public String TargetComponentNames; // 用逗号分隔的发送目标组件列表,运行时从配置项获取. public void OnTearDown() {} public void OnInit() {} // 确定适配器 public String getAdapterType() { return "Finance.PEXInboundAdapter"; } // OnProcessInput根据业务服务的'call interval' 设置会被定期调用. public java.lang.Object OnProcessInput(java.lang.Object messageInput) throws java.lang.Exception { String path = (String)messageInput; File file = new File(path); // 创建scanner对象读取文件. Scanner reader = new Scanner(file); // 实例化请求消息TransactionRequest对象. TransactionRequest request = new TransactionRequest(); // 设置消息属性. request.TransactionAmount = Float.parseFloat(reader.nextLine().split(":")[1]); String tempString = reader.nextLine(); // 解析嵌套的PaymentProfile对象,并赋值给请求消息的PayFrom属性. String[] tempStringArray = tempString.split(":"); String[] PaymentProfile = tempStringArray[1].split("\\|"); request.PayFrom.AccountNumber = Integer.parseInt(PaymentProfile[0]); request.PayFrom.RoutingNumber = Integer.parseInt(PaymentProfile[1]); request.PayFrom.UserName = PaymentProfile[2]; // 解析PaymentProfile对象,并赋值给PayTo属性. tempString = reader.nextLine(); tempStringArray = tempString.split(":"); PaymentProfile = tempStringArray[1].split("\\|"); request.PayTo.AccountNumber = Integer.parseInt(PaymentProfile[0]); request.PayTo.RoutingNumber = Integer.parseInt(PaymentProfile[1]); // 设置剩余属性. request.PayTo.UserName = PaymentProfile[2]; request.FromCurrency = reader.nextLine().split(":")[1]; request.ToCurrency = reader.nextLine().split(":")[1]; reader.close(); // 处理后删除文件. file.delete(); // 获取Split target business component string and send to each component. String[] targetNames = TargetComponentNames.split(","); for (String name : targetNames){ SendRequestAsync(name, request); } return null; } } 2.12 组装互操作产品并进行测试 将这些Java开发的组件组册后,就可以像InterSystems IRIS的本地组件一样使用了。我们将业务操作、业务流程和业务服务依次加入到Production,并配置好相应的配置项: 对于每个业务操作,需要配置一项: 文件路径:输出的文件夹路径 对于业务服务,需要配置两项: InboundFilePath: 监听的汇款请求文件夹路径 TargetComponentNames: 目标业务流程,这里应该填Finance.ProcessPaymentRequest 下面是用于测试的汇款请求文件内容,把它copy到一个文本文件中保存: TransactionAmount:59.43 PayFrom:232422|23532532|TJohnson21 PayTo:24224242|423533453|ERichards55 FromCurrency:USD ToCurrency:USD 启动Production后,可以将测试数据文件copy到业务服务监听到文件夹下。如果成功,应该可以看到这样的消息追踪结果,可以看到,用Java开发的PEX组件运行结果和IRIS自带的组件没有区别: 2.13 需要实现的Java类方法总结 下图总结了用Java开发不同组件时,需要实现的方法,以及这些组件间的调用流程和关系: 完整的规范参见这里。 三 在Java组件中使用Object Script开发的组件 上面是使用Java开发全套互操作产品组件的示例。实际情况下,InterSystems IRIS已经提供了大量适配器、消息和业务组件,而且使用低代码工具 - 例如业务流程建模图形化工具 - 往往更方便,所以通常Java可以使用Object Script开发的大量组件,而无需全部由Java开发。 在低代码开发业务流程时,可以直接在BPL里调用Java PEX开发的业务流程和业务操作,和IRIS本地开发的组件无异。 另外两种典型的用例是Java组件使用Object Script的消息、Java组件使用Object Script的适配器。在Java端使用Object Script类和对象,需要有前面讲的Java外部语言服务器的基础,文档参见这里。 3.1 Java组件使用Object Script的消息 在Java PEX中使用Object Script定义的消息,直接使用IRIS类的反向代理类IRISObject即可。例如在Java PEX业务操作的OnMessage方法中,要获得传入的Object Script消息的属性值,只需要把传入消息对象转换为IRISObject对象,并调用它的getXXX方法获取属性即可,可以这样: @Override public Object OnMessage(Object object) throws Exception { // 处理类型Ens.StringRequest的ObjectScript消息,获取StringValue属性的值 // 使用ObjectScript消息,将Object转换为 IRISObject IRISObject requestObj = (IRISObject)object; 通过IRISObject的getString方法获取它名为StringValue属性的值 String value = requestObj.getString("StringValue"); ... } 那怎么在Java组件中创建新的Object Script消息实例呢?你需要已经建立了IRIS连接的类型为com.intersystems.jdbc.IRIS的实例。 PEX的Java业务组件类和适配器类都继承于Common类,从Common类继承一个公共属性irisHandle,类型为IRISObject。而irisHandle有一个公共属性iris,类型为com.intersystems.jdbc.IRIS。因此可以通过它来创建Object Script消息实例。例如我们要创建一个类型为Ens.StringContainer的响应消息,并给其StringValue属性赋值: @Override public Object OnMessage(Object object) throws Exception { // 处理类型Ens.StringRequest的ObjectScript消息,获取StringValue属性的值 // 使用ObjectScript消息,将Object转换为 IRISObject IRISObject requestObj = (IRISObject)object; String value = requestObj.getString("StringValue"); // 创建一个类型为Ens.StringContainer的ObjectScript响应消息 IRISObject response = (IRISObject)(this.irisHandle.iris.classMethodObject("Ens.StringContainer","%New")); response.set("StringValue",value+"test me"); return response; } 3.2 Java业务组件使用Object Script的适配器 如果Java业务服务使用Object Script的适配器,无需做任何处理,适配器会将数据发送给Java业务服务的OnProcessInput方法,而Java业务服务只需要将接收的数据转换为IRISObject类型进行处理即可。 如果是Java业务操作要使用Object Script适配器,则需要调用适配器的方法。调用适配器方法,可以使用Adapter属性的invoke方法调用适配器类的方法,语法是 Adapter.invoke("方法名", 方法参数),例如: // 使用Object Script的出站文件适配器(EnsLib.File.OutboundAdapter),并调用它的Exists方法检查是否存在文件a.txt Object obj = Adapter.invoke("Exists", "a.txt"); 虽然这里介绍的是使用Java PEX开发互操作产品组件,您也可以使用.net 和Python进行开发,而且任何语言开发的PEX组件都可以一起使用。通过PEX,可以充分利用已有的生态代码和组件快速开发互操作产品。