2008年12月9日星期二

使用org.apache.tools.zip解决juva.util.Zip中不支持中文文件名操作的问题

jdk中的juva.util.Zip包处理有中文文件名的文件会出现问题,解压缩的时候就报异常,压缩后的文件用winzip打开就是乱码。原因是ZipOutputStream压缩和解压ZIP文件对文件名都是以UTF-8编码方式来处理的,而我们用winzip压缩文件对文件名只会以ASCII编码方式来处理.所以会出现编码不一致的问题。目前直到jdk6也没有解决这一问题,为解决非UTF-8文件名的问题,Apache Ant项目专门设计了替代java.util.Zip包的类。
  1. 解压缩含中文文件名的zip文件。
    import org.apache.tools.zip.ZipEntry;
    import org.apache.tools.zip.ZipFile;
    import java.io.InputStream;
    import java.util.Enumeration;
    ... ...
    private void extractSourceZipFile(ZipFile zipFile, File baseDir) throws IOException {
            ZipEntry zipEntry = null;
            Enumeration e = zipFile.getEntries();
            while (e.hasMoreElements()) {
                zipEntry = (ZipEntry) e.nextElement();
                if (zipEntry.isDirectory()) {
                    new File(baseDir + File.separator + zipEntry.getName()).mkdirs();
                } else {
                    new File(baseDir + File.separator + zipEntry.getName()).getParentFile().mkdirs();
                    log.info(baseDir + File.separator + zipEntry.getName());
                    FileOutputStream fos = new FileOutputStream(baseDir + File.separator + zipEntry.getName());
                    InputStream in = zipFile.getInputStream(zipEntry);
                    IOUtils.copy(in, fos);
                    in.close();
                    fos.close();
                }
            }
        }

  2. 压缩含中文文件名文件的目录
    import org.apache.tools.zip.ZipEntry;
    import org.apache.tools.zip.ZipOutputStream;
    ... ...
    private void exportZipHelper(File fs, ZipOutputStream zos, String zePath) throws IOException {
            File[] files = fs.listFiles();
           
            for (int i=0; i<files.length; i++) {
                if (files[i].isDirectory()) {
                    ZipEntry ze = new ZipEntry(zePath+"/"+files[i].getName()+"/");
                    zos.putNextEntry(ze);
                    zos.closeEntry();
                    exportZipHelper(files[i], zos, zePath+"/"+files[i].getName());
                } else {
                    FileInputStream fis = new FileInputStream(files[i]);
                    ZipEntry ze = new ZipEntry(zePath+"/"+files[i].getName());
                    zos.putNextEntry(ze);
                    IOUtils.copy(fis, zos);
                    zos.closeEntry();
                    fis.close();
                }
            }
       }

    public void exportZip(FIle fs, String zePath){
            ByteArrayOutputStream bais = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(bais);
               
            // Prevents java.util.zip.ZipException: ZIP file must have at least one entry
            ZipEntry ze = new ZipEntry(zePath+"/");
            zos.putNextEntry(ze);
            zos.closeEntry();
            exportZipHelper(fs, zos, zePath);
            zos.close();
    }

2008年9月7日星期日

