Jetspeed2.0最終release版本發布于2005年12月, 可以從以下網址下載源代碼和捆綁tomcat的壓縮文件: http://www.apache.org/dist/portals/jetspeed-2/ 。
與Jetspeed1.x比較,Jetspeed2.0 (以下簡稱J2)的架構發生了很大變化, J1.x使用了Turbine,在J2中Turbine不再使用, 而是使用了Spring Framework作為默認的組件框架,從官方的資料介紹看,J2架構支持將一種組件架構替換為別的組建架構如Pico,Spring僅僅是J2默認的Component Framework,從本節下文的敘述中可以看到替換的方式。
portlet 之間可以通過session等來進行交互。所以談不上 “JSR 168沒有定義portlet之間的事件模型”。 由于Jetspeed不是基于JSF的,所以它的門戶上的鏈接是無狀態的,也許獨立的AJAX可以讓它更容易被集成。
Jetspeed-2使用pluto作為Portlet 容器。
Jetspeed-2組件框架(Component Framework)的裝配是通過JetspeedServlet(org.apache.jetspeed.engine.JetspeedServlet)進行配置和實現的,見下圖:
JetspeedServlet在web.xml中配置,門戶應用啟動時即執行JetspeedServlet。JetspeedServlet中initializeComponentManager
方法為給定的組件框架裝載assemply(見WEB-INF/assembly),initializeComponentManager將spring framework作為默認的組件框架。并裝配WEB-INF/assembly下的xml文件來初始化spring引擎。然后組件框架來創建
JetspeedEngin:
engine = new JetspeedEngine(properties, applicationRoot, config,
initializeComponentManager(config, applicationRoot, properties));
下面是initializeComponentManager
方法的代碼:
protected ComponentManager initializeComponentManager(ServletConfig servletConfig, String appRoot, Configuration configuration) throws IOException
{
ServletConfigFactoryBean.setServletConfig(servletConfig);
// String relativeApplicationRoot = getRealPath("/");
String relativeApplicationRoot = appRoot;
String absApplicationRoot = new
File(relativeApplicationRoot).getCanonicalPath();
final String assemblyDir =
configuration.getString("assembly.dir","/WEB-INF/assembly");
final String assemblyFileExtension =
configuration.getString("assembly.extension",".xml");
String[] bootConfigs = new String[] {"/WEB-INF/assembly/boot/*.xml"};
String[] appConfigs = new String[] {assemblyDir+"/*"+assemblyFileExtension};
ServletContext servletContext = servletConfig.getServletContext();
SpringComponentManager cm = new SpringComponentManager(bootConfigs,
appConfigs, servletContext, appRoot);
return cm;
}
如果我們需要用別的組件框架替代Spring framework,就要覆蓋initializeComponentManager
方法,就是指用別的
ComponentManager替代SpringComponentManager。下面是CompomentManager相關的類圖:
從上面的分析說明Jetspeed2的基礎組架構是基于Spring組件的可伸縮的架構,Jetspeed2還有什么其他新的特性?
l Jetspeed 2.0 的final release版本完全兼容Portlet規范1.0(JSR-168)。Jetspeed2.0是Java Portlet API的完整實現。
l 支持SSO(Single Sign-On)單點登錄, 單點登錄技術是一種認證和授權機制,它允許注冊用戶只需要在任一成員網站上登錄一次,而后授權訪問其他連接的分支網站,無需再進行登錄。
l Jetspeed-Bridge使Jetspeed可以集成Struts,JSF,PHP,Perl,Velocity,WebWork開發的應用。可以將Struts Action、Velocity模板、Perl腳本、PHP腳本等以Portlet的形式展現,這對舊系統的移植將很有幫助。JetSpeed 2.0還實現了一組常用的示例Portlet,包括日歷、書簽等小工具。
l 可配置的管道請求處理器(Pipeline Request Processor)。管道可把一些訪問的請求根據參數,分配給portlet的容器。
l JAAS數據庫安全策略。
l Jetspeed支持AJAX XML API。
l portlet應用的自動部署。
l 基于LDAP及數據庫實現的安全組件。為用戶認證提供LDAP支持。
l 開發者可使用Jetspeed PSML語言裝配portlets。
l 門戶內容管理和導航:頁面、菜單、文件夾、鏈接。
l 多線程的聚合引擎。
l 集成主流的數據庫:Derby, MySQL, MS SQL, Oracle, Postgres, DB2
l 國際化支持
l 統計日志引擎。
l Portlet注冊
l 使用Lucene對Portlet組件進行全文搜索。
l 用戶注冊功能
l 遺忘密碼獲取功能
l 豐富的登錄和口令配置管理功能
l 基本頁面定制
l 管理Portlet:
- 用戶、角色、組、密碼和Profile管理
- JSR168 用戶屬性編輯器
- Portlet應用和生命周期管理
- Profiler系統管理
- 統計報表
門戶設計的特征:
l 可部署Jetspeed Portlet和頁面皮膚(Decorators)CSS組件。
l 可配置的CSS頁面外觀(Layouts)。
l 很容易為皮膚和Layouts組件使用Velocity宏語言
Jetspeed-2 工作流程
引擎部分是Jetspeed-2,而Container是Pluto Portlet Container,Portlet就是自己寫的Portlet;所以這張圖正好對照JSR168中的Portal—Portlet Container—Portlet的概念。
上圖描述的的工作流程:
1、request送至server后由JetspeedServlet(org.apache.jetspeed.JetspeedServlet)接收。JetspeedServlet通過Jetspeed(org.apache.jetspeed.Jetspeed)取得ComponentManager,然后通過ComponentManager取得
RequestContextComponent(org.apache.jetspeed.request.JetspeedRequestContextComponent) 。
2、RequestContextComponent會針對這個 request建立一個
RequestContext(org.apache.jetspeed.JetspeedRequestContext),并且讓這個request和新建的RequestContext能互相參照。
3、呼叫Engine(org.apache.jetspeed.JetspeedEngine)的service()方法,這個方法會把剛剛建立的RequestContext傳入,這樣后面的組件才能使用。
4、在service()方法中,Engine會依據request的目標URL來取得相對應的Pipeline(org.apache.jetspeed.pipelineJetspeedPipeline)來處理。Pipeline使用了chain of responsibility的pattern,是由一堆Valve(org.apache.jetspeed.pipeline.valve.Valve)串起來的。
5、各個Valve依序執行,其中某些Valve會和Container動作,某些Valve會負責產生要response的portal頁面。在這個過程中,Continer會執行相關的Portlet,并將結果返回至Pipeline,也就是Valve chain中。
6、將產生的portal頁面傳回給user,流程結束。
由上面的介紹,應該可以體會到Pipeline在J2中是非常重要的,這里附上Pipeline的官方UML圖做參考。
Jetspeed-2本身是Spring-based的架構,主要的Spring設定都在webapps"jetspeed"WEB-INF"assembly下。JetspeedServlet在init時會建立Spring容器并載入這些xml文件,而之前提到的ComponentManager就可以通過name或class在Spring容器中尋找需要的component。有關J2的component,請務必參考http://portals.apache.org/jetspeed-2/guides/guide-components.html及源代碼。
看一下assembly目錄中的pipelines.xml。這個XML是用來組合各個Pipeline和設定各Pipeline和其對應的URL。先看一下最后一段bean id="pipeline-map"的部份,在這邊可以看到URL和其相對應的Pipeline。另外找到bean id="jetspeed-pipeline"這一段,可以看到這個Pipeline中Valve的組合,而這個Pipeline也是default的Pipeline;有興趣的不妨參這個XML文件,把這個Pipeline中的Valve的原始代碼找到翻一翻,大致了解一下每個Valve在做啥。
Jetspeed-2性能:
在jetspeed2中還使用了多線程異步處理,用以提高Performance. 但是事實上第一次運行的開銷還是挺大的,比如一個Portal頁面上有20個Portlet,那么Portlet Container就需要初始20個web application. 加載class總是很耗資源的. 目前沒有十分好的方法。
Jetspeed-2安全機制
J2使用JAAS的來處理security有關的問題。在j2捆綁的tomcat中,從bin同級別目錄conf中查找Catalina"localhost"jetspeed.xml,打開這個文件可看到有關JAAS Realm及login的設定。
tomcat"conf" l及C:"tomcat"webapps"jetspeed"WEB-INF"web.xml看到有關及login的設定 :
<Context path="/jetspeed" docBase="jetspeed" crossContext="true">
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="Jetspeed"
userClassNames="org.apache.jetspeed.security.impl.UserPrincipalImpl"
roleClassNames="org.apache.jetspeed.security.impl.RolePrincipalImpl"
useContextClassLoader="false"
debug="0"/>
<Resource name="jdbc/jetspeed" auth="Container"
factory="org.apache.commons.dbcp.BasicDataSourceFactory"
type="javax.sql.DataSource" username="sa" password=""
driverClassName="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:hsql://127.0.0.1:9001"
maxActive="100" maxIdle="30" maxWait="10000"/>
</Context>
大致上來說,JAAS包含Principal、Permission、Policy三個概念。在J2中有user、role、group三種Principal。而Permission基本上有page、portlet,tab等等,當然也可以增加自定的Permission。至于Policy,J2并沒有使用JAAS的policy,而是使用自帶的RdbmsPolicy,也就是把Policy的信息存在資料庫中;而通過適當的設置, J2也可以使用相關App Server的JAAS。
底下是官方的security組加的架構圖:
在J2中,核心的部份就是"J2 Security Coarsed Services"里的4個Manager組件:UserManager,RoleManager,GroupManager,PermissionManager, J2的JAAS login module實際上是使用UserManager來進行authentication;UserManager通過OJB自數據庫中取出user的信息例如UserPrincipal、Crendential等并進行authorization.
J2在security的部份也提供了SPI的設計供開發人員加入自定的認證方式,例如使用LDAP,參考底下官方的連接:
http://portals.apache.org/jetspeed-2/multiproject/jetspeed-security/ldap.html ,可以知道如何使用LDAP來進J2上的認證。
Jetspeed-2的Portal Bridge
隨著Portal一步步走向成熟其結構和功能也發生了較大變化,從混和型服務走向以系統框架為核心,應用程序與部署、開發完全分開的階段,Portal相當與一個骨架一樣可以接納外部的這種技術架構開發的應用程序,使用Portals Bridges模式來連接不同的應用程序,可包括以下幾種:
集成Struts MVC模式開發的應用程序;
集成WebWorks開發的應用程序;
集成JSF開發的應用程序;
集成Perl開發的應用程序;
集成PHP開發的應用程序;
1 集成Struts MVC模式開發的應用程序
Struts已經成為了用Java創建Web應用的一個最流行的框架工具,Struts所實現的MVC模式給Web應用帶來了良好的層次劃分,同時也提供了一系列的工具來簡化Web應用的開發。
應用程序開發者無需關心Portal的規范,只要關心Struts本身的開發,這樣大大降低了開發成本和開發人員的再培訓。
主要實現類:public class StrutsPortlet extends GenericPortlet。
下面是Portlet的片斷:
<portletid="StrutsPortletDemo">
<init-param>
<name>ServletContextProvider</name>
<value>org.apache.jetspeed.portlet.ServletContextProviderImpl</value>
</init-param>
<init-param>
<name>ViewPage</name>
<value>/Welcome.do</value>
</init-param>
<init-param>
<name>HelpPage</name>
<value>/Tour.do</value>
</init-param>
<portlet-name>StrutsPortletDemo</portlet-name>
<display-name>Struts Portlet Demo</display-name>
<description>This is the struts MailReader portlet demo</description>
<portlet-class>org.apache.portals.bridges.struts.StrutsPortlet</portlet-class>
<expiration-cache>-1</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
2 集成WebWork開發的應用程序
WebWork是一個源代碼開放的Web應用框架,用于簡化基于Web的應用開發。可使用WebWork和JavaServerPages(JSP)、Velocity來建立注冊界面。通過Jetspeed2的Portals Bridges框架來實現和webwork的集成,主要實現類:
public class Webwork2Portlet extends GenericPortlet
3 JSP應用程序集成
JSF為廣大基于JAVA的 Web應用用戶界面的開發人員提供了標準的編程接口、豐富可擴展的UI組件庫(一個核心的JSP標記庫用來處理事件、執行驗證以及其他非UI相關的操作和一個標準的HTML 標記庫來表示 UI組件)、事件驅動模型等一套完整的Web應用框架,通過 JSF ,您可以在頁面中輕松自如地使用 WEB 組件、捕獲用戶行為所產生的事件、執行驗證、建立頁面導航…,同時您會發現,當使用支持JSF的開發工具來開發 JSF 應用的時候,一切將會變得異常簡單,就類似于我們現在開發VB或者PowerBuilder程序一樣的簡便,GUI方式拖放組件、修改組件屬性、建立組件間關聯以及編寫事件偵聽器等等,這樣,一個并不是特別熟悉Java的Web應用開發人員也能夠輕松地完成自己的任務了,這種易開發性對于J2EE而言無疑是太重要了。
3 集成PERL應用程序
Perl 就是 Practical Extraction and Reporting Language 的簡稱,是一種最廣泛應用于語法分析和 World Wide Web 的編程語言。它起源于 awk、C、sh 和 sed 語言,然而,它的應用開發遠比其他任何一種面向對象編程語言更加容易。
實現方法:
public class PerlPortlet extends GenericPortlet
直接通過HttpServletResponseWrapper來封裝獲取Response的字節流
Portlet的配置的片斷:
<portlet-name>perl-demo</portlet-name>
<display-name>Perl demo Portlet</display-name>
<portlet-class>org.apache.portals.bridges.perl.PerlPortlet</portlet-class>
<expiration-cache>-1</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
4 集成PHP應用程序
PHP是一個基于服務端來創建動態網站的腳本語言,您可以用PHP和HTML生成網站主頁。當一個訪問者打開主頁時,服務端便執行PHP的命令并將執行結果發送至訪問者的瀏覽器中,這類似于ASP和CoildFusion,然而PHP和他們不同之處在于PHP開放源碼和跨越平臺,PHP可以運行在WINDOWS NT和多種版本的UNIX上。它不需要任何預先處理而快速反饋結果,它也不需要mod_perl的調整來使您的服務器的內存映象減小。PHP消耗的資源較少,當PHP作為Apache Web服務器一部分時,運行代碼不需要調用外部二進制程序,服務器不需要承擔任何額外的負擔。實現類:
public class PHPApplicationPortlet extends GenericPortlet
相關技術介紹和規范
WSRP
WSRP由OASIS(一個由開發電子商務標準的行業專家所組成的非贏利性社團)創建,它規定Porlet的遠程渲染(rendering)。主要目的就是為網絡服務提供視覺化和使用者面對面服務的主要構件。WSRP最重要的特性就是它具有隨插隨用(plug-and-play)的功能,可以讓互聯網門戶或其他網絡應用(如手機,PDA等)從網絡不同的來源處將多樣內容或是應用聚集起來。WSRP使獲得原來極難實現的功能成為可能。例如,部署一次,但把它們傳遞到任何地方,將第三方的Portlet整合在一起,增強來自不同開發商的門戶之間的互操作性。WSRP也為客戶提供了一種構建聯合門戶的可行方法。聯合門戶由互操作的門戶網絡組成,由此,某一門戶托管的資源可以被許多門戶使用。采用聯合門戶有無數的好處,包括門戶合理化和更少的IT管理的Web資產。
過去,一個Portlet只能被托管它的同一門戶本地使用。而有了WSRP,則可以將一個Portlet從門戶表面(“使用”)的Portlet交給物理上、邏輯上獨立的基礎設施托管(“生產”)。由于這種革新,WSRP具有從根本上增強門戶部署靈活性的潛能。因為門戶能夠從任何地方的Portlet中提取內容,所以業務部門現在可以編寫和維護他們自己的Portlet。這可以在各個業務部門的本地基礎設施上完成,所以某一單個門戶內的所有portlet不必部署在單個門戶實例上。由于防火墻或者不同部署方案而一度難以更新和修改的內容,現在可以由各業務部門方便而快捷地進行。業務部門獲得了前所未有的獨立性和靈活性。WSRP拓寬了門戶可以利用的資源范圍。Porlet可以被所有J2EE門戶或者所有運行.Net的機器生產或者使用。整個企業都可以利用現有的Portlet,而不再受開發商制約,并且減少了IT方面的費用,節約了托管和部署重復portlet的時間。
對程序員簡而言之,開發符合WSRP規范的Portlet在發布和注冊后將可以供別人的Portal系統遠程使用。
盡管WSRP提出的遠景如此美妙,但由于WebService的復雜性,盡管已有一些廠商的產品支持WSRP,但實際使用中非常少。
Portlet容器
Portlet Container用來管理Portlet的生命周期并且提供其運行所需要的必要環境.。并且為Portlet Preferences提供持久性(Persistent)存取服務,但是其不支持內容的Aggregation.。Aggregation由Portal組件提供。
Portlet
一個 Portlet 是以 Java 技術為技術的 Web 組件,由 Portlet Container 所管理,專門處理客戶的 request 以及產生各種動態的信息內容。Portlets 為可插式 ( pluggable ) 的客戶界面組件,提供呈現層成為一個信息系統。
這些由 portlet 產生的內容也被稱為片段 (fragment),而片段是具有一些規則的Markup( HTML、XHTML、WML ),而且可以和其他的片段組合而成一個復雜的文件。而 Portlet 中的內容正常來說是與其他 Portlet 的內容聚合而成為一個 Portal 網頁。而 Portlet 的生命周期是被 Portlet Container 所管理控制的。
客戶端和 portlets 的互動是由 portal 通過典型的 request/response 方式實現,正常來說,客戶會和 portlets 所產生的內容互動,舉例來說,根據下一步的連接或者是確認送出的表單,結果 portal 將會接收到 portlet 的動作,將這個處理狀況轉向到目標 portlet。這些 portlet 內容的產生可能會因為不同的使用者而有不同的變化,完全是根據客戶對于這個 portlet 的設置。
Portlet生命周期
Portlet接口的四個方法構成一個完整的生命周期:
public void init(PortletConfig config) throws PortletException;
由Portlet容器調用,在將Portlet放入服務區前調用。Portlet容器在初始Portlet后,直接調用這個方法。
public void processAction (ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException;
由Portlet容器調用,用來處理action request。
public void render (RenderRequest request, RenderResponse response) throwsPortletException, java.io.IOException;
由Portlet容器調用,用來生成輸出。
public void destroy() ;
將Portlet從服務區中刪除。
一個Portal處理流程:
1. 一個客戶端(例如:一個web瀏覽器)在被驗證之后向Portal發出HTTP請求;
2. Portal(或稱為Portal Server)接收到請求;
3. Portal判斷請求是否包含與組成門戶網站網頁的portlet有關的動作;
4. 如果存在與某個portlet相關的動作,Portal請求portlet容器調用portlet處理動作;
5. Portal通過portlet容器調用portlet,獲得被包含在產生的門戶網站網頁中的內容片段;
6. Portal將portlet產生的結果聚集于門戶網站的網頁,然后將網頁返回至客戶端。
在下圖中需要注意的是Portal服務器是建立在Http服務器的基礎上的。Portal服務器不可獨立的運行。
Portlet Preferences
Portlet Preferences是Portlet的一個新特性,提供類似數據庫的功能。但是不是用來取代數據庫,只是用來存取簡單的Portlet參數配置。
JSR168規范
(先看一下在JSR168中提到的Portal page,可以了解一個Portal Page上大概有哪些element)
JSR-168 (Enterprise Portlet Specification 1.0 Final Draft 發表于2003-09-03,是用于portlet級別開發的新Java portlet標準。依循于 JSR-168的Portlet可以移植于其他的Portal Container上。 JSR-168規范的站點: http://www.jcp.org/en/jsr/detail?id=168
JSR168將Portal 的組成分為三部份 (1) Portal Server (2) Portlet Container (3) Portlet。
JSR168是Java 規范要求(Java Specification Request ,JSR)的縮寫,它為創建Portlet建立標準的API。很多重量級的Portal開發商和開源項目組參與了Java標準化組織(Java Community Process)創建JSR168標準的過程,并且很多Portal產品開始支持JSR 168。JSR168在2003年10月正式發布。最主要的Portal開發商已經宣布計劃支持JSR 168標準,查看JSR 168站點(http://www.jcp.org/en/jsr/detail?id=168 )可以得到目前為止JSR 168支持者的完整列表。
按照Java標準化組織(Java Community Process)所述,JSR 168 portlet擁有一個適用于所有Portal客戶端的簡單的、標準的API,支持多種類型的客戶端(多設備、多瀏覽器),支持本地化和國際化,允許門戶應用程序的熱部署和重新部署,并且包含聲明性安全(與servlet和企業JavaBean規范中使用的機制相同)。
現在開發商只需要支持一種Portlet集。結果,更多的ISV提供他們自己的通用的、開箱即用(out-of-the-box)的Portal集成構件。這是值得客戶高興的時刻,因為開箱即用的應用程序集成現在無需考慮選擇那個Portal開發商就可以使用。
JSR 168意味著在Portal市場上,爭奪主導地位的優勢不再是哪個開發商擁有最多數目ISV的開箱即用集成。相反,標準化通過使ISV支持他們自己的Porlet統一了這一領域。客戶的風險和成本降低,并且不再根據重建Portlet的的業務量來選擇門戶開發商。在選擇Portal開發商的時候,主要的決定性因素將是Portal產品與客戶企業體系結構的適應程度。
對程序員簡而言之,開發符合JSR168規范的Portlet將可以順利移植到符合該規范的不同Portal平臺上。
PSML
PSML的全名是Portal Structure Markup Language(門戶結構標記語言)。J2用PSML來定義Portal內的各種resource,包括Page、Folder、Link、Security、Menus等等,有關J2的PSML詳細介紹見:
http://portals.apache.org/jetspeed-2/guides/guide-psml.html。
這里要特別提一下PSML Page。在J2中,一個PSML Page就代表一個Portal page,其根元素為<page>,里面指定了這個Portal page所包含的portlet及排列方式(ex: 2行或3行)、這個Portal page所使用的樣板(稍后會提到的layout)還有這個Portal page的外觀(稍后會提到的decoration)等等。
另外一個要特別說明的是在PSML Page中所使用的<fragment>這個tag。fragment有portlet和layout二種,用type這個屬性來區別:<fragment type="portlet">代表一個portlet,<fragment type="layout">代表這個page所用的layout;然而不管是哪一種fragment,name屬性的值都應該依照"portlet-app-id::portlet-id"的格式。
事實上,layout fragment其實也是portlet。看一下
tomcat的webapps"jetspeed"WEB-INF"apps"里有一個jetspeed-layouts目錄,就是J2內部的一個Portlet application。因此"jetspeed-layouts::VelocityTwoColumns"回對到這個目錄下portlet-id為VelocityTwoColumns的portlet。總之,J2的layout也是portlet,如果再研究一下,其實這是個Velocity Bridge的portlet.
layout
J2中的layout指的是用來排列Portal page中各個portlet的樣板。默認的情況下,J2用Velocity來實現layout。
decoration
J2中的decoration是用來裝飾Portal page和portlet使其美觀,分為layout-decoration和portlet-decoration兩種。layout-decoration負責一整個Portal page(因此叫page-decoration),而portlet-decoration負責每一個Portlet fragment。默認的情況下,J2用Velocity和CSS來實現decoration。當J2在呈現一Portal page時,會依照這個Portal page指定的layout來排列這個page上的各個portlet,并且使用這個page所指定的layout-decoration和portlet-decoration來美化這個page和所有的portlet。有關decoration的細節可參考http://portals.apache.org/jetspeed-2/guides/guide-decorators.html 。
Aggregator
在J2中,一個Portal page的request最后通常會傳給Aggregator,然后由Aggregator負責跟Portal page內包含的所有portlet溝通并聚合各個portlet fragment以產生整個Portal page。從tomcat的webapps"jetspeed"WEB-INF"assembly"pipelines.xml),可以看到aggregatorValve這個bean被注入了org.apache.jetspeed.aggregator.PageAggregator這個Aggregator;再參考webapps"jetspeed"WEB-INF"assembly"aggregation.xml中,可已知道這個bean的類是org.apache.jetspeed.aggregator.impl.PageAggregatorImpl。
來看一下這個PageAggregatorImpl的中用來產生Portal page的方法(部份省略修改):
1 |
public void build( RequestContext context ){ //取得requested page ContentPage page=context.getPage();
//取得 root fragment ContentFragment root = page.getRootContentFragment();
//aggregate及render各Portlet,基本上render的結果都寫到context里 aggregateAndRender(root, context, page); //將結果寫入response context.getResponse().getWriter().write(root.getRenderedContent());
} |
首先要注意一下傳的是一個J2的RequestContext,基本上可以視為是用來存放這次request相關的一個context;此外,可以把ContentFragement視為portlet。而其中第6行取得root fragment,實際上就是取得前面所說的layout fragment,也就是"jetspeed-layouts::VelocityTwoColumns"這個portlet。
接著再看一下第9行的aggregateAndRender()方法(部份省略修改):
1 |
protected void aggregateAndRender( ContentFragment f, RequestContext context, ContentPage page ){ Iterator children = f.getContentFragments().iterator(); while (children.hasNext()){ ContentFragment child = (ContentFragment) children.next();
//遞歸 aggregateAndRender(child, context, page); }
// 開始真正做render的動作,基本上render的結果都寫到context里 renderer.render(f, context); //renderer是org.apache.jetspeed.aggregator.impl.PortletRendererImpl
//加上decoration addStyle(context, f.getDecorator(),ContentFragment.PORTLET);
} |
由上面的code,可以了解到J2先把整個page上所有的portlet由外到內串起來,再由內到外一個一個做render的動作,而每render完一個portlet,就加上對應的decoration,直到做完整個page。
在第12行中,render的動作實際上是renderer通過Pluto呼叫portlet(實際上是ContentFragment被包成portlet window)的render方法。PortletRendererImpl.render()方法里使用了常見的Worker Thread和Observer樣式,以達到render多個portlet的功能。
那如果想要新加外觀呢?最簡單的方式,就是先參考J2的layout portlet寫自已的layout,然后加入decoration。講起來容易,不過layout可是不太容易寫的,因為牽扯到的技術還蠻多,而且對J2也要有一定了解;但是如果能做出來,安裝就不會太麻煩。也許等以后J2紅起來以后,會有各式各樣的外觀可以玩吧。
Pluto
2003年10月JSR168規范1.0正式公布后,Jakarta Apache就開始實施Pluto計劃(冥王星計劃),最終開發出該規范的一個參考實現(Reference Implementation),即Pluto。Pluto的1.0.1-rc2版與2004年12月發布。
Pluto實現基于 JSR168的一個 Portlet Container,相當于為開發者提供了一個運行portlets的工作平臺。Pluto本身也提供了一個簡單的Portal模塊,該模塊僅僅是為了滿足Portlet容器和JSR 168的需要而寫的,因而顯得非常簡單,提供的實用的Portlet也非常少。從某種意義上說Pluto更像是一個Portlet Container,作為一個實用的Portal開發框架尚需要更強大的支持。但新版本的Pluto仍沒有推出。對于Pluto的應用開發,Apache更推薦使用Jetspeed項目框架。
盡管Pluto作為一個完整的Portal應用還非常欠缺。但不少有影響力的Portal項目使用Pluto作為Portlet Container。這些項目包括:Jetspeed 、Cocoon uPortal 、Jahia等。由此可見Pluto的重要性。從開發者和學習者的角度看,Pluto的意義還在于為開發者和學習者提供了一個深入了解Portlet Container的簡潔的參考實例。
eXo
eXo(支持JSR168)基于JSF的Portal實現。最新版本是2004年10月發布的1.0RC1版。
主要優點包括:
(1) 由AOP(AspectJ)實現的內容管理系統,極大提高了內容管理性能;
(2) 基于Pico Container的Portlet Container,Pico是一個著名的IoC3輕量級容器。同時也實現了上下文共享,二次開發的流程比較清晰;
(3) 使用Struts框架技術;
(4) 提供工作流技術服務(Workflow service)。
(5) 提供了很多交流工具,通過XML可以為結構化的信息輕易地創建視圖;
由上可見eXo采用了諸多先進技術,但存在不少缺點。主要缺點:由于Portal Server本身的數據是使用xmldb來進行處理,保存到數據庫的數據都是亂碼而且它所有默認的平臺字符集都是ISO-8859_1。缺乏中文的充分支持,對于中文門戶的開發并沒有優勢;由于JSF是重量級的表現層框架,使得exo的二次開發工作量比較大;對于商業Portal應用開發需要購買License。總體開發難度較大。
Liferay
Liferay (http://www.liferay.com ) 代表了完整的J2EE應用,使用了Web、EJB以及JMS等技術,特別是其前臺界面部分使用Struts 框架技術,基于XML的portlet配置文件可以自由地動態擴展,使用了Web Services來支持一些遠程信息的獲取,使用 Apahce Lucene實現全文檢索功能。
Liferay的缺點是它缺乏一個簡單清晰可拓展的架構設計,整個架構比較復雜且龐大;Struts1.1本身并不支持JSR168,所以Liferay在實現諸如上下文共享等問題上顯得十分笨重且沒有從根本上解決這些問題;portlet設計也顯得比較凌亂。此外,如果你的門戶系統準備應用于商業用途,你需要購買License。基于它進行二次開發比較困難。
Liferay(支持JSR168)代表了完整的J2EE應用 , 2005年1月推出的Professional 3.2.0。它的主要優點有:
(1)使用第三放的開源項目,如Hibernate等。特別是前臺界面部分使用了Struts技術;
(2)支持包括中文在內的多種語言;
(3)支持較多的先進技術,如Web Services、EJB, JMS, SOAP, XML等;
Jportal
JPortal (http://jportal.sourceforge.net ) 是目前最為符合JSR-168 Spec的Portal實現。他使用了攔截器技術和 Dynamic Proxy來實現Portlet的可插入設計。他目前只是一個原型的實現并且之關注于實現 Portal Container,并沒有過多的 Portlet實現和設計。 優點在于其的架構清晰,易于擴展,但在Portal的工業強度上需求的差距是比較大的,沒有分布式的概念是他目前架構的一個致命的地方。
Jetspeed-2相關資源鏈接
http://www.apache.org/dist/portals/jetspeed-2/
http://wiki.apache.org/portals/Jetspeed2/DevelopersDocumentation
API:
http://portals.apache.org/jetspeed-2/multiproject/jetspeed-api/apidocs/index.html
Spring Framework:
http://static.springframework.org/spring/docs/1.2.x/reference/introduction.html
http://portals.apache.org/jetspeed-2/guides/guide-components.html
http://portals.apache.org/jetspeed-2/
http://portals.apache.org/jetspeed-2/multiproject/jetspeed-security/
http://portals.apache.org/jetspeed-2/guides/guide-psml.html
http://portals.apache.org/jetspeed-2/guides/guide-decorators.html
http://portals.apache.org/jetspeed-2/guides/guide-portal-design.html http://portals.apache.org/jetspeed-2/guides/guide-jpt.html
http://community.java.net/portlet/
http://blogs.ittoolbox.com/km/portals/
http://jcp.org/en/jsr/detail?id=168
http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-portlet.html
http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-portlet2.html
http://developers.sun.com/prodtech/portalserver/reference/techart/jsr168/
http://jakarta.apache.org/pluto
http://www.sentom.net/list.asp?id=53 ( JSR#168 Portlet 說明)
http://www.jcp.org/en/jsr/detail?id=168
http://jakarta.apache.org/pluto