2009年6月3日星期三

博客搬家通知

     终于还是对GFW忍无可忍了,不知道Blogger何时才能解封,已经不报有任何幻想,在购买了域名、空间并进行备案后,决心转到了自己的独立域名网站(www.eleven-china.com)上去了,新站点名字将仍叫Dive into Technology ,这边的内容也将于近期搬过去,这里不出意外的话以后将不再更新或定期批量更新,希望朋友们能一如既往地关注和支持:)。

2009年5月10日星期日

Oracle Application Development Framework 简介

1.1    概述

    Oracle Application Development Framework是Oracle Fusion中间件体系架构的重要组成部分,是一个端到端的J2EE开发框架。ADF框架通过提供实用级别的基础架构服务和虚拟的声明式开发体验,从而简化了J2EE开发。不同于其他开源开发框架,Oracle ADF提供了一个包含Business Service、Model、View、Controller的完整MVC实现,在企业应用架构的每一个层次都提供了支持。

1.2    Oracle ADF 11g框架简介

    ADF架构图:
    如架构图所示,Oracle ADF 11g分别提供了MVC架构中每一层次的实现,并允许在不同层次使用不同的技术。如可以使用ADF Business Components构件Business Service层,使用structs构建Controller层等。这里主要描述使用Oracle ADF对MVC框架的实现构建,即Business Service层使用ADF Business Component,Model层使用ADF Model,Controller层使用JSF,View层使用JSF/ADF Faces。

1.2.1    View 层

    最简单的View层实现即为一个包含用户界面组件的页面,并允许该页面中的组件调用Model层中的方法。Oracle ADF为了提高View层的重用程度,引入了如下结构体系。
  • Page
    使用JDeveloper构建的Page即为最终向用户展现的Web 页面,其为Oracle 富客户端组件构建的基础。
  • Page Fragment
    Page Fragment的创建与使用与Page极其相似,对于开发人员来说,在JDeveloper中开发一个Page与开发一个Page Fragment基本没有什么区别。Page与Page Fragment的主要区别在于,Page Fragment并不是最终向用户展现的页面,它可以作为一个Page的组件所存在。在通常的开发场景下,常遇到部分页面的某部分布局和业务逻辑固定不变的情况。在ADF中可将其开发为一个Page Fragment,并将其作为页面组件放入所需Page中,以提高页面的可重用程度。
    得益于Page Fragment的可重用特性,在常见的应用场景中,并不需要为一个业务流程创建一组页面,而只需创建针对该业务流程的一个页面以及与其相对的一组Page Fragment即可。
  • Page Template
    Page Template可以用于构建Page 或 Page Fragment,并可将其上放置的ADF富客户端组件与Model/Controller绑定以执行业务逻辑。Page Template主要用于用于快速构建一组具有相同部分的页面。Oracle ADF开发人员可以创建一个模板,并基于模板创建Page或Page Fragment。
    在常的应用场景下,可以通过Page Template构建某应用的页眉、页脚、导航栏等,而将页面内容的构筑交予其他开发人员,进一步降低开发耦合度,提高团队协作水平。
  • Region
    Region是Fusion架构体系中新引入的概念,可以被应用于Page或Page Fragment。可以将Page Fragment或Task Flow作为Region放入Page中,而Page Fragment、Task Flow、目标Page将分别使用独立的上下文配置。
    常见的使用场景是使用Region构建页面内容,以实现导航菜单与页面内容的松耦合设计。
  • Contextual Event Framework
    Oracle ADF为实现View的松耦合设计,允许通过Context对页面富客户端组件添加绑定,以调用Controller或Model(Bussiness Service Application Model)中的方法,实现MVC架构中的调用关系。这种基于上下文的事件处理架构即称为Contextual Event Framework。
  • ADF富客户端组件
    在Fusion架构体系中,ADF提供了超过100种富客户端组件供开发人员在Page或Page Fragment上创建富用户交互界面。所有组件均基于JSF及AJAX技术构建。包括:
    • 页面布局控件
    • 表/树控件
    • List of Value控件
    • 输入控件
    • 导航控件
    • 输出控件
    • 查询控件
    • 数据图表组件