RHEL5安装Subversion

  1. 环境准备
    安装包采用RHEL5光盘上自带的subversion-1.4.2-2.el5.rpm,注意不能安装最新的subversion-1.5.1版本,经测试与sventon-1.4.0不能兼容。
    添加svn帐户svnroot,用于svn存储库。

  2. 配置svn存储库
    切换到svnroot身份,创建目录/home/svnroot/repository
    建立pal代码库,svnadmin create /home/svnroot/repository/pal
    修改代码库配置文件,/home/svnroot/repository/pal/conf/svnserve.conf,内容如下:
    [general]
    anon-access = none
    auth-access = write
    password-db = /home/svnroot/repository/pwd.conf
    authz-db = /home/svnroot/repository/authz.conf
    realm = pal

    删除/home/svnroot/repository/pal/conf/authz及/home/svnroot/repository/pal/conf/pwd两个文件。

  3. 建立访问用户及权限
    建立用户及口令,创建文件/home/svnroot/repository/pwd.conf,内容如下:
    [users]
    svnclient = svnclient1234
    testuser = testuser1234

    建立访问权限,创建文件/home/svnroot/repository/authz.conf,内容如下:
    [groups]
    admin = svnclient
    programer = testuser

    [pal:/]
    @admin = rw
    @programer = r

    [pal:/code]
    @programer = r

    [pal:/design]
    @programer =

    [pal:/document]
    @programer =

    [pal:/technical]
    @programer =
    以上的配置建立了两个用户组,admin和programer,给予admin组pal代码库根目录及其下子目录的读写权限,给予programer组pal代码库根目录和code子目录的只读权限,design,document,technical子目录拒绝访问。

  4. 将svn服务添加入xinetd
    切换回root帐户,进入/etc/xinetd.d/,新建文件svn,内容为:
    service svn
    {
            socket_type     = stream
            protocol        = tcp
            wait            = no
            user            = root
            server          = /usr/bin/svnserve
            server_args     = -i -r /home/svnroot/repository
            disable         = no
    }

    重新启动xinetd,svn服务自动启动。

  5. sventon安装
    sventon是一个Subversion的Web浏览工具,下载地址www.sventon.org,目前版本1.4.0。
    先安装tomcat 5.5以上版本,本例使用6.0.18,修改server.xml中的8080 connector配置如下:
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
                   connectionTimeout="20000"
                   URIEncoding="UTF-8"
                   useBodyEncodingForURI="true"
                   redirectPort="8443" />
    注意红色的部分,这样网页才能正常显示中文路径及文件名。
    将svn.war部署到tomcat容器中,浏览器中打开http://<host>/svn,出现配置页面。注意sventon有两种浏览模式,一种是全局使用一个用户,所有人都可访问svn库中的内容,此模式支持路径及文件名的搜索;另一种是使用者输入自己的svn用户名及密码,只能访问自己有权限的内容,此模式不支持搜索功能。

2008年8月31日星期日

Mysql常用命令及配置

  1. 创建用户
    格式:grant 权限1,权限2...(或*) on 数据库(或*).表名(或*) to 用户名@登录主机名("%"代表远程登录无限制) identified by '密码'
    例子:
              > grant * on *.* to xued@"%" identified by 'password' ;
              > flush privileges;
    注意以上方式创建的用户不能以localhost登录,必须使用mysql -u xued -h IP地址 -p 的方式登录。
    修改密码:
              > set password for 'xued'@'%' = password('********')

  2. 字符集及最大连接数
    修改my.cnf或my.ini,在[mysqd]下添加
    default-character-set=utf8
    character_set_server=utf8
    max_connections=100
    保存后重启。
    指定数据库的编码:
               > create database test charset utf8;
    jdbc的连接url参数添加字符集:jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=utf8


2008年5月26日星期一

