李李的技术博客

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  13 随笔 :: 0 文章 :: 61 评论 :: 0 Trackbacks

2005年10月7日 #

为了降低侵入性,更好的被引用,对bba96核心部分进行了大量重构,去除了冗赘的层次与不必要的接口,并借助jdk5.0范型进行了代码精简。发布了bba96 tiger beta2,这个版本已经是比较稳定的版本,具体的改动如下

  • 去除所有的接口依赖,可直接在任何项目中直接调用
  • service的两层合并为一层且去除service层的接口,但DAO曾仍保留接口以备扩展更多的orm实现
  • 增加sql execute的方法
  • 增强源自view的直接查询能力
  • 参数名由原来难看的oriNames, oriOperators, oriStringValues改为直观的searchName, searchOperator, searchValue
  • 增加了对QueryParam的toString功能,可打出对应的sql,便于调试,参见com.bba96.tiger.util.QueryWebUtils的main函数

下载页面地址:https://bba96.dev.java.net/servlets/ProjectDocumentList?folderID=4149&expandFolder=4149&folderID=0

如果你使用spring+hibernate,而又不喜欢hibernate criteria的麻烦,不妨尝试一下bba96,你可以把主要精力放到业务方面。DefaultEntityManager提供了很多单层逻辑的便利方法给你使用,其中也包括执行hsql或者sql查询/更新的方法,如果你要多层次逻辑的条件查询可以自己组装QueryObject,参见com.bba96.tiger.util.QueryWebUtils的main函数。bba96还提供给你在view层自由增加查询的能力。

tiger版本仅提供了dao/service部分,所以如果你希望在view 查询的安全性方面得到加强,可参考bba96 2.0其中的webwork view部分,权限部分也没有包含在tiger中,希望尽快把包括例子的权限部分迁移过来,但还需要一点时间,最近在忙一个CMS的产品,时间不够用啊……

SpringSide项目中webwork MVC部分应用到bba96 tiger对view部分的查询,有兴趣可以看看,这里也要推荐一下SpringSide,确实有很多很好的经验在里面可以借鉴。

posted @ 2006-06-10 19:16 李李 阅读(1418) | 评论 (2)编辑 收藏

bba96 CHANGELOG
==========================
http://bba96.dev.java.net

Changes in version 2.0 alpha3 (2006.4.3)
*fix action query parameters bug -- [XXX:...]
*fix distinct bug (discard Criteria.DISTINCT_ROOT_ENTITY)
*some minor improvement

Changes in version 2.0 alpha2.2 (2006.3.16)
*update webwork's jar for fixing example bug in weblogic
*remove all contentType setting in example

Changes in version 2.0 alpha2.1 (2006.3.8)
*fix example bug
*update readme.txt

Changes in version 2.0 alpha1 (2006.3.7)
*webwork 2.2 support
*hibernate 3.x support, then support native sql
*fix some bug
*add aop security module
*add action query parameters validation
*enhance action query parameters management
*support more logic in action query
*support multi orderby property


Changes in version 1.0 (2005.09.23)
*release first


源码下载(包含两个快速开发的例子。)
https://bba96.dev.java.net/servlets/ProjectDocumentList?folderID=4149&expandFolder=4149&folderID=0

简介参见http://www.blogjava.net/scorpio_leon/archive/2005/11/09/18878.aspx

posted @ 2006-03-08 01:24 李李 阅读(952) | 评论 (0)编辑 收藏

很容易找到getText实际的操作类是LocalizedTextUtil,方法public static String findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args, OgnlValueStack valueStack);

java doc 如下

Finds a localized text message for the given key, aTextName. Both the key and the message itself is evaluated as required. The following algorithm is used to find the requested message:

  1. Look for message in aClass' class hierarchy.
    1. Look for the message in a resource bundle for aClass
    2. If not found, look for the message in a resource bundle for any implemented interface
    3. If not found, traverse up the Class' hierarchy and repeat from the first sub-step
  2. If not found and aClass is a ModelDriven Action, then look for message in the model's class hierarchy (repeat sub-steps listed above).
  3. If not found, look for message in child property. This is determined by evaluating the message key as an OGNL expression. For example, if the key is user.address.state, then it will attempt to see if "user" can be resolved into an object. If so, repeat the entire process fromthe beginning with the object's class as aClass and "address.state" as the message key.
  4. If not found, look for the message in aClass' package hierarchy.
  5. If still not found, look for the message in the default resource bundles.
  6. Return defaultMessage

