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://exo.sourceforge.net/
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