用 UML 为 WebSphere Portal Portlet 建模 - 第 3 部分:Portlet 服务

发表于:2007-05-25来源:作者:点击数: 标签:umlPortalPortletwebsphere
高级 IT 专业人员(经认证) IBM Business Consulting Services Industrial-HCS Practice 2003 年 1 月 引言 我的一个最近开始使用 IBM WebSphere Portal (以下称为 Portal)的同事提出一个问题:在 portlet 之间共享功能的最好方式是什么?为了更好地理解


高级 IT 专业人员(经认证)
IBM Business Consulting Services
Industrial-HCS Practice
2003 年 1 月

引言

我的一个最近开始使用 IBM® WebSphere® Portal(以下称为 Portal)的同事提出一个问题:“在 portlet 之间共享功能的最好方式是什么?”为了更好地理解他试图完成什么,我们进行了简短的讨论,然后我建议他考虑使用 portlet 服务。这当然引起了进一步的讨论,即什么是 portlet 服务以及如何在 Portal 应用程序中使用 portlet 服务。Portlet 服务很自然地是对 portlet 的扩展,也是在关于设计门户网站应用程序的讨论中的下一个合理步骤。本 portlet 和 UML 系列的第 3 部分将讨论如何设计一个样本 portlet 服务以及如何为它建模,同时将简述一个使用这项服务的 portlet。

本文将继续在这一系列的第 1 部分第 2 部分中的讨论。第 1 部分讨论了如何利用 UML 来为 portlet 设计建模。第 2 部分扩展了 portlet 设计模型,从而更深入地讨论了如何为门户网站应用程序建模,第 2 部分同时介绍了关于为门户网站应用程序设计中的 portlet 服务、EJB 和其他相关联的对象建模的其他主题。

什么是 portlet 服务?

通过使用 portlet 服务,您可以开发在门户网站中的 portlet 之间进行共享的常见功能。Portlet 可以通过使用服务工厂进行的动态发现来实例化这些服务。服务工厂是用来创建或定位服务的对象。PortletService 接口在您的 portlet 中经由 PortletContext 来提供。getPortletService() 方法在工厂中查寻给定的服务,然后将结果返回到 portlet。这种方法具有以下优点:

  • 单个对象可以封装应用程序中的公共逻辑,以在整个门户网站内使用。
  • 您可以从视图-控制器(View-Controller)层分离出业务逻辑、助手类和访问层,从而提供更佳的抽象级别。
  • WebSphere portlet 可以提供一个被支持的方法来在 Portal 框架中共享常见功能。

一个小组可以开发将用于门户网站应用程序中的各种 portlet 服务。不同的供应商或远程小组也可以提供 portlet 服务。由于 portlet 服务由接口及其实现、设计前端(design upfront)和相应的方法存根组成,您可以利用 portlet 服务来围绕一个不完整服务开发 portlet。整个应用程序的完全集成可以在开发周期中的较晚时期完成。本文将提供一个样本 portlet 服务及其实现。WebSphere Portal InfoCenter 将提供附加的详细信息以及用来构建 portlet 服务和相关联的工厂的样本代码。其他对象(如 JSP 标记库,JSP Tag Library)也可以访问 portlet 服务。

服务类型

