比较 JSR 168 Java Portlet 规范与 IBM Portlet API.docx
《比较 JSR 168 Java Portlet 规范与 IBM Portlet API.docx》由会员分享,可在线阅读,更多相关《比较 JSR 168 Java Portlet 规范与 IBM Portlet API.docx(20页珍藏版)》请在冰豆网上搜索。
比较JSR168JavaPortlet规范与IBMPortletAPI
比较JSR168JavaPortlet规范与IBMPortletAPI
StefanHepper,架构师,WebspherePortalServerDevelopment,EMC
StefanHepper是位于德国的IBM Boeblingen实验室WebSpherePortal组的一名软件架构师。
它负责Java标准并且是JSR168的两位规范领导者之一。
他在国际会议上做过演说,出版过论文,申请过专利并且是PervasingComputing(Addison-Wesley2001)一书的合著者。
简介:
本文详细说明了JavaTMJavaTMStandardizationRequestfortheJavaPortlet规范(以下称为JSR168)和IBMWebSpherePortalVersion5.0支持的IBMPortletAPI之间的相似点和不同点。
文中解释了JSR168的一些基本概念和特征,并将它们与IBMPortletAPI进行了比较,并且为两个Portlet编程接口中的每一个都提供了一个示例Portlet。
本文是为那些对Java编程、Servlet或Portlet编程有良好理解并具备portal方面的基本知识的Portlet开发人员和Portal架构师准备的。
平均分(共3个评分)
引言
随着越来越多的企业Portal的出现,不同的厂商已经创建了各种用于Portal组件的API(称为 Portlet)。
存在多种不兼容的接口产生了应用程序提供者、Portal消费者和Portal服务器厂商之间的问题。
JavaCommunityProcess(JCP)定义的JavaPortlet规范(JSR168)提供了Portlet和Portal之间的互操作性的标准。
它将及时解决这些问题。
本文档的目的是比较JSR168和WebSpherePortalV5.0PortletAPI,并且给出了一些示例。
重要:
为了给顾客和合作伙伴提供一个方便的移植窗口,WebSpherePortal的下一个版本仍将支持IBMPortletAPI。
JSR168简介
JavaStandardizationRequest168(JSR168)定义了一个Portlet规范,包括Portlet容器和portlet之间的合约。
JSR168是由JavaCommunityProcess(JCP)定义的。
JSR168是由IBM和Sun共同领导的,并且有一个很大的ExpectGroup以帮助创建目前可用的最终版本。
这个专家组由ApacheSoftwareFoundation、ArtTechnologyGroupInc.(ATG)、BEA、Boeing、Borland、CitrixSystems、Fujitsu、Hitachi、IBM、Novell、Oracle、SAP、SASInstitute、Sun、Sybase、Tibco和Vignette组成。
关于这个JSR的更多信息可以在http:
//jcp.org/en/jsr/detail?
id=168上找到。
重要:
在本分析中提供的信息不承担任何性质的保证之责。
本分析旨在为读者提供一个指示性的工具。
JSR168定义
这部分提供了基本的JSR168定义,目的是帮助您理解JSR168如何融入整个Portal体系结构中。
Portal和Portlet容器
portal是一个Web应用程序,它通常提供不同来源的个性化、单点登录的内容集合,并且托管不同后端系统的表示层。
Portal的主要任务是将不同的应用程序集合到一个页面,这个页面的外观是Portal用户共有的。
Portal也可以有复杂的个性化特征,这些特征能够给用户提供自定义内容。
Portal页可以有不同的Portlet集,以便为不同的用户创建内容。
图1展示了Portal的体系结构,比如一个由WebSpherePortal提供服务的Portal。
客户端请求由PortalWeb应用程序进行处理,它为当前用户检索当前页上的Portlet。
然后,PortalWeb应用程序为每个Portlet调用Portlet容器来通过ContainerInvokerAPI检索它的内容。
Portlet容器通过PortletAPI调用Portlet。
ContainerProviderServiceProviderInterface(SPI)允许portlet容器通过Portal检索信息。
图1.基本的Portal体系结构
Portlet容器运行Portlet,给它们提供所需的运行时环境,并且管理它们的生命周期。
它为Portlet首选项项提供持久性存储,这使得能够为不同的用户生成自定义输出。
Portal页和Portlet
图2展示了基本的Portal页组件。
Portal页表示一个完整的标记文档并且聚集若干Portlet窗口;也就是说,它将不同的应用程序用户界面组合到一个统一的表示中去。
Portal页使用户能够通过登录对话框向Portal验证自己的身份以便访问个性化的Portal视图。
大部分Portal页包括一些导航机制以允许用户导航到其他的Portal页。
图2:
Portal页
Portlet窗口包括:
∙标题栏,带有Portlet的标题
∙修饰,包括用于更改Portlet的窗口状态的按钮(比如最大化或最小化Portlet)和用于更改Portlet的模式的按钮(比如显示帮助或编辑预定义的Portlet设置)
∙由Portlet产生的内容(也称为一个标记段)。
图3在不同的浏览器上展示了一个Portlet窗口。
如您所见,该portlet产生的标记段并不局限于HTML,而可以是任何标记。
图3:
在HTML浏览器(顶部)和WML浏览器(底部)中显示的Portlet
Portlet生命周期
基本的portlet生命周期必须:
1.初始化,使用初始化类初始化Portlet并将其放入服务中。
2.处理请求,处理不同种类的动作并呈现内容。
3.完成,使用销毁类除去Portlet。
Portlet基于用户与Portlet或Portal页的交互来接收请求。
请求处理分为两个阶段:
1.动作处理
如果用户单击Portlet上的链接,就会触发动作。
动作处理必须在页面上的任何Portlet呈现开始之前结束。
在动作阶段,Portlet可以改变Portlet的状态。
2.呈现内容
在呈现阶段,Portlet会产生要发送回客户端的标记。
呈现不应该改变任何状态。
它允许一个页面重新刷新而不需要改变Portlet 的状态。
一个页面上的所有Portlet的呈现都可以并行执行。
图4描述从客户端到Portlet的请求流,并且更详细地展示了动作和呈现阶段。
在这个示例中,PortletA接收了一个动作。
在该动作执行之后,页面(A、B、C)上的所有Portlet的呈现方法都被调用。
图4.从客户端到Portlet的请求流
Portlet模式
Portlet执行不同的任务并根据它们的当前函数来创建内容。
Portlet模式指示Portlet何时将执行函数。
Portlet模式指定Portlet应该执行哪一类任务和应该生成什么样的内容。
当调用Portlet时,Portlet容器提供当前对Portlet的请求的模式。
在处理动作请求时,Portlet可以程序化地改变它们的Portlet模式。
JSR168定义了三类Portlet模式:
1.必须支持的模式(语义同上)
Edit
显示一个或多个视图以让用户自定义个性化的Portletsettings.Help
Help
显示帮助视图。
View
显示Portlet输出。
2.可选择的客户模式
About
显示Portlet的目的、来源、版本和其他信息。
Config
显示一个或多个配置视图以让管理员配置对所有用户有效的Portlet设置。
Edit_defaults
设置可修改的首选项的缺省值,这些首选项通常可以在EDIT屏幕中进行更改。
Preview
呈现输出而不需要后端连接或特定于用户的可用数据。
Print
显示适于打印的视图。
3.特定于Portal厂商的模式
这些模式只适用于特定的厂商Portal。
窗口状态
窗口状态是分配给Portlet生成的Portal页面空间的指示器。
Portlet容器提供当前的窗口状态给Portlet,而Portlet 通过窗口状态来决定它应该呈现多少信息。
然而,在处理动作请求时,Portlet也可以程序化地改变它们的窗口状态。
JSR168定义了如下窗口状态:
Normal
Portlet与其他Portlet共享空间,在产生它的输出时应该对考虑这种状态。
Maximized
与处于正常的窗口状态相比,窗口有更真实的状态来提供它的输出。
Minimized
Portlet应该只呈现最小的输出或没有输出。
除了这些窗口状态之外,JSR168允许Portal定义自定义窗口状态。
数据模式
JSR168为Portlet定义了不同的机制以访问瞬态数据和持久性数据。
Portlet可以设置和获取下列作用域内的瞬态数据:
请求
请求有附加的数据,比如请求参数和属性,与Servlet类似。
请求可以包含一些特性,以允许进行扩展;也可以包含从Portal传送到Portlet的客户端头字段(反之亦然)。
会话
Portlet可以将数据存储在具有全局作用域的会话中,以让Web应用程序中的其他组件访问这些数据;也可以将数据存储在Portlet作用域中,这个作用域是Portlet私有的。
上下文
Portlet可以将数据存储在Web应用程序上下文中,与Servlet类似。
Portlet可以访问这些作用域内的持久性数据:
每个 Portlet
Portlet可以将配置和个人数据存储在Portlet引用中,以允许Portlet创建个性化的输出。
Portlet可以定义允许用户在编辑模式下更改那些数据(例如股票报价)以及哪些数据是只能由管理员在配置模式下进行更改的配置设置(例如股票报价服务器)。
每个用户
Portlet可以读取用户概要信息来针对用户调整它的输出(例如显示用户所在城市的天气情况)。
Portlet应用程序
所有资源、Portlet和配置描述符一起打包成一个Web应用程序档案文件(WAR)。
有两个配置描述符:
∙所有不是Portlet的Web应用程序资源必须在web.xml配置描述符中指定。
∙所有Portlet和Portlet相关的设置必须在portlet.xmldeployment描述符中指定。
回页首
比较JSR168与IBMPortletAPI
这一部分大概地比较了JSR168PortletAPI与IBMPortletAPI。
首先讲解了一些相似的概念,接着说明了两者之间的不同之处。
相似点
下列概念在JSR168和IBMPortletAPI中是非常相似的。
特征
相似点
不同点
Portlet模式
两者都支持基本的Portlet模式:
Edit、Help和View。
这种配置模式在JSR168中是可选的。
IBMPortletAPI不支持其他可选的JSR168模式(About、Edit_defaults、Preview、Print)。
窗口状态
支持如下窗口状态:
Maximized、Normal和Minimized。
Solo窗口状态只有IBMPortletAPI支持。
Portlet生命周期
生命周期是相同的:
初始化、处理请求、毁坏。
没有
请求处理
请求处理分为处理用户动作的动作阶段和产生标记的呈现阶段。
没有
URL编码
两者都支持创建指向Portlet或资源的URL。
没有
包含Servlet/JSP
Servlet和JSP可以包括在Portlet中。
没有
Portlet会话
Portlet可以存储瞬态信息,这些信息应该都在会话中的请求内。
没有
Portlet应用程序打包
两者都通过附加的部署描述符(名为portlet.xml)来将Portlet应用程序打包成WAR文件。
portlet.xml格式有所不同。
基于到期时间的缓存
Portlet可以支持基于到期时间的缓存。
API使用不同的机制来实现这一功能。
IBMPortletAPI使用轮询机制,在这种机制中,Portal查询Portlet以获取标记的有效时间,而在JSR168中,Portlet可以将到期时间附加到创建的每个标记上。
在用户之间共享缓存条目只有在IBMPortletAPI中才是可能的。
不同点
JSR168和IBMPortletAPI在以下几个方面有所不同。
特征
IBMPortletAPI
JSR168
Portlet应用程序实体
使您可以通过部署描述符将抽象的Portlet应用程序及其不同的实例定义为具体的Portlet应用程序。
这允许重用抽象的Portlet应用程序的设置,而只重写对于每个具体的Portlet应用程序惟一的部分。
该部署描述符紧跟在web.xml部署描述符之后,它定义一个应用程序及其Portlet定义。
Portlet实体
Web部署描述符中的每个Portlet配置都有一个Portlet对象实例。
根据Flyweight模式,可以有许多PortletSettings对象来参数化相同的Portlet对象(基于每个请求)。
PortletSettings中的改变会应用到这个具体的Portlet中的所有Portlet实例。
用户也可以具体Portlet的个人视图,它是通过使用自定义输出的PortletData呈现的。
PortletSettings和PortletData合并成一个名为PortletPreferences的对象。
请求/响应对象
Portlet在呈现调用中接收到的请求/响应对象与动作调用接收到的相同。
在JSR168中,有两个不同的对象。
JSR168独有的特征
这些项只适用于JSR168。
特征
描述
呈现参数
呈现参数允许Portlet存储它的导航状态。
呈现参数在随后的呈现请求中保持不变,而只是在Portlet接收到一个新的动作时才发生改变。
这启用了书签功能,并且解决了浏览器后退按钮问题。
全局HttpSession作用域
Portlets不仅可以存储具有Portlet可见性的数据,而且可以存储具有整个Web应用程序可见性的数据。
重定向
Portlet可以重定向到动作阶段中的其他Web资源。
IBMPortletAPI独有的特征
以下概念只适用于IBM?
PortletAPI。
特征
描述
事件
事件可以在?
Portlet之间发送。
附加的生命周期侦听器
除了动作和呈现之外,生命周期侦听器(比如首页)也不适用于JSR168的第一个版本。
Portlet菜单
让Portlet可以提供内容到菜单栏,以便通过Portal页使导航更加容易。
基于无效时间的缓存
让Portlet可以显式使缓存的内容无效。
回页首
示例Portlet
这一部分展示一个HelloWorldPortlet,在两个API的每一个中都有它的实现。
其主要的不同之处突出显示在第二个Portlet中。
这两个示例Portlet实现了相同的功能:
∙将JSP用于呈现输出
∙根据特定于用户的数据自定义Portlet输出
∙处理动作以允许用户改变这些动作
这个示例展示了一个个性化的HelloWorldPortlet。
它通过名称识别用户,并且允许用户进入编辑模式以设置一个新的名称。
在action方法(在IBMPortletAPI中称为actionPerformed,而在JSR168中称为processAction)中,Portlet持久化存储用户输入的新用户名。
清单1.IBMPortletAPI示例Portlet
首先看一看通过IBMPortletAPI实现的Portlet。
publicclassHelloWorldextendsAbstractPortletimplementsActionListener
{
publicvoiddoView(PortletRequestrequest,PortletResponseresponse)
throwsPortletException,IOException
{
//Gettheuser'snametodisplayfrompersistentstorage
PortletDataportletData=request.getData();
StringstringToDisplay=(String)portletData.getAttribute("userName");
if(stringToDisplay==null){
stringToDisplay=defaultString;//setdefaultstring
}
//Addthedisplaystringtotheportletrequesttomakeit
//accessiblebytheviewJSP
request.setAttribute("userName",stringToDisplay);
//GetacontextforthecurrentsessionforinvokingtheJSP
PortletContextcontext=getPortletConfig().getContext();
context.include(viewJSP,request,response);
}
publicvoiddoEdit(PortletRequestportletRequest,
PortletResponseportletResponse)
throwsPortletException,IOException
{
//CreatethecancelreturnURIfortheeditpage
PortletURIcancelURI=portletResponse.createReturnURI();
//PreservetheCancelURIintherequesttomakeit
//accessiblebytheeditJSP
portletRequest.setAttribute("cancelURI",cancelURI.toString());
//CreatethesaveURIfortheeditpage
PortletURIsaveURI=portletResponse.createReturnURI();
//Forthe"Save"buttonthereturnURImustincludethe"Save"action
//sotheActionListenerforthisportletwillbeinvoked
SimpleActionHelper.
addSimplePortletAction(getPortletConfig().getContext(),saveURI,"save");
//PreservetheSaveURIintherequesttomakeitaccessibleby
//theeditJSP
portletRequest.setAttribute("saveURI",saveURI.toString());
//Gettheuser'snametodisplayfrompersistentstorage
StringstringToDisplay=(String)
portletRequest.getData().getAttribute("userName");
if(stringToDisplay==null){
stringToDisplay=defaultString;//nonefound,setdefaultstring
}
//Addthedisplaystringtotherequesttomakeitaccessiblebythe
//editJSPasaninitalvalueoftheinputfieldontheeditform
portletRequest.setAttribute("userName",stringToDisplay);
//GetacontextforthecurrentsessionforinvokingtheJSP
PortletContextcontext=getPortletConfig().getContext();
context.include(editJSP,portletRequest,portletResponse);
}
publicvoidactionPerformed(ActionEventevent){
Stringaction=
SimpleActionHelper.getActionString(getPortletConfig().getContext(),
event);
HelloWorldhelloPortlet=(HelloWorld)event.getPortlet();
PortletLoglog=helloPortlet.getPortletLog();
//Ifthisisasaveaction,thenseeiftheus