1.2.2    Controller层

ADF Controller是ADF应用的重要组成部分,用于控制用户交互及程序流的执行。其核心为Task Flow,包含如下内容:
  • Task Flow
    Task Flow任务流供开发人员定义一组Page或Page Fragment之间的流程及逻辑关系。Task Flow中的对象可视为一组活动(activities),如每一个加入Task Flow中的Page或Page Fragment均被视为一个视图活动(View activity)。当用户在一个Task Flow中的各个页面间跳转时,即可视为在各视图活动之间的跳转。亦可在Task Flow中添加其它类型的活动。Oracle ADF已经将Task Flow中的各种活动包装为组件供用户调用。
    Task Flow在Oracle ADF中包含两种类型的实现:Bounded Task Flow/Unbounded Task Flow。
  • Bounded Task Flow
    Bounded Task Flow是Oracle ADF框架支持的两种Task Flow实现之一。该类型的Task Flow支持事务处理和作为Region重用,具体具有如下特性:
    • 定义明确的事务处理边界;
    • 单个Task Flow入口及零至多个定义明确的Task Flow出口;
    • 支持PageFlow级别的变量传递,可以将定义的变量在Task Flow的各个活动间传递;
    • 允许为该Task Flow创建新的实例;
    • 允许在退出该Task Flow之前执行commit或rollback的操作;
    • 当该类型Task Flow被其他Task Flow调用时,允许在进入该Task Flow时传入参数作为PageFlow级别的变量;
    • 当该类型Task Flow被其他Task Flow调用时,允许在退出该Task Flow时返回变量。
  • Unbounded Task Flow
    Unbounded Task Flow与Bounded Task Flow的主要区别在于Unbounded Task Flow没有定义明确的边界,不支持将某活动定义为Task Flow的入口,亦不可将其作为Page的Region使用。每一个ADF应用中只包含一个Unbounded Task Flow。典型的应用情境是使用Unbounded Task Flow构造导航栏,调用Bounded Task Flow。
    注意,若一个ADF应用中定义了多个Unbounded Task Flow文件,编译时会对Unbounded Task Flow进行合并。若一个Unbounded Task Flow中的视图活动(View activity)被设置为bookmarkable时,则可通过URL直接访问这个视图活动。
  • Task Flow Template
    Task Flow Template提供了重用一个或多个Bounded Task Flow的方法。这里的重用包含两种机制:复制(Copy)和引用(reference)。

1.2.3    Model层

    Model层提供了访问源数据及业务逻辑的功能。在Fusion架构中,将源数据的访问与业务逻辑的访问分为两部分:Data Control与Business Service。Data Control使用Databinding文件连接View层与Business Service/源数据,是Model层的主要组成部分;Business Service主要分为Application Module和ADF Business Components,通过Data Control连接至View层。这种分离式的架构允许在View层已经创建的前提下为View层添加数据访问或Business Service访问。
  • Model
    • Data Control
      Data Control用于为Page或Page Fragment创建数据访问界限(Data Bounds),可以实现为诸如XML文件、Web Service或ADF业务组件。使用JDeveloper进行开发,当创建Page或Page Fragment时,会自动创建对应的Data Control。
    • Placeholder Data Control
      当进行Page或Page Fragment的UI开发时专用的Data Control,用于在界面建立后连接数据源。
  • Business Service
    在Fusion体系架构中,ADF业务组件(ADF Business Component)是主要的数据访问和业务逻辑来源。ADF业务组件,亦称为ADF BC,主要由以下几个部分组成:
    • Application Module
      Application Module(AM)定义了一组可更新的数据模型及顶层的可调用方法(亦称为Service Methods),是用户界面进行数据操作的接口。AM中包含View Object对象。
      为了简化应用集成的复杂度,可以为Application Module启用服务接口。这里的服务接口指的是一组允许第三方应用程序使用标准Web Service协议完成查找、创建、更新、删除业务数据的任务的可编程API。所有的业务验证规则均被封装在Entity Object中,并会在进行业务数据操作时自动进行验证。
    • View Object
      View Object是一条SQL查询的持久化对象,允许对SQL查询的结果进行操作。同时,View Object间允许通过建立连接(link)的方式创建主从(Master-Detail)结构。当用户从用户界面改变数据时,View Object会将数据改变传递至Entity Object触发对应验证规则和保存改变。
    • Entity Object
      Entity Object是数据库中某张表的某个行的持久化对象。Entity Object内部通过DML操作将数据改变反映至数据库。Entity Object支持通过建立Association的方式进行Entity Object之间的关联,并支持通过此方式反映数据源层次的表关系,如数据表的外键关联。