Apache,GlasshFish与Comet HTTP streaming配置

  使用Apache Httpd作为GlassFish的Load Balancer有两种方式:mod_jk与mod_proxy方式,由于mod_jk不支持Comet,所以如果应用程序使用了Comet,就只能使用mod_proxy方式了。此外Httpd应使用2.2.8以上版本,之前的版本mod_proxy不能对HTTP response chunk做立即转发,必须达到8k的chunk数据才会转发,这样在使用Http streaming的Comet应用中严重降低了实时性,2.2.8解决了这一问题。
  1.   GlassFish配置。
    进入$GLASSFISH_HOME/domains/domain1/config,编辑domain.xml,注意如果是集群或使用其他Glassfish的instance,目录会有所不同。
    找到名称为http-listener-1的<http-listener>配置组,添加下面三项:
              <property name="cometSupport" value="true"/>
              <property name="authPassthroughEnabled" value="true"/>
              <property name="proxyHandler" value="com.sun.enterprise.web.ProxyHandlerImpl"/>
    第一行是启用Comet支持,后面两行是Apache SSL转发需要的。
    此外找到<jvm-options>-client</jvm-options>,改为-server。
  2. 配置mod_proxy HTTP转发
    打开httpd.conf文件,在末尾添加:
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
    LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    LoadModule proxy_connect_module modules/mod_proxy_connect.so

    NameVirtualHost *:80

    <VirtualHost *:80>
        ServerName www.cometserver.com
        ErrorLog logs/cometserver-error_log
        CustomLog logs/cometserver-access_log common

        ProxyRequests Off
        ProxyPass /comet/ http://localhost:8080/comet/ max=1500
        ProxyPassReverse /comet/ http://localhost:8080/comet/
    </VirtualHost>
    这里将mod_proxy配置加入了一个虚拟主机里面,只在 www.cometserver.com虚拟主机中生效。ProxyPass转发所有客户端http请求,ProxyPassReverse转发所有服务器端redirect请求。
  3. 调整Apache Httpd最大连接数
    在httpd.conf中加入或修改如下配置:
    <IfModule prefork.c>
    StartServers       8
    MinSpareServers    5
    MaxSpareServers   20
    ServerLimit      1500
    MaxClients       1500
    MaxRequestsPerChild  4000
    </IfModule>
    以上配置设置最大连接数为1500
  4. 配置mod_proxy HTTPS转发
    打开ssl.conf或自定义的mod_ssl配置文件,在</VirtualHost>之前添加:
    SSLProxyEngine on
    ProxyRequests Off
    ProxyPass /comet/ http://localhost:8080/comet/ max=1500
    ProxyPassReverse /comet/ http://localhost:8080/comet/
    配置基本上相同,只是多了SSLProxyEngine on开启SSLProxy。
  5. web.xml配置
    在web.xml中配置CometServlet:
        <servlet>
            <servlet-name>QuotationServlet</servlet-name>
            <servlet-class>com.xued.fxtrader.comet.QuotationServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>QuotationServlet</servlet-name>
            <url-pattern>/quote</url-pattern>
        </servlet-mapping>
  6. Comet Servlet中response Header
            response.addHeader("Expires", "0");
            response.addHeader("Pragma", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
            response.addHeader("Transfer-Encoding", "Chunked");
  启动Glasshfish和Apache httpd。
  经以上配置,即可实现通过访问80端口透明代理访问Comet Http streaming服务,响应无阻塞延迟。

2008年5月25日星期日

OpenMq与Spring 2.5配置

  在之前的一篇Blog中(http://herculesx.blogspot.com/2007/12/activemqspring25.html),记述了ActiveMq与Spring2.5的结合使用配置,OpenMq基本上与此类似,但有一点不同,即ConnectionFactory的获取。OpenMq支持两种生成ConnectionFactory实例的方式,一种是JNDI方式查找,相对简单,本文主要介绍第二种方式,即参数配置的方式。
  OpenMqConnectionFactory是一个对com.sun.messaging.ConnectionFactory的装饰类,用于Spring的Bean管理,代码如下:

  import com.sun.messaging.ConnectionConfiguration;
  import com.sun.messaging.ConnectionFactory;
  import javax.jms.Connection;
  import javax.jms.JMSException;

  public class OpenMqConnectionFactory implements javax.jms.ConnectionFactory{
   
    private ConnectionFactory connectionFactory;

    public OpenMqConnectionFactory(String brokerAddress) throws JMSException {
        connectionFactory = new ConnectionFactory();
        connectionFactory.setProperty(ConnectionConfiguration.imqAddressList, brokerAddress);
    }

    public Connection createConnection() throws JMSException {
        return connectionFactory.createConnection();
    }

    public Connection createConnection(String userName, String password) throws JMSException {
        return connectionFactory.createConnection(userName, password);
    }
   
  }
 
  主要是connectionFactory.setProperty(ConnectionConfiguration.imqAddressList, brokerAddress);用来设置远程OpenMq Server的地址和端口,格式为"host1:port,host2:port...",多个主机用逗号隔开。
  spring配置文件:

  <bean id="jmsFactory" class="com.xued.fxtrader.jms.OpenMqConnectionFactory" >
        <constructor-arg type="java.lang.String" value="10.100.1.156:7676" />
  </bean>
 
  这样在spring的配置文件中就可以使用OpenMq的ConnectionFactory了。

2008年5月5日星期一

使用JWebUnit测试JavaScript弹出Alert窗口

    JWebUnit提供了三个方法用于测试javascript弹出的Alert,Confirm和Prompt窗口,分别是:
  • setExpectedJavaScriptAlert
  • setExpectedJavaScriptConfirm
  • setExpectedJavaScriptPrompt
    下面的代码对于Alert窗口进行了测试:

public class TomcatHomeTest {
   
    private WebTester tester;

    public TomcatHomeTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Before
    public void setUp() {
        tester = new WebTester();
        tester.setTestingEngineKey(TestingEngineRegistry.TESTING_ENGINE_HTMLUNIT);
        tester.getTestContext().setBaseUrl("http://10.100.1.156:8080/");
    }

    @After
    public void tearDown() {
    }

    @Test
    public void testHomePage(){
        tester.beginAt("/index.jsp");
        tester.assertTitleEquals("Apache Tomcat/6.0.16");

        //Link Test
        tester.clickLinkWithText("Change Log");
        tester.assertTitleEquals("Apache Tomcat 6.0 - Changelog");
       
        //Javascript Alert Test
        tester.setExpectedJavaScriptAlert("foo");
        tester.clickLinkWithText("Alert");
        tester.closeBrowser();
       
    }

}

  closeBrowser()方法执行时会去检查是否弹出了名为foo的Alert窗口,Confirm和Prompt窗口与此类似。

使用NetBeans与Ant实现Web项目自动集成测试


       NetBeans创建Web项目缺省是以Ant为基础进行构建,可以自动生成基本的编译,打包等Ant脚本,省去了手工编辑的繁琐,另外预留了一些Ant任务可供覆写和扩展,本文的目的是在NetBeans生成的Ant脚本基础上进行扩展,以实现一个完整的自动构建集成测试过程。
一、环境准备
  1.   NetBeans 6.1

  2.   测试所需的jar包:
    asm-2.2.1.jar
    asm-tree-2.2.1.jar
    cobertura.jar
    commons-codec-1.3.jar
    commons-collections.jar
    commons-httpclient-3.1.jar
    commons-io-1.3.1.jar
    commons-lang-2.3.jar
    cssparser-0.9.4.jar
    dom4j-1.6.1.jar
    hamcrest-core-1.1.jar
    hamcrest-library-1.1.jar
    htmlunit-1.14.jar
    jaxen-1.1.1.jar
    jdom-1.0.jar
    jmock-2.4.0.jar
    js-1.6R7.jar
    junit-3.8.2.jar
    jwebunit-core-1.4.1.jar
    jwebunit-htmlunit-plugin-1.4.1.jar
    nekohtml-0.9.5.jar
    pmd-4.2.1.jar
    regexp-1.3.jar
    servlet-api.jar
    strutstest-2.1.4.jar
    xercesImpl-2.6.2.jar
    xml-apis-1.3.02.jar
    xmlParserAPIs-2.6.2.jar
    xom-1.0.jar

  3. Ant 1.7.0,此外需要activation.jar,commons-net-1.4.1.jar,jakarta-oro-2.0.8.jar,mail.jar。将以上jar包拷贝到ANT_HOME/lib目录下,设置路径加入ANT_HOME/bin,还有环境变量ANT_OPTS=-Xms512m -Xmx1024m

  4. 一台远程部署服务器,安装Tomcat 6.0.16和Apache Httpd 2.2.8

  5. 在NetBeans中创建一个Web工程,使用strutsTest和JMock编写单元测试,JWebUnit编写端对端测试,编译打包通过。
二、在build.xml中添加Ant脚本
  1. 远程部署
        <property file="build.properties" />
        <!-- 覆写-post-dist任务,加构建版本号和时间 -->
        <target name="-post-dist" description="Record build information">
            <propertyfile file="build.info">
                <entry default="0001" key="build.number" operation="+" pattern="0000" type="int" />
                <entry default="now" key="build.time" pattern="yyyy.MM.dd HH:mm:ss" type="date" />
            </propertyfile>
            <copy file="build.info" tofile="${dist.dir}/build.info" />
            <ftp server="${ftp.server}"
                 remotedir="${ftp.remotedir}"
                 userid="${ftp.user}"
                 password="${ftp.password}"
                 depends="true"
                 binary="true"
                 verbose="true"
                 ignorenoncriticalerrors="true">
                <fileset dir="${dist.dir}" />
            </ftp>
        </target>
        <!-- 取消远程部署的旧版本应用 -->
        <target name="remove-remote-app" >
            <property name="status.file" location="deploy-${tomcat.server}.txt" />
            <get src="${tomcat.manager.url}/remove?path=/${webapp.name}"
                 dest="${status.file}"
                 username="${tomcat.username}"
                 password="${tomcat.password}" />
            <loadfile property="deploy.result" srcfile="${status.file}" />
            <echo>${deploy.result}</echo>
        </target>
        <!-- 部署新版本 -->
        <target name="deploy-remote-server" depends="clean,dist,remove-remote-app">
            <property name="install.file" location="deploy-remote-install.txt" />
            <property name="redist.url" value="file://${target.dir}" />
            <property name="target.url" value="path=/${webapp.name}&amp;war=${redist.url}" />
            <get src="${tomcat.manager.url}/install?${target.url}"
                 dest="${install.file}"
                 username="${tomcat.username}"
                 password="${tomcat.password}" />
            <loadfile property="deploy.remote.result" srcfile="${install.file}" />
            <echo>${deploy.remote.result}</echo>
        </target>

    build.properties为新建的资源文件,内容如下:
    reports.dir=build/test/results
    reports.xml.dir=${reports.dir}
    reports.html.dir=${reports.dir}/junit-html
    coverage.xml.dir=${reports.dir}/cobertura-xml
    coverage.html.dir=${reports.dir}/cobertura-html
    pmd.html.dir=${reports.dir}/pmd-html
    instrumented.dir=${reports.dir}/cobertura-inmt

    smtp.hostname=10.100.1.16
    smtp.hostport=25
    mail.user=xxxx
    mail.password=xxxx
    smtp.from=xxxx@xxxx.cn
    smtp.tolist=xxxx@xxxx.cn

    ftp.server=10.100.1.156
    ftp.remotedir=dist
    ftp.reportdir.junit=/home/httpd/html/htdocs/hosptest/junitreport
    ftp.reportdir.cobertura=/home/httpd/html/htdocs/hosptest/coberturareport
    ftp.reportdir.pmd=/home/httpd/html/htdocs/hosptest/pmdreport
    ftp.user=deployer
    ftp.password=deployer

    tomcat.server=10.100.1.156
    tomcat.manager.url=http://${tomcat.server}:8080/manager
    tomcat.username=system
    tomcat.password=manager
    webapp.name=hosp
    target.dir=/home/deployer/dist/hosp.war
    report.url=http://10.100.1.156/hosptest/

  2. 运行测试,生成JUnit单元测试报告,Cobertura测试覆盖率报告及PMD代码质量检查报告
        <!-- 装入Cobertura和PMD插件 -->
        <path id="cobertura_classpath">
            <fileset dir="lib">
                <include name="test/cobertura.jar" />
                <include name="test/asm-2.2.1.jar" />
                <include name="test/asm-tree-2.2.1.jar" />
                <include name="jakarta-oro-2.0.8.jar" />
                <include name="log4j-1.2.14.jar" />
            </fileset>
        </path>
        <taskdef classpathref="cobertura_classpath" resource="tasks.properties"/>
        <path id="pmd.classpath">
            <fileset dir="lib">
                <include name="test/pmd-4.2.1.jar" />
                <include name="test/asm-2.2.1.jar" />
                <include name="test/jaxen-1.1.1.jar" />
            </fileset>
        </path>
        <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath"/>
        <target name="instrument" depends="init,compile">
            <delete file="cobertura.ser"/>
            <delete dir="${instrumented.dir}" />
            <cobertura-instrument todir="${instrumented.dir}">
                <ignore regex="org.apache.log4j.*" />
                <fileset dir="${build.classes.dir}">
                    <include name="**/*.class" />
                    <exclude name="**/*Test.class" />
                </fileset>
            </cobertura-instrument>
        </target>
        <target name="-pre-test-run" depends="init" if="have.tests">
            <mkdir dir="${reports.dir}"/>
            <mkdir dir="${instrumented.dir}" />
            <mkdir dir="${reports.html.dir}" />
            <mkdir dir="${coverage.xml.dir}" />
            <mkdir dir="${coverage.html.dir}" />
            <mkdir dir="${pmd.html.dir}" />
        </target>
       
        <target name="coverage-test" depends="init,-pre-test-run,compile-test">
            <junit dir="${basedir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${platform.java}" showoutput="true">
                <classpath location="${instrumented.dir}" />
                <classpath location="${build.test.classes.dir}" />
                <classpath location="${build.classes.dir}" />
                <classpath path="${javac.test.classpath}" />
                <formatter type="xml" />
                <test name="${testcase}" todir="${reports.xml.dir}" if="testcase" />
                <batchtest todir="${reports.xml.dir}" unless="testcase">
                    <fileset dir="${test.src.dir}">
                        <include name="**/*Test.java" />
                        <exclude name="com/xued/hosp/jwebunit/*Test.java" />
                    </fileset>
                    <fileset dir="${test.src.dir}">
                        <include name="com/xued/hosp/jwebunit/*Test.java" />
                    </fileset>
                </batchtest>
            </junit>
            <junitreport todir="${reports.xml.dir}">
                <fileset dir="${reports.xml.dir}">
                    <include name="TEST-*.xml" />
                </fileset>
                <report format="frames" todir="${reports.html.dir}" />
            </junitreport>
        </target>
        <target name="coverage-check">
            <cobertura-check branchrate="34" totallinerate="100" />
        </target>
        <target name="coverage-report">
            <cobertura-report srcdir="${src.dir}" destdir="${coverage.xml.dir}" format="xml" />
        </target>
        <target name="alternate-coverage-report">
            <cobertura-report destdir="${coverage.html.dir}">
                <fileset dir="${src.dir}">
                    <include name="**/*.java"/>
                </fileset>
            </cobertura-report>
        </target>
        <!-- 运行所有测试,包括JUnit单元测试和JWebUnit端对端测试,生成测试报告 -->
        <target name="coverage" depends="instrument,coverage-test,coverage-report,alternate-coverage-report" />
        <!-- 运行PMD,生成代码质量报告 -->
        <target name="pmd">
            <pmd shortFilenames="true" classpath="." rulesetfiles="conf/pmd.xml">
                <formatter type="html" toFile="${pmd.html.dir}/index.html" linkPrefix="http://pmd.sourceforge.net/xref/"/>
                <fileset dir="src/java">
                    <include name="**/*.java"/>
                </fileset>
            </pmd>
        </target>

    pmd.xml指定了代码检查的规则集:
    <?xml version="1.0" encoding="UTF-8"?>
    <ruleset name="Custom ruleset"
        xmlns="http://pmd.sf.net/ruleset/1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
        xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
        <rule ref="rulesets/basic.xml"/>
        <rule ref="rulesets/braces.xml"/>
        <rule ref="rulesets/controversial.xml">
            <exclude name="OnlyOneReturn" />
            <exclude name="DataflowAnomalyAnalysis" />
            <exclude name="AvoidFinalLocalVariable" />
        </rule>
        <rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/>
        <rule ref="rulesets/codesize.xml/ExcessiveParameterList"/>
        <rule ref="rulesets/codesize.xml/CyclomaticComplexity" />
        <rule ref="rulesets/design.xml">
            <exclude name="ConfusingTernary" />
            <exclude name="UncommentedEmptyConstructor" />
        </rule>
        <rule ref="rulesets/imports.xml"/>
        <rule ref="rulesets/naming.xml"/>
        <rule ref="rulesets/optimizations.xml">
            <exclude name="MethodArgumentCouldBeFinal" />
            <exclude name="LocalVariableCouldBeFinal" />
            <exclude name="UseStringBufferForStringAppends" />
        </rule>
        <rule ref="rulesets/strictexception.xml">
            <exclude name="SignatureDeclareThrowsException" />
        </rule>
        <rule ref="rulesets/strings.xml"/>
        <rule ref="rulesets/typeresolution.xml">
            <exclude name="SignatureDeclareThrowsException" />
        </rule>
        <rule ref="rulesets/unusedcode.xml"/>
    </ruleset>

  3. 将测试报告上传,并且发送Email
        <!-- 删除旧的远程文件 -->
        <target name="clean-remote-report">
            <ftp server="${ftp.server}"
                 remotedir="${ftp.reportdir.junit}"
                 userid="${ftp.user}"
                 password="${ftp.password}"
                 action="del"
                 depends="true"
                 binary="true"
                 verbose="true"
                 ignorenoncriticalerrors="true">
                <fileset includes="**/*" />
            </ftp>
            <ftp server="${ftp.server}"
                 remotedir="${ftp.reportdir.cobertura}"
                 userid="${ftp.user}"
                 password="${ftp.password}"
                 action="del"
                 depends="true"
                 binary="true"
                 verbose="true"
                 ignorenoncriticalerrors="true">
                <fileset includes="**/*" />
            </ftp>
            <ftp server="${ftp.server}"
                 remotedir="${ftp.reportdir.pmd}"
                 userid="${ftp.user}"
                 password="${ftp.password}"
                 action="del"
                 depends="true"
                 binary="true"
                 verbose="true"
                 ignorenoncriticalerrors="true">
                <fileset includes="**/*" />
            </ftp>
        </target>
        <!-- 上传新的远程文件 -->
        <target name="ftp-report" depends="clean-remote-report">
            <ftp server="${ftp.server}"
                 remotedir="${ftp.reportdir.junit}"
                 userid="${ftp.user}"
                 password="${ftp.password}"
                 depends="true"
                 binary="true"
                 verbose="true"
                 ignorenoncriticalerrors="true">
                <fileset dir="${reports.html.dir}" />
            </ftp>
            <ftp server="${ftp.server}"
                 remotedir="${ftp.reportdir.cobertura}"
                 userid="${ftp.user}"
                 password="${ftp.password}"
                 depends="true"
                 binary="true"
                 verbose="true"
                 ignorenoncriticalerrors="true">
                <fileset dir="${coverage.html.dir}" />
            </ftp>
            <ftp server="${ftp.server}"
                 remotedir="${ftp.reportdir.pmd}"
                 userid="${ftp.user}"
                 password="${ftp.password}"
                 depends="true"
                 binary="true"
                 verbose="true"
                 ignorenoncriticalerrors="true">
                <fileset dir="${pmd.html.dir}" />
            </ftp>
        </target>
        <!-- 发送Email -->
        <target name="notifyteam" depends="ftp-report">
            <property file="build.info" />
            <mail mailhost="${smtp.hostname}"
                  mailport="${smtp.hostport}"
                  user="${mail.user}"
                  password="${mail.password}"
                  subject="Test build #${build.number}"
                  from="${smtp.from}" tolist="${smtp.tolist}" messagemimetype="text/html">
                <message>The build #${build.number} is now available.Please browse ${report.url} to see reports</message>
            </mail>
        </target>

  4. 将所有任务集成
    <target name="intergrate" depends="deploy-remote-server,coverage,pmd,notifyteam"/>

  5. 在命令行下输入ant intergrate即可完成所有任务,将此命令定制成自动执行脚本,即可实现自动集成。
  注意:以上步骤未包括最初从代码库中获取最新的代码,实际使用时可自行加入CVS或SVN任务实现这一步骤。