- 浏览: 581381 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
liuhuo:
总算找到一个可用的了,非常感谢楼主!其他的都不靠谱啊
Flex与Javascript相互调用例子(附源码) -
Array_06:
你好,请问,一个今年7月拿大学毕业证,应届生,大专学历,做Ja ...
为什么程序员得到的报酬与他们的生产力不成正比 -
778856:
sam_kee 写道晕了哦,我想知道快捷键本来默认就是没有快捷 ...
利用eclipse(MyEclipse)快速生成set、get方法的方法 -
hhsc00:
你真对不起老鸟这个称号……
坑爹的360(不吐不快) -
white_crucifix:
somewhater 写道我还以为去360工作去了呢。。。。。 ...
坑爹的360(不吐不快)
【IT168 技术文档】
tapestry的URL形如/examples/app?service=page/Admin 能够保证有效运行的一个非常重要的原因是,用有状态的javabean代替无状态的servlet构建一个tapestry应用。page是有状态的,他只能在一个线程里为一个用户处理一个request,而一个servelet,没有用户的状态,可以在并发线程中为任何数量同时发生的request提供服务。使用有状态的page遇到的问题和使用数据库的连接遇到的问题非常相似。
engine
engine是每个tapestry应用的中心,它是一个负责支持和组织应用所有方面的对象,他把所有小的子系统绑在一起构成一个tapestry应用,它首先负责管理server端的状态,管理Visit对象及持久页面属性,他会被保存在session中。engine对象的service()方法,负责进来的request处理和把响应返回给客户端。 ApplicationServlet调用public boolean service(RequestContext context)方法figure 7.4,执行request处理,此服务不仅要进行很多的初始化工作,更重要的是它包括多级的异常捕捉、报告,任何未捕捉的异常会由异常页来呈现。过程如下:
1).调用AbstractEnginer的protected void setupForRequest(RequestContext context)方法,确保engine对象被设置,这个方法很重要,细节可参看API文档,在覆写类方法的子类中,必须首先第一句调用这个方法
2).调用自己的getService(String name)
3).new RequestCycle(IEngine engine, RequestContext requestContext, IEngineService service, IMonitor monitor)
4).调用IEngineService的service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)方法
5).调用RequestCycle对象的cleanup()
6).调用自己的cleanupAfterRequest(IRequestCycle cycle)方法
Engine service
Engine service是实现了IEngineService接口的对象,他包含很多创建和服务应用URL的方法,且全是在一个对象中,Engine service更象servlet,他能被很多线程共享,不能记录客户状态。tapeestry默认是有9个service,4个最长用的是home, page,direct和external,可见Table 7.3,大部分service有相对应的部件
IEngineService的service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)方法,IRequestCycle的一些方法调用等,各个service的调用是不相同,这些步之后各个service都要回调IEngine对象的renderResponse()方法,处理也是一样的。
home Service:
1).调用IRequestCycle的getPage(String name),返回home page
2).调用IRequestCycle的activate(IPage page)方法,此方法为request设置最终返回客户端显示的活动页面,活动页面典型的由service设置,但因为可能被替换要显示的页面,也会经常被validator方法pageValidate(PageEvent event)改变,这个方法的操作过程如下:它调用page对象的validate(IRequestCycle cycle)方法,(validate()方法用于基本的安全验证,这个方法实际上并不执行任何检查Figure7.06,page对象可以有多个PageValidateListener,The validate()方法调用每个validator对象的pageValidate()。最通常的方法是page对象自己实现PageValidateListener接口,会自动注册成为自己的validator。validator可以通过throw a PageRedirectException激活不同的页面,当PageRedirectException异常被扔出,由service处理的request过程将被中止,被异常指定的页面被激活并被立马呈现给客户端。)
3).service对象回调engine的renderResponse()方法,将使活动页面被呈现并响应给客户端
page service:
除了service对象和home service不一样,其他步骤相同
direct service:
DirectLink和Form部件使用这个服务,这两个部件都实现IDirect接口,当处理form的submit时,会首先执行一个rewind动作,之后执行form指定的listener动作。direct service能够检查session是否过期,DirectLink和Form部件的“stateful”属性,默认为“false”,设置为“true”就可以进行session检查,当呈现响应时,direct service会生成URL,形如:/examples/app?service=direct/1/Guess/select,URL中的1,就标明这需要检查session是否过期,
一旦session过期,用户就会看到Session已经过期的页面,默认的是个很简陋的,可以创建一个命名为“StaleSession”的page,来给用户提供一个更友好的界面。处理请求,DirectService的service()方法处理过程:
1).调用IRequestCycle的getPage(String name),返回page
2).调用IRequestCycle的activate(IPage page)方法,此方法为request设置最终返回客户端显示的活动页面,活动页面典型的由service设置,但因为可能被替换要显示的页面,也会经常被validator方法pageValidate(PageEvent event)改变,这个方法的操作过程如下:它调用page对象的validate(IRequestCycle cycle)方法,(validate()方法用于基本的安全验证,这个方法实际上并不执行任何检查,page对象可以有多个PageValidateListener,The validate()方法调用每个validator对象的pageValidate()。最通常的方法是page对象自己实现PageValidateListener接口,会自动注册成为自己的validator。validator可以通过throw a PageRedirectException激活不同的页面,当PageRedirectException异常被扔出,由service处理的request过程将被中止,被异常指定的页面被激活并被立马呈现给客户端。)
3).调用IPage的getNestedComponent(String path),返回一个IDirect对象
4).调用IDirect对象的isStateful(),如果为true,session过期检查将要发生,检查HttpSession过期,StaleSessionException异常将被服务扔出
5).调用IRequestCycle的setServiceParameters(Object[] parameters),由service调用,service参数被解开并存入request cycle的serviceParameters属性中
6).调用IDirect对象的trigger(IRequestCycle cycle),调用部件的listener方法,执行相应的action
7).service对象回调engine的renderResponse()方法,将使活动页面被呈现并响应给客户端
需要注意的是,各方法调用顺序很重要,validate()发生的比较早,那时还不能访问service参数,session检查发生在validate()之后
对于DirectLink部件,trigger()方法内部处理过程:
1).调用IActionListenerr的actionTriggered(IComponent component,IRequestCycle cycle)方法
1.1).通过反射机制调用listener方法
对于Form部件,trigger()方法执行,要执行rewind,内部过程Figure 7.12:
1).调用IRequestCycle的rewindForm(IForm form,String targetActionId)方法
1.1).调用page对象的beginPageRender(),触发适当的事件
1.2).回调IForm对象的rewind(IMarkupWriter writer,IRequestCycle cycle)
1.2.1).调用IForm对象的render(IMarkupWriter writer, IRequestCycle cycle)
1.2.2).调用监听方法等
1.3).调用page对象的endPageRender(),触发适当的事件
1).调用IRequestCycle的getPage(String name),返回page
2).调用IRequestCycle的setServiceParameters(Object[] parameters),由service调用
3).调用IRequestCycle的activate(IPage page)方法,此方法为request设置最终返回客户端显示的活动页面,活动页面典型的由service设置,但因为可能被替换要显示的页面,也会经常被validator方法pageValidate(PageEvent event)改变,这个方法的操作过程如下:它调用page对象的validate(IRequestCycle cycle)方法,(validate()方法用于基本的安全验证,这个方法实际上并不执行任何检查,page对象可以有多个PageValidateListener,The validate()方法调用每个validator对象的pageValidate()。最通常的方法是page对象自己实现PageValidateListener接口,会自动注册成为自己的validator。validator可以通过throw a PageRedirectException激活不同的页面,当PageRedirectException异常被扔出,由service处理的request过程将被中止,被异常指定的页面被激活并被立马呈现给客户端。)
3).调用IExternalPage的activateExternalPage(Object[] parameters, IRequestCycle cycle)
4).service对象回调engine的renderResponse()方法,将使活动页面被呈现并响应给客户端
从池中获得一个页面
虽然采用池化技术,因为page众多,我认为,在最开始池中是没有page的,只有第一次访问生成一个完整page,直接返回给request使用,使用完毕page返回池中等待复用。
Figure 7.19 IRequestCycle的getPage(String name)方法返回一个page实例,这个实例被request cycle对象在整个request期间缓存,将来调用同名page名字的getPage()会返回相同实例,getPage()方法内部步骤是,
1).用IPageSource的getPage(IRequestCycle cycle, String pageName, IMonitor monitor)方法,IPageSource就是page池,他能实例化一个新的page实例,如果池中没有可用的page实例,page实例调用自己的attach(IEngine value)以把自己绑定到一个具体的engineh上,一直到request cycle结束,才解除绑定返回池中。
2).调用page的setRequestCycle(IRequestCycle cycle)
3).调用IEngine的getPageRecorder(String pageName,IRequestCycle cycle),IPageRecorder是一个对象,负责追踪page的持久页面属性变化的,当持久页面属性改变了,新值就会被记录在HttpSession中。page持久状态是特定于一个专门用户,完全和page实例分开的。IPageRecorder通过简单的通知机制被钩入page实例,IPageRecorder观察到持久属性改变,就会他作为一个命名的session属性把持久属性值安全的保存到HttpSession,各自的持久页面属性被作为独自的HttpSession属性保存
4).调用IPageRecorder的rollback(IPage page),将页面持久属性恢复到HttpSession属性保存的值
创建一个新Page实例
当请求page,而池中又没有实例可用,page source会利用PageLoader(是类不是IPageLoader接口)来创建一个page实例figure 7.20:
PageLoader不是threadsafe,PageSource要创建一个新的PageLoader实例为每一个要装载的页面,为解决多线程的问题
<!---->PageLoader的IPage loadPage(String name, INamespace namespace, IRequestCycle cycle, IComponentSpecification specification)
过程:
1).new一个page实例,java page class被实例化
2).初始化属性,page的初始属性被设置,包括page名字
3).page实例调用自己的attach(IEngine value)以把自己绑定到一个具体的engineh上
4).page包含的部件被递归创建,每一个部件被创建,page loader就会调用部件的finishLoad()方法,从BaseComponent类继承的部件在这时也会装载他的模板
5).page的finishLoad()方法被调用
一旦page的finishLoad()方法执行完毕,一个初始化和配置过的完整的page对象被返回给request cycle。对于页面和部件来说,当在page or component specification中对有的初始化不能被表达时,重载后的finishLoad()方法是个进行这种最终初始化的好地方,经常这类初始化要涉及page中的其他部件。finishLoad()有两个方法,
<!---->public void finishLoad( IRequestCycle cycle, IPageLoader loader, IComponentSpecification specification); protected void finishLoad();
尽量重载protected的无参的finishLoad(),且无需先调用父类的方法,除非要使用到3个参数,才会重载public的,且当重载public的带3个参数的方法时,必须先调用父类的public的同名方法,一旦调用失败,就会造成加载page或component的模板失败,也会造成其他方面的影响
在request结束时,response被发送回client之后,附着在request上的page必须被返回池,页面属性包括持久的临时的都必须被重置回初始值,以供其他用户的request使用。如果保留属性值不重置是非常危险的,因为所有的page实例是完全共享的,另一个request完全有可能从池中获得上一个用户使用过的page,所以信息就会暴露。IRequestCycle的cleanup()方法Figure 7.21,会释放所有他拥有的资源,就包括释放page回page source,过程如下:
1).调用IPageSource的releasePage(IPage page)方法
1.1).IPage的detach()方法
1.1.1).清除changeObserved属性,Clears the changeObserved property
1.1.2).调用所有注册的相关监听器的PageDetachListener.pageDetached(PageEvent)
1.1.3).调用org.apache.tapestry.AbstractPage.initialize()清除重置所有属性
1.1.4).Clears the engine, visit and requestCycle properties,the page's visit,engine,and requestCycle properties are reset to null.
子类可以覆写这个方法,但是必须在子类方法中调用父类的同名方法,通常是在方法的最后(以上detach()说明主要参见AbstractPage.detach()方法API文档)
实际上只要你用<property-specification>元素来声明持久或临时属性,就不必关心页面的清除工作, detach()或initialize()方法主要是早期版本中要顾及的。
页面呈现过程:
tapestry呈现的核心是IRender接口,只有一个方法: public void render(IMarkupWriter writer, IRequestCycle cycle);
这个接口被希望参与页面呈现处理的所有对象所实现,他是IComponent的父接口,因此所有的部件都可以被呈现。IMarkupWriter接口一个很重要的工作,把所有xml保留字自动转换,如><等,不用程序来干预。BasePage类实现了 getResponseWriter(),源码为:
<!---->public IMarkupWriter getResponseWriter(OutputStream out) ...{ return new HTMLWriter(out, getOutputEncoding()); }
HTMLWriter的getContentType()方法默认会返回一个字符串“text/html; charset=UTF-8”,因此若要返回xml类型,应该在BasePage的子类中覆写getResponseWriter()方法,如下:
<!---->public IMarkupWriter getResponseWriter(OutputStream out) ...{ return new HTMLWriter("text/xml",getOutputEncoding(),out); }
若要返回wml类型,应该在BasePage的子类中覆写getResponseWriter()方法,如下:
<!---->public IMarkupWriter getResponseWriter(OutputStream out) ...{ return new WMLWriter(out, getOutputEncoding()); }
engine对象的renderResponse()方法:
1).调用IRequestCycle对象的getPage(),得到page对象
2).调用page对象的public IMarkupWriter getResponseWriter(OutputStream out)方法,返回一个IMarkupWriter对象
3).调用IMarkupWriter对象的getContentType(),这个值用来设置HttpServletResponse的setContentType()方法
4).调用IRequestCycle对象的renderPage(IMarkupWriter writer),呈现指定的页面,应用应该总是用这个方法来呈现页面,而不是直接调用IRender.render(IMarkupWriter, IRequestCycle),因为在呈现之前cycle对象必须进行一些设置;
4.1).IRequestCycle对象的renderPage()调用page对象renderPage(IMarkupWriter writer,IRequestCycle cycle),被调用来呈现完整页面,这个方法应该只由IRequestCycle.renderPage(IMarkupWriter writer)调用,这个方法内执行呈现的具体过程如下Figure 7.18
4.1.1).调用PageRenderListener的pageBeginRender(org.apache.tapestry.event.PageEvent)方法
4.1.2).调用page对象的beginResponse(IMarkupWriter, IRequestCycle),这是最后一次机会可以修改持久属性
4.1.1).回调IRequestCycle的commitPageChanges()方法,这个方法会通知负责持久属性管理的page recorders进行相应的保存
4.1.1).调用page对象的render(IMarkupWriter, IRequestCycle),page开始呈现他的模板的内容,同样的递归呈现他包含的部件
4.1.1).调用PageRenderListener的pageEndRender(org.apache.tapestry.event.PageEvent) (this occurs even if a previous step throws an exception).
一旦呈现页面开始,持久页面属性就不能再被修改!!!
页面属性
声明的属性,持久的、临时的都可以有一个初始值,初始值或者是<property-specification>元素的"initial-value"属性的值,或者是<property-specification>元素体的内容,初始值是OGNL表达式,此表达式只被计算一次并且表达式的值被保存起来,是在page或component的finishLoad()方法被调用之后。表达式的值被用来给属性赋初值,当page被从request拆开时,为复用返回page池之前,此表达式的值被用来更新属性。初始值也可以不在<property-specification>元素指定,可以在finishLoad()方法内设置,finishLoad()方法调用完毕,tapestry框架会读这个属性,读出的值就将是属性的初值,会被保存为以后用,当page拆开时返回前,此保存的初值会被重新赋给属性,也就是说,无论是在initial-value或者是在finishLoad()中,都可指定初值,然后此初值被tapestry保存用于为属性恢复初值!
发表评论
-
Weblogic的boot.properties文件位置变了
2015-03-24 10:57 1312从10.3.2之后boot.properties文件不再位 ... -
Tomcat启动时报错:java.net.BindException: Permission denied <null>:80
2013-11-09 22:52 2198问题描述:Tomcat启动时报一系列错误: 问题1: ... -
Weblogic启动慢解决方法
2013-09-06 09:08 14717添加 启动参数 : -Xms256m -Xmx ... -
如何在eclipse中安装Eclipse SQL Explorer
2012-02-24 00:19 2692About Eclipse SQL Explorer ... -
用Lucene检索数据库
2012-02-08 18:04 26211.写一段传统的JDBC程序,讲每条的用户信息从数据库读 ... -
手把手教你如何修改Eclipse中所使用的Tomcat的内存大小
2011-07-13 11:43 1386最近在开发新项目的时候,由于用到缓存比较多,导致Eclipse ... -
WINE QQ 2009教程 看很多人还为QQ着急
2011-04-17 14:29 1373一、安装好 Wine 1.2(1.2 ... -
程序员需要具备的基本技能
2011-03-21 21:19 1086软件开发是一个跨度 ... -
为什么程序员得到的报酬与他们的生产力不成正比
2011-03-21 21:18 1294编者按:原文作者J ... -
经验丰富的程序员和代码行数
2011-03-21 21:15 1408编者按:原文作者John D. Cook是一位数学教授、程序 ... -
10句编程箴言,每个程序员都应该知道
2011-03-21 21:11 911所谓谚语,就是用言简意赅、通俗易懂的方式传达人生箴言 ... -
项目管理工具Redmine安装
2011-02-28 10:47 1626关键字: redmine 可以选择直接在http:/ ... -
JavaScript 字符串转换数字
2011-01-06 17:34 1090方法主要有三种 转换函数、强制类型转换、利用js变量弱类 ... -
java使用jdbc轻松连接访问access
2010-11-29 14:50 1171import java.sql.Connection; ... -
java读取文件大全
2010-10-28 16:53 11921、按字节读取文件内容2、按字符读取文件内容3、按行读取文件内 ... -
weblogic启动受管服务器的一个错误
2010-10-09 21:18 3005错误如下: Server is Running in ... -
对Java编程思想的忠告
2010-09-20 15:23 982编写Java程序的注意事项,对Java编程思想的忠告。 ... -
Tomcat调整内存所能容纳的最大值
2010-08-03 21:41 1610以下为网络摘抄: Tom ... -
weblogic中如果使用80端口和根目录作为应用的默认目录
2010-07-23 19:29 2265使用根目录作为默认目录,需要新建一个工程可以叫做index,然 ... -
Hibernate对各数据库的连接方言
2010-07-20 09:56 1107<session-factory> < ...
相关推荐
资源名称:深入浅出Tapestry内容简介:本书以循序渐进的方式,从...本书详细介绍了Hivemind框架的原理与应用,使读者不但可以通过Hivemind来重构Tapes 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。
Tapestry5最新中文教程.doc 作者 Renat Zubairov & Igor Drobiazko译者 沙晓兰 发布于 2008年7月2日 下午9时30分 社区 Java 主题 Web框架 ----------------------------------------- Tapestry5.1实例教程.pdf ...
tapestry 实例tapestry 实例tapestry 实例tapestry 实例
Tapestry 4 官方文档中文版本,现在中文资料比较少,和大家共享一下
, 本书详细介绍了Hivemind框架的原理与应用,使读者不但可以通过Hivemind来重构Tapestry的官方实现,还可以使用Hivemind来搭建J2EE Web应用程序的业务层。在本书还提供了一个以Hibernate+Hivemind+Tapestry 4.0为...
Tapestry是一个基于控件的框架以致于用它开发Web应用类似开发传统的GUI应用。你用Tapestry开发Web应用时你无需关注以操作为中心的(Operation-centric) Servlet API.引用Tapestry网站上的一句话:"Tapestry用对象...
Tapestry5.0.16文档和大家一起学习
tapestry3开发指南,带tapestry3所有jar包
Tapestry4开发指南
tapestry5.2.6 最新jar包,Tapestry框架是一个位于java servlet容器和Tapestry应用程序之间的层
tapestry技术 Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得...
包含: tapestry 的源代码, tapestry集成spring2.0 tapestry快速启动 tapestry upload tapestry hibernate tapestry annotations
Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html...
Tapestry简明教程
本文介绍Tapestry框架版本5。本文利用Tapestry 5开发一个简单的具有创建/读/更新/删除功能的应用,在创建这个应用的过程中,本文体会到Tapestry带来的开发效率的提升。从多方面来讲解 Tapestry应用,比如应用的...
Tapestry通用WEB框架支持,切换皮肤,自主分页,
最新Tapestry 5 電子書
强大的tapestry框架的学习入门资料,详细介绍了tapestry的常用开发文档。
tapestry源码文档以及API,需要更早版本请私信