2008年07月09日

grails 是类似于rails的Web快速开发框架,其使用的语言是groovy。使用groovy、grails最大的好处是可以利用Java已有的许多好的技术和框架,grails的很多插件使得这些好的技术或框架使用起来更加便利。下面ppt介绍的是grails searchable,一个封装的非常好的数据全文检索插件,底层技术采用的是Compass和Lucene,经封装之后使用起来非常方便。与大家共同分享:

http://www.groovyland.net/pptshare上有更多关于groovy 和 grails的ppt)

2006年09月04日

用手机很多年了,可一直搞不清楚在漫游的时候移动是怎样收取话费的。虽然移动网站上也有资费标准,但基本没有什么参考价值。虽然咱是被服务者,但鉴于人家移动是垄断行业,所以为了搞清楚咱到底是怎么被服务收费的,还得自己动手。以下资费标准是以陕西移动所出具的通话祥单计费标准总结而来的,如其他地方与此有不同之处,请自行修正。(由于案例不是很充裕,因此可能有误)

 

术语:

所属地:办理手机卡的所在地

漫游地:手机所处的非“所属地”地点

外地:除上述两个定义的其他地点

漫游费率:处在漫游的固定通话费率(一般是0.6/分钟,不足一分钟的按一分钟计)。

长途费率:长途电话费率(一般是 0.07/6秒,不足6秒钟的按6秒计)。

IP话费率:使用17951拨打长途所收取的费用费率(一般是0.3/分钟,不足以分钟的按一分钟计)。

漫游费:= 漫游费率 * 通话分钟数(不足以分钟的按一分钟计)。

长话费:= 长话费率 * 通话时间有多少个6秒(不足6秒的按6秒计)。

IP话费:= IP话费率 * 通话分钟数(不足以分钟的按一分钟计)。

 

以下表格所描述是持手机人处在漫游地的通话资费标准:

移动漫游资费标准

连接方式

情景

资费标准

被叫(接电话)

1. 接通所属地手机或座机的呼叫

2. 接通外地手机或座机的呼叫

3. 当所属地或外地手机也漫游到漫游地,接通此类呼叫

漫游费 + 长话费

4. 接通漫游地手机或座机的呼叫

漫游费

主叫(打电话)

1. 拨打所属地手机或座机

2. 拨打外地手机或座机

漫游费 + 长话费

3. 使用17951拨打所属地手机或座机

4. 使用17951拨打外地手机或座机

漫游费 + IP话费

5. 拨打漫游地手机或座机

6. 当所属地或外地手机也漫游到漫游地,拨打此类电话

漫游费

 

2006年04月05日

表现:
    页面显示如下错误
———————————————————
500 Internal Server Error
oracle.jbo.PCollException: JBO-28030: ?????????? ID ? 1, ?? ID ? 108,636 ?? PS_TXN ?
        at oracle.jbo.PCollException.throwException(PCollException.java:39)
        at oracle.jbo.pcoll.OraclePersistManager.insert(OraclePersistManager.java:1845)
        at oracle.jbo.pcoll.PCollNode.passivateElem(PCollNode.java:561)
        at oracle.jbo.pcoll.PCollNode.passivate(PCollNode.java:684)
        at oracle.jbo.pcoll.PCollNode.passivateBranch(PCollNode.java:643)
        at oracle.jbo.pcoll.PCollection.passivate(PCollection.java:461)
         ……

## Detail 0 ##
java.sql.SQLException: ORA-01653: ?SCDD.PS_TXN????128?????SCDDDATA????
ORA-06512: ?line 1
        at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:137)
        at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:304)
        at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:271)
        at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:625)
        ……
———————————————————

?译英:
    错误信息问了我一堆?,搞得我一头雾水:)。后来在网上搜索了一下,翻译如下:

oracle.jbo.PCollException: JBO-28030: Could not insert row into table PS_TXN, collection id 108,636, persistent id 1

java.sql.SQLException: ORA-01653: unable to extend table SCDD.PS_TXN by 128 in tablespace SCDDDATA

    如果翻译的有不准确的地方,还希望大家踊跃指正。

原因:
    SCDDDATA表空间已满

处理方法:
    找DBA扩大表空间容量(清理PS_TXN的数据可能也能暂时起些作用)

PS_TXN:
    这个表是BC4J Application Module pool使用的。This table is used by BC4J Application Module pool to save the current session of your application module (AM) as the default behviour in JDeveloper is Stateful or (managed) mode.

