解惑

解己之惑,解人之惑

分类:Java (第11页共20页)

Java技术

删除指定时间之前的文件

我们的自动测试会生成报告,原来的实现比较简单,就是删除32天前的那个目录,问题是可能某些天的build会失败,那么task不会被调用,这样可能保存的历史记录大于31了,偏离我们的目的了。查看了下ant的手册,发现有一个selector可以用,得到如下的内容:
    <target name="backup-report">
        <tstamp>
            <format locale="en" property="deletedDir" pattern="MM/dd/yyyy hh:mm aa" offset="-32" />
          </tstamp>
        <tstamp>
            <format property="thisDir" pattern="yyyy-MM-dd" />
          </tstamp>
        <mkdir dir="${reports-dir}/${thisDir}"/>
        <copy todir="${reports-dir}/${thisDir}">
            <fileset dir="${report-dir}">  
                <include name="**/*"/>
            </fileset>             
        </copy>       
        <delete>
            <fileset dir="${reports-dir}" includes="*">
                <date datetime="${deletedDir}" when="before"/>
            </fileset>
        </delete>
    </target>

问题是这个似乎不能删除目录,只有1.6.2以后才支持删除目录。
最终一个简单的方法就是在最开始就删除32天前的目录,这样就不会有太老的记录保留下来了。

严格的MANIFEST.MF格式

今天才发现这个文件的格式要求比较严格,因为使用的包比较多,所以那个Class-path的内容就比较多,我全部放在了一行,结果服务器启动读取那个文件的时候报错,错误信息是行太长,把它们切成多行,结果又是无效的头字段(java.io.IOException: invalid header field),和工程里面的其它文件比较了下,发现换行后要在前面加一个空格,后来又发现明明包含了一个包,但是找不到类,又在每行的后面加了一个空格,这下才完全搞定。

为什么要使用Pluto?

这两天一直在看Pluto的东西,给我的感觉一直都不是很好,随着了解的深入,这种感觉越来越明显,其实也不是别的,就是它的要求太高了,它所声明的一些东西它又没有真正做到(例如可以运行在JDK1.4下,可以在Tomcat5.0下运行),但是同时它又不是一个完善的Portal框架,因为它所提供的功能实在是太少了,它只是提供了一个JSR168规范的参考实现。我到现在都不明白美国那边的架构师为何要选择它,在我们研究后说它不能在JDK1.4下运行时,他们竟然一再质疑我们的结论。在我今天成功的发布到Tomcat5.0.28后,我想将它集成到我们的产品中,结果又出问题,原因也很简单,就是要把应用配置为crossContext的,但是我不知道如何设置,因为我们的产品使用的是Jboss+tomcat,那个pluto.xml文件是自动生成的,我手工修改也没有用。后来再研究了下,可能要修改jboss-web.xml文件,到了下班的时间就回来了,明天再试试了。不过明天我会和美国的架构师讨论下,我考虑使用Light Portal,因为它提供的功能更丰富,可以大大减少我们的工作量(包括AJAX的拖放式配置效果)。

将Pluto1.1发布到Tomcat5.0

上次也已经提到了很难将Pluto1.1发布到Tomcat5.0,经过另外几个小时的艰苦努力,总算是成功了。
第一是因为它使用了一个JDK1.5的API,解决方法是修改org.apache.pluto.core.ContainerInvocation,将CONTAINERS.remove();注释掉。(可能有潜在的问题,猜测可能是会有内存泄漏)
第二是它提供的参考实现的war包的配置使用了testsuite那个应用,必须修改pluto-portal-driver-config.xml,删除其中对testsuite应用的portlet的引用:
<?xml version="1.0" encoding="UTF-8"?>

<pluto-portal-driver
    xmlns="http://portals.apache.org/pluto/xsd/pluto-portal-driver-config.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://portals.apache.org/pluto/xsd/pluto-portal-driver-config.xsd
                        http://portals.apache.org/pluto/xsd/pluto-portal-driver-config.xsd"
    version="1.1">

    <portal-name>pluto-portal-driver</portal-name>
    <portal-version>1.1.0</portal-version>
    <container-name>Pluto Portal Driver</container-name>

    <supports>
        <portlet-mode>view</portlet-mode>
        <portlet-mode>edit</portlet-mode>
        <portlet-mode>help</portlet-mode>
        <portlet-mode>config</portlet-mode>

        <window-state>normal</window-state>
        <window-state>maximized</window-state>
        <window-state>minimized</window-state>
    </supports>

    <!– Render configuration which defines the portal pages. –>
    <render-config default="About Pluto">
        <page name="About Pluto"
            uri="/WEB-INF/themes/pluto-default-theme.jsp">
            <portlet context="/pluto" name="AboutPortlet" />
        </page>
        <page name="Pluto Admin"
            uri="/WEB-INF/themes/pluto-default-theme.jsp">
            <portlet context="/pluto" name="PlutoPageAdmin" />
            <portlet context="/pluto" name="AboutPortlet" />
        </page>
    </render-config>

