文章
· 一月 31 阅读大约需 21 分钟

用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,可以充分利用已有的生态代码和组件快速开发互操作产品。

讨论 (0)2
登录或注册以继续