参考:
    http://forums.oracle.com/forums/thread.jspa?messageID=829192&#829192
    http://www.attask.com/projectmanagement/usermanual/UserManual-210.html

表现:
页面出现了如下错误
—————————————————————————-
Validation Error
You must correct the following error(s) before proceeding:
  • JBO-29000: $Proxy4
  •    $Proxy4
—————————————————————————-
后台并没有打印任何错误信息。
另外,$Proxy4 后面的 “4”也有可能是其他数字“1”,“2”…。我并没有仔细研究数字不同有没有什么深刻含义。(如果哪位大侠已经有所研究的话,请赐教)。
 
原因:
在Action中将ApplicationModuleA 强制转换成ApplicationModuelB,而这两个Application之间没有任何继承或实现关系。以下面的代码为例,geAppModuleA(ctx)获取到了ApplicationModuleA,但是用户却期望所获得的是ApplicationModuelB,将其强制转换成B:
    ApplicationModuelB am= (ApplicationModuelB)geAppModuleA(ctx);
    System.out.println(am.getDefFullName());
 
返回的am并非是ApplicationModuelB,但却强制转换成了ApplicationModuelB,因此会出现这样的错误。
 
注意:
返回的是WSApplicationModule的情况,尽管也不是ApplicationModuelB,但是如果把它强制转换成ApplicationModuelB,所出现的错误并不是这个,而是(JBO-29000: oracle.jbo.common.ws.WSApplicationModuleImpl)
 
解决方法:
    保证你所获得的ApplicationModule是你所期望的,而不是其他的ApplicationModule类型。可以把ApplicationModule的实例所对应得类名打出来看看:System.out.println("am="+am.getDefFullName());

表现:

页面出现了如下错误

—————————————————————————-

Validation Error

You must correct the following error(s) before proceeding:

  • JBO-29000: oracle.jbo.common.ws.WSApplicationModuleImpl

  •    oracle.jbo.common.ws.WSApplicationModuleImpl

—————————————————————————-

后台并没有打印任何错误信息。

 

原因:

    Action中将所获取的oracle.jbo.common.ws.WSApplicationModuleImpl转换成所期望的自定义的ApplicationModule的时候会出这样的错误。

看一个实际的例子来说明这个问题。代码的前一部分(这里并未列出)是在Action中获得相关的DCDataControl,从而获得applictionModule;下面这一部分是想从applicatioMpdule中获取其nested ApplicationModule —— SchAppModule1。但实际上在Action获取nested ApplicationModule所返回的并不是所期望的SchAppModule1,而是oracle.jbo.common.ws.WSApplicationModuleImpl(如果有哪位大侠能在action中获取到所期望的嵌套ApplicatioinModule,请赐教)。如果想把WSApplicationModuleImpl转换成我们所期望的ApplicationModule类型 —— SchAppModule,便会出现这样的错误。

ApplicationModule am=applicationModule.findApplicationModule("SchAppModule1");

SchAppModule amm=(SchAppModule)am;

 

当然,还有其他情况。不过只要你想把WSApplicationModuleImpl转换成自定义的ApplicationModule的时候,便会出现这个错误。

 

解决方法:

   保证你所获得的ApplicationModule是你所期望的,而不是oracle.jbo.common.ws.WSApplicationModuleImpl。可以把ApplicationModule的实例所对应得类名打出来看看:System.out.println("am="+am.getDefFullName());

表现:

页面出现了如下错误

—————————————————————————-

Validation Error

You must correct the following error(s) before proceeding:

  • JBO-29000: JBO-25063: 由于未绑定有效集对象, 无法执行操作 first

  •    JBO-25063: 由于未绑定有效集对象, 无法执行操作 first

—————————————————————————-

后台并没有打印任何错误信息。

 

 

 

原因:

Action中使用appModule访问其所包含的View的时候,如果该View并没有出现在Action所引用的UIModel配置文件中,即Binding中从未使用过该View,那么就会出现该错误。

看一个实际的例子来说明这个问题。以下面的代码为例,UserView并没有在Action所所引用的UIModel配置文件中被使用,ADF不会实例化该View,因此从am中获取SchAppModule1中的视图并循环取值,即会出现错误。

   

ApplicationModule am=getApplicationModule("SchAppModule1");//自定义方法

System.out.println("am="+am.getDefFullName());

ViewObject v=am.findViewObject("UserView");

v.first();v.previous();

       while (v.hasNext()){

      

    }

 

 

 

