当前位置:文档之家› OracleEBS OAFramework

OracleEBS OAFramework

OracleEBS OAFramework
OracleEBS OAFramework

OracleEBSOAFramework

(一)开发环境搭建

关键字:OracleEBSERPOAFrameworkOAF关键字:最近公司开始了一个OracleERP二次开发项目,使用的是EBSR12版本,这个版本由于比较新,从这个版本中可以看到OracleERP二次开发的主要技术有向Web方面发展的趋势,其中主要使用的就是OracleOAFramework应用框架.

网上这些资料不好找,我通过查看OAFrameworkGuide整理了一些文档,后面陆续会发布到blog中与大家共享.

内容基本上是按我的学习顺序组织的,学到哪里写到哪里,由于是初学OAFramework,而它又与我们通常接触的开源框架差异较大,因此理解上难免出现偏差,有不正确的地方请大家指正.由于系统的限制,不能发过多的插图,文章中的插图没有全部贴上来,这些插图都来自于OAFrameworkGuide.

环境塔建按以下几个步骤:

1.从MetaLink上下载p5856648_R12_GENERIC.zip

2.从你的EBS服务器上下载dbc文件,比如我的dbc位置/u02/prod/inst/apps/PROD_ebs/appl/fnd/12.0.0/secure/PROD.dbc

3.启动JDeveloper,从JDeveloper解压目录中找到ToolBox工程,初次打开时会提示代码更新.

4.在工程的属性中找到OracleApplications配置好DatabaseConnection.

5.在工程的属性中找到OracleApplications->RuntimeConnection页,将DBCFileName设置为从服务器上下载的dbc文件.UserName和Password为登录ebs环境时使用的用户名和密码.Responsibility中设置好开发所使用的应用简称和职责.这个职责只需要是UserName所具有的职责就可以了.

Page基础

在浏览器看来,OAFramework页面与其它web页面一样,被渲染为HTML.

在中间层中,页面是由内存中层级分布的Javabeans组成——非常像传统的Java客户端UI.每个UI构件,比如按钮,表格,tab,商标图像等,被渲染为页面中对应的构件.

浏览器向一个页面发出请求时,Framework读取页面定义的元数据创建webbean结构.OA每个bean与一个UI控制器关联,Framework调用你编写的代码初始化页面.OA页面处理完成后,FrameworkOA将webbean结构交给UIX框架处理以生成发送给浏览器的HTML.

当浏览器发出一个表单提请求时,OAFramework重新创建bean及其层次结构(只在必要的时候才重新创建,通常这些bean是被缓存的,只在特定的情况下才重新创建),然后调用为pagebean编写的事件处理代码.当页面处理完成后,页面HTML重新生成并发送给浏览器.

OAFrameworkMVC架构:

模型Model

模型包括下层的数据和应用业务逻辑.它也提花了现实世界对象和应用服务间的抽像层.

应用模块ApplicationModules

BC4j应用模块本质上是一个容器,它管理和提供对"相关"BC4J模型对象的访问.这里的"相关"指的是同一个任务中的参与者.比如所有的BC4J对象在同一个任务中参与同一个事务——即使对应的用户界面需要用户访问多个页面.应用模块:

应用模块是oracle.apps.fnd.framework.server.OAApplicationModuleImpl类的子类.

每个OAFramework页都有一个根(root)应用模块,它与最顶层的页面区域(pageregion)关联.根应用模块提供事务环境和连接数据库.

如果多个页面参与同一个物理或虚拟事务,它们应该共享相同的根应用模块.如果一个页面功能不依赖于其它东西,它需要拥有自己的应用模块.

注意:注意:一个根应用模块可能包含一个或多个嵌套的应用模块,可以嵌套任意多的层次.这种情况下,根应用模块可以访问它包含的子对象的数据和对象,所有子对象共享根应用模块的事务.你可以在创建需要重用的与数据库操作相关的UI区域时使用这个功能.

实体对象(实体对象(EntityObjects)和关联对象(AssociationObjects))和关联对象()

BC4J实体对象包含了业务规则(校验,动作等)与数据库表中的一行关联.注意:

注意:实体也可以基于视图,同义词,快照而定义.OAFramework支持Java和PL/

SQL实体.

实体对象:

多数实体是oracle.aps.fnd.framework.server.OAEntityImpl的子类(PL/SQL继承于特殊版本的OAEntityImpl).

表和实体对象一一对象,所有实体应该包含与之关联的表的所有列.实体对象使用映射了它的属性和数据库列,并自动实现了查询,插入,更新,删除等操作.多数情况下,我们只需要添加校验逻辑.实体对象可以用于任何程序(不限于OAFramework).

关联对象AssociationObjects用于定义实体间的关系.

视图对象(视图对象(ViewObjects)和视图链接(ViewLinks))和视图链接()BC4J视图对象处理数据库查询.查询执行后,视图对象提供了访问它的结果集的功能.结果集包含了一个或多个视图行,视图行与数据库查询的行相对应.视图对象:

所有的视图对象都是oracle.apps.fnd.framework.server.OAViewObjectImpl类的子类.视图对象可以配置为使用下面的策略查询数据:

它的属性映射到简单的SQL语句的列(通常用于小的只读的视图对象)它的属性映射到实体对象的属性(用于插入,更新和删除实体)一些属性映射到实体对象,一些直接映射到SQL(用于增加实体临时数据,这些数据不能通过实体获得,比如计算值或用于UI显示需要)

在OAFramework应用中,将在下面情况下使用视图对象:

呈现用于优化用户界面细节的数据.如果用户界面支持实体的插入,更新,删除,你将通过视图对象执行这些操作.为poplists,listsofvalues和其它UI组件创建简单的查询.为业务逻辑创建有效的"校验查询(validationqueries)".比如,在定单处理时使用一个校验视图对象获得最大可以购买的商品数量.

可以为视图对象编写代码用于实现复合查询或查询时的数据绑定(以便视图对象知道怎样"查询"自己).视图链接ViewLinks与实体对象类似,也可以为视图对象建立关联,称为视图链接(viewlinks).比如可以在定单头视图对象和定单内容间建立视图链接对象.这可以用于在运行时访问定单头时自动查询定单内容.

OADBTransaction

OADBTransaction:

注意:注意:准备的来说这个图应该要包含实现类oracle.apps.fnd.framework.server.OADBTransactionImpl替代oracle.apps.fnd.framework.OADBTransaction接口.

如图所示,OADBTransaction扮演的是模型中的中心角色,因为它与一个根应用模块关联,管理JDBC连接/数据库会话,直接拥有你创建的任何实体(根应用模块拥有的视图对象中的行指向实体对象).可以使用OADBTransaction在模型代码中完成下面的操作:

创建一个语句执行PL/SQL函数和存储过程访问应用会话级环境信息(session-levelApplicationcontextinformation),比如:用户名,id,当前责任(resposibility)等.访问一个oracle.apps.fnd.framework.OANLSServices对象,如果你需要page2执行NLS操作,比如转换服务器时间到用户日期/时间等.

可以通过根应用模块访问OADBTransaction.

视图

视图格式化当前模型数据给用户.

定义页面

在OracleApplications开发时,将使用XML页面定义文件.当产品发布后,OAFramework从数据库获取页面定义.使用JDeveloper定义的页面(pages)由区域(regions)和条目(items)组成.

条目是简单的构件,比如按钮,输入域,图像等,它不包含子构件.

区域是容器对象它可以包含条目和其它区域.比如区域包含文件头(headers),表格和特别的布局组件(layoutcomponents).定义的每个区域和条目都有style属性,它告诉OAFramework使用哪个webbean对象来描述它.比如,如果你定义区域的style属性为"table",OAFramework将使用oracle.apps.fnd.framework.webui

.beans.table.OATableBean.所有页面必须有一个单一的top-levelregion(通常称为"rootregion")它的style为pageLayout.它将使用https://www.doczj.com/doc/be11231430.html,yout.OAPageLayoutBean.regions和items显示在JDeveloperpagetree中的顺序告诉了Framework将这些对象添加在什么位置.

属性集AttributeSets

每个region或item通过使用attributesets可以继承一组属性集合.attributesets是一个被命名的属性的集合,可重用于任何UI对象,包括:regions,items和其它属性集.当使用attributesset创建UI时,你可以覆盖所继承的属性.组件重用如果需要在页面使用共同对象,可以简单的从它继承.

比如,可以创建一个通用的region.新建region时,将新region的Extends属性设置为通用region 的命名.注意:注意:共享的通用region在引用它的page中是不可编辑的,属于它的选项目在JDeveloper中将显示为灰色.数据源绑定