portlet 服务几乎可以封装应用程序层中能被抽象的所有事物。服务允许开发者设计连接到 LDAP 或类似的持久存储器的抽象层,或者提供到一组 EJB 或域对象的一致接口。以前提到过,第三方供应商可以使用 portlet 服务来向外部应用程序(如内容管理和搜索应用程序)打开新的 API。这使第三方供应商可以很快地在他们的产品中提供简单而功能强大的接口。众多内部 portlet 服务(如 ContentAclearcase/" target="_blank" >ccessService 和 CredentialVaultService)已经在 WebSphere Portal 4.1 中提供。

通过使用 portlet 服务,您可以为您的用于 portlet、JSP 标记库和其他对象的方法提供一个被支持的、著名的并且受控制的访问点。Portlet 服务也允许小组开发不同体系结构层之间的标准访问点。

服务工厂

Java™ 术语中,服务类指一组无状态的并提供瘦接口的功能接口。Portal 利用工厂为创建和访问服务类提供了一种内部机制。目前,Portal 打包并安装了两个缺省工厂。您可以将这些工厂用于您的 portlet,这些工厂是 Java 包 org.apache.jetspeed.portletcontainer.service 的一部分。这两个工厂是:

  • PortletServiceDefaultFactory 在每次被调用时,该缺省工厂创建并且返回一个您的服务的新实例。
  • PortletServiceCacheFactory 在每次被调用时,该高速缓存工厂返回 portlet 服务的同一个实例。

您可以按特定需要来开发附加工厂。例如,您可能希望创建可以高速缓存和重用的服务池,而非依赖于在每次使用时返回同一个实例或创建一个新实例的缺省工厂。本文并不深入讨论如何开发服务工厂。关于如何开发服务工厂的详细信息,请参阅 WebSphere Portal InfoCenter 中的完整示例。

构建 portlet 服务

在本例中,您将在 Portal 中创建用户管理或自助服务功能。Portal 提供了一组标准的用户管理和自助服务选项。然而,对于许多公司而言,它们对于该功能的需求远比取出即可用的 portlet 所能提供的更为复杂。而且,您可能需要重新设计 UI 或信息体系结构,从而更容易地与应用程序的其他部分结合。

下图 1 显示了一个简单用例图,它概述了一组用户管理功能的基本需求。除了这些需求,用于该样本应用程序的安全性体系结构还要求使用 Tivoli® Access Manager 作为门户网站的安全性管理器。这意味着您需要设计定制功能(该功能能够利用 Tivoli Access Manager 提供的密码规则)和以后将会需要的其他安全性方法。

图 1. 用例

设计 portlet 服务

从研究您将用来定义 portlet 服务的接口开始。该接口可以充当服务开发者和其他正在开发使用该服务的 portlet 或其他对象的小组成员之间的合同。该服务最初由两个公共方法组成:

  • changePassword(UserObject user) 这一方法允许您修改用户密码。该方法接受用户对象作为参数。用户对象将包含修改密码需要的所有信息。
  • resetPassword(String userid) 这一方法允许您重设用户忘记的密码。该方法接受用户标识作为参数。该信息允许方法查询用户、重设密码,然后把新密码发送到存档中该特别用户的电子邮件地址。

接口是创建整个服务包的几个文件之一。其他所需文件为:

  • UserManagement 接口 服务使用者可以访问的公共方法。
  • UserManagementImpl 服务接口的实现。该类将实现接口方法和所有需要的助手方法。
  • PortalUser 服务和其他 portlet 用来封装用户信息的用户对象。
  • PortletServices.properties 虽然这并非您实际上所需提供的文件,但是您的确需要编辑该文件来注册您的服务。下面提供了关于该活动的信息。

图 2 显示了一旦服务被开发完成后看起来的样子的可视化示例。除了定义已经提到的类和方法,该图也包括关于其他类可能看起来的样子的信息。该图也包括用户对象中的私有方法和用户信息:

图 2. 服务类图
 

清单 1(这也将在以下的下载 ZIP 文件中提供)提供了创建 portlet 服务接口的代码。该文件,尽管简单,但包含了一些注释,以使服务使用者能完全理解如何使用每一个所提供的方法。

清单 1. 服务接口

	/**
            * User Management Service Interface
            **/
            package com.ibm.wps.service.usermanagement.portletservice;
            import com.ibm.wps.service.usermanagement.*;
            /**
            * The UserManagementService interface contains methods
            * which allow user management functionality within the
            * portal. User profile and password management.
            *
            * @author	Joey Bernal
            * @version	1.0
            * @since	version 0.0
            */
            public interface UserManagementService {
            /**
            * <P>changePassword(PortalUser user)</P>
            * <P>Change the users password.</P>
            *
            * @param	PortalUser user
            * @return	PortalUser
            * @exception	none
            */
            public PortalUser changePassword(PortalUser user);
            /**
            * <P>resetPassword(PortalUser user)</P>
            * <P>Generate a new password and reset the current
            * users password to the newly generated one.  Also
            * send an e-mail to the users e-mail address on file.</P>
            *
            * @param	String userid
            * @return	boolean
            * @exception	none
            */
            public Boolean resetPassword(String userid);
            }
            

接下来,您可以开始实现所提供的用于服务的接口。首先,您可以为这些方法提供存根,从而允许其他开发者可以立即按服务开始开发。随着实现了更多的功能,您可以进行更新并分发更新。

UserManagementServiceImpl 类将实现两个接口:您刚创建的接口(即 UserManagementService 接口)和 PortletServiceProvider 接口。

清单 2. 服务接口实现

public class UserManagementServiceImpl implements
            UserManagementService, PortletServiceProvider {

一旦声明了类,实现中的私有属性就被用来存储 Tivoli Access Manager 连接信息。字符串被初始化为连接到 Tivoli Access Manager 主机所需的属性值。

private static String PDADMIN_ID = "sec_master";
            private static String PDADMIN_PWD = "wpsadmin";
            private static String PROGRAM = "Portal User Management Service";
            private static String PD_URL_LOCATION =
            "file:///C:/WebSphere/AppServer/java/jre/PdPerm.properties";
            private static String PD_HOSTNAME = "wpsdev.ibm.com";			

以下的下载 ZIP 文件将提供用于该实现的完整代码样本(请参阅下载的清单 2)。

考虑用另一种不同方法来测试您的 portlet 服务

当在 Portal 中使用 portlet 服务时,请在开发过程中考虑以下内容:

当服务发生更改并且需要被重新部署时,您需要重新启动 Portal 以便可以重新装入新服务。以下是一个您可以在开发工具中(例如,WebSphere Studio Application Developer,以下称为 Application Developer)用来测试大多数服务的简单窍门。

注意在前面的清单 2 中,私有字符串声明被初始化为测试值。同样,代码清单包含两个 init 方法:

  • portlet 服务使用的 init() 方法
  • 一个被注释掉了的类构造函数

如果使用 Application Developer 来开发,您可以取消注释构造函数头并且注释掉 init() 方法。这样将会使您在将一些方法部署到 Portal 之前使用一个测试类在 Application Developer 中运行和测试这些方法。测试类是一种运行每种方法并且打印出结果的简单方法。当利用 Application Developer 在本地测试时,您也必须注释掉用来读取服务参数的 config.getParam 调用。通过使用该方法,服务将成功运行,因为您设置的值在您创建变量时就被初始化了。

理解 PortalUser 类

PortalUser 类被设计为一个门户网站中的用户的全局代表。尽管一些人也许认为这是一个崇高目标,但这个类的确为维护一组关于用户的扩展属性提供了方便之所。存在一些关于应该如何创建该类型对象及其应该在何处驻留的设计方法。而这只是一个方法。一般而言,portlet 将创建该 bean 的实例并将其存储在 PortletSession 中。这允许 portlet 在交互作用发生时维护所需的用户信息。

不同的 portlet 在必需时可以使用 PortalUser 对象。您也可以通过扩展服务来高速缓存和共享 PortalUser 对象从而包括适当的逻辑。依据 PortalUser 对象的复杂性,您可以扩展服务从而在必需时创建实例,这可能是通过使用构建器模式从多种数据源植入对象来实现的。

围绕 PortalUser 的实现相当简单。这是一个传递信息和消息到门户网站中的不同对象的单个 bean。以下的下载 ZIP 文件中的清单 3 将提供实现 PortalUser 类的完整代码。

部署 portlet 服务

在将 portlet 服务部署到 Portal 之前,您需要完成以下工作。一旦服务完成,您需要将其打包为 JAR 文件并且将其置于 WebSphere\AppServer\lib\app 目录下,Portal 将识别该目录。同样,在 PortletServices.properties 文件中,您必须定义服务工厂和服务所需的所有参数。该文件位于 WebSphere\PortalServer\app\wps.ear\wps.war\WEB-INF\conf 目录中。

属性设置由两部分组成。首先,声明服务及其相关联的工厂:

# -------- Setup the User Management Service and declare the necessary factory ------
            com.ibm.wps.service.usermanagement.portletservice.UserManagement =
            com.ibm.wps.service.usermanagement.portletservice.UserManagementImpl
            com.ibm.wps.service.usermanagement.portletservice.UserManagementImpl.factory =
            org.apache.jetspeed.portletcontainer.service.PortletServiceCacheFactory			

接下来,配置服务所需的所有参数,以便可以在必要时将服务部署到不同的门户网站:

#-------- User Management Service Parameters --------------
            com.ibm.wps.service.usermanagement.portletservice.UserManagementImpl.PD.ADMIN = sec_master
            com.ibm.wps.service.usermanagement.portletservice.UserManagementImpl.PD.PASSWORD = wpsadmin
            com.ibm.wps.service.usermanagement.portletservice.UserManagementImpl.PD.PROGRAM =
            Portal User Management Service
            com.ibm.wps.service.usermanagement.portletservice.UserManagementImpl.PD.PROPFILE =
            file:///C:/WebSphere/AppServer/Java/jre/PdPerm.properties
            com.ibm.wps.service.usermanagement.portletservice.UserManagementImpl.PD.HOSTNAME =
            wpsdev.ibm.com

该示例将使用 PortletServiceCacheFactory,它是 Portal 提供的缺省工厂之一。

创建 portlet

既然您已经设计好了 portlet 服务(以及比如说,另一个小组不再忙于实现所需的功能),您可以开始设计样本的使用者端(也就是 portlet)了。portlet 遵循与这一系列中的第 1 部分第 2 部分中所讨论的类似的设计。一个主要的不同在于现在您可以扩展实用程序类来利用服务中的应用程序逻辑。图 3 概述了用于 portlet 的类表。该设计将使用用于 portlet 的标准类:

  • ChangePasswordHTMLController 类
  • ChangePasswordUtility 类

图 3 也将说明如何集成 portlet 和服务来提供分层方法从而补充所需功能。

图 3. Portlet 类表
 

由于这是个相对简单的 portlet,它仅需要单个操作处理程序(ACTION_CHANGE)来调用实用程序类中的 processPasswordChange() 方法。processPasswordChange 创建用户 bean 以及使用该服务来执行修改密码功能并返回结果。您可以通过声明和调用与服务相关的服务工厂来为服务创建句柄。由于您定义了服务来使用 PortletServiceCacheFactory,然后 portlet 服务注册表将管理该服务并且仅创建该服务的一个实例以及把引用传递到该服务的单个实例。这在许多用户可能单击该服务的多线程环境中很重要。

	UserManagementService umService;
            umService = (UserManagementService)
            PortletServiceRegistryAccess.getPortletService
            (com.ibm.wps.service.usermanagement.portletservice.
            UserManagementService.class);	

当在 portlet 中提供服务时,您可以在必需时调用所有需要的方法:

	newBean = umService.changePassword(bean);
            

以下的下载 ZIP 文件中的清单 4 将提供 processPasswordChange() 方法的完整示例。

结束语

超越了简单的 portlet 设计,本文进一步构建了一个多层应用程序体系结构。您可以注意到 WebSphere Portal 提供了一个被很好地定义了的、分层式的方法从而允许应用程序超越了现存的层,同时将仍然利用 framework 设计。当您自己熟悉了该示例,您将开始考虑在您自己的设计中可以充分利用 portlet 服务的地方。

本文提供的代码清单将包括重新创建本文简述的样本的足够的详细信息。该清单也强调用户管理服务本身。有许多方法可以实现如上所述的 portlet,如果需要,您可以在任何 portlet 设计中使用所提供的 processChangePassword() 方法,而不需要把一种特定的方法强加给用户。您也可能发现提供的服务很有价值,因为 changePassword() 方法功能良好,而且是关于您可以如何使用 Tivoli Access Manager 来实现用户管理功能的很好的示例。

本文未详细讨论的一个观点是 portlet 开发者可以使用这些 portlet 服务来开发而无需理解服务的底层实现。这意味着您可以利用用户管理功能的数据库实现来构建以上样本,以及稍后转变为 Tivoli Access Manager 实现类型。这是使用 portlet 服务的主要好处之一。

原文转自:http://www.ltesting.net