2. Windchill API基础

Windchill 的二次开发能力几乎全部建立在 Java API 之上。理解 API 的分类方式、包与类的组织逻辑,以及远程方法调用(RMI)的底层机制,是写出第一个可运行接口程序的前提。本节从“是什么”讲到“怎么跑通”,并给出一个可直接参考的示例。

一、Windchill API 的分类

按调用位置与用途,Windchill API 大致可分为四类:

  • 业务服务 API(Business Services):面向业务对象的高层接口,如 wt.part.WTPart、wt.doc.WTDocument、wt.change2.WTChangeOrder2,用于创建、查询、修订、检入检出等操作。
  • 持久化与查询 API:如 wt.fc.PersistenceHelper、wt.fc.QueryResult、wt.query.QuerySpec,负责对象存取与条件检索。
  • 服务端扩展 API:如 wt.services.StandardService、wt.method.RemoteAccess,用于编写自定义服务并暴露给远程调用。
  • 客户端与集成 API:如 wt.client 包下的远程代理、wt.util.WTProperties 读取配置,用于外部系统对接。

分类的意义在于:写业务逻辑优先用业务服务 API,做数据检索用查询 API,而要让外部系统调用,则必须理解服务端扩展与远程调用机制。

二、常用包与类

Windchill 的包名以 wt. 开头,按功能域划分。下表列出开发中最常打交道的包与代表类:

包名代表类典型用途
wt.fcPersistenceHelper、WTCollection、QueryResult对象持久化、集合与查询结果处理
wt.partWTPart、WTPartMaster零部件创建与版本管理
wt.docWTDocument、WTDocumentMaster文档对象操作
wt.queryQuerySpec、SearchCondition、ColumnExpression构造条件查询
wt.sessionSessionHelper、WTPrincipal会话与用户上下文
wt.methodRemoteMethodServer、RemoteAccess远程方法调用入口
wt.utilWTProperties、WTException配置读取与异常处理

其中 PersistenceHelper.manager 与 SessionHelper.manager 是几乎所有接口程序都会用到的两个“管理器”入口,前者负责持久化,后者负责会话上下文。

三、远程方法调用机制

Windchill 采用 RMI(Remote Method Invocation)实现客户端与服务端之间的方法调用。其核心是:客户端持有服务端对象的远程代理(stub),调用方法时参数被序列化,经 RMI 传输到服务端,由服务端执行后把结果序列化返回。整个过程对开发者基本透明,但有几个关键约束:

  • 被远程调用的类必须实现 wt.method.RemoteAccess 接口,或继承 wt.services.StandardService。
  • 方法参数与返回值必须可序列化(实现 java.io.Serializable)。
  • 服务端需通过 RemoteMethodServer.getDefault() 获取实例,再用 invoke() 调用。
  • 调用前必须建立会话,通常用 SessionHelper.manager.setAdministrator() 或指定用户登录。

下图展示了从客户端到服务端的完整调用链与关键对象:

Windchill RMI 远程调用链 客户端程序 SessionHelper 登录 获取远程代理 stub 调用业务方法 RMI 传输层 参数序列化 网络传输 结果反序列化 服务端方法 RemoteMethodServer PersistenceHelper 持久化 返回 QueryResult 请求 转发 响应 返回 远程调用关键约束 ① 服务类实现 RemoteAccess 或继承 StandardService ② 参数与返回值必须可序列化(Serializable) ③ 调用前必须建立会话(SessionHelper 登录) ④ 通过 RemoteMethodServer.getDefault().invoke() 触发 ⑤ 异常统一包装为 WTException 或 RemoteException

四、开发环境准备

在写第一个接口程序前,需要完成以下准备:

  1. JDK 版本匹配:Windchill 11.x/12.x 通常要求 JDK 8 或 JDK 11,需与服务器端一致,避免序列化版本冲突。
  2. 类路径配置:将 Windchill/codebase 下的 wt.jar、Wncustom.jar 等加入 IDE 的 Build Path。
  3. 连接配置:在 wt.properties 或 wt.rmi.client.properties 中配置 RMI 主机、端口(默认 wt.rmi.port=1099)及服务名。
  4. 登录凭据:准备 Windchill 管理员或具备相应权限的用户账号,用于 SessionHelper 登录。
  5. 编译与部署:自定义类编译后放入 codebase 或通过 wt.load 工具加载,确保服务端可加载到该类。
建议在 IDE 中先写一个仅做“登录 + 查询”的最小程序,确认 RMI 通道畅通后,再逐步加入创建、修订等写操作。

五、第一个接口程序示例

下面是一个查询指定编号零部件的远程接口示例。它演示了登录、构造查询条件、执行查询并输出结果的完整过程。示例中的零件编号 P-1001 为教学假设值,实际运行时请替换为系统中真实存在的编号。

import wt.fc.PersistenceHelper;
import wt.fc.QueryResult;
import wt.part.WTPart;
import wt.query.QuerySpec;
import wt.query.SearchCondition;
import wt.session.SessionHelper;
import wt.method.RemoteMethodServer;

public class FirstPartQuery {

    public static void main(String[] args) throws Exception {
        // 1. 建立会话(示例使用管理员)
        SessionHelper.manager.setAdministrator();

        // 2. 获取远程方法服务器
        RemoteMethodServer rms = RemoteMethodServer.getDefault();

        // 3. 构造查询条件:按零件编号精确匹配
        QuerySpec qs = new QuerySpec(WTPart.class);
        qs.appendWhere(new SearchCondition(
                WTPart.class, "number", SearchCondition.EQUAL, "P-1001"), new int[]{0});

        // 4. 执行查询
        QueryResult qr = PersistenceHelper.manager.find(qs);

        // 5. 遍历结果
        while (qr.hasMoreElements()) {
            WTPart part = (WTPart) qr.nextElement();
            System.out.println("找到零件: " + part.getNumber()
                    + " | 名称: " + part.getName()
                    + " | 版本: " + part.getVersionIdentifier().getValue());
        }
    }
}

运行后若控制台输出类似 找到零件: P-1001 | 名称: 示例支架 | 版本: A,说明 RMI 通道、会话与查询 API 均已正常工作。若抛出 WTException,优先检查:类路径是否包含 wt.jar、RMI 端口是否可达、登录用户是否有该零件的读取权限。

远程调用中不要传递未序列化的自定义对象;若必须传递,请让其实现 Serializable 并确保客户端与服务端使用同一版本类。

掌握以上内容后,你已经具备编写并运行一个基础 Windchill 接口程序的能力。后续更复杂的创建、修订、工作流触发等操作,都建立在这套“会话 + 远程服务 + 持久化”的调用模型之上。