高級 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。這種方法具有以下優點:
一個小組可以開發將用于門戶網站應用程序中的各種 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 的一部分。這兩個工廠是:
您可以按特定需要來開發附加工廠。例如,您可能希望創建可以高速緩存和重用的服務池,而非依賴于在每次使用時返回同一個實例或創建一個新實例的缺省工廠。本文并不深入討論如何開發服務工廠。關于如何開發服務工廠的詳細信息,請參閱 WebSphere Portal InfoCenter 中的完整示例。 構建 portlet 服務在本例中,您將在 Portal 中創建用戶管理或自助服務功能。Portal 提供了一組標準的用戶管理和自助服務選項。然而,對于許多公司而言,它們對于該功能的需求遠比取出即可用的 portlet 所能提供的更為復雜。而且,您可能需要重新設計 UI 或信息體系結構,從而更容易地與應用程序的其他部分結合。 下圖 1 顯示了一個簡單用例圖,它概述了一組用戶管理功能的基本需求。除了這些需求,用于該樣本應用程序的安全性體系結構還要求使用 Tivoli® Access Manager 作為門戶網站的安全性管理器。這意味著您需要設計定制功能(該功能能夠利用 Tivoli Access Manager 提供的密碼規則)和以后將會需要的其他安全性方法。 圖 1. 用例圖 設計 portlet 服務從研究您將用來定義 portlet 服務的接口開始。該接口可以充當服務開發者和其他正在開發使用該服務的 portlet 或其他對象的小組成員之間的合同。該服務最初由兩個公共方法組成:
接口是創建整個服務包的幾個文件之一。其他所需文件為:
圖 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 方法:
如果使用 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 的標準類:
圖 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.anti-gravitydesign.com