主要就是查找resource bundle,下面说明一下
1. 先查找该class(一般我们是在action调用,就是该action对应的class了)对应的properties文件,找不到再去找对应的接口,找不到再去从该class的继承树上去重复前面的步骤。
2. 如果是ModelDriver,以上找不到再以model的class去重复1的步骤
3.继续找,如果key是符合ognl表达式还以ognl表达式去解析类,如果能找到类,还以以上的步骤去查找
4. 还找不到,就从根据package以及package的继承树去找,这还包括了该class的继承树所有的class的package树(这一步存在了太多的重复查找工作,因为很多package都是相同的)
5 使用默认的resource bundle

java.util.ResourceBundle虽然有cache,但是ww为了减少调用getResourceBundle方法,也维护了一个miss的hashset,找不到的bundle name就丢进去,那么每一次查找都同步了这个miss,如果很多次查找,开销也是很大的。

我就举一个例子,就说第四步查找package树好了

        // nothing still? alright, search the package hierarchy now
        for (Class clazz = aClass;
             (clazz 
!= null&& !clazz.equals(Object.class);
             clazz 
= clazz.getSuperclass()) {

            String basePackageName 
= clazz.getName();
            
while (basePackageName.lastIndexOf('.'!= -1) {
                basePackageName 
= basePackageName.substring(0, basePackageName.lastIndexOf('.'));
                String packageName 
= basePackageName + ".package";
                msg 
= getMessage(packageName, locale, aTextName, valueStack, args);

                
if (msg != null) {
                    
return msg;
                }

                
if (indexedTextName != null) {
                    msg 
= getMessage(packageName, locale, indexedTextName, valueStack, args);

                    
if (msg != null) {
                        
return msg;
                    }
                }
            }
        }

假设你的action继承树是这样
com.bba96.core.webwork.actions.DefaultActionSupport
com.xxxx.web.actions.XXXActionSupport
com.xxxx.web.user.actions.UserAction
com.xxxx.web.user.ViewUserAction
且不说ww没有判断是否是com.opensymphony.xwork.ActionSupport或者ww的接口就停止,光是自己的继承树,就是4+3+3+3=13次,再加上往上的继承树以及对应的接口,com.opensymphony.xwork.ActionSupport以及Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable, ContinuableObject的接口,查找次数超过30次甚至更多,这里的每一次都有一个同步miss的过程,开销相当大。

如果你的key所在的resource bundle没有对应到合适的class或package时,例如说放在了default bundle中,ww会浪费很多时间。这种情况下,我在没有并发的时候测了一下,一次getText大概耗时40ms左右

所以在实际应用我们应该避免这种情况出现,要不让resource bundle一一对应class,要不就自己实现一个简单的getText,其实要是ww的ActionSupport的textProvider允许改变就最好了。

posted @ 2006-01-21 13:26 李李 阅读(1492) | 评论 (0)编辑 收藏

   调试IIS+Tomcat,装IIS的时候居然出现staxmem.dll不能复制,google了一下,居然很多人说要重装才能解决,晕,又找到http://support.microsoft.com/?kbid=894351,根据上面说的,我是属于method 2情况,但是没有xp原盘,装的时候就是sp2了,又倒……
  最后看到有人情况跟我的类似,就是用method 1的第一步 esentutl /p %windir%\security\database\secedit.sdb 就可以了%windir%那里应该写你的xp安装路径,不用管什么警告,确认就对了,IIS安装成功……开始配置。
posted @ 2005-12-21 23:29 李李 阅读(1865) | 评论 (3)编辑 收藏

一个例子,原来的

<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>

可改写为
<interceptor-ref name="validation">
    <param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="workflow">
    <param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>

那么,对于简单的需验证页面,不需要再因为避免不必要的校验而分两个action。

只有com.opensymphony.xwork.validator.ValidationInterceptor, com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor 定义并实现了这个excludeMethods,实现的也还是比较粗糙的,我们在做类似实现的时候可以参考一下,有必要也可以改进,扩展一下,例如增加includeMethods
    public void setExcludeMethods(String excludeMethods) {
        
this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
    }

    
public String intercept(ActionInvocation invocation) throws Exception {
        
if (excludeMethods.contains(invocation.getProxy().getMethod())) {
            log.debug(
"Skipping workflow. Method found in exclude list.");
            
return invocation.invoke();
        }
        
    }
posted @ 2005-12-03 22:29 李李 阅读(1382) | 评论 (2)编辑 收藏

https://bba96.dev.java.net/servlets/ProjectDocumentList?folderID=4149&expandFolder=4149&folderID=0
修正一处batchRemove的bug,
将action的与持久化相关的方法,以及getResults方法保护起来
添加了一个Book example. 包括简单用户管理,书籍的查询与租借。
Book Example 参见 http://book.bba96.com
Advanced Example 参见 http://www.gopherbook.com


posted @ 2005-11-18 09:37 李李 阅读(404) | 评论 (0)编辑 收藏

https://bba96.dev.java.net/
源文件下载
https://bba96.dev.java.net/servlets/ProjectDocumentList?folderID=4149&expandFolder=4149&folderID=0


1. 核心持久层部分基于spring/hibernate,实现强大灵活的动态query功能,可独立使用。
2. 权限部分,基于RBAC,支持数据权限,依赖1部分的接口。
3. Action层,基于1以及webwork,良好架构,减少大量代码,支持view灵活进行query且有参数教验支持保证安全性。

简单说bba96就是基于hibernate/spring的快速开发框架,其中包含了对Hibernate Critiera,Projection的封装,通过一个强大而灵活的QueryObject对象,方便动态添加与删除条件。
通过统一的query与数据库交互,方便AOP,其中的RBAC权限模块(支持数据权限)即是通过AOP操作QueryObject对象来实现的。bba96核心可以跟流行的view整合,目前只有webwork整合的版本。

bba96 不再需要自己写DAO/SERVICE,借助简单的spring ioc即可配置使用缺省DAO/SERVICE,而且通过灵活方便,易扩展的后台持久层与webwork的整合,完全实现了快速开发的目的。


Get Up And Running Quick

Example:
   (1) enter the example/simple or emample/book folder.
       NOTE:all following operation is under the folder you entered
   (2) copy your JDBC driver (default mysql) to the lib directory
       -- webapps\ROOT\WEB-INF\lib
   (3) edit hibernate.properties for database info (default mysql)
       -- src\main\java\hibernate.properties
   (4) run "ant"
   (5) create database via the sql script generated at database\schema-export.sql
   (6) edit applicationContext.xml for database info (default mysql)
       -- webapps\ROOT\WEB-INF\applicationContext.xml (line 5 - 21)
   (7) start server and see this example


有使用上的讨论,请联系我 MSN: hotmail的帐号scorpio_leon
posted @ 2005-11-09 00:51 李李 阅读(6086) | 评论 (45)编辑 收藏

  1. 如果你用hibernate+spring,注意spring的OpenSessionInView的Filter要在webwork的Filter之前
  2. ww:property这个tag缺省是escape html的,在tag可以指定escape="false"避免html字符转义
  3. 一些原来用单引号表示字符串的都要去掉单引号,例如 " 'test' "  要改为 "test"
  4. No object in the CompoundRoot has a property named,这是由于在webwork.properties设置了webwork.devMode=true,会检查页面上传递过来的参数是否在action定义过。
posted @ 2005-10-19 15:36 李李 阅读(744) | 评论 (1)编辑 收藏

public interface ModelDriven {
    Object getModel();
}

而我需要的是
public interface ModelDriven {
    Object getModel() 
throws Exception;
}

因为要拦截可能抛出的异常,流程是这样service - my service interceptor - action - xwork interceptor
现在断在action这里了,很奇怪,webwork其他方法都有throw exception,独独这个没有,难道又要hack webwork?
恩,有了AOP后,接口设计应该要多考虑一下,是否允许抛出异常……

posted @ 2005-10-18 18:22 李李 阅读(517) | 评论 (1)编辑 收藏

看看下面的应用例子,程序执行三秒后会在后台开始发Email,只有几行程序,很简单吧。
本来就应该这么简单,还能再省么,呵呵,谢谢开源的力量……

    SimpleEmail email = new SimpleEmail();
    email.addTo(
"receiver@somemail.com""Receier's Name");
    email.setSubject(
"Email from www.bba96.com");
    email.setMsg(
"Hello, guy!");
    EmailScheduler emailScheduler 
= new EmailScheduler();
    emailScheduler.process(email);

这里用到了jakarta common email中的SimpleEmail
EmailScheduler是一个利用Opensymphony Quartz做简单的调度,其中EmailJob实现了Quartz的Job接口
以下是EmailScheduler以及EmailJob源代码。

package com.bba96.scheduler;

import java.util.Date;

import javax.mail.Authenticator;

import org.apache.commons.mail.Email;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;

public class EmailScheduler {

    
public void process(Email email, Authenticator authenticator)
            
throws SchedulerException {
        
// TODO if can be optimized with static instance.
        SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
        Scheduler sched 
= schedFact.getScheduler();
        sched.start();

        JobDetail jobDetail 
= new JobDetail("EmailJob"null, EmailJob.class);
        jobDetail.getJobDataMap().put(EmailJob.EMAIL, email);
        jobDetail.getJobDataMap().put(EmailJob.AUTHENTICATIOR, authenticator);
        
//Create a trigger that fires exactly once, three seconds from now
        long startTime = System.currentTimeMillis() + 3000L;
        SimpleTrigger trigger 
= new SimpleTrigger("emailTrigger"null,
                
new Date(startTime), null00L);
        sched.scheduleJob(jobDetail, trigger);
    }

    
public void process(Email email) throws SchedulerException {
        process(email, 
null);
    }

}

 

package com.bba96.scheduler;

import javax.mail.Authenticator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class EmailJob implements Job {

    
protected final Log logger = LogFactory.getLog(EmailJob.class);

    
public static String EMAIL = "EMAIL";

    
public static String AUTHENTICATIOR = "AUTHENTICATIOR";

    
public static String DEFAULT_HOST = "your smtp mail server";

    
public static int DEFAULT_SMTP_PORT = 25;

    
public static String DEFAULT_USER = "yourmail@yourserver.com";

    
public static String DEFAULT_PASSWORD = "your password";

    
public static String DEFAULT_FROM_ADDRESS = "yourmail@yourserver.com";

    
public static String DEFAULT_FROM_NAME = "Your Name";

    
public void execute(JobExecutionContext context)
            
throws JobExecutionException {
        Email email 
= (Email) context.getJobDetail().getJobDataMap().get(EMAIL);
        
if (email != null) {
            Authenticator authenticator 
= (Authenticator) context
                    .getJobDetail().getJobDataMap().get(AUTHENTICATIOR);
            
if (email.getHostName() == null) {
                email.setHostName(DEFAULT_HOST);
            }
            
if (email.getSmtpPort() == null) {
                email.setSmtpPort(DEFAULT_SMTP_PORT);
            }
            
if (authenticator == null) {
                authenticator 
= new DefaultAuthenticator(DEFAULT_USER,
                        DEFAULT_PASSWORD);
                email.setAuthenticator(authenticator);
            }
            
if (email.getFromAddress() == null) {
                
try {
                    email.setFrom(DEFAULT_FROM_ADDRESS, DEFAULT_FROM_NAME);
                } 
catch (EmailException e) {
                    logger.error(
"Email address invalid", e);
                    
return;
                }
            }
            
try {
                email.send();
            } 
catch (EmailException e) {
                logger.error(
"Email send error", e);
            }
        }
    }

}

posted @ 2005-10-15 22:01 李李 阅读(1990) | 评论 (0)编辑 收藏

原来用着一个朋友的手机最近经常没信号,不得不换一个,还是用回Nokia,6030,还很不错。偶很喜欢,咔咔

……

为什么今天上来写两句,不是无聊……因为心情很郁闷,很郁闷很郁闷…… Sigh, MM真是太作了,痛苦……

bba96申请毕业总算有回应了,dev.java.net来信说bba96 example不错,希望把binary文件也放上去,有助于用户尝试……找个时间放上去吧。另外用properties文件在加强参数安全性的校验,限定所接受的nameTypes, oriOperators, stringValues的范围,这样,就可以兼顾灵活性与安全高兴了。

有空也可以整理整理那个RBAC权限的框架,成熟了也放到dev.java.net上吧。
posted @ 2005-10-14 18:04 李李 阅读(315) | 评论 (0)编辑 收藏

今天尝试了一下SkypeOut,打到国外确实比普通IP电话省钱,平均0.20-0.30/分钟。音质还不错:D
posted @ 2005-10-07 02:52 李李 阅读(237) | 评论 (1)编辑 收藏