2009年4月27日星期一

ADF Validator

    实际应用中经常遇到对业务相关的数据进行Validate的情况。比如对输入数据进行格式限制/范围限制等。ADF为开发人员提供了相对灵活的解决方案。这里提供了几种Validator的不同实现方式。

    (下述均使用Oracle XE自带的HR示例中Employees表作为示例表)
  1. 使用EO层次的Validator

    首先,ADF框架中所有的Validator默认都使用EO级别的Validator。EO层次可以设置Entity级别的Validator或Attributes级别的Validator。

    选择相应的级别,点击界面上的加号即可创建Validator,ADF提供了灵活的Validator以供选择


    选择需要的Validator Rule Type,写入相应的验证规则后,即可在Failure Handling中写入验证失败的抛出消息。在此处设置的消息将写入资源文件中。


    最后,当VO被拖入页面时,对应控件将自动包含一个<f:validator>子控件,其绑定为EO层次的Validator。


  2. 在ManageBean中实现Validator

    ADF本身提供的Validator相对比较灵活,但当EO的重用程度比较高时(如不同的VO使用相同的EO,需要设置不同验证规则/不同弹出消息,甚至不同页面使用相同VO,需要不同验证规则),EO级别的Validator显然不能满足要求。则可以通过重写Validator并添加至页面控件的绑定以实现。
    <f:validator>绑定的对象为一个属性,所以首先应为该Validator创建一个实现Validator接口的Class,最简单的如下(可以写入更复杂的验证逻辑)

    public class testValidator implements Validator {
    public void validate(FacesContext context, UIComponent component,
    Object obj) throws ValidatorException {
    throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_WARN, "TEST", "TEST MESG"));
    }
    }

    在MB中创建一个该属性的实例,并构造相应的get/set方法如下

        private testValidator test = new testValidator();

    public void setTest(testValidator test){
    this.test = test;
    }

    public testValidator getTest(){
    return this.test;
    }

    最后,通过EL表达式将该属性绑定至<f:validator>

    <f:validator bindings="#{backing_ExpsProYbudgetUpdate.test}">


2009年4月24日星期五