</pluto-portal-driver>

阅读全文

痛苦的Pluto使用经历

项目中要使用到Pluto,今天研究了一下,但是经历着实痛苦。
我们的tomcat使用的是古老的jboss带的版本,我就用我自己安装的tomcat5.0.28做了下试验,结果不成功,后来下载了一个bundle版本,其实就是已经包含了tomcat的版本,但是它带的版本是5.5.20,我就对照了下,把我能看出来的不同都对应的在tomcat5.0.28下做了修改,应用是可以跑起来了,但是登录进首页的时候出了一个NullPointerException,原因不明也没有那么多时间去研究,后来就下载了老版本的1.0.1试验,结果应用都不能起来。没有办法,只能从原代码编译试试,又去下载maven,结果使用JDK1.4无法编译,它的代码中使用了一个JDK1.5才有的方法,手工修改源代码,编译通过了,但是在安装的时候又出了问题,报告pluto的一个plugin不存在。然后又下载pluto的1.0.1版本的原代码,又下载maven1.0.2版本编译,依然不成功,原因是不能解析project.xml文件,彻底无语了。

更新:
回家后又弄了一下,终于在tomcat5.0.28下成功手工发布了pluto1.1,问题是我依然要使用JDK1.5才能看到结果运行正常,使用JDK1.4时会出现编译pluto1.1时遇到的那个问题的运行期版本。步骤为将bundle版本下的文件拷贝到tomcat5.0.28的对应目录:

  • conf\Catalina\localhost\pluto.xml
  • \shared\lib
  • \PlutoDomain\pluto-portal-1.1.0.war
  • 编辑tomcat-users.xml文件,增加pluto用户

要解决JDK版本问题,可能的办法就是修改源代码(pluto-1.1.0-src\pluto-container\src\main\java\org\apache\pluto\core\ContainerInvocation.java,把64行注释掉就行)后在JDK1.4下编译,然后把那个有问题的类替换掉,当然可能会有其他的问题。

表现层的一些想法

上次也说过表现层是最难解决的,主要是解决复用和开发速度,目前的一些基本想法:

  • 有一个类似ECS的通用页面基本元素模型
  • 在上面的基本元素的基础上有项目需要的粒度更大一些的组件,例如下拉列表、表格甚至页面模版
  • 页面Builder,根据一定的规则可以自动创建页面的框架,然后开发人员只需要做一些小的调整
  • 和项目的模型层绑定,这样很多地方拿到模型后,使用Builder就可以使用非常少的代码得到外观一致的页面了
  • 引入AJAX,特别是一些过滤条件,根据一定的规则获取并更新到(可能增加一个客户端缓存),特别是Intranet应用,大部分可能都可以考虑使用AJAX
  • 基于规则的请求转发,不需要进行配置

其实,考虑这么多,主要是现在的视图层太灵活,因此代码风格以及解决问题的风格太不一致,维护起来简直是噩梦,给开发人员提供一个沙箱,他们只能在这个沙箱中发挥,那么产品整体的可维护性和一致性会大大提高。而且,开发的工作量也可以减少一倍以上,当然,搭建这个框架也需要很长时间,但是可以慢慢来,逐步的重构。

深度克隆的简单通用实现

今天看ECS的源代码,发现一个深度克隆的简单通用实现,当然这个实现会克隆所有的成员,因此如果你的类有一些不能保存或者克隆的成员,那么这个就无效了,但是如果你的类就是简单的POJO,那么这个还是不错的,正在为我的持久层的克隆发愁,这个应该是我正想要的。我也相信这个对很多人一样有用,虽然性能可能不是很好:

    /**
        Allows all Elements the ability to be cloned.
    */
    public Object clone()
    {
        try
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(baos);
            out.writeObject(this);
            out.close();
            ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream in = new ObjectInputStream(bin);
            Object clone =  in.readObject();
            in.close();
            return(clone);
        }
        catch(ClassNotFoundException cnfe)
        {
            throw new InternalError(cnfe.toString());
        }
        catch(StreamCorruptedException sce)
        {
            throw new InternalError(sce.toString());
        }
        catch(IOException ioe)
        {
            throw new InternalError(ioe.toString());
        }
    }
   

CVS开发方式是软件维护性的杀手