解决方法:

   Action所对应的jsp页面中拖拽该View作为Binding对象(UIModel中会出现使用UserView的相关配置),在Action中就可以访问这个View了。

2006年03月29日
表现:
    页面出现了下面这样的错误
—————————————————————————-

Validation Error

You must correct the following error(s) before proceeding:

  • JBO-29000: JBO-33004: 对配置文件进行语法分析时出错
  •    JBO-33004: 对配置文件进行语法分析时出错
  •       Expected name instead of <.
—————————————————————————-
  后台并没有打出任何错误信息,从字面上也看不出是那个配置文件出事了。
原因:
 bc4j.xcfg的格式有问题,不符合xml格式规范。
  原来是进行update的时候发生了冲突,造成了bc4j.xcfg 文件中出现了<<<<<< 以及>>>>>>这样的非法字符 。
  当然,也可能是其他原因引起的bc4j.xcfg格式问题。
解决方法:
  编辑bc4j.xcfg,解决冲突,并用 “Check XML Syntax”检查无误即可。
引申:
    既然说到这了,顺便看看另一个与bc4j.xcfg有关的错误JBO-33005 —— 找不到bc4j.xcfg。

原文参考:

JBO-33004: JboException

Cause: This exception is thrown when there is an error passing the bc4j.xcfg Configuration file. The Configuration file is an XML file and it should be ‘well formed’. This error is likely to occur, if you accidentally modified the bc4j.xcfg file outside of JDeveloper.

Action: Fix the error in xcfg file. In JDeveloper save the file with XML extension, like my.xml, right click on the my.xml node and select validate xml.

JBO-33005: JboException

Cause: This exception is thrown when the named Configuration is not found in the bc4j.xcfg file.

The bc4j.xcfg file defines one or more Configuratons each identified by a name. This name is later used in the client code. For example, it is used in the createRootApplicationModule() method of the oracle.jbo.client.Configuration class.

http://213.35.38.54/otn_hosted_doc/jdeveloper/904preview/developing_bc_projects/jboerrormessages.html

2005年12月10日

1.描述:
      前一篇文章通过试验说明了setWhereClause()与executeQuery()是如何影响视图实例结果集的。我们注意到了插入一行后,如果还未提交,即使使用ViewObject.setWhereClause()重新设置了包含新增行的查询条件(例如“1=1”),新增行也无法查询出来。那么如果我们想在提交前还对新增行的数据做些修正,该怎么办呢?
      通过进一步试验,当不设置任何条件进行查询时,是可以查出新增但还未提交的行的。定位到具体的行,则可以通过getFilteredRows(),来完成。

2.验证:
   
2.1 开发环境: Oracle JDeveloper     Version 10.1.2.0.0(Build 1811)

2.2 原表中数据:

 DEPTNO  DNAME  LOC
 10  hhhh   NEWYORK
 20  ggg  20
 30  GGGG  CHICAGO
 56  56    56
 23  tt  23
 66   6666661  7777777777
 50  烁程软件  西安高新区


2.3 代码片断: (变化或新增的部分用黑体表示)

//不加任何条件,结果集应为表中所有记录
    appModule=getPanelBinding().getBindingContext().getDefaultDataControl().getApplicationModule();
    ViewObject vo=appModule.findViewObject("DeptView1");
    System.out.println("count1="+vo.getRowCount());

//ViewObject中插入、修改、删除一行。
//insert a row——————————
    Row insRow=vo.createRow();
    insRow.setAttribute(0,""+99);
    insRow.setAttribute(1,""+99);
    insRow.setAttribute(2,""+99);
    vo.insertRow(insRow);
//update a row——————————
//    Row updRow=vo.last();
//    updRow.setAttribute(0,""+11);
//    updRow.setAttribute(1,""+11);
//    updRow.setAttribute(2,""+11);
//delete a row——————————
//    Row delRow=vo.last();
//    vo.setCurrentRow(delRow);
//    vo.removeCurrentRow();
   System.out.println("count2="+vo.getRowCount());
   
//设置where条件,重新查询
    vo.setWhereClause("1<>1");
    vo.executeQuery();
    System.out.println("count3="+vo.getRowCount());