对于需要与数据库交互的bean,你需要指定数据源,将它绑定到ViewInstanceName,并关联好ViewAttributeName.这个绑定是至关重要的,因为OAFramework使用它获取数据,并将用户输入的数据写入下面的视图对象.

ViewInstanceName指向当前上下文环境中包含应用模块中的视图对象(所有视图对象"生活"于一个应用模块中,在包含它的容器对象中有一个实例变量名).比如,如果SuppliersVO视图对象,在页面的根应用模块中有一个实例变量"MySupVO".ViewAttributeName指向视图对象中映射到数据库列的属性.

定义菜单定义页面流个性化页面

控制器

控制器响应用户动作控制应用流转.

控制器可以与视图中的region级的对象关联(任何实现oracle.apps.fnd.framework.webui.beans.OAWebBeanContainer的OAFrameworkwebbean都可以与控制器关联).控制器是oracle.apps.fnd.framework.webui.OAControllerImpl的子类

.控制器代码的行为:

生成/初始化UI中途截取或处理用户事件,比如按钮按下请求处理

当浏览器向OA.jsp请求一个页面时:

1.oracle.apps.fnd.framework.webui.OAPageBean(OAFramework主页面处理类)根据请求的页面

名称检查需要哪个根应用模块,并从应用模块池(applicationmodulepool)中取出.这个应用模块将为页面从JDBC连接池中获取连接和事务上下文.

