通过 URL 打开 Eclipse Rich Client Platform 应用程序
2009-12-18 00:00:00 来源:WEB开发网Eclipse Rich Client Platform (RCP) 为富客户机提供了一个极为灵活且功能丰富的框架。但是它的一个缺点是不能轻松地从其他源链接 RCP 应用程序中的业务对象。如果用户能够在其他应用程序中单击某个链接并被带到 RCP 应用程序中,并且已经打开了该链接所引用的业务对象,那将十分有帮助。例如,假定有一个用于处理费用申请的 RCP 应用程序。可能生成有关过期偿付的报表并以电子表格的形式发布(或者是在内部网中,或者作为富文本文档,或者作为电子邮件,或者其他形式等等)。该报表可能对每个过期申请使用一个引用编号。报表不会强制使用者把该引用编号复制并粘贴到 RCP 应用程序的搜索对话框中,而是包含启动 RCP 应用程序的超级链接 URL,该 URL 将把用户直接引导到对应的费用申请。本文将说明如何完成上述过程。
读者应当拥有编写 Eclipse 插件的经验,以及 Windows® 注册表和 TCP 协议的一般知识。虽然本文提供的示例针对 Windows 操作系统,但是在其他操作系统中也可以实现相同的功能。
解决方案概述
让我们从整体上查看解决方案的工作原理,然后进行细分并讨论如何实现各个部分。
遵循图 1 中的流程:
假定用户已经在桌面中打开 RCP 应用程序。
然后假定此用户在他的常用邮件客户机中收到了一封电子邮件,该邮件中包含链接 rcp://claim=25222 — 这是指向过期申请的引用 (1) 。
该用户单击链接,这将启动该用户的默认浏览器以处理请求 (2)。
该浏览器知道它不能在本机打开此 URL,因此它将查询 Windows 注册表以确定应当怎样委托该操作 (3)。
注册表将查找 rcp:// 协议并确定有一个与它绑定在一起的批处理文件 (4)。
此批处理文件将被执行 (5),这将触发独立的 Java™ 客户机 (6),捕捉 URL 的参数,并因此向 RCP 应用程序中内嵌的 TCP 服务器发出一个本地 TCP 调用 (7)。
该 TCP 服务器将解析来自该 URL(即,claim=25222)的参数并请求 RCP 应用程序打开相应的业务对象 (8)。
然后将在 RCP 应用程序 UI 中向用户呈现所请求的业务对象 (9)。
图 1. 使用 URL 打开 RCP 应用程序的流程控制
此过程涉及到许多步骤,但幸运的是,每个步骤都相对简单并且可以根据您的环境和应用程序进行调整。最后几步将帮助解决如何使 RCP 应用程序获得 Windows 焦点之类的细节。
解决方案详解
向 Windows 中的 URL 协议注册您的应用程序
Windows 使用注册表中的条目识别有效的 URL 协议和确定应当向哪个应用程序发送带有特定协议的请求。要使我们的 RCP 应用程序能够响应 URL,必须在 HKEY_CLASSES_ROOT hive 下创建一个键。键名必须匹配正在创建的协议。在本文中,我们将使用 “rcp://” URL 协议,因此必须把键命名为 “rcp”。该键下的默认字符串值与新协议的显示名称相对应。在 “rcp” 键下,还必须创建带有一个字符串值的 shell\open\command 键,该字符串值包含在收到 “rcp://” 请求时 Windows 应当打开的应用程序的路径。
在本文中,我们将把 Windows 指向一个批处理文件。该键的字符串值应当在其末尾附加了 %1,这将告诉 Windows 把该 URL 查询字符串传递给您的应用程序。这是我们把上下文信息(例如要打开的特定业务对象)传递给 RCP 应用程序的方法。
下面的 Windows 批处理文件代码片段将在注册表中创建相应的键,该键带有将启动记事本的 “rcp://” 协议。要自定义该脚本,请用需要使用的协议替换 rcp 的所有实例,并使用需要 Windows 执行的文件的完整路径替换 C:\Windows\Notepad.exe。
清单 1. 把 URL 协议注册到 Windows 注册表的批处理文件代码 reg add HKCR\rcp /ve /d "URL:RCP Protocol"
reg add HKCR\rcp /v "URL Protocol"
reg add HKCR\rcp\Shell\Open\Command /ve /d "C:\Windows\Notepad.exe %%1"
注册过该 URL 协议后,您可以通过在浏览器的地址栏中键入 rcp:// 并单击 Go 进行测试。记事本(或者选择注册的文件)现在应当已打开。
其他操作系统(例如 Linux®)把注册 URL 协议的工作委托给浏览器。
批处理文件
当您测试过我们定义的 rcp:// 协议可以按预期打开记事本后,请尝试把 rcp:// 协议重新映射到启动 TCP 客户机的批处理文件。为此,需要更改 HKCR\rcp\Shell\Open\Command 注册表条目的值。参见清单 2 以查看批处理文件如何启动 TCP 客户机的示例。
清单 2. 启动 TCP 客户机的批处理文件代码@echo off
set JAVA_BIN=c:\<insert your java directory here>
cd <root location of your URIClient application's package.>
%JAVA_BIN%\java.exe com.company.uri.URIClient %1
EXIT
表 1. 清单 2 的注释
行号 | 注释 |
2 | 例如,set JAVA_BIN=C:\Program Files\IBM\Java50\jre\bin |
3 | 例如,包含 TCP 客户机的 parent 包的目录 |
4 | 下面将介绍 URIClient |
TCP 客户机/服务器对
如概述中所述,用户单击 rcp:// 超级链接的操作最终将触发调用 RCP 应用程序内嵌的 TCP 服务器的 TCP 请求。此解决方案包括一些网络编程,但幸运的是,Java API 将为我们处理 TCP 通信的细节。
在我们的示例中,TCP 服务器将在 RCP 插件的启动代码中被启动并且等待来自 TCP 客户机的调用。呼叫将在客户机和服务器已知的端口号上从客户机发送到其本地主机所在的服务器上。客户机将通过 Java 套接字把 URL 请求的详细信息传递给服务器。TCP 服务器随后负责执行相应的 RCP 操作以打开业务对象。这些操作专用于特定应用程序,但是我们将在 “处理业务对象” 中处理此问题。
对于我们的演示,将使用 com.company.uri 包中的四个 Java 类。
URIClient.java 由 URL 选择触发的独立 TCP 客户机URIServer.java 和 URIServerThread.java 包含嵌入到 RCP 应用程序中的 TCP 服务器URIConstants.java 客户机和服务器之间共享的一些常量
这些 Java 文件可以下载获得。
TCP 服务器 — URIServer 和 URIServerThread
负责侦听请求。在侦听到请求时,它将生成处理与 TCP 客户机之间的连接的 URIServerThread 线程。
URIServer
URIServer 可以在插件的初始化类中启动。每个 RCP 插件都有一个可以扩展 org.eclipse.ui.plugin.AbstractUIPlugin 的相关的启动类。该类的 start 方法可以初始化 URIServer。
RCP 应用程序将生成 URIServer,方法是调用新的 URIServer().start(),在它自己的线程中启动服务器并防止 RCP 应用程序由于等待 TCP 请求而被阻塞。
URIServerThread 将处理打开业务应用程序的逻辑。该过程将在 “处理业务对象” 中详细讨论。
注意,URIServer 和 URIServerThread 都扩展 java.lang.Thread。
清单 3. 样例插件启动方法/**
* This method is called upon plug-in activation, starts up URIServer
*/
public void start(BundleContext context) throws Exception {
super.start(context);
new URIServer().start();
}
TCP 客户机应用程序 — URIClient
TCP 客户机被部署为不会被 RCP 应用程序引用的独立 Java 文件。在由与 rcp:// 协议相关的批处理文件触发后将执行 URIClient.main()。
构造函数将把 URL 参数传递给 tcpConnect 方法。此方法将通过 URIConstants 在客户机和服务器已知的主机编号上构造一个套接字,该套接字以本地主机上的 TCP 服务器为目标。
提示:考虑一下,虽然 Java 客户机没有被 RCP 插件引用,但是在插件内部署 Java 客户机将允许通过 Eclipse 更新程序框架更新代码。如果它驻留在插件外部,那么部署代码更新将变得更加困难。
处理 TCP 请求
TCP 客户机与服务器之间如何通信?假定 RCP 应用程序和 TCP 服务器已在运行。正如我们已经说明的那样,注册表和批处理文件将处理 TCP 客户机的启动。URIClient 将移除参数(即,claim=25222)并将尝试在客户机和服务器已知的端口号上建立与 URIServer 之间的套接字连接。
现在连接已建立,服务器将通过发送常量文件中存储的(客户机和服务器已知的)字符来确认客户机并请求进一步指令。在示例中,服务器将发送字符 sendAction。当客户机收到这条指令后,它将通过向服务器发送包含所需业务对象的信息的名称-值对 — 在本例中为 “claim=25222” — 进行响应。此时,客户机和服务器将终止它们的连接。当然,只要服务器已知要接收的内容,就可以自定义要发送的特定名称-值对。
现在该由 TCP 服务器解析实参并启动相应的操作。
在理想情况下,上述 TCP 客户机和服务器都可以由 RCP 应用程序启动,因此不需要使用独立的 Java 应用程序并减少需要部署的工件数。只要使用 URL 触发了 RCP 应用程序,就会使用应用程序的 .exe 或批处理文件启动程序按照常规启动应用程序。但是,早在应用程序的初始化阶段,应用程序就将检查它的实例是否已在运行。如果应用程序已在运行,则 TCP 客户机将被初始化并把 URL 实参传递给在运行的 RCP 应用程序中等待收到此类通知的嵌入式 TCP 服务器。服务器将打开各自的业务对象,如上面示例所示。但是,如果 RCP 应用程序尚未运行,它将在此时继续处于打开状态,并且它将使用 URL 实参作为 RCP 程序实参以打开相应的业务对象。
如果您不能访问应用程序的早期启动代码(例如如果您要在现有应用程序之上部署插件),则可能无法在 RCP 应用程序中嵌入 TCP 客户机。鉴于此原因,本文介绍了更灵活的独立 TCP 客户机方法。
处理业务对象
如前所述,URIServerThread 将处理打开业务对象的事务。为了简单起见,在这里提供的清单中,代码将启动一个显示 URL 中提供的业务对象 ID 的对话框。在实际应用程序中,我们将执行的某些操作要有趣得多,如调用 Action,它将查找并打开提供了标识符的业务对象。
Eclipse 有一个用于管理用户界面的线程,而且某些 SWT API 方法只能通过该线程调用。由于 URIServerThread 正在作为它自己的线程运行,因此我们需要考虑到这个限制。为了使衍生(spawned)线程能够回调 Eclipse 工作台,它必须使用 Display 对象中的方法才能获得对 UI 线程的访问。如果不这样做,将在运行时抛出 ERROR_THREAD_INVALID_ACCESS 错误。
最后几步
默认情况下,单击 rcp:// 链接将打开 RCP 应用程序中的业务对象,但是 RCP 应用程序可以隐藏在其他应用程序背后,例如包含 rcp:// 链接的应用程序。为 RCP 应用程序获得焦点十分重要。在 URIServerThread 清单中,注意负责使 RCP 应用程序获得焦点的下列语句:
shell.setActive();
shell.setMaximized(true);
shell.setVisible(true);
shell.setFocus();
我们还没有介绍错误处理,但是在某些情况下这个功能非常必要。首先,TCP 通信附带有需要进行恰当处理的 try/catch 块。此外,还需要确保能够处理各种难看的 URL,尤其要防止受到故意攻击。
您可能已经注意到,把 rcp:// 协议的解析委托给 Windows 默认浏览器的一个不好的副作用是使浏览器窗口保持打开状态。虽然不太理想,但是这是可以接受的问题。我们期待您可以提出解决这个问题的方法,尤其是在 RCP 应用程序被广泛分布并且无法调整 Firefox 的用户设置的环境中。
结束语
上述过程详细介绍了使用 URL 打开 RCP 应用程序中的一个业务对象的框架。不过,可以通过一些有趣的方式扩展这个想法。例如,可以在 URL 中包括多个名称-值对以执行更复杂的操作。考虑一个订单录入应用程序,其中 URL 可用于给订单预填充某些产品。遵循这些步骤,可以通过单击链接从任意应用程序访问 RCP 应用程序中定义的任何操作。
本文示例源代码或素材下载
- ››打开Win8系统自带计算器方法
- ››URL Rewrite实现jsp网站伪静态
- ››通过远程管理更改ESXi主机root用户密码
- ››通过JS得到当前焦点(鼠标)的坐标
- ››通过Mysql命令行语句来导入、导出数据库文件
- ››Url传参数被IE截断的解决方案
- ››通过查看mysql 配置参数、状态来优化你的mysql
- ››URL和HttpCore,HttpClien(不用DNS解析,直接访问...
- ››通过oracle的sys密码重置其它密码
- ››打开outlook ,提示outlook.pst 不是个人文件夹的修...
- ››通过HashMap和ArrayList容器实现一个Key对多个值
- ››通过传时间实现UDP对时
更多精彩
赞助商链接