呵呵,不要误会,这里的CVS不是指版本管理的CVS,而是指程序员们最熟悉的三个快捷键:CTRL+C(复制)CTRL+V(转贴)CTRL+S(保存),一个软件产品中的很多代码都是这么得来的,以我们公司产品为例,最典型的莫过于Action的execute方法的前面对session是否过期的判断,以及调用后台的Session Bean的时候的异常处理,以及JSP中的大段类似代码。一旦需求发生变化,这些相关的代码可能都需要修改,我到这个公司的时候就发生过一次这样的事情:一个简单的修改要在百十几个Action中重复进行。
以我这些年的开发经验,我更加倾向于给开发人员提供一个受限的开发环境,可以供选择的接口很少,只有在必要的情况下才增加接口供开发人员使用,共通的功能只能通过共通的接口进行,否则你的工作量可能是使用正确的接口的十几倍。当然,这个开发方式比较适用于产品开发,因为项目的情况差异太大,而且开发周期相对比较短,这样做反倒延缓开发进度,增加成本。
至于如何提供那些接口,就是一个渐进的过程,开始的框架是一个宽泛的接口集,如果一段代码被重复三次,并且以后可能还会重复或者有类似的片断,那么就要马上对原来的代码进行重构,这样在第一个版本出来之前,我们就会得到一个比较好产品。在每个版本的开发前期、中期和后期都做一次代码检查,发现类似这样的代码重复问题并及时修改。

OO设计模式和设计原则(转帖)

很好的文章,下面是摘录,请直接下载原文阅读

1.1 设计正在“腐烂”的征兆(Symptoms of Rotting Design)
有四个主要的征兆告诉我们该软件设计正在“腐烂”中。它们并不是互相独立的,而是互相关联,它们是过于僵硬、过于脆弱、不可重用性和粘滞性过高。
1. 过于僵硬Rigidity
Rigidity 致使软件难以更改,每一个改动都会造成一连串的互相依靠的模块的改动,项目经理不敢改动,因为他永远也不知道一个改动何时才能完成。
2. 过于脆弱Fragility
Fragility 致使当软件改动时,系统会在许多地方出错。并且错误经常会发生在概念上与改动的地方没有联系的模块中。这样的软件无法维护,每一次维护都使软件变得更加难以维护。(恶性循环)
3. 不可重用性immobility
immobility 致使我们不能重用在其它项目中、或本项目中其它位置中的软件。工程师发现将他想重用的部分分离出来的工作量和风险太大,足以抵消他重用的积极性,因此软件用重写代替了重用。
4. 粘滞性过高viscosity
viscosity有两种形式:设计的viscosity和环境的viscosity。
当需要进行改动时,工程师通常发现有不止一个方法可以达到目的。但是这些方法中,一些会保留原有的设计不变,而另外一些则不会(也就是说,这些人是hacks)。一个设计如果使工程师作错比作对容易得多,那么这个设计的viscosity 就会很高。
环境的viscosity高是指开发环境速度很慢且效率很低。

2 面向对象的类设计原则
2.1 开放关闭原则The Open Closed Principle (OCP)
A module should be open for extension but closed for modification.一个模块应该只在扩展的时候被打开(暴露模块内部),在修改的时候是关闭的(模块是黑盒子)。
在所有的面向对象设计原则中,这一条最重要。该原则是说:我们应该能够不用修改模块的源代码,就能更改模块的行为。

2.1.1 动态多态性(Dynamic Polymorphism)
2.1.2 静态多态性(Static Polymorphism)
另外一种使用OCP的技术就是使用模板或范型,如Listing 2-3。LogOn函数不用修改代码就可以扩展出多种类型的modem。
阅读全文

表现层是最难解决的问题

在Web开发中,表现层是最难于通用化的,个人的感觉,Tapestry是一个不错的思路,可惜学习起来并不简单,而且也需要积累才能真正的简化开发。其它的表现层框架我都不是很看好,目前我的思路倾向于使用类生成页面,和模型层绑定,这样在产品或者大型项目中可以大大的简化工作量,也减少很多问题。目前,公司的产品中虽然是使用的这种思路,但是力度不够,组件太少,和模型的绑定也不够,需要写的代码太多,一种问题在不同的地方都需要小心,搞得QA也是很不爽。
而且表现层似乎也是搞开发的人中最不喜欢做的部分,因为“技术含量太少”,基本上堆代码肯定可以搞定。虽然我也不喜欢做表现层的工作,但是必须承认,如果能够实现一个易于使用的表现层框架,对于整个项目的贡献是很大的,至少有30%的代码量,因此可以简化的工作量实际上很多。公司考虑将更多的工作转移到中国来做,希望自己有机会能够改变这个情况,让表现层的工作更加的简单。

更早的文章 更新的文章

© 2025 解惑

本主题由Anders Noren提供向上 ↑