Oracle ADF VO排序及VO的查询模式

    常规应用中,当需要使用Table向终端用户展示数据时,Table中数据的显示排序一致性极大程度的影响到了客户体验。通常希望诸如多次查询结果显示顺序相同、插入数据在原数据上方等的实现。

    ADF为开发人员提供了两种级别的排序,即数据库级别的排序及内存级别(In-Memory)的排序。需要同时使用这两种排序法,才能取得合适的排序效果。
    (使用Oracle示例数据库HR中的Employees表作为示例)

  1. 数据源排序
    编辑VO的Query,设置Order by字段,这里设置Manager作为排序字段
    需要注意的是,这里的排序只是针对从数据源选取数据时的排序,当对VO进行插入/删除操作时,修改并不会立即Commit至数据库,而是存储在EO/VO中,这就导致这种排序法对于不在数据库中存在实体行的数据是无效的,也是需要使用In-Memory排序方式的原因。


  2. VO的查询模式(View Object's SQL Mode)
    在开始VO的In-Memory排序之前,首先应该了解VO的查询模式。
    ADF中一个VO具有如下查询模式
    • ViewObject.QUERY_MODE_SCAN_DATABASE_TABLES
      VO的默认查询模式,该模式下VO每次executeQuery时会从数据库检索数据

    • ViewObject.QUERY_MODE_SCAN_VIEW_ROWS
      检索已经存在于VO的Row set中的数据,允许在此查询模式下使用VO的In-Memory Filtering

    • ViewObject.QUERY_MODE_SCAN_ENTITY_ROWS
      检索存储于EO缓存中的数据

    可以使用setQueryMode()方法进行VO查询模式的设置。可以单独设置一个查询模式或使用Java的OR(|)设置多个查询模式。例如
    setQueryMode(ViewObject.QUERY_MODE_SCAN_DATABASE_TABLES | ViewObject.QUERY_MODE_SCAN_ENTITY_ROWS)

    当设置多个查询模式时,会自动跳过重复行。
    设置过查询模式后,当执行executeQuery()方法时,查询模式的设置即可生效。


  3. In-Mamory排序
    使用setSortBy()方法进行针对VO的运行时In-Memory排序。setSortBy()方法的输入参数类似于SQL中的order by子句,不同的是将列名称替换为VO上的Attribute Name。例如
    setSortBy("ManagerId desc, EmployeeId");

    根据查询模式的设置不同,当执行executeQuery()时,setSortBy()会自动转换为相应的排序方法。如当使用数据库检索时,会将setSortBy转换为ORDER BY子句,当使用In-Memory查询时,会将setSortBy转换为SortCriteria对象。
    使用示例:
    vo.setSortBy("ManagerId");
    vo.setQueryMode(ViewObject.QUERY_MODE_SCAN_VIEW_ROWS);
    vo.executeQuery();

    只需要在如插入数据时执行该语句,即可完成In-Memory的排序功能。


  4. 自定义VO的排序方法
    当需要的排序方法比较复杂,使用setSortBy设置排序规则无法满足需求时,可以通过重写VO的public void sortRows(Row[] rows)方法和public Comparator getRowComparator()方法达成目的。其中sortRows方法即是进行In-Memory排序时执行的排序方法;getRowComparater方法返回一个Comparator类型对象,被VO的compareTo()方法调用。

2009年4月20日星期一

Weblogic开启关闭


概述
近日由于项目需要,花了些时间部署了我们开发的demo环境到客户公司,客户公司使用的是IBM的AIX操作系统,由于是ADF应用,应用服务器也就毫无疑问地选择了Weblogic。而在应用部署过程中,总结了一些比较有用的Weblogic启动和关闭的脚本。

实现
1、使用相关Telnet工具登录到远程服务器,创建将要发布应用的domain,这里名为demo_domain。
2、正常启动Weblogic:
cd到/bea/user_projects/domains/demo_domain/bin
使用命令./startWebLogic.sh启动Weblogic
此时,Weblogic可以正常启动,但是当使用ctrl+c或关闭当前窗口后,Weblogic即立刻停止,显然在正式应用中这样的方式一般来说是不符合要求的。
3、后台启动(以服务方式启动)Weblogic:
为解决上面描述的问题,需要在后台启动Weblogic,也就是经常提到的以服务的方式启动Weblogic,将信息输出到文件中,这里输出到demo.log。
#nohup ./startWebLogic.sh >demo.log 2>&1 &
在执行上面的命令后,将返回一个进程号,可以记录该进程号,当Weblogic无法正常关闭时,可以通过命令行结束进程。
4、一般来说,启动Weblogic时一般需要输入用户名和密码,在这里假定用户名和密码都是weblogic。当后台启动Weblogic时,输出信息到提示输入用户名时即停止,无法继续正常开启。为解决这样的问题,可以通过修改相应的启动脚本。在这里,我修改了bin目录下的setDomainEnv.sh,添加了如下代码:
WLS_USER=weblogic
WLS_PW=weblogic
JAVA_OPTIONS=-Dfile.encoding=UTF-8
5、停止Weblogic:
./stopWebLogic.sh
有时使用此命令无法正常停止Weblogic,经测试,这种现象还是经常发生的,在出现该状况时需要强行停止该进程。
首先使用ps –ef|grep java查看当前进程,找到该进程,当然,如果刚才已经记录了进程编号,这里就无需再进行查询。
查到后使用 kill -9 进程编号 停止该进程。
有的操作系统用线程模拟进程,部分操作系统下面,Weblogic进程变现为多线程,需要用脚本杀死Weblogic多线程。
ps –ef|grep java |awk ‘{printf “kill -9 ”$2}’>killjava
sh killjava 就可以停掉Weblogic的java进程,但是需要注意该机器是否还有其他java进程,切记小心停错!

参考:http://cyr1974.itpub.net/post/2066/247321
http://liwp_stephen.itpub.net/post/3553/24829
http://www.lupaworld.com/bbs/thread-14112-1-1.html

ADF实现树状查询

最近项目遇到要用start with connect by做树状查询,即:选择一个部门老大,要把老大下面的小老大和各个小弟全查出来,ADF貌似没有提供这类查询(至少我没发现,呵呵,如果有那就更好了,可以不给下面看了),这个办法不一定最好,但是,绝对可以实现,~~
1.数据库里面表的结构示例:
user(userid username PanrentId)
2.建VO的sql
2_1)如果你能知道你要查询的最顶层user的userid,那么你可以这样建VO,绑定一个参数p_userId,默认值就是最顶层的user的userid;VO上面的sql为:
select * from user start with userid=:p_userId connect by prior parent_id = user_id
2_2)如果你不知道你要查询的最顶层user的userid,那么你可以这样建VO,绑定一个参数p_userId,默认值就是最顶层的user的userid;VO上面的sql为:
select * from user start with userid in (select userid from (select userid, 1 flag from users union all select :p_userId, 2 flag from dual) where flag = decode(:p_userId, null, 1, 2) ) connect by prior parent_id = user_id