//再重新获得ViewObject,并重新设置where条件(如果这里不重设条件,条件依然会是1<>1)
    ViewObject vo2=appModule.findViewObject("DeptView1");
    vo2.setWhereClause("");         //注意查询条件
    vo2.executeQuery();
    System.out.println("count4="+vo2.getRowCount());
    System.out.println("last row="+vo2.last().getAttribute("Dname"));

    vo2.first();vo2.previous();
    while (vo2.hasNext()){
        Row aRow=vo2.next();
        System.out.println("——"+aRow.getAttribute("Dname"));
    }

    Row[] rows=vo2.getFilteredRows("Deptno",new Integer(99));
    if (rows!=null && rows.length>0){
       System.out.println("lenth="+rows.length+"; rows[0]="+rows[0].getAttribute("Dname"));
    }


//提交事务(或回滚)
    //appModule.getTransaction().commit();
    appModule.getTransaction().rollback();
   
//再设置与提交前同样的where条件
    vo2.setWhereClause("1=1");
    vo2.executeQuery();
    System.out.println("count5="+vo2.getRowCount());
    System.out.println("last row="+vo2.last().getAttribute("Dname"));


2.4 验证结果:
  试验打印结果如下:

insert:(rollback)
———————————————–
count1=7
count2=8                            //做了新增行操作
count3=0
count4=8                            //vo2.setWhereClause("");可以查出这一行
last row code=烁程软件 //但新增行未必出现在最后一行
——99                                //可以访问到新增行
——hhhh
——ggg
——GGGG
——56
——tt
——6666661
——烁程软件
lenth=1; rows[0]=99      //用getFilteredRows()可以定位到该新增行
count5=7                         //rollback
last row code=烁程软件

2005年12月09日

1.描述:

   (摘自《Oracle 9i JDeveloper开发手册–构建J2EE应用程序》14.9在运行时改变视图用例的WHERE子句)
    如果您想完整地替换掉一个视图用例的Where子句,可以调用ViewObject.setWhereClause()方法。调用setWhereClause()之后,您需要调用executeQuery()刷新视图用例的结果集,以反映新的约束条件。这样也会把当前指针重置到第一条记录之前的空位上。…
    …
    当您调用executeQuery()时,您的实体缓存也许包含数据(例如改变过的属性,新的记录或删除的记录),而这些数据还没有发送出去。executeQuery()将不会重写这些改变;实体缓存将会一直保存这些自上一次向数据库发送数据以来已经创建、删除或者改变的属性和记录,并将它们合并进从数据库中检索到的任何其他数据中。
    …

    注解:用例可能就是实例(instance)吧,没有原文,不得而知。

2.验证:
   
2.1 开发环境: Oracle JDeveloper     Version 10.1.2.0.0(Build 1811)

2.2 原表中数据:

 DEPTNO  DNAME  LOC
 10  hhhh   NEWYORK
 20  ggg  20
 30  GGGG  CHICAGO
 56  56    56
 23  tt  23
 66   6666661  7777777777
 50  烁程软件  西安高新区


2.3 代码片断:

//不加任何条件,结果集应为表中所有记录
    appModule=getPanelBinding().getBindingContext().getDefaultDataControl().getApplicationModule();
    ViewObject vo=appModule.findViewObject("DeptView1");
    System.out.println("count1="+vo.getRowCount());

//ViewObject中插入、修改、删除一行。
//insert a row——————————
    Row insRow=vo.createRow();
    insRow.setAttribute(0,""+99);
    insRow.setAttribute(1,""+99);
    insRow.setAttribute(2,""+99);
    vo.insertRow(insRow);
//update a row——————————
//    Row updRow=vo.last();
//    updRow.setAttribute(0,""+11);
//    updRow.setAttribute(1,""+11);
//    updRow.setAttribute(2,""+11);
//delete a row——————————
//    Row delRow=vo.last();
//    vo.setCurrentRow(delRow);
//    vo.removeCurrentRow();
   System.out.println("count2="+vo.getRowCount());
   
//设置where条件,重新查询
    vo.setWhereClause("1<>1");
    vo.executeQuery();
    System.out.println("count3="+vo.getRowCount());

//再重新获得ViewObject,并重新设置where条件(如果这里不重设条件,条件依然会是1<>1)
    ViewObject vo2=appModule.findViewObject("DeptView1");
    vo2.setWhereClause("1=1");
    vo2.executeQuery();
    System.out.println("count4="+vo2.getRowCount());
    System.out.println("last row="+vo2.last().getAttribute("Dname"));
   
//提交事务(或回滚)
    appModule.getTransaction().commit();
    //appModule.getTransaction().rollback();
   