2.用户会话校验;如果无效,将显示登录页面(这里是简化的说法,具体细节在Developer'sGuid 中有说明).

3.如果用户有效,OAPageBean根据请求参数处理HTTPPOST或GET.处理GET请求当浏览器发起GET请求一个page时(或你手工forward时),OAFramework使用描述的UI定义构建webbean层级结构:

page31.OAPageBean调用页面的top-levelpageLayoutbean的processRequest()方法,然后进入webbean层级结构中继续递归调用来初始化webbeans(包括任何相关的模型组件).1.每个webbean可以有自己的控制器,如果有就调用控制器的processRequest(OAPageContextpageContext,OAWebBeanwebBean)方法.这个方法可以用于构件或修改页面布局,设置webbean属性和执行任何手工的数据初始化工作(比如,打开页面时自动执行查询).2.一些复杂的webbeans(比如:oracle.apps.fnd.framework.webui.beans.table.OATableBean和oracle.apps.fnd.framework. https://www.doczj.com/doc/be11231430.html,yout.OAPageLayoutBean)通过调用它们的prepareForRendering()(这个方法在JavaDoc中的说明)方法执行post-controller处理.3.每个webbean调用它的子对象的processRequest()方法.2.oracle.apps.fnd.framework.webui.

OAPageBean将webbean结构传递给UIX渲染并发送给浏览器处理POST请求

当浏览器向服务器页面发出POST请求时:

1.OAPageBean检查webbean层级结构是否在内存中.如果没有它就像在GET请求中一样创建一个webbean层级结构.

2.OAPageBean调用整个层级结构中的webbean的processFormData(OAPageContextpageContext,OAWebBeanwebBean)方法,并将form中的数据写入模型(它在pageLayoutregion上调用processFormData(),然后在它的子对象上递归的调用processFormData()方法).将form数据写入模型时将自动调用属性和实体级别(attributeandentity-levelvalidations)的校验,如果抛出了任何校验异常,处理将停止,错误信息将显示给用户.

3.如果在执行processFormData()期间没有异常抛出,OAPageBean将使用与上面相同的方法在层级结构中的所有webbean上调用processFormRequest(OAPageContextpageContext,OAWebBeanwebBean)方法.这里给了你的控制器响应用户动作的机会.

4.如果没有JSPforward或redirect发出,或在执行processFormRequest()方法时没有异常被

抛出.则页面刷新OAPageContext当OAFramework收到一个OA.jsp请求时,OAPageBean创建一个oracle.apps.fnd.framework.webui.OAPageContext,这个类仅在页面处理过程中存在.上面描述的三个方法(processRequest(),processFormData(),processFormRequest())都有一个OAPageContext参数,任何将要编写的控制器代码都使用了这个至关重要的类.

如上图所描述的,OAPageContext有指向request和根应用模块的引用.根据这个关系,OAPageContext被传递到每个控制器的响应处理方法中,你将看到如何在下面的通用任务中使用OAPageContext:访问请求参数可以使用getParameter(Stringname)方法读取请求参数.技巧:技巧:

页面上的每个webbean(buttons,fields等等)传递给getParameter()的是你定义在页面上的唯一ID属性.比如,使用下面的代码可以得到用户是否按下了名为"

GoButton"的按钮:processFormRequest(OAPageContextpageContext,OAWebBeanwebBean)

{if(pageContext.getParameter("GoButton")!=null){//Theuserp

ressedthe"Go"button,dosomething……}}

访问根应用模块

OAPageContext缓存了根应用模块的引用,它可以访问视图对象和事务.如果需要访问应用模块,可以通过OAPageContext:processFormRequest(OAPageContextpageContext,OAWebBeanwebBean){OAApp licationModuleam=(OAApplicationModule)pageContext.getRootApplicationModule();}发出导航指令使用方法告诉OAFramework执行JSPforward或客户端重定向.比如: processFormRequest(OAPageContextpageContext,OAWebBeanwebBean)

{if(pageContext.getParameter("CreateButton")!=null){//Theuserpressedthe"CreateSupplier"butto n,nowperformaJSPforwardto//the"CreateSupplier"page.

pageContext.setForwardURL("OA.jsp?page=/oracle/apps/dem/employee/webu

i/EmpDetailsPG",null,OAWebBeanConstants.KEEP_MENU_CONTEXT,null,null,true,//RetainAMOA WebBeanConstants.ADD_BREAD_CRUMB_YES,//Showbreadcrumbs OAWebBeanConstants.IGNORE_MESSAGES);}}访问应用上下文信息与模型中的

page4OADBTransaction类似,OAPageContext可以访问servletsession级的OracleApplication上下文信息,如:用户名,ID,当前职责等.比如,下面的片段用于获取用户名:

processRequest(OAPageContextpageContext,OAWebBeanwebBean)

{StringuserName=pageContext.getUserName();}

WebBean架构

所有OAFrameworkwebbeans都与UIXframework中的bean对应.比如,OATableBean继承自oracle.cabo.ui.beans.table.TableBean("cabo"是UIXframework早期的名字,包定义仍然使用了旧名).

每个OAFrameworkwebbean都实现了一组接口,这些接口实现了OAFramework添加到基础的UIXbeans上的行为.

oracle.apps.fnd.framework.webui.beans.OAWebBean定义了所有webbeans的通用行为(比如,其中在这里定义的关键的行为有processRequest,processFormData,processFormRequest方法,一些beans自己实现了这些方法).oracle.apps.

fnd.framework.webui.OAWebBeanConstants用于视图和控制器的常量集合.oracle.apps.fnd.framework.webui.beans.OAWebBeanData定义通用的个性化定义和数据源管理行为oracle.apps.fnd.framework.webui.beans.OAWebBeanContainer定义所有可以作为其它webbeans容器的webbeans的特性.比如,所有layoutwebbeans都实现了这个接口.只有实现了这个接口的beans才可以与控制器关联.OAWebBean定义了bean在OAFramework上下文环境中的内在特性.比如,OATableBean实现的oracle.apps.fnd.framework.webui.beans.OAWebBeanTable接口.

webbean例子(OATableBean):

内部Bean结构每个webbean自己包含了下列的信息:

_indexedChildren子webbeans_namedChildren子webbeans特殊行为的UIX标记._attributeswebbean的特性(属性描述),下表的图表描述描述webbean使用Dictionary保存键值对属性:

数据绑定值

与上面的图表描述的情况不同,OAFrameworkwebbean的attributes实际上是用数据绑定值实现的,这意味着它是由下层的数据源提供的,在组件被渲染时才被获取.后面将看到如何定义用户自定义绑定值.渲染在页面渲染时,UIXframework处理webbean层级对象产生页面的HTML代码.

对于每个webbean属性,UIX调用它的getAttributeValue()方法.并传递给它一个渲染上下文

(renderingcontext),renderingcontext是UIX决定绑定值的全部基础.对于给出的属性,比如,renderingcontext知道下层的视图对象实例,视图属性和当前的行.数据绑定使用rendering context通过查询它的数据源所提供的返回值传递给UIX以产正确的HTML. OAFrameworkJavadoc手册

每个OAFramework包的描述:

oracle.apps.fnd.framework

包含的类和接口可以安全的从模型(server)和用户界面控制器或视图(client)访问.比如,需要在页面中访问根应用模块,应该使用oracle.apps.fnd.framework.OAApplicationModule接口(不应该在客户端访问它的实现).这个包也包括:

所有OAFramework异常OANLSServices类用于执行国际化操作oracle.apps.fnd.framework.server

包含了OAFrameworkModel-View-Controller中用于实现model的类和接口.

这些类规定用于任何客户端用户界面(不仅仅是OAFrameworkHTMLpages)[译注:根据后面的意思,这里似乎应该是不能用于!],并且不允许被任何oracle.apps.fnd.framework.webui包和其子包中的类和接口引用,也不允许应用中的webui包和其子包引用.当建造OAFramework应用模型时,应该使用这个包中的类替代BC4J中继承的类.警告:永远不要从控制器或视图代码中调用这个包中的类.警告:

oracle.app.fnd.framework.webui

包括了构造OAFrameworkHTML用户界面的核心类.一些这个包中最常用的类和接口: OAControllerOAPageContext任何下面所描述的beans子包中的类

警告:警告:永远不要从模型代码中调用这个包中的类.

oracle.app.fnd.framework.webui.beans

包含用于用户界面组件的webbean.你将在编写用户界面控制器时编程的方式处理这些webbeans.

这个包和其子包中的类与UIX组件对应,它们继承关系如下.当构造OAFramework应用页面时,应该使用OAFramework类,除非你要使用一个已经介绍给UIX的新的功能,但目前这还不被支持.注意:注意:OAFramework类是在JDeveloper中描述的MDS页面中使用. UIXPackageoracle.cable.ui.beansoracle.cable.ui.beans.formoracle.c

https://www.doczj.com/doc/be11231430.html,youtoracle.cabo.ui.beans.mess

ageoracle.cabo.ui.beans.navoracle.cabo.ui.beans.tableOAPackageoracle.

apps.fnd.framework.webui.beansoracle.apps.fnd.framework.webui.beans.form

oracle.apps.fnd.framework.webui.beans.includeoracle.apps.fnd.framework.we

https://www.doczj.com/doc/be11231430.html,youtoracle.apps.fnd.framework.webui.beans.messageoracle.apps

.fnd.framework.webui.beans.navoracle.apps.fnd.framework.webui.beans.table

警告:警告:永远不要在模型代码中调用这些类.

oracle.apps.fnd.framework.webui.beans.form

包含了HTMLform组件相关的webbean类.包括了提交按钮和各种数据入口/特定的控件(checkbox,radio,group,shuttle,textinputfield等).可以在编写用户界面控制器时使用这些类,需要用编程的方式处理webbeans.

与这个包中其它的webbeans不同的是oracle.apps.fnd.framework.webui.beans.message包(messagewebbeans可以显示错误,信息,带警告图标的说明信息)

.当在JDeveloper中创建页面时,OAFramework为同一个包中的这些组件自动显示消息.应该只在下面的情况下使用这个包中的这个类:

类没有messagebean供选择.(比如,这个包中唯一的类OASubmitButtonBean)不能使用

messagebean替换的时候.

警告:警告:永远不要在模型代码中调用这些类.

oracle.apps.fnd.framework.webui.bean.include

包含了用于将外部资源(servlet,JSP,HTML)中包含到用户界面的webbean类.

将在编写用户界面控制器时编程的方式处理这些webbeans.警告:永远不要在模型代码中调用这些类.警告:

https://www.doczj.com/doc/be11231430.html,yout

包含了OAFramework程序中页面布局的webbean类,包括特殊的layout件,比如,hide/show,contentcontainer,bulletedlists,headers,standardizedt

emplates等等.将在编写用户界面控制器时编程的方式处理这些webbeans.警告:

警告:永远不要在模型代码中调用这些类.

oracle.apps.fnd.framework.webui.beans.message

包含了HTMlform数据相关组件具有显示相关错误,警告信息或带信息图标的说明性消息的webbean类(比如,如果用户在文本框中输入了错误的值,下次渲染这个页面时,这个文本框前将显示一个表示出错的图标).将在编写用户界面控制器时编程的方式处理这些webbeans.

这个包中的许多webbean也包含在oracle.apps.fnd.framework.webui.bean

.form包中,没有显示额外的消息文本和图标文本的能力.当在JDeveloper中创建页面时,OAFramework自动将messagebean添加这两个包中的组件.应该只在不能使用包含messagebean的页面上使用不带消息显示能力的类.警告:警告:永远不要在模型代码中调用这些类.

oracle.apps.fnd.framework.webui.bean.nav

包含了用户界面导航的组件(links,trees,menuelements,quicklinks,breadc

rumbs等).将在编写用户界面控制器时编程的方式处理这些webbeans.

警告:警告

:永远不要在模型代码中调用这些类.

oracle.apps.fnd.framework.webui.beans.table

包含显示table和HGrid组件的webbean类.将在编写用户界面控制器时编程的方式处理这些webbeans.

警告:警告:永远不要在模型代码中调用这些类.

https://www.doczj.com/doc/be11231430.html,f

包含用于控制HTML渲染特性,包括页面观感和上下文细节(比如,内容能为打印效果而优化显示在浏览器中或用于e-mail)的工具.警告:警告:永远不要在模型代码中调用这些类.

bean_arch.gif描述:文件大小:看过的:bean_arch.gif14KB文件被下载或查看5次

概述

这个文档用于描述OAFramework状态管理架构,包括缓存应用系统用户数据和从页面间值传递的机制.

结构预览

主要状态管理组:

根应用模块(数据库会话和事务状态)根应用模块(数据库会话和事务状态)

如OAFramework页面解析一文中描述的,每个OAFramework页面与一个根应用模块关联,根应用模块提供事务环境和JDBC数据库连接.注意:注意:OAFramework中,一个数据库会话与一个JDBC连接关联.根应用模块是任何OAFramework模块的中枢,因为核心应用数据(存储在BC4J视图,实体对象,等等)和页面webbean层级结构自动缓存于根应用模块的oracle.apps.fnd.framework.OADBTransaction对象中.警告:可以查看Supportingthe警告:使用浏

览器后退按钮将导致应用模块状态丢失.BrowserBackButton一文.任何存储于事务中的数据可以被任何共享同一个根应用模块实例的页面访问(在页面间导航时使用下面描述的方式保留应用模块).OAFramework提供了方法用于从事务中存储,获取和移除值.可以在控制器(client)和模型(server)代码中访问单一的事务对象,这些工具在oracle.apps.fnd.framework.webui.OAPageContext(controller中)和OADBTransaction(model中)类可以访问.

根应用模块保留

缺省情况下,当用户从一个页面导航到另一个页面(比如使用GET请求或JSPforward)时,OAFramework渲染新的页面,与前一个页面关联的应用模块实例被"释放",一个新的实例请求被发送到应用模块池.

导航到新的页面时,缺省情况下的原页面的根应用模块将被释放:注意:注意: OAFramework在表单提交(POST)期间不会释放应用模块,除非你显式的在控制器中释放应用模块.比如,如果用户对表格中的数据排序或在表格数据中导航——两个动作隐式的提交了页面表单——页面的根应用模块实例被自动保留.在页面间保留应用模块在多个页面处理同一个任务时相关的页面需要参与同一个虚拟事务.这时,不同页面需要关联到同一个根应用模块实例.相关页面共同同一个根应用模块(和事务):

为达到这个目的,必须执行下面的操作:

申明各个页面关联同一个类型的根应用模块.设置应用模块的保留标记.通过指定URL参数retainAM=y设置模块保留标记.对于GET请求.当新的页面被渲染时(注意,OAFramework对于POST请求将一直保留应用模块而不管retainAM参数的值).如果设置为"Y",前一个页面的应用模块实例将被保留.如果设置为"N"(或不指定,缺省为"N"),OAFramework将释放所有应用模块——包括到达这点前任何可能显式申明为保留的.也可以在调用JSPforwardOAPageContext中的方法时设置这个参数.

警告:警告:不能简单的让不同页面关联相同的根应用模块.如果忘记设置retainAM标记,每个页面仍将使用不同的应用模块实例和事务,即使这些页面关联的是同一个类型的应用模块.注意:技术上来说,这依赖于应用模块池的状态.PageB可能获取到与PageA注意:使用的同一个物理应用模块.但是,对象的状态将完全被重置,就像被新创建的一样.从这个观点来看,可以看作一个"新的实例".两个页面引用相page7同类型的应用模块,但没有设置RetainAM标记:

同样,retainAM标记设置为"Y"——但没有将页面的根应用模块设置为相同将的类型.这将产生不同的应用模块实例(每个页面一个),各自有自己的事务.有条件的保留和释放应用模块有些情况下,你需要通过一个条件来决定是否保留或释放应用模块.这时,你可以让应用模块实现oracle.apps.fnd.framework.webui.OAReleaseListener接口,详细描述见Javadoc.警告:警告:OracleApplication开发人员应该在使用这个接口时通知OAFramework开发团队.不正确的使用这个接口将导致内存泄漏.OAFramework团队正在跟踪这个问题.显式的释放应用模块可以显式的通过代码在OAFramework处理之前释放根应用模块.可以在页面控制器中调用OAPageContext.releaseRootApplicationModule()方法,OAFramework将在页面渲染完成后尽快释放这个页面的根应用模块,而不是等到下次应用模块请求时.

根应用模块保留的使用场景根应用模块保留的使用场景

下列情况下推荐保留/释放应用模块.

情况

推荐操作

无关的当导航到两个不相关的页面时不保留应用模块.比如一连串的不相关的管理任分离的务,它们是独立运行的(即使这们与同一个菜单项目关联),保留应用模块是不任务必要的.多页面当在相关的页面间导航时,这些页面合作完成同一个完整的任务处于单个事务中流时,保留

应用模块相关页当在关联同一个业务对象(即使页面为用户设置了不同的提交点)的不同任务间面(虚拟的相关页面间导航时,如果UI关联得比较紧密则保留应用模块.比如,一个模事务)块可以查询,查看,

更新,删除,打印写单则应该使应用模块保留多页面有一个多页面流使用了分支事务,比如,在创建定单时创建供应商时,在主流程流中使中保留应用模块,而在创建供应商的页面使用用分支OAPageContext.releaseRootApplicationModule方法释放模块.事务注意:注意:在介绍OAFramework的钝化和JDBC池化/回收之前,鼓励开发人员经常的释放应用模块,因为保留JDBC连接是一个昂贵的开销.在了解钝化功能后这不再是个问题.

ServletSession

可以在servletsession中缓存小型的,可序列化的对象(OAFramework限定为字符串,数字和日期类型)注意:注意:使用session缓存那些需要在多个页面设置或访问的简单值,这些页面可以有不同的根应用模块.(事务缓存不在这个范围内).

由于session变量失效时间较长,且没有好的事件可以释放内存,因此应该把session作为最后一种缓存选择.技巧:技巧:隐藏域通常不被推荐使用.因此,OAFramework当前的菜单实现(一些菜单发送GET请求而不是POST请求),并不总是能在用户点击菜单时添加额外的值,根应用绑定是交叉的.可以使用OAPageContextput*(),get*()和remove*()方法访问session变量值. Oracle应用用户Session

当用户登录到OAFrameworkapplication时,OAFramework将创建一个AOL/

https://www.doczj.com/doc/be11231430.html,n.WebAppsContext对象和一个基于session的浏览器cook

ie以跟踪OracleApplicationcontext信息的key.OracleApplication

context中的信息包括当前的责任,组织机构id和用户的各种属性,比如:用户

名,用户id,雇员id等等.

cookie包含了一个加密的key用于标识存储于Application数据库中的一个session行.每次请求时WebAppsContext获取这个key的值,并使用它查询当前session状态.OracleApplication用户session与一个servletsession关联,

但是它有自己的生命周期和超时特性.o通常,OracleApplication用户session的生存时间比servletsession更长.servletsession超时快一些.o一个OracleApplication用户session可能关联到多个servletsession中.比如,当用户在创建开支报表时,打电话的过程中servletsession超时了,然后在OracleApplication用户session超时前恢复工作.如果OracleApplication用户session 超时了,只要用户没有关闭浏览器窗口(因此基于浏览器session的coolie并没有丢失)并且没有人删除ICX_SESSION表中相应的session行,用户可以在提示登录后重新登录并恢复她之前停止时的事务点.

如果你需要访问任何存储于OracleApplicationusersession的信息,可以从OAPageContext(在控制器代码中)或OADBTransaction(在模型代码中)获得.

应用状态(应用状态(ApplicationContextState))

当不同访问OAPageContext(Java服务层代码或PL/SQL)时,可以使用Applica

tioncontext存储一些状态信息.使用WebAppsContext.setSessionAttribute(java

.lang.StringpName,https://www.doczj.com/doc/be11231430.html,ng.StringpValue)方法.

页面环境(Context)页面环境(PageContext)

每次请求接收一个页面时,OAFramework创建一个OAPageContext并持续到新页面处理完成.明确,OAPageBean的主要能力是在页面后面处理创建OAPageContext

.

请求和页面边界

web应用的工作单元是一个请求/响应对:浏览器提交一个请求,servlet处理请求并返回一个

响应.发送一个响应表示单个请求的结束,或者说一个已经完成的请求和一个新请求之间的"边界".同样,OAPageBean完成一个页面处理时,当这就是当前页面和新页面的"边界".因此,在下面的简单场景中当用户从PageX转到PageA然后再转到PageB,这里有两个请求边界:第一个是PageX和PageA之间,第二个位于PageA和PageB之间.这里也有两个页面边界位于PageX 和PageA,PageA和PageB之间.请求和页面边界相同:

有些情况下,请求和页面边界是不相同的.比如下面的JSPForward情况:用户如上面的图中所示的,从PageX导航到PageA.当在PageA上时,用户选择了一个控件,PageA的代码在决定在响应中显示哪个页面前进行计算.浏览器发出请求到PageA,OAFramework进行处理,并为页面创建了一个OAPageContext.一旦PageA的处理完成后,第一个页面的边界到达了,已经如下面的图所示的.在PageA的代码中,开发人员执行用户选择的控件并发出JSPForward到PageB.而不是在这时提供了一个HTTP响应,因为我们不想显示PageA,OAFramework首先处理PageB,并为这个页面创建一个新的OAPageContext对象.一旦PageB的处理完成,第二个页面边界到达.由于PageB现在必须显示给用户了,一个HTTP响应被发送给浏览器.这时响应边界到达了.

在JSPForward情况下,请求界面和页面界面不同:

明确这个区别是很重要的:

请求参数生存于请求生命周期中,它可以跨越多个页面边界.想像下面的情况:o用户选择了PageX中的一个链接导航到PageA.PageA的URL包含了参数foo=baroPageA请求JSPForward 到PageB.现在,尽管已经在新页面中了,但请求仍然包含了foo=bar.o如果你不希望请求参数在执行JSPForward后仍然存在,你必须的替换它.比如,在调用OAPageContext.setForward*()之前,简单的重新设置foo=X.o注意:不能从请求中移除参数.注意:o技巧:比较好的处理方式是将参数值设置为一个不需要的值,这样代码可技巧:以忽略它.而不要简单的将值设置为"".由于pagecontext和request不是一一对应的,一些人可以会对从OAPageContext中访问请求参数觉得迷惑.只要记住每个页面是一个独立的实体,从它的观点来看,OAPageContext表现了request.当了钝化的细节后,将更清楚明白页面和请求边界的区别,甚至是受钝化的影响也不同.

请求Request

对每个HTTPrequest都将创建一个请求对象.这个对象包含下面的应用状态:任何URL参数,不论是POST或GET请求如果浏览器发出一个POST请求:任何form字段值如果浏览空对空发出POST请求:webbean和事件名称与用户选择的动作或控件组件关联.比如:如果用户选择了"GO"按钮执行一个查询,请求将包含以这个按钮命名的webbean,以便你能获取到是这个按钮被按下了而做出响应.

使用OAPageContextgetParameter*()方法获取任何请求值.不能直接与requ

est对象交互.设置request变量值(首选的两个页面间通讯的方法)时,你可以使用page9下面介绍的方法.参考视图实现和控制器实现的相关信息.

使用隐藏域

可以在JDeveloper中设置域的style属性为formValue.运行时,是使用oracle.apps.fnd.framework.webui.beans.form.OAFormValueBean来实现的.

在JSPForward或客户端重定向时指定值

当显式的forward到新页面时,使用OAPageContextsetForward*()方法或调用OAPageContext.sendRedirect()请求客户端重定时,可以随意设置请求的参数值.

调用OAPageContext.putParameter()指定参数值指定参数值

OAPageContext包含了一个putParameter()方法,它可以在页面是过程中传递

值到webbean结构中.通过调用putParameter()指定的值技术上来说并不是加到

request中的,而是存储于特殊的页面缓存中.技巧:技巧:可以把这个方法与servlet2.1API中的HttpServletRequest.setAttribute()方法等同起来.

申明URL参数

可以在JDeveloper中开发时指定URL参数.警告:警告:URL长度是受限的;对于添加大量URL 参数要谨慎注意它的长度.由于URL对于用户是可见的,要注意加密敏感的数据.

状态持久化模型(Passivation')状态持久化模型('钝化Passivation')

OAFramework应用主要是事务导向的.许多事务跨越了多个页面,这些页面的事务需要某种机制保持到用户完成相关的任务.HTTP协议天生就是无状态的;它不保留任何应用状态信息或保证状态的持久化.甚至,即使是在JVM实例提供的servletsession失败或servletsession超时后,应用状态也将丢失,挂起的事务也不能恢复

.OAFramework具有透明的保存和恢复客户端状态的能力——即使servletsession超时(未来的版本将提供JVM失效的支持):

将应用状态保存到辅助介质上的过程叫作钝化(passivation).从辅助介质上恢复状态的过程叫作激活(activation).

OAFramework当前提供了下面的状态管理功能.

可伸缩的应用当资源占用比较高的情况下,需要为新的服务线程创建新的资源,OAFramework 将保存挂起的线程的状态并回收它们的资源以供其它用户使用.当挂起的用户线程被唤醒后,保存的应用状态被恢复.简单来说,内在被重新分配给JDBC连接,应用模块,用户session而不会影响用户的使用.Servletsession超时恢复servletsession允许超时,而不需要强制用户启动一个新的事务.(将来,这个功能将扩展为支持中间层失效)

应用模块池

为提高性能和可伸缩性,OAFramework池化(缓存和重用)应用模块.重用比重新创建更有效. 每个JVM有一个应用模块池管理器,它包含并管理各个应用模块池.每个应用模

块池包含多个同一应用模块的实例.应用模块池中的实例被设计为可以置为可用或不可用(现在被称为"checkedout").只有根应用模块被池化;嵌套的应用模块不会被池化为根应用模块的子应用模块.

应用模块池:

设计模型对象

客户/服务代码分离

在OAFramework的MVC框架中,OAFramework划出了客户端和服务端类的清析界限,典型的JSP应用有3个物理层浏览器web应用服务(中间层包含UIwebbean结构和应用业务逻辑)数据库服务器

在中间层OAFramework对"客户端"和"服务端"类划出了界限:

客户端类(视图类和控制器代码)驱动HTML用户界面.服务端类(模型代码)支持任何客户端(不只是OAFramework)用户界面.

这个区别是非常重要的,它保证了从不同客户端访问服务代码的能力.OAFramework"洋葱形"的代码层次边界:

page10通常可以在这些边界征用,对象引用下层的数据流,而不会引用上层的.

模型代码不应该直接引用控制器代码.不要在客户端引用或导入任何服务端的实现类或接口(位于oracle.apps.fnd.framework.server包中的类和接口)如果需要服务端代码执行一些操作,应该一直通过使用根应用模块接口(oracle.apps.fnd.framework.OAApplicationModule)调用根应用模块的通用远程方法调用invokeMethod()方法,或者为你的应用模块创建一个接口,以便于在编译时检查方法的调用.应用模块可以代理或实现所需要的逻辑.

注意:注意:OAApplicationModule接口位于oracle.apps.fnd.framework包中,所有位于这个包中的类,接口,异常都可以在客户端和服务端代码中使用如果选择为你的应用模块创建接口而不是使用invokeMethod()方法,应该在应用模块所在包的直接上级包中创建.比如,为

https://www.doczj.com/doc/be11231430.html,bsolution.server.EmployeeAMImpl所创建的接口EmployeeAM应该位于https://www.doczj.com/doc/be11231430.html,bsolution包中.

永远不要直接在客户端代码中包含JDBC或其它服务端处理的代码.如果UI客户端需要服务端的信息,它应该通过应用模块,由应用模块代理或实现适当的响应.

保持编码规范一致

阅读下面的文章: OracleApplicationJavaCodingStandardsOracleFrameworkNameing/File/Package/DirectoryStructur eStandards

OracleFrameworkModelCodingStandards

推荐的构建方法

编写OAFramework应用模块时,按下面的流程编写会简单一些.

1.创建BC4J模型对象所需要的业务组件包.

2.实现公布的BC4J应用模块,实体对象,实体关联对象和页面所需要的视图对象和视图链接义.将视图对象添加到根应用模块中.这一步不要担心编写代码.

3.创建应用的菜单定义.

4.为页面创建OA用户界面组件.

5.创建和实现控制器代码.

6.为页面实现UI应用模块代码.

7.实现实体对象业务逻辑.

业务组件包

包有BC4J模型组件必须属于业务组件包(BusinessComponents(BC4J)).如果要修改已经存在的BC4J包使用的数据库连接,可以如下操作:

1.2.3.4.5.选择OAProject中的业务组件包.右键,选择EditBusinessComponentsProject.在BusinessComponetsProjectWizard中,选择Connection.指定新的数据库.选择OK保存修改.

实体对象

实体对象为指定的表,视图或同义词实现业务规则.实体对象被确定为用于多种客户端,应该处理与表相关的校验和行为.

每个表应该只有至多一个实体.实体对象应该在它的属性中包含表中的所有列.

可以创建自己的公用实体对象.通常需要为实体添加对象初始化,属性校验,实体级的验证和其它功能性的行为.也可以在综合性的业务对旬中创建"entityexpert"的单例对象用于在多个相关实体对象间共享.比如,定购单有定单头,定单行和销售信息.其它相引用的实体可以使用entityexpert来执行轻量的校验(比如,定单可能需要使用供应商的entityexpert检查自己所使用供应商id是否有效).最后,你可以根据需要为模型代码创建"helper"对象和接口.比如,OAFramework在的ToolBox教程中,你可以创建一个或多个helper对象在多种实体对象上执行处理.

实体关联(关联对象)实体关联(关联对象)

关联可以创建实体之间的关系.在运行时,BC4J使用这些关系来协调相关的对象.有两种基本类型的关联:

聚合这是强关联,源实体对象拥有目标实体对象.也就是说,目标不能离开源对象独立存在.比如,定单头由多个行组成,离开它们的头信息后就没有含义了.引用这是弱关联,源对象只引用目标实体.比如,定单引用供应商,但供应商在没有被定单引用的时候仍然可以存在.

page11聚合关系适合于在运行时创建,初始化和管理.BC4J自动将聚合作为一个逻辑单元.比如,定单对象将在修改它的条目时被锁定.引用关系适合于在运行时候修改,引用.比如,在定单和供应商之间建立关联,如果在编辑定单时可以修改供应商,并不需在供应商和货品条目间建

立关联.

编程控制

关联对象没有代码,并不需要为它们编写代码.

视图对象和视图行

视图对象包含了数据库查询,通过它可以访问相关的实体对象.关于视图对象的设计的重要决策就是它是应该基于SQL还是实体对象.

所有锁碎的UI视图对象,比如ListsofValues(LOV)和poplists等基于SQL.所有验证性的视图对象,用于为实体对象实现简单业务规则的基于SQL.为UI创建的视图对象,不管它们是否可以更新,应该基于实体对象.

基于性能的原因,视图对象需要被优化.在一些UI组件中,创建多个小型的处理特定任务的视图对象优于共同一个单一的大型的视图对象.视图对象应该是为UI而定制的.只要可能就应该避免使用动态WHERE子句(视图对象支持用编程的方式修改它的定义).如果可能,为相同的SELECT定义3个不同的视图对象,每个带一个WHERE子句,用于在运行时绑定.但是,在复杂查询时修改WHERE子句是合适的,因为不可能为所有可能的查询定义独立的视图对象.视图对象,与任何BC4J对象一样,可以用申明的方式或编程的方式创建.基于性能的原因,如果可以的话通过申明的方式定义视图对象.所有视图对象都是o

racle.apps.fnd.framework.server.OAViewObjectImpl的子类.视图对象有SQL视图对象,实体视图对象和混合视图对象.主键几个所有视图对象都需要主键.可以在定义属性时指定主键,或者通过编程的方式调用OAViewObjectImpl类的setKeyAttributeDefs()方法设置主键.

编程控制

查询处理每个视图对象都实现了查询,如果需要,它应该能够翻译传递进来的参数,并将它绑定到WHERE子名中的变量上.在编码上通常处理这个工作的方法被命名

为initQuery()或其它类似initNameEmployeesQuery()之类的"init"方法上.注意:

注意:必须使用Oracle风格的参数绑定方式(FOO>=:1)而不是ANSI风格的(FO

O>=?).尽管代码只复杂一点点,OAFramework团队计划在Fusion版本中不支持ANSI风格的绑定.下面是修改WHERE子名和绑定查询条件的例子://InitializeandexecutethequerypublicvoidinitQuery(Stringname,StringonHold,Stringnumber){S tringBufferwhereClause=newStringBuffer(100);Vectorparameters=newVector(3);intclauseCount= 0;intbindCount=0;setWhereClauseParams(null);//Alwaysresetif((name!=null)&&(!("".equals(nam e.trim())))){whereClause.append("NAMElike:");whereClause.append(++bindCount);parameters.a ddElement(name+"%");clauseCount++;}if((number!=null)&&(!(""Equals(number.trim())))){Numbe rsupplierId=null;//SUPP

LIER_IDisaNUMBER;datatypesshouldalways

//match,andtheparameterpassedtothismethodisa//String.try

{supplierId=newNumber(number);}catch(Exceptione){}if(clauseCount>0){whereClause.append("A ND");}whereClause.append("SUPPLIER_ID=:");whereClause.append(++bindCount);parameters.ad dElement(supplierId);

clauseCount++;}if((onHold!=null)&&(!(""Equals(onHold.trim())))){i

f(clauseCount>0){whereClause.append("AND");}whereClause.append("ON_HOLD_FLAG=:");wher eClause.append(++bindCount);parameters.addElement("Y");clauseCount++;}setWhereClause(wh ereClause.toString());if(bindCo

unt>0){Object[]params=newObject[bindCount];//thecopyInto()is1.1.8compliantwhich,asof4/02/0 3,isrequiredbyARUparameters.copyInto(params);setWhereClauseParams(params);}executeQuery ();}//endinitQuery()

业务逻辑视图对象不适合放置业务逻辑;不应该在视图对象或视图行对象编写校page12验规则.视图行尽管应该总是创建视图行对象,但很大程度上,你不需要编写视图行代码.视图行代码用于需要计算临时属性的的情况下.比如,你不能或不希望在查询中包含逻辑(可能性能开销太大).你可以使用视图行代码执行简单的校验或添加用于UI的临时性变量,或者调用实体对象的自定义方法.自定义视图行方法不能直接从客户端访问.客户端必须先在应用模块中调用一个方法,由它将任务委派给视图对象.由视图对象来访问视图行.此外,对于有视图行类的应该使用生成的setter/getter方法.因为它比调用通用的setAttribute("")和getAttribute("")更快.

视图链接

与上面描述过的实体关联类似.视图链接定义了两个视图间的关系,通过它BC4J能自动从当前的源视图对象查询到相对应的目标视图对象.视图链接可以基于关联对象或者申明两个视图对象间的join链接.比如,两个表有基于外键的主从关系.相应的实体对象通过关联对象关联,基于这两个实体的视图对象可以通过基于关联对象的视图链接相关联.尽管视图链接可以非常方便,但在web应用页面上应该保守的使用.因为它缓存了主表和从表的记录,当用户从一个主表记录移到另一个主表记录时,

这个开销可能相当大.使用视图链接通常只在下面的情况:

当特定的beans(比如HGrid)需要.当你有一个可更新的主/从视图对象(在同一个页面或不同的页面),这们下面的实体对象是使用聚合关联的,你必须在他们之间定义视图链接.当你在同一个页面上有一个只读的主/从视图对象时,导航到一个主记录行的时候将导致自动查询子对象.

编程控制

由于视图链接没有实现类,所以不需要编写代码.但可以使用oracle.jbo.ApplicationModule.createViewLinkBetweenViewObjects动态创

建视图对象.注意:编程方式产生的视图链接中的主/从视图对象必须属于同一个应用模块注意:实例.

应用模块

这里介绍的是应用模块创建/重用的基础.

应用模块使用

下面列出来在应用中的应用模块的承担的角色:

UI根应用模块(UIRootApplicationModule)为一个或多个相关的UI页面建立事务环境.每个页面有一个根应用模块它可以包含任何视图对象或这个页面使用的嵌套应用模块.UI共同区域应用模块(UISharedRegionApplicationModule)任何用于在多个页面使用的UI区域(region)应该包含自己的应用模块.当这个区域在页

面中使用时,OAFramework自动嵌套于页面的根应用模块之下.UIListofValues ApplicationModule这是前一个角色中的一种特殊情况.当创建ListofValues(LOV)视图对象时,你将这些组件添加到一个应用模块中用于获取LOV集合.验证应用模块(ValidationApplicationModule)校验应用模块聚集相关视图,执行轻量级的SQL校验.实体对象或experts使用校验应用模块,它与用户界面无关.

应用模块是oracle.apps.fnd.framework.server.OAApplicationModuleImpl的子类.重要:重要:如果你没有完全实现和保证页面的钝化支持,就不要设置应用模块的RetentionLevel为MANAGE_STATE.可以在应用模块属性的Peoperties页,创建一个属性,属性名为RETENTION_LEVEL,属性值为MANAGE_STATE.生成应用模块接口产生应用模块接口可以便于编译时检查,而不用使用invokeMethod()来调用,可以在应用模块编译页面,选择ClientMethods 启用invokeremotely选择好Availablelist.

编程控制

不要将数据校验等业务逻辑放在应用模块中;这些应该放在下层的实体中.应用模块适合放下面的逻辑:

访问任何BC4J相关的对象.执行多种服务端动作,或者跨多个视图对象的单个事件或方法调用.从服务端返回客户端从OAPageContext访问不到的值.调用特殊的PL/SQL程序.技巧:技巧:如果PL/SQL程序是用于处理单行(或行的集合)时你应该使用基于PL/SQL的实体对象.

方法命名任何直接用于UI支持的应用模块中的方法应该命名为相应的UI"epage13vents".比如,如果用户按了Create按钮,应用模块方法应该被命名为"create".实体对象创建下列描述了应用模块方法创建新插入一行到SuppliersVO视图对象.这个视图对象是基于SupplierEOImpl 实体对象的,因此BC4J在行被创建时在幕后处理这些.publicvoidcreateSupplier(){OAViewObjectvo=getSuppliersVO();

Rowrow=vo.createRow();vo.insertRow();//AsspecifiedinOAFramework ModelCodingStandards,newrowstatetoSTATUS_INITIALIZED.row.setNewRo

wState(Row.STATUS_INITIALIZED);}视图对象查询下面显示了一个应用应用模块方法查询SuppliersVO视图对象,用于搜索客户端设置的条件.publicvoidquery( StringsupplierName,StringonHoldFlag,StringsupplierNumber){Suppliers

ExpVOImplvo=getSuppliersExpVO();if(vo==null){MessageToken[]token

s={newMessageToken("OBJECT_NAME","SuppliersExpVO")};thrownewOAExce

ption("ICX","FWK_TBX_OBJECT_NOT_FOUND",tokens);//setthe

}vo.initQuery(supplierName,onHoldFlag,supplierNumber);}//endqu

ery()

下面的例子显示了当用户导航到页面上时初始中化页面.publicvoidinit(St

ringstatus){PoSimpleSummaryVOImplvo=getPoSimpleSummaryVO();if(vo=

=null){MessageToken[]tokens={newMessageToken("OBJECT_NAME","PoSim pleSummaryVO")};thrownewOAException("ICX","FWK_TBX_OBJECT_NOT_FOUND",t okens);}//FollowsBackButtonstandardofneverperformingablindquer

ywithout//checkingtoseeifthisisnecessary.if(!vo.isPreparedForEx

ecution()){vo.initQuery(status);}}//endinit()

实体删除/***DeletesapurchaseorderfromthePoSimpleSummaryVOus

ingthe*poHeaderIdparameter.*/publicvoiddelete(StringpoHeaderId){

//First,weneedtofindtheselectedpurchaseorderinourVO.//When

wefindit,wecallremove()ontherowwhichinturn//callsremoveon theassociatedPurchaseOrderHeaderEOImplobject.intpoToDelete=Integer.

parseInt(poHeaderId);OAViewObjectvo=getPoSimpleSummaryVO(); PoSimpleSummaryVORowImplrow=null;//Thistellsusthenumberofr owsthathavebeenfetchedinthe//rowset,andwillnotpulladditional

rowsinlikesomeofthe//other"getcount"methods.intfetchedRowCoun

t=vo.getFetchedRowCount();//////rows//Weuseaseparateiterator-

-eventhoughwecouldstepthroughtherowswithoutit--becausewedon' twanttoaffectrowcurrency.Notethattherearealsoconveniencemethod sforfindingmatchinginaviewobject(seejavadoc).

RowSetIteratordeleteIter=vo.createRowSetIterator("deleteIter");if

(fetchedRowCount>0){deleteIter.setRangeStart(0);deleteIter.setRangeS

ize(fetchedRowCount);for(inti=0;i

oSimpleSummaryVORowImpl)deleteIter.getRowAtRangeIndex(i);//Forperforman cereasons,wegenerateViewRowImplsforall//ViewObjects.Whenweneed toobtainanattributevalue,//weusethenamedaccessorsinsteadofa genericStringlookup.//NumberprimaryKey=(Number)row.getAttribute("He aderId");NumberprimaryKey=row.getHeaderId();if(https://www.doczj.com/doc/be11231430.html,pareTo( poToDelete)==0){row.remove();getTransaction().commit();break;//onl yonepossibleselectedrowinthiscase}}}deleteIter.closeRowSetItera

tor();

}//enddeletePurchaseOrder()

自定义的动作"Approve"自定义的动作"Approve"这里描述了如何查找到视图对

象的行并调用自定义的实体事件./***StepsthroughthePOSimpleSummaryVOto lookforselectedrows.For*eachselectedrow,thiscallstheapprove(

)methodonthe*PurchaseOrderHeaderEOImplclass.*/publicvoidapproveP urchaseOrders(){//TocallacustommethodonanEntityObjectyoushou

ldaddawrapper//intheVO's*RowImplclass(see//oracle.apps.fnd.fra

page14mework.toolbox.schema.server.PoSimpleSumaryVORowImpl).OAViewObjectvo= getPoSimpleSummaryVO();PoSimpleSummaryVORowImplrow=null;intmatches=

0;////////rows//Thistellsusthenumberofrowsthathavebeenfe

tchedintherowset,andwillnotpulladditionalrowsinlikesomeofth eother"getcount"methods.Notethattherearealsoconveniencemethods forfindingmatchinginaviewobject(seejavadoc).

intfetchedRowCount=vo.getFetchedRowCount();//Weuseaseparatei

terator--eventhoughwecouldstepthroughthe//rowswithoutit--bec

ausewedon'twanttoaffectrowcurrency.RowSetIteratorapproveIter=vo

.createRowSetIterator("approveIter");if(fetchedRowCount>0){approveIt

er.setRangeStart(0);approveIter.setRangeSize(fetchedRowCount);

for(inti=0;i

electedcheckbox,wewantcall//theapprove()wrapperonthePOSimpleSu mmaryVORowImplwhich//inturncallstheapprove)methodonthePurchase OrderHeaderEOImpl.row=(PoSimpleSummaryVORowImpl)approveIter.getRowAtRan geIndex(i);//Forperformancereasons,wegenerateViewRowImplsforall/

/ViewObjects.Whenweneedtoobtainanattributevalue,//weusethen amedaccessorsinsteadofagenericStringlookup.//StringselectFlag=

(String)row.getAttribute("SelectFlag");StringselectFlag=row.getSelectF

lag();if("Y"Equals(selectFlag)){row.approve();matches++;}}}appro

veIter.closeRowSetIterator();//Iftheuserdidn'tactuallyselectanyro

ws,displayanerrormessage.if(matches>0){getTransaction().commit()

;}else{thrownewOAException("ICX","FWK_TBX_T_SELECT_FOR_APPROVE");}

}//endapprove()

提交CommitExample/**

*Providesa"commit"wrappersoUIcontrollercodedoesn'tneedto* getahandletothetransactionitselfwhichisaviolationofthe*clie

nt/severtierseparationrules.*/publicvoidapply(){getTransaction().

commit();}//endapply()

测试应用模块

在应用模块中添加完视图对象后,可以使用BusinessComponentBrowser(BC4JTester)在为它们构建UI前执行视图对象,或者编写代码支持BC4J对象.EntityObjects,EntityExperts,'Validation'ApplicationModulesand'Validation'ViewObjects

这节介绍这些对象在一个应用中所扮演的角色.

ValidationViewObjectc

在实体对象中实现业务逻辑时,经常会发现需要执行一些简单的SQL语句,而不是纯校验目的.在执行这种SQL之前,你可以使用SQL语句动态创建一个视图对象,或者先定义一个视图对象.实现从实现的角度来看,ValidationViewobject与正

规的viewobject没有区别;这们的主要区别是在使用上. ValidationApplicationModules(VAMs)

预先定义的视图对象必须被赋给应用模块以便在运行时被访问.也就是说,视图对象不能存在于应用模块环境之外.

由于实体对象(和他们的关联校验视图对象)可以被多个UI客户端(根应用模块可以当作客户端)共享,它不适合为具体的页面包含视图校验功能.将这些有用的视图对象进行分组,便于重用,并为每个业务逻辑对象创建一个validationapplic

ationmodule包含它们.业务对象可以是实体对象聚合的顶级定义,或者是一个单独的实体对象.比如OAFrameworkToolBox教程中定单由3个实体组成,但PurchaseOrderHeaderEOImpl类描绘出了定单业务对象.比如,在OAFrameworkToolBox教程中,我们创建了业务对象级的校验应用模块PurchaseOrderVAM并将所有定单校验视图对象添加给了它.实现从实现的角度来看,validationapplication对象与正规的应用对象没有区别;只是使用方式的不同.创建validationapplicationmodule

page15并把相关的validationviewobjects关联给它.

EntityExperts

entityexpert被定义为一个单例对象,是业务对象一个特殊的分支(聚合中的顶级实体对象,或一个单独的实体对象)它包含有能被拥有它的业务对象调用,.或者被其它业务对象调用的简单校验例程.比如,PurchaseOrderHeaderEOImpl类不需要整个SupplierEOImpl类,只需要查找出外键supplierId是否有效.因此,它调用了supplier的entityexpert单例对象的isSupplierIdValue(NumbersupplierId)

方法,这是一个更加轻量级的操作.实现创建entityexpert,先创建一个oracle.apps.fnd.framework.server.OAEntityExpert的子类.然后将它关联到一个实体对象上.注意:注意:对于聚合类的业务对象,将expert关联到顶级的对象上.否则关联到单独的实体对象. 重用业务对象

EntityObjects,Associations,ValidationAMs,ValidationVOs,Entity

Experts

如果希望创建可重用的EntityObjects,Associations,Validation

AMs,ValidationVOs,EntityExperts,应该知道下面的规则:

下层数据库方案的拥有者,拥有对应的EntityObjects,Associations,ValidationApplicationModules,ValidationViewObjects,和EntityExperts.拥有业务对象的产品团队必须编写并发布相应的文档供其它产品团队重用.当你创建包括你的EO和另一个产品团队的OtherBaseEO的关联对象时,在创建关联前,你必须继承OtherBaseEO到你的产品空间中(OtherExtendedEO),并将关联建立在EO和OtherExtendedEO 之间.另一个产品团队使用你拥有的业务对象时应该要继承你提供的校验

.那种情况下,消费产品团队应该继承EntityObject,ValidationApplicationMod

ule,ValidationViewObject和EntityExpertand包括扩展的自定义代码.继承校验方法时,确保在继承的校验方法的开始位置调用了super().

扩展业务对象下表描述了创建业务对象和关联到需要扩展的校验时要的相关对象.

第一行列举了定义实体时所有可能创建的对象.第一个格子说明了创建一个实体对象时将产生两个文件:元数据定义的XML文件,和实际的Java实现类文件.实体对象处理属性级和记录级的校验.这些校验通常需要使用ValidationViewObjects(VVO).校验对象在ValidationApplicationModule(VAM)中分组.与实体对象类似,创建VVO和VAM产生了元数据定义XMl文件,并为每个对象产生了Java实现类文件.最后,实体对象有时会接收辅助类提供的一些服务,为实体对象提供的验证服务.辅助类是EntityExpert通过实体对象的属性连接到实体对象.上图描述了所有业务对象继承时的情况.虽然并不总是这样.多数情况下,将对继承的结果满意.注意,不应该修改蕨类的定义或复制基类.应该使用继承.

页面

创建页面的基本步骤是创建pages,region,items.

PageLayoutRegion的关键属性

创建一个pageLayout区域时,应该特别注意下面的属性:

AutoFooter将这个设置为true以保证在页面上有应用的保密和版权说明链接.HelpTarget如果你需要为当前页显示帮助按钮,必须在这里指定帮助文件(通常是文件名).AMDefinition用于设置页面的根应用模块.必须使用类的全名,比如:oracle.apps.fnd.framework.toolbox.tutorial.server.SearchAM

FunctionName总是设置页面的保密函数WindowTitle浏览器窗口标题Title显示在pageheader 中的文本.Form在pageLayout中设置为true,这通常是默认设置,不要在其子对象中添加亲折form.OAFramework在同一个页面中只支持一个form.pageLayoutComponents注意OAFramework页面基础一文中提到的,页面包含了特殊的被命名的组件,其中一个就是标识图案.为了在页面关联标识图案,选择pageLayout区域或pageLayoutComponents节点,然后右键菜单中选择创建imagei

tem,并把它的ImageURI属性设置为.gif.

Item的关键属性

page16每个item类型都有自己的一套属性,不可能每个都介绍,这里介绍一些通常的公共属性.

Extends说明新的item继承于一个已存在的item.AttributeSet命名了的item的属性集合.DestinationURI对于支持页面导航的对象,这个是导航的目标,比如:OA.jsp?page=/oracle/apps/fnd/framework/toolbox/tutorial/webui/PoDetailsPG&retainAM=Y.( ClientAction)ActionType标明item是否可以提交表单,或者产生局部页面渲染事件(partialpagerendering(PPR)).CSSClass指定item使用的样式表.(多数item,UIX将把这个值按BLAFUI指导方案中的值设置).

Rendered指明相应的对象是否包含了webbean层级结构,需要UIX将HTML发送给浏览器渲染.对于多数item来说,这用于指定一个item是否显示,但有些item是不会实际显示出来的(比如隐藏域),实际上是指定对象是否存在于页面上.ViewInstance让item绑定到下层的视图对象上以便读写数据,这里标明将item绑定到哪个视图对象实例(包含在一个应用模块中的).ViewAttribute将视图对象实例的属性与item绑定.AdminPersonalization决定是否允许系统管理员进行个性化定制.UserPersonalization决定是否允许用户个性化定制.InitialValue定义item的缺省值.

SimplestPossibleExpressionLanguage(SPEL)对于所选的属性,OAFramework支持使用SPEL表达式快速的将属性绑定到下层数据源提供的属性值上.比如,你可以将按钮的Rendered属性绑

定到一个视图对象的属性上以检查是否需要显示或隐藏.属性中使用的SPEL语法如下:${oa..}技巧:技巧:SPEL是一个业界标准的表达式语言,它包含于JSTL中.

组件重用

OAComponent开发环境所宣称的一项关键优势就是可以重用通用的page,region,item定义. Regions共享

可以按下面的步骤创建共享的region.注意:注意:共享region可以包含一个或多个子region. 顶级共享region必须保存在它的XML文件中.可以将共享region设置为接收其它region的值.值可能通过"状态管理"一文中描述的方式通过请求传递,或者使用页面事务缓存的值.共享region必须处理失效的情况.比如,如果没有合适的参数传递到region,共享region应该接收或者抛出一个有意义的异常.如果region的scope被设置为Public:o顶级region必须有自己的应用模块.应用模块应该包含与这个region相关的视图对象.o顶级region必须有自己的控制器.如果需要可以为子region添加控制器.共享region必须添加完整的注释文档.

特殊情况:特殊情况:LOVLOV与共享region的区别:

LOV不需要关联控制器当在页面上使用LOV时,并不从它继承,而是将页面字段的ExternalLOV 属性配置为页面与LOV的数据交换.

Pages共享

page实际上只是顶级region为共享region的pageLayout组件.共享page与共享region的创建过程类似.

如果要重用一个单独的page或pageflow,只要简单的创建一个新的菜单功能并将它指向主页面.如果需要将页面插入到另一个使用了不同根应用模块的pageflow,则必须创建一个新的page,并继承共享的page的pageLayoutregion下的内容.记住正确设置将新页面的根应用模块. Items共享可以从任何区域的单个item继承,尽管我们推荐将准备重用的item放到一个重用region中.共享容器region将确保不会任意的修改item而不明确这样修改将影响使用这个item的页面.通过设置item的Extends属性设置共享.

属性集AtributeSets

属性集是一个命名了的可重用的属性集合,可以用于任何OA组件,包括regions,items和其它属性集.它被设计为可以在整个OracleApplication中可以重用的组件,它有效的节约了Oracle 和其客户的开销.

page17Oracle节约了翻译和管理的开销客户可以更快的定制应用的全局个性化效果.另外,少数UI元素占用更少的中间层内存,提高了性能和伸缩性.

通常,attributessets被组织到OA组件包中(独立的XML包文件中),这个包与数据训表对应,一个包对应一个表:

包名与不带下划线的数据库表名对应.比如,在OAFrameworkToolBox中,有一个表FWK_TBX_PO_HEADERS.对应的属性集包名为FwkTbxPoHeaders.各个属性集是为了显示表中各个列而设置的.基于列的属性集命名与列一致.比如,在FWK_TBS_PO_HEADERS表有一个名为HEADER_ID的列.对应的属性集被命名为HeaderId.如果多个属性集对应于同一个列(这个值被用于不同的情况并使用了不同的prompt属性)时根据实际使用的位置使用不同的前缀来区分.属性集也可以包含通用域头部和按钮等的设置.命名则使用与它们相关联的标签.

使用属性集

在下面的情况下使用属性集:

所有的items都与table.column数值关联.比如,供应商查询字段和数据列表中的供应商字段可以使用同样的属性集.所有通用按钮(确定,应用,退出等等).这种情况下也可以继承按钮的快捷键.

技巧:技巧:OAFramework通用按钮属性集包位于/oracle/apps/fnd/attributesets/Buttons/.

所有通用表格动作列(像删除,修改等等)应该使用相应的OAFramework按钮属性集.

产品中任何通用的按钮;不应该为单独使用的按钮创建或使用属性集.产品中任何共同区域的头部;不应该为单独使用头部创建或使用属性集.

在item上使用属性集:

item的AttributeSet属性可以设置它的属性集.

将光标放在AttributeSet字段,使用PropertyInspector的SettoDefault按钮可以清除属性集.编程方式访问属性集可以在控制器中访问属性集.比如,下面代码显示了如何保留通用的Create 控制属性集的prompt属性.importoracle.apps.fnd.framework.webui.AttributeSet;……publicvoidprocessRequest(OA PageContextpageContext,OAWebBeanwebBean){super.processRequest(pageContext,webBean);A ttributeSetattrSet=newAttributeSet(pageContext,"/oracle/apps/fnd/attributesets/Buttons/Create ");StringcreatePrompt=(String)attrSet.getAttributeValue(pageContext,PROMPT_ATTR);}

参数:Tokens,Encryption,URL参数:Tokens,Encryption,Encoding

Tokens

当在页面定义中指定URL参数时,可以直接指定字符串值或使用token-substituted值,在渲染时它保留了从相关的视图对象的属性(item与视图对象绑定的情况下).这是很常见的,比如,在表格的列中传递主键到明细页面以便于查询.TokenSustitution的例子(使用了视图对象的"OrderNum"属性):OA.jsp?OAFunc=FWK_TBX_T_PO_PAGE&order={@OrderNum}

产生的链接为:

OA.jsp?OAFunc=FWK_TBX_T_PO_PAGE&order=123Token类型Tokens使用了特殊的字符前缀告诉OAFramework如何获取值.

{!Attr}当URL中存在{!}时将加密属性值(比如,OA.jsp?……&ssn={!SSN}&…

…).使用OAPageContext.getParameter("ssn")将返回解密后的值.{@Attr}当URL中存在{@}时属性值将被编码(比如,OA.jsp?……&addr={@EmpAdd}&……).使用OAPageContext.getParameter("addr")将得到解码后的值.{$attr}原tokensubstitution(不进行编码和加密)因此你必须确保参数值不会打断URL.{@@RETURN_TO_MENU}可以用于指定应用组件的DestinationURI属性,如果你希望用户返回EBS套件的个人主页.如果需要在执行JSPforward时指定这个,可以使用常量OAWebBeanValues.RETURN_TO_MENU_URL.{@@RETURN_TO_PORTAL}用于指定组件的Destination

URI属性,以便让用户返回Portal页.JSPforward中可以使用常量OAWebBeanVa

lues.RETURN_TO_PORTAL_URL.在page18编码

任何为请求指定的参数必须遵循HTTP语法规则.比如,不能在URL参数值传递空格;当访问的URL中包含:buyerName=JohnDoe时将产生运行时错误.为修正这个错误,我们将对这些值进行编码,编码将替换有问题的字符,将值变为:byerName=John%20Doe.

当OAFramework添加参数到请求中时(比如表字段的值),它将对它们自动编码.当调用setForward*方法设置参数时,OAFramework将自动编码.当你自己组装URL参数时(比如,通过调用setDestination方法设置某个bean的URL时),必须对字符串中可能出现的非法字符进行编码.可以将字符串传递给oracle.apps.fnd.framework.webui.OAUrl工具类的encode方法进行处理.

技巧:技巧:如果手工设置URL参数不包含非法字符(比如,"value=Y")则不需要担心编码的问题. 当使用OAPageContext.putParameter设置参数时,如果需要也必须对字符串进行编码.

当使用OAPageContext.getParameter*方法时OAFramework将自动解码参数值,下列情况除外: 当为JavaScript函数tokens使用"#"字符时,OAFramework对token值编码

相关主题
文本预览
相关文档 最新文档