引言 已经开发和交付了为数众多的 Portlet,这些 Portlet 可以安装在 WebSphere Portal 中。除了包含在 WebSphere Portal 中的内部 Portlet 以外,企业应用程序供应商为了提供对他们的系统的访问也开发了许多的 Portlet,单个开发人员为了执行特定的门户功能或者为了提供针对特定问题的解决方案也纷纷推出了许多的 Portlet。单单通过 WebSphere 门户目录就已经可以找到成百上千的 Portlet 可供使用,这些 Portlet 涵盖了各种各样的应用程序和行业。通常,门户将使用一个或多个现有的 Portlet 来提供特定的功能并加速开发过程。在某些情况下,由于安全性控制或不公开的接口的缘故,从门户访问特定于厂商的企业应用程序的惟一途径就是使用现有的 Portlet。
虽然 Portlet 一般会通过配置提供一些自定义功能,但通常这是很有限的。在将现有的 Portlet 用于门户之前,有时还需要其他的自定义功能,包括简单的自定义(如提供与门户的其他部分更一致的外观)和复杂的自定义(如添加新的功能)。我们来考虑一个现有的文件上传 Portlet。我们可能需要加入一种常规算法来检查待上传的文件内容;如果文件内容不合适,那么在它抵达后台系统之前会被拒绝。对于一个提供实时世界新闻的现有新闻频道 Portlet,它可能只关注特定地区或特定主题的新闻,而不应该显示其他的新闻。在很多情况下,门户范围的性能调优可能需要在门户的每一个 Portlet 中添加其他的逻辑,以便测量执行时间。
有多种方法可以修改和自定义现有的 Portlet。最常用的方法就是面向对象的继承,它使你能够从现有的 Portlet 派生新的 Portlet 以便添加新的功能,因为 Portlet 的核心是一个或多个 Java 类。这种方法的主要缺点是:
首先,新的 Portlet 要想能够自定义,就必须从现有的 Portlet 创建。
其次,因为 Portlet 应用程序是作为 web 应用程序档案文件(WAR)交付的,所以新的 Portlet 不能直接引用现有的 Portlet 的 WAR 中的类;WAR 中 的所有类及其依赖性都必须先解包,然后再重新打包到新的 Portlet 的 WAR 中。
另外,调用 Portlet 方法(如 service 和 actionPerformed)时还必须谨慎以防它将只被容器调用。
与基于继承的自定义相比,WebSphere Portlet 过滤器技术提供了一种更容易且更好的方法来重用和自定义现有的 Portlet:
Portlet 过滤器是一个(或多个)可重用的 Java 类,可以通过一种标准的方式来声明性地添加或删除,而无需对它所修改的现有 Portlet 或 Portlet 组进行更改。
过滤器并不是一个 Portlet;过滤器不创建对请求的响应,但是它截取和修改请求(在请求传送到目标 Portlet 以进行处理之前)及响应(在响应聚集到门户页面之前)。
过滤器并没有绑定到任何特定的 Portlet,因此它的生命周期不依赖于任何单个 Portlet。这就意味着,一旦过滤器初始化完毕,它就能够动态地应用到所有的可应用 Portlet,而无需进一步的初始化。
另外,由于过滤器独立于任何 Portlet,所以现有的 Portlet 或 Portlet 的 WAR 几乎不需要创建过滤器。
WebSphere 代码转换和机器翻译是基于 Portlet 过滤器技术。关于 WebSphere 代码转换和翻译的详细描述可以在版本 5.0 的 WebSphere portal 信息中心中找到,而相关的文章列表请见参考资料部分。
本文介绍了 WebSphere Portlet 过滤器的基础知识、Portlet 过滤器和 Servlet 过滤器的不同之处、以及如何开发和使用 Portlet 过滤器来自定义 Portlet。另外,还将解决各种开发问题以帮助简化其使用。一种称为文件内容过滤器(File Content Filter)的过滤器为现有的文件上传 Portlet 添加了细粒度的文件控制机制,本文就是以它为例来说明 Portlet 过滤器的使用的。
您可以找到一些适用于 WebSphere Portal 的文件上传 Portlet。在 WebSphere Portal 中 Portal Document Manager(PDM)Portlet 和 Portlet Installation Portlet 都是缺省安装的。更有许多是在 WebSphere Portal Catalog 中列出的。本文以 PDM Portlet(PDM)为例来说明文件内容过滤器的使用。在 WebSphere Portal V5 中,PDM Portlet 在缺省状态下自动安装在 My Portal 中的 Document 页面内。它给门户的用户提供了简单实时的文档查看和解决方案。PDM 让用户具有编辑者(Editor)的权限,使得他们几乎可以上传任何类型的文件。然而,对于许多组织来说,这种功能的需求可能远远比 PDM Portlet 提供的标准行为复杂得多。例如,文件控制机制可以用于控制能够上传的文件的类型、记录上传的文件和它们的属性、报告上传成功或失败的状态等等。本文中的文件内容过滤器将修改 PDM Portlet 的行为,这样就只有某些类型的文件被允许上传。
Portlet 过滤器与 Servlet 过滤器 如果您熟悉 Servlet 过滤器(请参阅 Java Servlet 规范以获得详细信息),从已经阅读的资料中,您可能已经注意到了 Portlet 过滤器和 Servlet 过滤器的相似性。实际上,它们之所以是相似的,是因为二者都可以声明性地嵌入,从而截获并修改请求和响应。但是理解它们之间存在着很大的不同是非常重要的。在一定程度上,它们之间的差异是与 Servlet 和 Portlet 之间的差异相联系的:Servlet 过滤器是一个门户级过滤器,它可以修改由一些小的部分(来自页面上所有 Portlet 的响应)集合而成的整个门户页面;而 Portlet 过滤器只能用于那些小的部分。Servlet 过滤器(如果已经安装的话)是接收和修改客户端请求的第一个组件,同时也是修改对客户端的响应的最后一个组件(请参见图 1)。
图 1. 带有 Servlet 过滤器和 Portlet 过滤器的客户端请求事件序列
如图 1 所示, Servlet 请求(步骤 1)在分派给一个或多个 Portlet 请求(步骤 3)之前首先通过一个 Servlet 过滤器链进行处理(步骤 2)。在结果集聚到一起(步骤 6 和 7)之前,Portlet 请求进一步转发到 Portlet 过滤器链进行处理(步骤4)。接着,将集聚的结果发送回 Servlet 过滤器进行处理,之后,将集聚的结果最终显示给用户(步骤 9)。
一个过滤器链包含一个或多个过滤器。在一个过滤器完成处理之后,新的请求和响应将传送到链上的下一个过滤器;链上的最后一个过滤器调用目标资源(Servlet 或 Portlet)。
与 Servlet 过滤器一样,Portlet 过滤器也是 WebSphere portal 体系结构中的一个可选的组件。因此在解决实际的问题时,可以使用一种类型的过滤器,也可以同时使用两种类型的过滤器,还可以不使用过滤器。例如,Servlet 过滤器可以用于压缩和加密整个门户页面,而 Portlet 过滤器可能更适合只压缩和加密门户页面的一部分。在 WebSphere Portal Transcoding Technology(请参见参考资料)中,Portlet 级代码转换使用 Portlet 过滤器来进行内容转换、标记转换和注解等等,而门户级代码转换使用 Servlet 过滤器(或门户过滤器,在 WebSphere portal 中是这样称呼的)来提供 Deck 片段。
Portlet 过滤器的支持和开发 Portlet 过滤器的支持类定义在 WebSphere portal 的 com.ibm.wps.pe.pc.legacy.cmpf 包中。PortletFilter 接口提供了三个方法来管理 Portlet 的生命周期:
void init(PortletFilterConfig config)
容器调用一次这个方法来准备用于服务的过滤器。对象 PortletFilterConfig(config) 使得过滤器能够访问配置参数以及对门户上下文的引用。
void destroy()
这个方法是在将过滤器从服务移除之后调用的。这个方法使得过滤器能够清除任何存放的资源。
void doFilter(PortletFilter.Method method, PortletRequest request, PortletResponse response, PortletFilterChain filterChain)
这个方法执行实际的过滤工作。这个方法使得过滤器能够检查和修改请求和响应,或者完全跳过请求的处理。第一个参数(method)是过滤器能够调用的请求方法的类型(如 SERVICE 或 ACTIONEVENT)。最后 的参数(filterChain)包含一个已经注册且正在运行的过滤器的列表。
包中的 PortletFilterAdapter 类为 PortletFilter 接口提供了一个缺省的实现。根据作为 doFilter 方法中的第一个参数传送的请求方法的类型,可以将 doFilter 方法的缺省实现委托给一组 do 方法(doService、doTitle、doActionEvent、doMessageEvent、doLogin、doBeginPage 和 doEndPage)。do 方法的缺省实现做的惟一一件事情就是将最初的请求和响应发送到链上的下一个过滤器或目标 Portlet。过滤器的每个 do 方法都是在目标 Portlet 的对应方法调用之前调用的。表 1 列出了每个过滤器方法和目标 Portlet 方法之间的映射。
表 1. Portlet 和 Portlet 过滤器方法
自定义的 Portlet 过滤器应该扩展 PortletFilterAdapter 类,并且覆盖表 1 中所列的一个或多个方法。举例来说,如果自定义过滤器仅支持 Portlet VIEW 并且修改输出,那么就只需要覆盖 doService 方法。然而,如果过滤器支持 Portlet ActionEvent 并且修改输出,那么 doService 和 doActionEvent 都应该被覆盖(请参见下一部分以获得详细信息)。WebSphere Portal 提供了三个便利的包装类:
PortletRequestWrapper(用于 PortletRequest)
PortletResponseWrapper(用于 PortletResponse)
ClientWrapper(用于客户端接口)
包装类应该用于创建自定义请求、响应和客户端类,这样,就可以容易地添加新的功能而不必实现整个接口了。
图 2. 带有 Portlet 过滤器的服务请求的请求