//再设置与提交前同样的where条件
    vo2.setWhereClause("1=1");
    vo2.executeQuery();
    System.out.println("count5="+vo2.getRowCount());
    System.out.println("last row="+vo2.last().getAttribute("Dname"));


2.4 验证结果:
试验是严格按insert(rollback)、insert(commit)、update(rollback)、update(commit)、delete(rollback)、delete(commit)顺序做的。各试验打印结果如下:

insert:(rollback)
———————————————–
count1=7
count2=8           //做了新增行操作
count3=0
count4=7
last row=烁程软件  //新增的行并没有生效
count5=7
last row=烁程软件  //新增的行无效了

insert:(commit)
———————————————–
count1=7
count2=8           //做了新增行操作
count3=0
count4=7
last row=烁程软件  //新增的行并没有生效
count5=8
last row=99        //新增的行永久生效了

update:(rollback)
———————————————–
count1=8
count2=8
count3=0
count4=8
last row=11    //修改的值临时生效了
count5=8
last row=99    //rollback后修改的值无效了

update:(commit)
———————————————–
count1=8
count2=8
count3=0
count4=8
last row=11    //修改的值临时生效了
count5=8
last row=11    //commit后修改的值永久生效了

delete:(rollback)
———————————————–
count1=8
count2=7          //做了删除行操作
count3=0
count4=7
last row=烁程软件 //删除临时生效了
count5=8
last row=11       //rollback后删除无效了

delete:(commit)
———————————————–
count1=8
count2=7           //做了删除行操作
count3=0
count4=7
last row=烁程软件  //删除临时生效了
count5=7
last row=烁程软件  //commit后删除永久生效了


3. 结论:

    对插入操作:如果未提交,后执行了ViewObject.executeQuery();,查询出的结果集不会包含新增的一条。对于后续查询来说这一行相当于没有插入(但是这一行仍然保留着)。如果以后作了commit()操作,这一行会永久保存,再执行ViewObject.executeQuery();会查出这一行。
    对删除操作:如果未提交,后执行了ViewObject.executeQuery();,虽然未提交但仍查不到删除的这行数据。除非执行了rollback()方法,否则,对后续查询来说这一行相当于已经被删除了。如果以后作了commit()操作,这一行会永久删除。
    对修改操作:如果未提交,后执行了ViewObject.executeQuery();,虽然未提交但仍查到的是修改后的数据。除非执行了rollback()方法,否则,对后续查询来说这一行相当于已经被修改了。如果以后作了commit()操作,这一行修改会永久保存。

2005年12月06日

oracle.jbo.AttributeLoadException: JBO-27022: Failed to load value at index 40 with java object of type java.lang.String due to java.sql.SQLException.

现象:
       出错的TestView是用qurey所定义的,原来共40列:其中前38列直接对应的实体属性(实体共38个属性,对应着数据库表Test的所有字段),最后两列是计算列。  后来由于应用需要,Test表新增一列,实体同步后也增一列(共39列)。之后,在JDeveloper中,双击TestView图标,打开编辑界面,把新增列选进TestView,系统自动把该新增列放在最后(第41列,列号为40)。View修改完成之后,执行原来的程序,即出现JBO-27022错误。

原因:
       观察对应的实体TestImpl.java,该文件对表格中的字段所对应的列号作了定义(从0开始)。前面的39个(0-38)是实际的字段所在列号;后面的依次递增的编号并不对应实际的列,而是反映了该表的关系,包括该表指向主表的外键关系以及子表指向该表的外键关系,对这些关系,都会分配一个编号来对应。
       按理说,ADF在影射View到实体并访问实体的某属性时应该使用名字作为影射关键字,不应该出现这种问题。但实际上似乎除了名字之外,还要看列号,否则也不会出现这样的错误(这里的原因是从表现猜测出来的,没有理论根据。如果要探求真正原因,希望从Oracle相关文档中找寻答案)。因此,当表中增加一列,实体同步后也增加一列,并在实体TestImpl.java中为新增列定义列号。注意,ADF会自动把这个新增的列的列号放在表示关系的列号之前,表示关系的列号会自动后推。本例中,新增的列被编号为38(第39个)。
       这样,通过前面的方法,把新增列加入View中,使得列号40(第41列)对应回实体的列号40(第41列,实际应该对应到列号为38的列),找到的并非是想要的实体的属性,而是是实体的外键关系。因此就无法对应而报错。

解决方法:
       对于有计算列的View,最好通过直接改写qurey语句的方法,在Qurey语句中把新增列放在计算列之前。这样可以避免本文前面所提到的错误。