|
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!-- END RESERVED FOR FUTURE USE INCLUDE FILES-->
|
本文将快速浏览 Apache 门户项目组的所有项目,并着重介绍门户项目组中的核心项目-Jetspeed-2。
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
<!-- END RESERVED FOR FUTURE USE INCLUDE FILES-->
引言
JEE作为建立在
Java平台上的企业级应用解决方案,经过这些年不断发展,已经成为企业级开发的工业标准和首选平台。众多厂商如IBM,BEA和Oracle等都围绕该
规范推出了相应的,功能强大的产品。JEE规范组中最受业界认同和取得最大成功的就是JEE
Web层面规范,发展到今天,已经步入门户(Portal)的时代。
门户,简言之就是提供包括内容聚合、单点登陆、个性化定制和安全管理等服务的基础Web平台。众多JEE产品提供商基于JEE
Web层技术推出了自己的Portal产品,著名的产品有IBM WebSphere Portal Server,BEA Weblogic
Portal
Server等。一直处于技术前沿的著名开源社区Apache,经过这几年的技术积累也形成了自己的门户项目组。该项目组目前已经初具规模,并且拥有了一
定的用户群体,经受了一定的市场考验。
本文主要面向有一定JEE编程经验的Java开发者和试图构建自己的门户软件产品的产品经理,因为基于开源项目构建企业级的商用产品,已经在国外取得了许多成功案例。
名词解释
名词 |
解释 |
Portal |
门户,提供包括内容聚合、单点登陆、个性化定制和安全管理等服务的基础Web平台。 |
Portlet |
Portlet
是基于web的Java组件。它由Portlet容器管理,能够处理请求,产生动态内容。Portlet被Portal用作为可插拔的用户接口组件,为信
息系统提供展现。由Portlet动态产生的内容也被叫做fragment。fragment是遵循某种规则的标记(例如:HTML,
XHTML,WML),可与其他的fragment一起建立一个完整的文档。一般一个Portlet产生的内容和其他的Portlet产生的内容聚集在一
起形成Portal网页。 |
Portlet Container |
Portlet在Portlet容
器中运行,Portlet容器为Portlet提供必需的运行环境。Portlet容器包含Portlet(组件)并且管理它们的生命周期,它也为
Portlet的参数设置提供持久化的存储。Portlet 容器不是一个类似于 servlet 容器的独立容器。它是在 servlet
容器上通过扩展方式实现的,并重用 servlet容器提供的功能。从Portal的角度来看,Portlet
Container是Portal平台所提供的众多服务之一。 |
JSR168,JSR286 |
由于越
来越多的公司开发了各自的Portal组件和基于其的Portal产品(如Bea, IBM, Oracle, Sun, Sybase,
Novell, SAP, Jetspeed, Vignette 等.这种互不兼容的接口实现不断带给程序提供商各种问题和麻烦,
为了解决这种问题, JCP发布了JSR168 (Java Specification Request), Portlet
Specification, 用以提供不同Portal和Portlets之间的互用性。JSR
286是168规范的延伸,是目前最新标准规范,目前仍处在draft状态。 |
SSO Single |
Sign-
On,即单点登陆。当一个大系统中存在多个子系统时,用户只需要正确登陆其中任何一个子系统,就可以在各个子系统中来回自由切换和使用授予该用户权限的各
种资源。一般可以分为两种类型:Web应用之间的单点登陆和门户Web应用和它所连接的后台系统之间的单点登陆。SSO是任何一个门户产品必须解决的问
题,必须提供的服务。 |
WSRP |
WSRP是OASIS组织的一个规范,它定义了远程门户网站的Web服务。通过Web Service将远程内容抓取到本地,最后通过本地内容聚合引擎展示出来。 |
|
|
Apache门户项目组整体架构
在
引言中已经列举了Apache门户项目组的组成项目包括:Jetspeed-1/2,Bridges,Pluto,WSRP-4J和Graffito。由
于Jetspeed-1和Jetspeed-2角色相同,下文中如果没有特别指出,所有Jetspeed都是指Jetspeed-2。
图一Apache门户项目组架构图
上图中粉红色包围部分为Apache门户项目,其它由土黄色包围部分为它们的依赖项目。通过上图可以很清楚看到,全部项目都构建在JEE Web
Tier上,理论上只要支持Servlet
2.3或以上版本规范的Web容器,都可以作为Apache门户项目的基础平台,但Jetspeed官方其实仅仅声明Tomcat是其唯一支持的Web容
器。另一块必要的依赖,是构建在O/R mapping项目Apache
OJB之上的数据仓库,用于存放Portal系统信息和用户个性化配置(Profile)。
Portals Bridges
项目其本质
就是由一组类库构成的轻量级框架,通过该桥接器框架可以在门户上支持众多流行的Web框架,如上图括号中所列举。用户通过它可以很容易的将已有的基于这些
流行Web框架的Web应用程序,通过少量的修改和配置,作为Portlet应用程序发布单元发布到Portal上。这个项目不但在Jetspeed上取
得的成功,还被众多开源的,甚至商用的门户实现所使用,如JBoss Portal
,GridSphere Portal
,Stringbeans Portal
,Vignette Application Portal
,Apache Cocoon Portal
和Jetspeed Portal
。
Jetspeed
项目是整个Apache Portal项目组的核心,它是一个功能完备的,易于扩展的企业级Portal实现,将在下面的文章中着重介绍它。
Pluto
是Jetspeed默认的本地
Portlet
Container实现,它是一个完全符合JSR-168规范的Portlet容器实现,其前身为IBM捐赠的源代码,因此我们至今还能够在
WebSphere Portal
5.1.1中看到它的身影。这里要注意本地的意思是指运行在该Portlet容器里的Portlet应用程序在物理上与Portal在同一个JVM进程
中。
WSRP-4j
是WSRP规范的JAVA实现,目前该项
目还处在孵育状态,尚未吸引到足够多的开发者的兴趣。其实,我个人认为这是一个很有前途的技术发展方向,它可以提供类似Html
IFrame这样速成的内容抓取能力。Jetspeed已经为WSRP-4j预留了远程Portlet Container的配置选项。
Graffito
是用于构建内容管理应用程序的框架,从它自身的架构设计
上
来看应该是一个独立平台,但事实上该项目复用了大量Jetspeed的模块,并且其表现层为发布到Jetspeed上的几个Portlet应用程序,因
此,我在上面的架构图中,将它放在了Jetspeed之上。该项目目前也处在孵育状态下,由于其该项目目前不太活跃,那几个Portlet应用程序都有些
小问题。
企业级的门户实现--Jetspeed
产品特性
标准
- 完整兼容Java Portlet API标准1.0(JSR-168)
- 通过JSR-168规范兼容性测试
- 基于JAAS标准的认证和授权服务(默认支持数据库的实现)
- 基于LDAP的用户认证
体系架构
- 基于Spring Framework的组件架构
- 灵活可配置的请求通道(通过Spring Bean XML配置)
- Portlet应用发布单元热部署
- Jetspeed AJAX XML API(基于著名的开源AJAX Framework - DOJO
)
- 扩展的Portlet页面结构语言(支持持久化到文件或数据库)
门户核心特性
- 声明风格的安全约束
- 基于角色的Portlet安全方面的API
- 门户内容管理和导航,包括页面、菜单、文件夹和超链接
- 单线程或多线程的内容聚合引擎(通过Spring Bean可以轻易切换)
- 高度可扩展的Jetspeed 单点登陆服务框架
- 基于权限和规则的门户页面和资源定位配置
- 支持所有主流的数据库,包括:Derby、MySQL、MS SQL、Postgres、Oracle、DB2、 Hypersonic
- 不依赖客户端类型的capability engine (html, xhtml, wml,vml)
- 多语言支持(12国语言,包括简体中文和繁体中文),而且完全可扩展
- 完整的性能统计日志引擎
- 利用著名开源搜索引擎Lucene提供对所有门户资源的全文本检索和元数据搜索服务
- 用户注册服务和忘记密码的邮件通知服务
- 丰富的登陆密码配置策略
门户管理
- 用户,角色,用户组,密码和Profile管理
- JSR 168协议规范定义的用户属性编辑器
- 门户页面管理
- 单点登陆服务管理
- Portlet应用程序管理
- Profiler管理
- 门户性能统计报告
对Web框架的支持和例子Portlets
- 通过Bridges项目支持几乎所有的主流Web Framework与Jetspeed门户的整合,包括:JSF(Sun的标准JSF实现和Apache MyFaces)、Apache Struts、PHP、Perl、Velocity
- 例子Portlet包括:RSS、IFrame(通过Jetspeed SSO API还可以支持SSO效果)、日历、书签。
- 支持Spring MVC
用户个性化
- 门户页面管理
- 页面用户定制(包括增删查改门户页面,页面的风格,Portlet框体风格,Portlet的位置,Portlet的布局等等)
- 支持两种门户定制风格,包括传统的基于页面刷新的风格和基于AJAX技术的风格
门户设计
- 支持Portlet和Portal页面皮肤的打包发布
- 基于CSS技术的可配置布局
- 支持Velocity模版引擎
门户开发工具
- 支持Maven 1.x和Maven2.0.x,部分功能支持Ant脚本
- 支持通过Maven插件生成自定义门户基础框架
- 热部署Portlet应用发布单元和门户资源
- 支持通过API调用的方式部署Portlet应用发布单元
- 支持Eclipse3.2.x开发环境
应用服务器
- Apache Tomcat 5.0.x
- Apache Tomcat 5.5.x
- IBM WebSphere Application Server 5.1/6.0
- JBoss
- Geronimo 1.0(非官方支持,详见:JS2-444
)
架构体系
本节将从Jetspeed和Spring的关系,运行时架构以及Jetspeed service架构这三方面详细介绍Jetspeed的架构体系。
Jetspeed和Spring
Jetspeed架构体系最大特点,也是其高度可订制的根基就是,它选用著名开源POJO框架Spring作为其底层实现。在项目之
初,Jetspeed的开发者们也面临着Spring和PicoContainer的抉择,但事实证明当初的选择是正确的,因为随着Spring不断成长
完善,Jetspeed的组件架构也跟着收益良多。从另一个角度来看,Jetspeed也可以作为利用Spring构建自己产品架构的经典范例,值得我们
考察和学习。
下图简单描述了目前Jetspeed对Spring的依赖关系:
图二 Jetspeed使用到的Spring组件
Beans BeanFactory and the ApplicationContext
Jetspeed主要使用了Spring最核心的IoC引擎BeanFactory和ApplicationContext,管理所有
Jetspeed
Components的生命周期和依赖关系,所有这些组件的Spring声明全部定义在名为assembly的文件夹中的XML文件里。如果第三方开发者
认为默认的Jetspeed组件不足以满足要求,只要按照自己需求编写Jetspeed
Component的Interface的实现类,然后修改Spring Bean XML定义,就可以轻易替换掉默认的实现。例如:
Jetspeed SearchEngine Component Definition
<beans default-lazy-init="false" default-dependency-check="none"
default-autowire="no">
<!--
SEARCH COMPONENT
-->
<bean id="org.apache.jetspeed.search.SearchEngine"
class="org.apache.jetspeed.search.lucene.SearchEngineImpl" abstract="false"
singleton="true" lazy-init="default" autowire="default"
dependency-check="default">
<constructor-arg index="0">
<value>${applicationRoot}/WEB-INF/search_index</value>
</constructor-arg>
<constructor-arg index="1">
<null />
</constructor-arg>
<constructor-arg type="boolean">
<value>true</value>
</constructor-arg>
<constructor-arg>
<ref bean="org.apache.jetspeed.search.HandlerFactory" />
</constructor-arg>
</bean>
</beans>
|
Jetspeed在实现过程中遵循着面向接口编程的最佳实践,上图中的Bean
id为org.apache.jetspeed.search.SearchEngine,事实上这是一个定义在核心jetspeed-api组件中的接
口,org.apache.jetspeed.search.lucene.SearchEngineImpl为该接口的实现类,这个类定义在
components/search组件中,后面的内容就是SearchEngineImpl的构造函数的输入参数,注意最后一个参数
org.apache.jetspeed.search.HandlerFactory也是一个Java
Interface的接口。Spring在实例化SearchEngine的时候,会首先分析它的构造函数参数是否已经全部满足条件(实例
化),Spring会根据搜索bean
id为org.apache.jetspeed.search.HandlerFactory的bean,如果已经实例化就直接注入到
SearchEngineImpl的构造函数调用里;如果没有就实例化这个bean之后,再注入。
Apache OJB O/R Mappers
由于Spring对Apache OJB提供良好的支持,因此Jetspeed中与数据库相关的功能基本上都用过Spring的PersistenceBrokerDaoSupport
实
现。这些组件包括:Capablity、DatabasePageManager、PipeLine、Preferences、Profiler、
Registry、Security、SSO等。O/R
Mapping的信息定义在上面这些组件jar包中的JETSPEED-INF/ojb/%component
name%_repository.xml文件中,其中%component name%需要用组建名称替代。
Declarative transaction management
在Jetspeed中,你找不到一行有关于数据库事务的代码,这是因为它采用了Spring的declarative transaction机制,下面一段XML定义了SSOProvider的事物管理:
Declarative Transaction
<beans default-lazy-init="false" default-dependency-check="none"
default-autowire="no">
<!--
SSO Implementation
-->
<bean id="PersistenceBrokerSSOProvider"
class="org.apache.jetspeed.sso.impl.PersistenceBrokerSSOProvider"
init-method="init" abstract="false" singleton="true" lazy-init="default"
autowire="default" dependency-check="default">
<constructor-arg index="0">
<value>JETSPEED-INF/ojb/sso_repository.xml</value>
</constructor-arg>
</bean>
<bean id="org.apache.jetspeed.sso.SSOProvider" parent="baseTransactionProxy"
name="ssoProvider" abstract="false" singleton="true" lazy-init="default"
autowire="default" dependency-check="default">
<property name="proxyInterfaces">
<value>org.apache.jetspeed.sso.SSOProvider</value>
</property>
<property name="target">
<ref bean="PersistenceBrokerSSOProvider" />
</property>
<property name="transactionAttributes">
<props>
<prop key="addSite*">PROPAGATION_REQUIRED</prop>
<prop key="updateSite*">PROPAGATION_REQUIRED</prop>
<prop key="removeSite">PROPAGATION_REQUIRED</prop>
<prop key="addCredentialsForSite">PROPAGATION_REQUIRED</prop>
<prop key="updateCredentialsForSite">PROPAGATION_REQUIRED</prop>
<prop key="removeCredentialsForSite">PROPAGATION_REQUIRED</prop>
<prop key="setRealmForSite">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS</prop>
</props>
</property>
</bean>
</beans>
|
由上图可知,通过Spring 的Declarative
Transaction机制,Jetspeed很轻易实现了细颗粒度的事物管理,用户可以很容易配置需要管理事务的方法,
如"addSite*"、"updateSite*"和"removeSite"等等,其中"*"为通配符,详细信息见此处
。
Spring MVC
由于Jetspeed对Spring的天生依赖,很自然Jetspeed也支持基于Spring MVC framework,详见Jetspeed自带的例子Portlet应用程序。
Jetspeed 组件架构启动过程
看了前面的介绍,你一定想知道Jetspeed是如何将基于Spring的组件架构和标准JEE Web Application架构融合在一起,本节将通过描述Jetspeed Web Application的启动过程来了解融合的细节。首先请看下图:
图五 Jetspeed Portal启动流程图
请点击这里查看Jetspeed Portal启动流程图的大图
由
上图可知,Jetspeed Portal从JEE角度来看其实就是一个标准的Web应用程序,只不过在Servlet架构上引入了Component
Manager的概念,然后用Spring实现了ComponentManager接口。因此如果你不满意Spring
:,更换它也是有可能的。当Servlet被容器停止时,也会同时关闭SpringComponentManager。Servlet启动完毕后,所有通
过Spring Bean XML定义POJO都被实例化了,除了那些指定了lazy init属性为true的Bean。
Runtime架构
JetspeedServlet
Jetspeed的运行时大环境是符合Servlet 2.3或以上规范的JEE Web容器,因此大家可以通过观察其web.xml了解或扩展其功能。下面是Jetspeed.war的web.xml:
<web-app>
<display-name>Jetspeed-2 Enterprise Portal</display-name>
<!--
Log4JConfigurator context-listener parameters
-->
<context-param>
<param-name>log4j.config.file</param-name>
<param-value>/WEB-INF/conf/Log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4j.config.webApplicationRoot.key</param-name>
<param-value>applicationRoot</param-value>
</context-param>
<filter>
<filter-name>AJAXFilter</filter-name>
<filter-class>org.apache.jetspeed.ajax.AJAXFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>AJAXFilter</filter-name>
<url-pattern>*.ajax</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.apache.jetspeed.webapp.logging.
Log4JConfigurator</listener-class>
</listener>
<listener>
<listener-class>org.apache.jetspeed.engine.JetspeedServlet
</listener-class>
</listener>
<servlet>
<servlet-name>jetspeed</servlet-name>
<servlet-class>org.apache.jetspeed.engine.JetspeedServlet
</servlet-class>
<init-param>
<param-name>properties</param-name>
<param-value>/WEB-INF/conf/jetspeed.properties</param-value>
</init-param>
<init-param>
<param-name>applicationRoot</param-name>
<param-value>webContext</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
- <!--
Define Velocity template compiler
-->
<servlet>
<servlet-name>velocity</servlet-name>
<servlet-class>org.apache.jetspeed.velocity.
JetspeedVelocityViewServlet</servlet-class>
<init-param>
<param-name>org.apache.velocity.toolbox</param-name>
<param-value>/WEB-INF/toolbox.xml</param-value>
</init-param>
<init-param>
<param-name>org.apache.velocity.properties</param-name>
<param-value>/WEB-INF/velocity.properties</param-value>
</init-param>
<init-param>
<param-name>org.apache.jetspeed.cache.size</param-name>
<param-value>50</param-value>
</init-param>
<init-param>
<param-name>org.apache.jetspeed.cache.validation.interval
</param-name>
<param-value>10000</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet>
<servlet-name>LoginProxyServlet</servlet-name>
<servlet-class>org.apache.jetspeed.login.LoginProxyServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>org.apache.jetspeed.login.LoginServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginErrorServlet</servlet-name>
<servlet-class>org.apache.jetspeed.login.LoginErrorServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginRedirectorServlet</servlet-name>
<servlet-class>org.apache.jetspeed.login.LoginRedirectorServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>org.apache.jetspeed.login.LogoutServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>ManagerServlet</servlet-name>
<servlet-class>org.apache.jetspeed.manager.ManagerServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jetspeed</servlet-name>
<url-pattern>/portal/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jetspeed</servlet-name>
<url-pattern>/portlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jetspeed</servlet-name>
<url-pattern>/jetspeed/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jetspeed</servlet-name>
<url-pattern>/fileserver/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jetspeed</servlet-name>
<url-pattern>/ajaxapi/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jetspeed</servlet-name>
<url-pattern>/desktop/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jetspeed</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
- <!--
Map *.vm files to Velocity
-->
<servlet-mapping>
<servlet-name>velocity</servlet-name>
<url-pattern>*.vm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginProxyServlet</servlet-name>
<url-pattern>/login/proxy</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login/login</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginErrorServlet</servlet-name>
<url-pattern>/login/error</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginRedirectorServlet</servlet-name>
<url-pattern>/login/redirector</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/login/logout</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ManagerServlet</servlet-name>
<url-pattern>/manager/*</url-pattern>
</servlet-mapping>
<!--
The Usual Welcome File List
-->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--
JNDI Db resource
-->
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/jetspeed</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!--
Protect LogInRedirectory.jsp. This will require a login when called
-->
<security-constraint>
<web-resource-collection>
<web-resource-name>Login</web-resource-name>
<url-pattern>/login/redirector</url-pattern>
</web-resource-collection>
<auth-constraint>
<!--
the required portal user role name defined in:
-->
<!--
/WEB-INF/assembly/security-atn.xml
-->
<role-name>portal-user</role-name>
</auth-constraint>
</security-constraint>
<!--
securing the ManagerServlet
-->
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/manager/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<!--
Login configuration uses form-based authentication
-->
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Jetspeed</realm-name>
<form-login-config>
<form-login-page>/login/login</form-login-page>
<form-error-page>/login/error</form-error-page>
</form-login-config>
</login-config>
</web-app>
|
由于信息太多,这里只能选取重要的来解释。首先,请注意名为
jetspeed的servlet,这就是前面一个小节里提到的入口servlet,它同时也是Portal
runtime的入口,它被映射到几乎所有的URL Pattern。当来自客户端的Http请求满足这些Pattern时,jetspeed
servlet将会触发如下图所示的处理流程:
图六 Jetspeed runtime execution process
请点击这里查看Jetspeed runtime execution process的大图
JetspeedServlet
首先会通过RequestContextComponent为当前Http
Request创建RequestContext实例,然后在这个context下调用engine的service方法。然后就会进入Pipeline
的处理过程。
Pipeline
Jetspeed Pipeline实际上就是设计模式中常见的Chain of Responsibility
模
式的具体实现,其设计概念类似Servlet
Filter,一个封装了HttpServletRequest和HttpServletResponse
Object的Context在Pipeline中传递,每个valve都根据自己的需要从HttpServletRequest
对象中获取信息并将处理的结果写入context或HttpServletResponse对象,以传递给后面的valve使用。
这些Valve的定义和排序都是通过Spring Bean来配置的,定义文件为pipelines.xml,下面为该文件片断截取:
<bean id="securityValve"
class="org.apache.jetspeed.security.impl.SecurityValveImpl"
init-method="initialize" abstract="false" singleton="true" lazy-init="default"
autowire="default" dependency-check="default">
<constructor-arg>
<ref bean="org.apache.jetspeed.profiler.Profiler" />
</constructor-arg>
<constructor-arg>
<ref bean="org.apache.jetspeed.security.UserManager" />
</constructor-arg>
<constructor-arg>
<ref bean="PortalStatistics" />
</constructor-arg>
</bean>
|
<bean id="jetspeed-pipeline"
class="org.apache.jetspeed.pipeline.JetspeedPipeline" init-method="initialize"
abstract="false" singleton="true" lazy-init="default" autowire="default"
dependency-check="default">
<constructor-arg>
<value>JetspeedPipeline</value>
</constructor-arg>
<constructor-arg>
<list>
<ref bean="capabilityValve" />
<ref bean="portalURLValve" />
<ref bean="securityValve" />
<ref bean="localizationValve" />
<ref bean="passwordCredentialValve" />
<ref bean="loginValidationValve" />
<ref bean="profilerValve" />
<ref bean="containerValve" />
<ref bean="actionValve" />
<ref bean="DecorationValve" />
<ref bean="aggregatorValve" />
<ref bean="cleanUpValve" />
</list>
</constructor-arg>
</bean>
|
<bean id="pipeline-map" class="java.util.HashMap" abstract="false"
singleton="true" lazy-init="default" autowire="default"
dependency-check="default">
<constructor-arg>
<map>
<entry key="/portlet">
<value>portlet-pipeline</value>
</entry>
<entry key="/portal">
<value>jetspeed-pipeline</value>
</entry>
<entry key="/ajaxapi">
<value>ajax-pipeline</value>
</entry>
<entry key="/login">
<value>jetspeed-pipeline</value>
</entry>
<entry key="/fileserver">
<value>fileserver-pipeline</value>
</entry>
<entry key="/desktop">
<value>desktop-pipeline</value>
</entry>
<entry key="/action">
<value>desktop-action-pipeline</value>
</entry>
</map>
</constructor-arg>
</bean>
|
上面表格第一行定义了Security
Valve,第二行定义了名为JetspeedPipeline的一个Pipeline,第三行定义了这些Pipeline对应的URL
Pattern。门户开发者可以很容易的定义自己特有的Pipeline
Valve(只需要实现org.apache.jetspeed.pipeline.valve.Valve接口,并在这个xml文件中定义它),或者改
变现有Pipeline中valve执行顺序,甚至创建新的Pipeline,并把它映射到某个URL Pattern上。但这里需要注意的是新URL
Pattern映射不能跟现有的重复,这是因为映射是通过Map数据结构实现。让我们再把注意力返回到图六,接下来的Container处理由一个竖线分
隔,这是由于在Pipeline的aggregatorValve发生了cross context
dispatch。需要注意的是Valve的实现类并不是Thread
Safe的,开发者必须自己管理共享变量,最好就是不要定义对象成员变量,全部使用方法内部变量。
Jetspeed的设计者之所以要自己实现这种链式模式而不直接使用Filter的可能原因有二:其一,Filter是标准Servlet规范定义
的接口,使用上肯定受规范限制,为了获取更大的控制权和灵活度需要自己的Pipeline。其二, Application
Server,由于每种应用服务器可能对Filter的实现和配置方法上有异,为了实现一个Jetspeed
Portal能够在各种应用服务器上发布并运行,因而必须自己实现类似Filter的功能。
Container
讲到这里,我们必须首先理清楚Portal和Portlet
Container之间的关系。Portal并不等价于Portlet
Container,一个企业级的门户实现,可以包含或者说支持多种Portlet Container同时运行,例如IBM WebSphere
Portal就既包含兼容JSR-168规范的Portlet Container又包含了支持一些IBM特有功能属性的Portlet
Container;BEA WebLogic也是采用相同策略,既有其旧有的基于Struts技术的Portlet
Container,又支持JSR-168标准。随着JSR标准规范进一步深化完善,如JSR-286规范定稿,也许这些大的Portal厂商会逐渐放弃
其旧的架构,完全拥抱标准。
对于Jetspeed而言,它同样关注的是门户本身的实现,而不是Portlet
Container的实现,但由于Jetspeed-2完全抛弃Jetspeed-1的架构,而决定彻底拥抱标准,因此Jetspeed只有一个标准的
Portlet Container实现,这就是Pluto项目。
Pluto的设计目标,其实既是一个完整的、自包含的轻量级门户,又是一个易于内置的Portlet
Container。它不需要Jetspeed也能够单独工作,例如Apache唯一的应用服务器项目Geronimo就内置Pluto
Portlet Container,作为它的Console实现平台。然而,这与Jetspeed的定位起了冲突。在2005年底的Apache
Con上,门户项目组开发者齐聚一堂,就该问题作了深入的探讨,也许这两个项目在将来会更加关注于自身的技术领域。
Jetspeed所内置的Pluto版本为稳定的1.0.1版,它所提供的内置集成方式不如目前尚未正式发布的Pluto1.1版本丰富,因此
Jetspeed采用了Servlet 规范中的Cross Context
Dispatch机制,将之集成了起来,这就是为什么Runtime架构图上,两者要用竖线分隔开来,因为他们其实是两个完全不同的Web应用,有着不一
样的Context设置,之间通过Cross Context
Dispatch机制联系起来的。因此当门户开发者需要在其它应用服务器上部署Jetspeed门户时,必须注意开启Cross Context
Dispatch机制,也同时要注意这种使用方式所带来的安全问题。例如Tomcat是通过设置文件%TOMCAT_ROOT%/conf
/Catalina/localhost/jetspeed.xml(注意粉红色高亮字体):
<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="" password=""
driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
url="jdbc:derby:/tmp/j2" maxActive="100" maxIdle="30" maxWait="10000" />
<Valve className="org.apache.catalina.authenticator.FormAuthenticator"
characterEncoding="UTF-8" />
</Context>
|
在Pluto和Jetspeed相互配合下,通过JetspeedContainerServlet,最终执行控制权会交给Portlet的实现
类。JetspeedContainerServlet就定义在Portlet应用程序所属的Web应用单位中,也就是说所有在Jetspeed中运行的
Portlet
Web应用都必须在Web.xml中包含JetspeedContainerServlet的定义。在Tomcat中,这是通过deploy-tool组
件完成的,在其它应用服务器平台,很可能就要靠应用发布者手动添加了,需添加的信息包含:
<servlet>
<servlet-name>JetspeedContainer</servlet-name>
<display-name>Jetspeed Container</display-name>
<description>MVC Servlet for Jetspeed Portlet
Applications</description>
<servlet-class>org.apache.jetspeed.container.
JetspeedContainerServlet</servlet-class>
<init-param>
<param-name>contextName</param-name>
<param-value>rss</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JetspeedContainer</servlet-name>
<url-pattern>/container/*</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>http://java.sun.com/portlet</taglib-uri>
<taglib-location>/WEB-INF/tld/portlet.tld</taglib-location>
</taglib>
|
Jetspeed Portlet Extension Service
前面介绍了实现架构和运行时架构,接下
来我们一起来看看Jetspeed为Portlet应用提供的Jetspeed
Service架构。如果了解JSR-168规范的开发者就会知道,这个规范是基于Servlet
2.3规范基础上的一个简单扩展,因此并没有对Portlet开发提供任何特别的支持。因而每家Portal厂商都提供了自己的扩展。
Jetspeed
提供的扩展方式跟很多厂商对Servlet规范的扩展一样,定义了一个名为jetspeed-portlet.xml的文件,作为标准的
portlet.xml的扩展。只要你在打包发布portlet应用时将这个文件与portlet.xml放在一起,Jetspeed的发布程序就会自动
读取这个文件,并根据其内容执行一系列的操作。它们的关系如同BEA
Weblogic应用服务器里面的weblogic.xml与web.xml;JBoss应用服务器里面的jboss-web.xml与web.xml。
下面我们来看看这个文件的格式:
<portlet-app id="j2-admin" version="1.0"
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:js="http://portals.apache.org/jetspeed"
xmlns:dc="http://www.purl.org/dc">
<js:services>
<js:service name="ApplicationServerManager" />
<js:service name="DeploymentManager" />
<js:service name="EntityAccessor" />
<js:service name="GroupManager" />
<js:service name="PageManager" />
<js:service name="PermissionManager" />
<js:service name="PortalAdministration" />
<js:service name="PortletFactory" />
<js:service name="PortalAdministration" />
<js:service name="PortletRegistryComponent" />
<js:service name="PortalStatistics" />
<js:service name="Profiler" />
<js:service name="RoleManager" />
<js:service name="SearchComponent" />
<js:service name="SSO" />
<js:service name="UserManager" />
<js:service name="HeaderResource" />
</js:services>
</portlet-app>
|
跟据XML
Element的名字,可以理解就是提供给j2-admin这个Portlet应用程序使用的一些Services。那么这些Services是怎么定义
的呢?以UserManager这个服务为例,首先回到前面提到过的assemble目录下,找到jetspeed-services.xml和
security-managers.xml,下面分别是它们的内容节选:
jetspeed-services.xml
<beans default-lazy-init="false" default-dependency-check="none" default-autowire="no">
<!--
Portlet Services
-->
<bean id="PortalServices"
class="org.apache.jetspeed.services.JetspeedPortletServices"
abstract="false" singleton="true" lazy-init="default" autowire="default"
dependency-check="default">
<constructor-arg>
<map>
<entry key="SearchComponent">
<ref bean="org.apache.jetspeed.search.SearchEngine" />
</entry>
<entry key="UserManager">
<ref bean="org.apache.jetspeed.security.UserManager" />
</entry>
<entry key="PageManager">
<ref bean="org.apache.jetspeed.page.PageManager" />
</entry>
</map>
</constructor-arg>
</bean>
</beans>
|
security-managers.xml
<beans default-lazy-init="false" default-dependency-check="none" default-autowire="no">
<bean id="org.apache.jetspeed.security.UserManager"
class="org.apache.jetspeed.security.impl.UserManagerImpl" abstract="false"
singleton="true" lazy-init="default" autowire="default"
dependency-check="default">
<constructor-arg>
<ref bean="org.apache.jetspeed.security.SecurityProvider" />
</constructor-arg>
</bean>
</beans>
|
由上面的两个文件,我们可以清楚地看出UserManager是
定义security-managers.xml文件中的,但是为了能够在portlet服务中引用它,还必须在jetspeed-
services.xml中再次引用它的bean
name,org.apache.jetspeed.services.JetspeedPortletServices封装了一个Map数据结
构,Map中存放的就是服务名称和该服务POJO对象引用,这一切便利都是由Spring带来的。
下面是在Portlet的代码中使用该服务的例子:
protected UserManager userManager = null;
public void init(PortletConfig config) throws PortletException {
super.init(config);
userManager = (UserManager)
getPortletContext().getAttribute(CommonPortletServices.
CPS_USER_MANAGER_COMPONENT);
if (null == userManager) {
throw new PortletException("Failed to find the User Manager
on portlet initialization");
}
}
|
Jetspeed鼓励Portlet开发者在开发过程中,将公共
的Service用Spring
Bean的方式封装起来,然后添加到Jetspeed-services中,这样就可以在Portlet代码中轻松复用这些公共Service了,并且还
可以利用Spring来管理这些Service的生命周期。事实上,Jetspeed自带管理界面Portlet应用程序就大量采用了这种技术。
还有一个需要注意的问题是,用户自定义的Service必须放到Tomcat的shared\lib下面去,以保证JAVA Classloader能够找到它。
Jetspeed核心组件简介
介绍了那么多Jetspeed架构方面的信息,下面我们一起来快速浏览一下Jetspeed Portal的核心组件。
Jetspeed-Api
路径:components/jetspeed-api
定义几乎所有的jetspeed-api interfaces,一般的开发者都使用这个组件中定义的接口进行二次开发。
Component Manager
路径:components/cm
Jetspeed组件管理器,通过接口org.apache.jetspeed.components.ComponentManager屏蔽了Spring的实现细节。可以通过实现该接口替换Spring。
Deploy-Tool
路径:components/deploy-tool
当Web Container为Tomcat时,通过该组件,读取已打包好的portlet应用程序中的portlet.xml和web.xml,检查是否包含JetspeedContainerServlet的定义,如果没有则修改web.xml加入这部分信息。
Id-Generator
路径:components/id-generator
用于生成全局唯一的portlet实例id。
Locator
路径:components/locator
提供定位门户资源的服务,资源包括:模板,Profiler等。
Page-Manager
路径:components/page-manager
对著名的门户结构描述文件-PSML(Portal Structure Markup Language),提供了Java对象模型映射,并且支持文本风格的PSML和数据库风格的PSML,以及PSML管理器。
Portal
路径:components/portal
实现绝大部分的jetspeed-api组件中定义的interface,是最核心的组件。
Preferences
路径:components/prefs
实现了Portlet属性偏好功能,提供将这些属性持久化到数据库的服务。
RDBMS
路径:components/rdbms
Jetspeed中所有与Apache OJB O/R Mapping框架有关的组建的基础组件。
Search
路径:components/search
提供整个门户资源的全文本搜索服务,具体实现依赖于Apache Lucene。
Security
路径:components/security
提供基于标准JAAS的认证服务,支持数据库和LDAP作为认证信息仓库。基于角色的授权服务,默认支持数据库作为权限仓库。
Single Sign-on
路径:components/sso
提供一个可扩展的单点登陆服务接口和一个简单的基于JAAS Subject的实现,该组件主要提供Portal门户与后台应用之间的单点登陆功能。
Statistics
路径:components/statistics
提供一个简单的访问请求统计服务的实现,支持将统计信息持久化到数据库。在Jetspeed-2管理界面中,还提供了专门的Portlet浏览这些统计信息。
总结
本文带读者浏览了Apache Portal项目组的所有成员,并着重介绍了Apache Jetspeed-2
Portal。希望能够使不了解门户技术的朋友对它有一个初步的认识,找到自己感兴趣的方向,继续深入研究;同时对那些试图在项目中使用开源软件的开发
者,提供一些可以借鉴的信息。纵观目前开源软件中的门户实现,还没有哪一个社区能够提供像Apache
Portal项目组这样完整的解决方案同时,还拥有如此友好的许可策略。只要去深入了解,开源软件往往能够给人们带来意外的惊喜。
|
相关推荐
在JetSpeed中开发portlet项目是一项涉及Java Web技术的重要工作,主要基于JSR168(portlet规范1.0)标准。JetSpeed是一个开源的企业门户服务器,它支持portlet的开发和集成,提供了一个灵活且可扩展的框架来构建企业...
**Jetspeed2 门户技术开发文档** Apache Jetspeed2 是一个开源的、可扩展的、基于标准的门户框架,用于构建企业级的门户应用。它提供了丰富的功能,包括个性化、内容管理、工作流程以及安全机制,使开发者能够快速...
在Jetspeed中,这些文件可能用于设置初始用户、组和其他对象,或者进行自定义的目录结构设置。initData.ldif 可能包含了默认的系统用户和角色,而 custom.ldif 可能是为了满足特定项目需求而创建的额外配置。 理解...
Jetspeed是Apache组织开发的一个...Apache开源组织的企业门户项目,现有两个版本:jetspeed1与jetspeed2。由于jetspeed1在设计上的“缺陷”,现在已经升级到jetspeed2。目前大陆还没有成功使用jetspeed2开发的案例。
本文档旨在详细介绍如何在个人PC上安装配置Jetspeed,并指导用户创建一个简单的Portlet。 #### 二、系统需求 - **硬件需求**: - 个人PC - 操作系统:Windows XP - **软件需求**: - JDK版本:1.5.0.12 - ...
JetSpeed是Apache软件基金会的一个开源项目,用于构建Web门户和无线门户。它采用Java编写,提供了一套Portal API,使得开发portlet变得简单快捷。Portlet是门户中负责显示内容的小型Java应用程序。 ##### JetSpeed ...
文档中会详细介绍Jetspeed2的架构,包括Portlet容器、内容管理系统、权限管理、用户会话管理等核心组件。此外,还会涵盖portlet开发,如MVCportlet的实现,以及如何利用Jetspeed的API和服务进行集成。开发者可以通过...
本文将详细介绍基于开源项目Jetspeed的Portlet开发过程,包括Jetspeed的基本架构、Portlet的开发流程以及如何优化Portlet的外观设计。 #### 二、Jetspeed概述 ##### 2.1 Jetspeed体系结构 Jetspeed是一个基于Java...
在给定的文件名称列表中,"nps2D2C.tmp.pdf"、"nps6E20.tmp.pdf"可能是关于Jetspeed 2的教程文档或技术资料,而"门户总结.ppt"很可能是一个关于Jetspeed 2门户应用的总结报告,包含了项目实施的实践经验、遇到的问题...
1. Jetspeed For Developers: Jetspeed 开发指南,提供了关于 Jetspeed 的详细介绍和开发指南,包括如何创建 portlet 应用程序、构建和创建 Jetspeed 门户的扩展部分。 2. Portlets and Apache Portals Book: ...
Jetspeed 是一个开源的企业门户平台,它允许组织构建和管理个性化的工作环境,提供了一系列的portlet 和集成服务。这里我们主要探讨两个版本:Jetspeed 1 和 Jetspeed 2。 **Jetspeed 1** Jetspeed 1 是早期版本,...
标题“Jetspeed2.0中的PSML介绍”向我们揭示了文档的主题,即PSML(Portal Structure Markup Language)在Apache Jetspeed 2.0中的应用。Apache Jetspeed是一个开源的企业信息门户解决方案,它提供了一个框架和一...
Jetspeed是一个开源的portlet容器和企业信息门户平台,它允许集成多种应用和服务,提供个性化和协作功能。 首先,构建和部署Jetspeed 2.2需要以下前提条件: 1. **Java Development Kit 1.5**:这是编译和运行...
Jetspeed是一款开源的企业门户平台,它提供了一个统一的入口,让用户可以访问到各种企业应用和服务。这个"jetspeed中文文档"包含的详细信息是对于中国用户来说非常宝贵的资源,因为它们以中文呈现,使得理解与学习...
Jetspeed2 是一个开源的企业门户框架,它提供了丰富的功能,包括安全管理、内容管理、个性化以及portlet集成。本文档是Jetspeed2 Deployer Guide的中文翻译,旨在帮助初学者理解如何部署和配置Jetspeed2的安全机制。...
Jetspeed2是一款开源的企业级portlet容器和门户框架,它基于Java技术栈,主要用于构建可定制、可扩展的企业级门户系统。这个资料包包含了关于Jetspeed2的详细信息,对于理解并使用Jetspeed2进行门户开发具有很高的...
JetSpeed是开源的企业门户平台,它基于Java技术栈,提供了构建和管理企业级Web门户的能力。这个特定的版本,jetSpeed 2.2.2,是该软件的最新更新,适用于Java开发环境,特别是那些使用JDK 1.5或更高版本的开发者。...
jetspeed2是一款基于Java的企业门户框架,它提供了丰富的功能来构建复杂的Web应用程序。本文档旨在帮助开发者理解jetspeed2样式的开发流程与细节,特别是关于如何创建和自定义样式。 #### 二、基础知识要求 在开始...