對門戶和portlet程序的事件和公共賦值參數的工具支持
Java portlet 規格 2.0 中引入的新特性,基於 JSR 286,支持 portlets 之間的協作。事件和公共賦值變量是 portlets 相互之間可以交流的兩個機理。在對一些關鍵概念做簡短介紹之後,本文向您介紹如何使用 IBM® Rational® Application Developer V7.5 中的 Portal Toolkit,來創建一個 JSR 286 基本 portlet 的范例。在這個過程中,它解釋了 Portal Toolkit 是怎樣加速整個過程以升級這些功能的。
關鍵概念
本文首先介紹一下關鍵概念,然後使用范例 portlet 程序來展示一下這些概念。
事件
Java™Specification Request(JSR)286 規格的 2 版本,使 portlets 發送和接受事件成為可能。事件能使 portlets 相互之間進行交流。IBM® Rational® Application Developer V7.5 提供了一系列的工具,以定義事件,激活 portlets,並使用事件在它們之間傳遞數據。一個 portlet 可以處理交流的雙方:
向其他 portlets 發送事件
從其他 portlets 那裡接受和處理事件
事件的屬性
每一個事件必須有一個名字,可能還要有其他屬性:
Name:事件獨一無二的名字。該事件名必須是一個完整的 QName,跟在 XML 規格中定義的名字一樣,它由一個名字區(例如,http://www.ibm.com)和本地區(例如,sampleEvent)組成。您可以為多個事件使用相同的名字區,只需將其宣布為默認的名字區,然後為每一個事件只指定本地區。
Description:(可選項)對事件所做的描述。
Value type:(可選項)隨事件一起傳遞的值的 Jazz 類名。
Alias:(可選項)事件名字區特定的名字。
按照如下步驟,創建一個 portlet 程序,該程序集成了事件和公共賦值變量,以便在 portlets 之間進行交流:
創建一個 JSR 286 portlet 項目和 portlets。
在 portlet 部署描述器(PDD)中創建一個事件定義。
添加事件作為 portlet 支持的發布或者處理的事件。
編輯 portlet 類中的過程行為或者事件代碼,以發布或者處理事件。
添加公共賦值變量。
向服務器發布 portlet 項目。
將 portlets 集中到一起。
通過使用 Rational Application Developer V7.5 提供的工具,可以極大地簡化這些任務。
公共賦值變量
JSR 286 規格提供了支持 portlet 之間協作的另外一個機理:公共賦值變量(查看資源以找到更多關於它的信息)。這些參數為在 portlet 之間共享請求參數提供了一種途徑。
公共賦值變量的屬性
每一個變量必須要有一個名字,或者可能還要有其他的屬性:
Name:(必需的)參數獨一無二的名字,要麼是一個字符串要麼是名字空間特定的名字。選擇默認的名字空間或者指定一個不同的。您所輸入的作為事件名的本地字符串會添加到名字空間。
Identifier:(必需的) portlet 代碼中使用的字符串以引用賦值變量。
Description:(可選的)對賦值變量的描述。
Alias:(可選的)對參數的名字空間區域內的名字。
本文中使用的范例程序
在本文中,范例的 portlet 程序展示了 JSR 286 的事件和公共賦值變量的實用性。傳遞公司使用的范例程序,以維持它的順序和客戶。它由三個 portlets 組成:
Orders portlet 維持了公司順序每月的細節信息。
OrderDetails portlet 顯示了某個順序的細節信息。
TrackingDetails portlet 顯示了某個順序的追蹤細節信息。
文章描述了怎樣創建事件和公共賦值變量,以及怎樣在例子中使用它們。
范例的用例
用戶可以選擇一個月的順序 ID,以查看它的順序和追蹤細節信息。這是通過使用事件和公共賦值變量得以實現的。 Orders portlet 總結了一個月內所有順序的信息。當用戶點擊 Orders portlet 中順序的 ID 時,portlet 就會激發一次事件。該事件會由顯示被選中順序 ID 細節信息的 OrderDetails portlet 處理的。然後 OrderDetails portlet 會從順序細節信息那裡獲取順序的追蹤 ID,並將細節信息作為賦值變量傳遞給 TrackingDetails portlet 。最後 TrackingDetails portlet 會顯示出該順序的追蹤細節信息。
為了讓該用例運轉,使用 Rational Application Developer 7.5 中的 Portal Toolkit,來聲明一個名為 OrderIDType 的事件。該事件對於 Orders portlet 是作為支持的公布事件而添加,對於 OrderDetails portlet 是作為支持的處理事件而添加。
您可以創建 TrackingIDType 公共賦值變量,並使 OrderDetails 和 TrackingDetails portlets 支持該參數。
創建 JSR 286 portlet 項目和 portlets
Rational Application Developer 中的 Portlet Project 向導,支持對 JSR 286-compliant portlet 項目的創建。
按照以下步驟創建 portlet 項目:
點擊 File > New > Portlet Project 以打開向導。
指定細節信息,如圖 1 所示:
對於目標運行時環境,選擇 WebSphere Portal v6.1。
對於 portlet API,選擇 JSR 286 Portlet。
對於 portlet 類型,選擇 Basic Portlet.
圖 1. JSR 286 portlet 項目創建向導
接下來的一步,是向您創建的 portlet 程序添加需要的 portlets 。既然文章在范例程序中涉及到了三個 portlets,那麼您就可以向 portlet 項目添加這些 portlets (見於圖 2 ):
右擊 portlet 部署描述器並選擇 New > Portlet。
輸入 portlet 名為 OrderDetail,然後點擊 Finish。
重復以上的步驟,以添加其他兩個 portlets:OrdersPortlet 和 TrackingPortlet。
圖 2. Portlet 創建向導
注意:
本文並沒有討論怎樣編輯 Java™Server Pages(JSP™)文件,並添加您想對 portlets 所要的功能,因為現在的重點是創建事件和公共賦值變量。我們的假設是 portlets 得到變動時, Orders portlet 會顯示該月的順序,OrderDetail portlet 會顯示順序的細節信息,而 Tracking portlet 會顯示順序的追蹤細節信息。
圖 3 顯示了當 OrdersPortlet 發布在 WebSphere Application Server V6.1 上時是什麼樣子的。
圖 3. Orders Portlet
在 portlet 部署描述器中創建一個事件定義
使用 Rational Application Developer 中包含的事件向導創建事件會十分容易 。按照以下方法創建三個事件:
在 Project Explorer 中展開 portlet 項目。
右擊 portlet 部署編輯器並選擇 Event。
如圖 4 所示,在 Event 下有兩個可用的選項:
對 Publish Event 激活該 Portlet
對 Process Event 激活該 Portlet
圖 4. 事件選項
添加事件作為 portlet 公布事件
當您選擇第一個選項時會執行這些操作,該選項就是“對 Publish Event 激活該 Portlet”。
向 portlet 程序添加事件定義
添加事件作為 portlet 支持的公布事件
編輯 processAction() 或者 processEvent() 方法以公布事件
當您選擇其他的選項,也就是“對 Process Event 激活該 Portlet”時,執行以下的操作:
如果該事件定義尚未存在,那麼就向 portlet 程序添加事件定義
向 portlet 添加作為支持處理的事件
編輯 processEvent() 方法以處理事件
接下來的一步是使用向導來創建事件。按照以下方法,激活 Orders portlet 以公布 OrderIDType 事件:
右擊 portlet 部署描述器下面的 Ordersportlet 。
選擇 Event > Enable this Portlet to Publish events。該操作將會打開向導。
指定細節信息,如圖 5 所示:
對於 Event 名字,選擇 OrderIDType。
對於 Value 類型,指定 String。
圖 5. 激活 portlet 以公布事件的向導
點擊 Finish。
該向導將會對 portlet 部署描述器做出以下兩個更改:
向 portlet 程序添加事件定義
添加事件作為 portlet 支持的公布事件
列表 1 所示的代碼,顯示了事件向導是怎樣編輯 portlet 部署描述器代碼的。
列表 1. 部署描述器代碼更改
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
id="com.ibm.jsr286eventrenderparam.JSR286EventRenderParamPortlet.19a07d46c1">
<portlet>
<portlet-name>OrderDetail</portlet-name>
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
id="com.ibm.jsr286eventrenderparam.JSR286EventRenderParamPortlet.19a07d46c1">
<portlet>
<portlet-name>OrderDetail</portlet-name>
<display-name xml:lang="en">OrderDetail</display-name>
<display-name>OrderDetail</display-name>
<portlet-class>
com.ibm.jsr286eventrenderparam.OrderDetailPortlet
</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>
com.ibm.jsr286eventrenderparam.nl.OrderDetailPortletResoure
</resource-bundle>
<portlet-info>
<title>OrderDetail</title>
<short-title>OrderDetail</short-title>
<keywords>OrderDetail</keywords>
</portlet-info>
</portlet>
<portlet>
<portlet-name>OrdersPortlet</portlet-name>
<display-name xml:lang="en">OrdersPortlet</display-name>
<display-name>OrdersPortlet</display-name>
<portlet-class>
com.ibm.jsr286eventrenderparam.OrdersPortlet
</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>
com.ibm.jsr286eventrenderparam.nl.OrdersPortletResource
</resource-bundle>
<portlet-info>
<title>OrdersPortlet</title>
<short-title>OrdersPortlet</short-title>
<keywords>OrdersPortlet</keywords>
</portlet-info>
<supported-publishing-event>
<name>OrderIDType</name>
</supported-publishing-event>
</portlet>
<portlet>
<portlet-name>TrackingPortlet</portlet-name>
<display-name xml:lang="en">TrackingPortlet</display-name>
<display-name>TrackingPortlet</display-name>
<portlet-class>
com.ibm.jsr286eventrenderparam.TrackingPortlet
</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>
com.ibm.jsr286eventrenderparam.nl.TrackingPortletResource
</resource-bundle>
<portlet-info>
<title>TrackingPortlet</title>
<short-title>TrackingPortlet</short-title>
<keywords>TrackingPortlet</keywords>
</portlet-info>
</portlet>
<default-namespace>http://JSR286EventRenderParam/</default-namespace>
<event-definition>
<name>OrderIDType</name>
<value-type>java.lang.String</value-type>
</event-definition>
</portlet-app>
編輯 portlet 類的過程操作代碼,以發布事件
processAction()方法會得到編輯以發布事件,如列表 2 所示。
列表 2. 對 processAction()事件所做的編輯
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, java.io.IOException {
if( request.getParameter(FORM_SUBMIT) != null ) {
// Set form text in the session bean
OrdersPortletSessionBean sessionBean = getSessionBean(request);
if( sessionBean != null )
sessionBean.setFormText(request.getParameter(FORM_TEXT));
}
//Initialize the fields in the class as per your requirement
java.lang.String sampleObject = new java.lang.String();
response.setEvent("OrderIDType", sampleObject);
}
您必須編輯事件向導生成的代碼,以滿足您的需求。因為 OrderIDType 需要被發送出去,所以在選中順序 ID 時,操作請求會產生順序 ID(見於列表 3)。
列表 3. 發送 OrderIDType 的代碼
String order_id = request.getParameter(ORDER_ID);
if (order_id!=null)
response.setEvent("OrderIDType", order_id);
向導會編輯 portlet 部署描述器下面的 portlet,如圖 6 中的 Project Explorer 所示。在 OrdersPortlet 節點下,會出現 OrderIDType 事件。
圖 6. Project Explorer
添加 portlet 支持的處理事件
接下來,OrderDetail portlet 需要接受順序 ID。換句話說,OrderDetail portlet 現在需要處理發布的事件了。
按照以下步驟,激活 portlet 以處理事件:
展開 Portlet Deployment Descriptor 節點。
右擊 OrderDetailPortlet 並選擇 Event > Enable this Portlet to Process Event。
圖 7. 過程事件選項
“Enable this portlet to process events”向導會打開,如圖 8 所示。
圖 8. 對 Process 事件窗口激活 Portlet
對於 Event Name,選擇 OrderIDType,它已經使用事件發布向導得到聲明了。您不能在這裡編輯事件定義,但是您可以在 portlet 部署描述器中手動編輯它。
點擊 Finish 以完成這個過程:
為 OrderDetail Portlet 添加 supported-processing-event 元素(當您發布該事件時您已經添加了事件定義)。
編輯 processEvent() 方法以處理事件
OrderDetail portlet 的 portlet 部分如列表 4 所示得到編輯。
列表 4. 對 OrderDetail portlet 所做的更改
<portlet>
<portlet-name>OrderDetail</portlet-name>
<display-name xml:lang="en">OrderDetail</display-name>
<display-name>OrderDetail</display-name>
<portlet-class>
com.ibm.jsr286eventrenderparam.OrderDetailPortlet
</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>
com.ibm.jsr286eventrenderparam.nl.OrderDetailPortletResoure
</resource-bundle>
<portlet-info>
<title>OrderDetail</title>
<short-title>OrderDetail</short-title>
<keywords>OrderDetail</keywords>
</portlet-info>
<supported-processing-event>
<name>OrderIDType</name>
</supported-processing-event>
</portlet>
在 portlet 類中編輯事件代碼以處理事件
如列表 5 所示,processEvent()方法也得到了更改,該方法對處理接受的事件負責。
列表 5. 對 processEvent( ) 方法所做的更改
public void processEvent(EventRequest request, EventResponse response)
throws PortletException, java.io.IOException {
Event sampleEvent = request.getEvent();
if(sampleEvent.getName().toString().equals("OrderIDType")) {
Object sampleProcessObject = sampleEvent.getValue();
}
您需要從 OrderDetail portlet 向 Tracking portlet 發送 TrackingID。因此,您需要編輯 processEvent() 方法,如列表 6 中的粗體代碼所示。
列表 6. 對 processEvent( ) 方法所做的更改
public void processEvent(EventRequest request, EventResponse response)
throws IOException, PortletException {
Event sampleEvent = request.getEvent();
if(sampleEvent .getName().equals("OrderIDType")) {
Object sampleProcessObject = sampleEvent.getValue();
response.setRenderParameter(ORDER_ID, sampleProcessObject.toString());
//set the order id as a render parameter
OrderDetail od = ShippingDB.getOrderDetail(ev.getValue().toString());
if (od != null) {
request.getPortletSession().setAttribute(ORDER_DETAIL, od);
response.setRenderParameter("TrackingID", od.getTrackingId());
//fetch the tracking id from the order details, and set it as a
render parameter.
}
}
}
為了讓 OrderDetails Portlet 顯示 Order Details,您就需要編輯 doView() 方法以添加如列表 7 所示的粗體代碼。
列表 7. 對 doView( ) 方法所做的編輯
String orderId = (String) request.getParameter(ORDER_ID);//get the order set
in the processAction()
OrderDetail od = ShippingDB.getOrderDetail(orderId);
PortletURL actionURL = ShippingUtils.createSimpleActionURL(ORDER_DETAILS, response);
odb.setActionURL(actionURL);
if (od != null)
odb.setOrderDetail(od);
getPortletContext().getRequestDispatcher(getJspFilePath(request, VIEW_JSP))
.include(request, response);
添加公共賦值變量
接下來的一步,就是使用公共賦值變量機理來共享 OrderDetail portlet 和 Tracking portlet 之間的追蹤 ID。
為 EventSample 項目打開 portlet 部署描述器。
選擇 Render Params 項,然後點擊 Add 以創建帶有默認名(NewPublicRenderParam)的公共賦值變量。
將 Name 和 Identifier 區域更改為 TrackingID,如圖 9 所示。
圖 9. Portlet Deployment Descriptor 編輯器中的 Render Params 項
該操作將會添加如列表 8 所示的部分,到 portlet 部署描述器中的 portlet 程序定義中。
列表 8. 添加至 portlet 部署描述器中的代碼片段
<public-render-parameter>
<identifier>TrackingID</identifier>
<name>TrackingID</name>
</public-render-parameter>
因為該參數需要由 Tracking 和 OrderDetail portlets 共享,所以您需要添加一個參數,作為每一個 portlets 都支持的公共賦值參數。
從 Portlets 項中,選擇 TrackingPortlet。
切換至右邊窗格中的公共賦值變量,並點擊 Select。
對於名字,選擇 Tracking ID,它是在編輯器中的 Render Params 項中創建的,如圖 10 所示。
點擊 OK。
重復第 4 步和第 5 步,以添加 TrackingID 作為 OrdersPortlet 的公共賦值變量。
圖 10 顯示了添加給 portlets 的公共賦值變量。
圖 10. 添加的公共賦值變量
對 portlet 部署描述器做如列表 9 所示的更改。
列表 9. 對 portlet 部署描述器所做的更改
<portlet>
<portlet-name>OrdersPortlet</portlet-name>
<display-name xml:lang="en">OrdersPortlet</display-name>
<display-name>OrdersPortlet</display-name>
<portlet-class>
com.ibm.jsr286eventrenderparam.OrdersPortlet
</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>
com.ibm.jsr286eventrenderparam.nl.OrdersPortletResource
</resource-bundle>
<portlet-info>
<title>OrdersPortlet</title>
<short-title>OrdersPortlet</short-title>
<keywords>OrdersPortlet</keywords>
</portlet-info>
<supported-publishing-event>
<name>OrderIDType</name>
</supported-publishing-event>
<supported-public-render-parameter>
TrackingID
</supported-public-render-parameter>
</portlet>
<portlet>
<portlet-name>TrackingPortlet</portlet-name>
<display-name xml:lang="en">TrackingPortlet</display-name>
<display-name>TrackingPortlet</display-name>
<portlet-class>
com.ibm.jsr286eventrenderparam.TrackingPortlet
</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>
com.ibm.jsr286eventrenderparam.nl.TrackingPortletResource
</resource-bundle>
<portlet-info>
<title>TrackingPortlet</title>
<short-title>TrackingPortlet</short-title>
<keywords>TrackingPortlet</keywords>
</portlet-info>
<supported-public-render-parameter>TrackingID
</supported-public-render-parameter>
</portlet>
您必須編輯 Tracking portlet 的 doView() 方法,以顯示追蹤 的細節信息,它建立在順序的 TrackingID 的基礎之上(見於列表 10 )。
列表 10. 對 doView( ) 方法所做的更改
String renderParam = request.getParameter("TrackingID");
//fetch the tracking id render param which was set in the OrderDetails Portlet
TrackingDetailBean tdb = new TrackingDetailBean();
request.setAttribute(TRACKING_DETAIL_BEAN, tdb);
if (renderParam!=null && renderParam.length()>0) {
PortletURL actionURL =
ShippingUtils.createSimpleActionURL(TRACKING_DETAILS, response);
tdb.setActionURL(actionURL);
PortletURL rdActionURL =
ShippingUtils.createSimpleActionURL(ROUTING_DETAILS, response);
tdb.setRoutingDetailActionURL(rdActionURL);
TrackingDetail td = ShippingDB.getTrackingDetail(renderParam);
if (td != null) {
tdb.setTrackingDetail(td);
getPortletContext().getRequestDispatcher(getJspFilePath
(request, VIEW_JSP)).include(request, response);
} else {
//Tracking id not found; print error page
tdb.setErrorMessage("Tracking Id " + renderParam + " not found.");
getPortletContext().getRequestDispatcher(getJspFilePath
(request, ERROR_JSP)).include(request, response);
}
}
公布 portlet 項目
現在您就可以在 WebSphere Application Server V6.1 上發布 portlet 程序了:
右擊 portlet 項目(見於圖 11 )並選擇 Run As > Run on Server。
圖 11. 發布 portlet 項目
選擇 WebSphere Portal V6.1 Server,如圖 12 所示。
點擊 Next,然後點擊 Finish。
圖 12. 選擇您想要運行 portlet 程序的服務器
將 portlets 集中起來
入口服務器可用的布線工具,可以幫助您集中 portlets 之間的關系。
按照以下方式,訪問布線工具:
為 portlets 所在的頁面選擇 Edit Page Layout。
選擇 Wires 項。
對源 portlet,從下拉菜單中選擇 OrdersPortle,對於目標 portlet,選擇 OrderDetail Portlet(圖 13)。對於事件名,為 Sending 和 Receiving 區域右擊下拉箭頭。
圖 13. 在 portlet 程序中添加線以定義關系
點擊加號然後點擊 Done。
選擇一個順序 ID(例如, OrdersPortlet 中的第一個順序)。
當您點擊順序 ID 時,會由 Orders portlet 激發一次事件,它將會向 Order Details portlet 發送 Order_ID 值。當該 portlet 接受順序 ID 時,Order Details Portlet 會處理事件。它獲取了順序 ID 的細節信息並為用戶顯示出這些信息。另外,Order Details portlet 會獲取順序的追蹤 ID,並交流 ID 以追蹤細節部分的 portlet,因為 TrackingID 已經為 Order Details 和 Tracking portlets 作為共享的賦值參數而得到添加。因為,一旦用戶點擊順序 ID,那麼順序的細節信息和追蹤的細節信息就會顯示給用戶了(見於圖 14)。
圖 14. Orders portlet
現在用戶可以看到順序和追蹤的細節信息,如圖 15 所示。因為,事件和公共賦值變量用於向各自的 portlets 傳遞 OrderID 和 TrackingID。
圖 15. Order 和 Tracking 細節的 portlets
正如您在這裡看到的那樣, Rational Application Developer 7.5 提供的工具,極大地簡化了事件和公共賦值變量的創建。您只需編輯生成的代碼,以滿足程序的需要。
本文配套源碼