这样,如果用户没有输入查询参数,查出来的就是全部;如果用户输入了查询参数,把用户输入的userid在manageBena或者vo实现类里面赋值给VO上面的绑定参数

解决ORA-00020错误

项目上使用的Oracle服务器经常出现无法登陆的情况,尝试查看数据库dump文件,没有发现在无法登陆时的报错信息,使用SecureCRT连接服务器登录sqlplus时出现错误"ORA-00020: maximum number of processes (150) exceeded",解决方法如下:

开始时怀疑数据库死锁,通常这种情况下可以通过查询下列表/视图,杀死死锁的进程解决:
V$LOCK列出当前Oracle持有的锁和未解决的锁请求
V$SESSION列出当前连接到数据库的Session信息
DBA_BLOCKERS显示锁住对象的会话
DBA_WAITERS显示等待被锁住对象的会话
DBA_DDL_LOCKS列出所有DDL锁和未解决的DDL锁请求
DBA_DML_LOCKS列出所有DML锁和未解决的DML锁请求
DBA_LOCK列出所有锁和latch,以及所有未解决的锁请求
DBA_LOCK_INTERNAL每个锁或latch显示一行,每个未解决的锁请求显示一行


通过查询V$SESSION视图,发现连接总量已达到上限150,由于在做Oracle ADF开发,该OracleDB作为开发数据库,连接较多属于允许范围内,遂增大最大连接数,修改对应init.ora文件中"procdsses=150",重启DB。

10g里面如此修改无效,可以通过sqlplus连接至数据库
SQL> show parameter processes; //查看processes连接数设置
SQL> show parameter sessions; //查看sessions连接数设置
SQL> alter system set processes=300 scope=spfile; //设置processes连接数
不需要设置sessions连接数,sessions连接数为processes * 1.1 + 5

重启DB,问题解决。

附:用于确定锁住数据库对象的锁的SQL

select c.owner,
c.object_name,
c.object_type,
b.sid,
b.serial#,
b.status,
b.osuser,
b.machine   
from v$locked_object a,
v$session b,
dba_objects c   
where b.sid = a.session_id   
and a.object_id = c.object_id;