解惑

解己之惑,解人之惑

2007年3月 (第2页共4页)

Java很简单也很难

说Java简单,是因为它的语法,这个也是当初最吸引我的,我被C++的语法搞蒙了
但是,在实际的工作中,能够真正把Java使用得自如的人并不是很多,见到的大部分的人写代码没有问题,但是如果遇到一些问题就茫然了,不知道如何去解决问题,虽然有些人知道用google可以解决很多问题,但是有时候是因为自己的某些问题导致的问题,也有时候仅仅是开发环境的一些干扰导致的,很少有人和他遇到的问题完全一样。在这种情况下,就可以看出真正的功底了,对Java更加了解的人并不会急于解决问题,而是详细的查看出错信息,思考最有可能的原因。虽然就是简单的两句话,但是每一句都是建立在大量的经验的基础上的。
先说出错信息,我们知道Java的出错信息往往有很多冗余,在这么多信息里面怎么找到关键信息呢?加上有时候代码编写不规范,出错信息被吞掉了,或者配置的日志工具有问题,出错信息不输出到控制台,而是输出到日志文件。
再说最有可能的原因,你遇到的错误足够多了,你才能在脑海中搜索类似的问题,而且要保持一个开放的思想,因为错误信息稍微差一点,错误的原因可能就千差万别,还有时候信息一样也可能是不同的原因导致的。

有时候并不是很喜欢IoC/DI

相信现在做Java的人都应该听说过IoC/DI,也就是由容器负责类之间的初始化和组装,好处是很明显的,你不用自己写代码维护类之间的依赖关系,而且如果别人想用某个实现替换你的,也很简单,修改下配置文件就可以,但是有时候,例如你在看别人的源代码的时候,你想知道某个类谁在使用,很可能用IDE的工具是找不到的(例如Eclipse的References功能),但是这个类确实是被别的类引用的。
呵呵,当然,这个只是我发个牢骚,IoC/DI还是非常好的功能,对于中型以上的应用是非常有效的,对于小型应用可能就没有太大的必要了,反而影响别人读你的源代码。典型的例子就是Pluto,呵呵,一共就声明了9个Bean,这个关系用代码很好维护的。

Pluto的session问题

按照JSR168规范的说明,在Portlet中,我们可以通过PortletSession访问存储在HttpSession中的属性,我看了Pluto的实现,也确实是这样做的:
    // PortletSession Impl: Attributes —————————————–
   
    public Object getAttribute(String name) {
        return getAttribute(name, DEFAULT_SCOPE);
    }
   
    /**
     * Returns the attribute of the specified name under the given scope.
     *
     * @param name  the attribute name.
     * @param scope  the scope under which the attribute object is stored.
     * @return the attribute object.
     */
    public Object getAttribute(String name, int scope) {
        ArgumentUtility.validateNotNull("attributeName", name);
        String key = (scope == PortletSession.APPLICATION_SCOPE)
                ? name : createPortletScopedId(name);
        return httpSession.getAttribute(key);
    }

但是当我把pluto集成到我们的应用里面的时候,问题就来了,用户登录后,访问其它的页面和访问portlet的页面的时候的session id是不同的,历经磨难,找到一些前人的文章:

 
From testing with Jetspeed/Pluto on Tomcat 5.0 and the default configuration of 5.5, servlets accessed directly do not share the portlet session. In Tomcat 5.5 configured with emptySessionPath="true", behaviour is correct as described in the portlet specification.

So, to summarize what I’ve learned, if you need to pass session objects from a portlet to a servlet using Pluto as your servlet container, the following three conditions must all be true:

  1. You must run Tomcat 5.5.x, or later.
  2. You must set crossContext="true" in your web app’s element.
  3. You must set emptySessionPath="true" in the element in Tomcat’s server.xml file.

If you omit any one of these three steps, it won’t work.

所以问题的核心就是emptySessionPath,在我们的环境中使用的是tomcat5.0,crossContext是设置为true的。

2007年3月21日下午更新:
集成中的问题是我犯了一个错误,我在获取HttpSession中的属性的时候忘了应该使用APPLICATION_SCOPE,而不同的session id是因为我的另外的代码导致的(我写了一个Bridge类去获得Struts的Action的执行结果并输出,在Bridge中的请求相当于另外一个客户端)。
从Portlet中,使用RenderRequest..getPortletSession().getAttribute("xxxx", PortletSession.APPLICATION_SCOPE)就可以拿到其它的普通servlet和jsp中设置的值了。

Pluto admin在IE下不工作

这里的不工作是指添加删除按钮不工作,点击完全没有反应,解决办法是WEB-INF\fragments\admin\page\view.jsp,给button标签加上type="submit",这样按钮就有反应了(可能还会有其它的BUG,我是直接升级到这个文件的最新版本的),但是这不能解决全部的问题,因为添加按钮不能完全正常工作,你只能给第一个页面添加portlet,如果你选择了其它的页面,然后想用下面的添加按钮给那个页面添加portlet,结果是你的点击不会产生任何效果,因为后台prtolet认为是remove操作,但是没有选择要删除的portlet,解决办法是修改PageAdminPortlet:
        String availablePortlets = request.getParameter("availablePortlets");
        if(availablePortlets!=null) {
            doAddPortlet(request);
        }
        else {
            doRemovePortlet(request);
        }
这样做其实也是有问题的,就是如果你在下面选择了想添加的portlet,但是实际点击的是remove按钮,其结果和你预期的不同。

其实所有的这些问题都是源于Pluto不成熟,它只是给出了一个最最简单的参考,并没有经过充分的测试,而且它的开发人员可能是使用FF作为测试的主要浏览器的。

JSR168

JSR168规范是定义portlet容器及portlet之间的关系的,但是由于定稿比较早(2003年10月),所以没有涉及到portlet的独自渲染和刷新,而这个是现在的web2.0或者新一代web界面所不可或缺的,当然,新的JSR286规范可能会解决这个问题,但是我们不能等待这个规范的出台。就目前的情况看,融合jsr168和AJAX并不会很困难,问题的关键是没有一个轻量的组件或者成熟的解决方案,有的只是大的软件厂商在他们的portal产品中提供这种特性的支持。这段时间一直在用pluto,刚刚整合到我们的系统中,看了下pluto最终渲染出来的页面片断:
  <!– Assemble the rendering result –><br />
 
<div id="/testsuite.TestPortlet!764587357|0" class="portlet"><br />
  
<div class="header"><br />
      <!– Portlet Mode Controls –><br />
      <a href="http://localhost:8080/pluto/portal/__pm0x3testsuite0x2TestPortlet1!764587357|0_view"><span class="view"></span></a><br />
      <a href="http://localhost:8080/pluto/portal/__pm0x3testsuite0x2TestPortlet1!764587357|0_edit"><span class="edit"></span></a><br />
      <a href="http://localhost:8080/pluto/portal/__pm0x3testsuite0x2TestPortlet1!764587357|0_help"><span class="help"></span></a><br />
      <!– Window State Controls –><br />
      <a href="http://localhost:8080/pluto/portal/__ws0x3testsuite0x2TestPortlet1!764587357|0_minimized"><span class="min"></span></a><br />
      <a href="http://localhost:8080/pluto/portal/__ws0x3testsuite0x2TestPortlet1!764587357|0_maximized"><span class="max"></span></a><br />
      <a href="http://localhost:8080/pluto/portal/__ws0x3testsuite0x2TestPortlet1!764587357|0_normal"><span class="norm"></span></a><br />
      <!– Portlet Title –><br />
    
<h2 class="title">Test Portlet #1</h2>
<br />
    </div>
<br />
  
<div class="body"><br />
从这个输出来看,我们需要做的可能很简单,替换portlet-skin.jsp,重新定义那些按钮的输出为一个javascript,这样应该就可以部分刷新了。目前我们产品的其它一个功能已经可以做到这个了。现在的问题就是转换了。

删除指定时间之前的文件

我们的自动测试会生成报告,原来的实现比较简单,就是删除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天前的目录,这样就不会有太老的记录保留下来了。

学英语

呵呵,说来惭愧,学用英语近16年了,但是英语还是很差,看点东西问题还不大,但是一和老外说话就完蛋了。这次一个朋友给了我一个机会,和一个老外互换语言,我教他中文,他教我英语,虽然他是德国人,但是英语说得很好,而且他学习语言非常的快,去年8月到中国,没有正规的学习过中文,全靠自己学习摸索,竟然已经可以说一些简单的中文的,虽然有时候发音还不太标准。
昨天晚上是我们的第一次课,发现很多日常的单词我都不知道,竟然连杯子这样简单的词都不知道
另外比较少说英语,用得也不多,发现现在的语法也忘记了很多,哎,路还很远啊。

严格的MANIFEST.MF格式

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

开始准备装修

现在本来应该已经拿到产权证的,但是上家最后把产权证的密码输错了,搞得我们实际上3月5号才把过户申请交上去了,拿到产权证要等到4月多,我们等不急了,要开始着手装修了,上家开始还不太愿意现在把房子交给我们,因为银行的贷款还没有放给她,不过责任完全不在我们,而且合同上已经说了2月28号之前交房的,磨了半个多小时,她最终答应周三交房。

周末约了两个装修公司,一个报价4万9,一个报价5万8,都超过了我们的预算,本来我们想全包的,今天到公司问了下装修过的同事,都建议我半包,这样材料上我们可以把好关,也不会被装修公司宰,问题就是我们自己要辛苦点了。不过我们对装修一无所知,所以我也要开始恶补装修的知识了。看来人长大了确实要操很多心,很多原来不用掌握的知识都要去了解了,好在每个人都有一个圈子,有什么不懂的可以问问有经验的人,自己再去学习学习,经验慢慢的就有了,虽然不能成为专家,但是经历过后总归是会有些收获的。

奇怪的时间自动更新问题

这两天电脑的时间很奇怪,被自动的更新到一个错误的时间了,但是我已经关闭了那个Internet时间同步的功能,把系统服务里面的Window Time服务也停掉了,但是毫无作用,更加奇怪的是这个时间也不是单纯的时区问题,在分钟数上也有差别,大约和正常时间相差16个半小时,郁闷

2007年3月12日更新:
晕死,到头来,原来是CMOS的时间被修改的缘故,但是我并没有修改过CMOS时间啊。可能是周日的问题导致的,那天开机发现屏幕没有显示,和上次的症状一样,把显卡重新装了下还是不好使,后来关闭电源放了几个小时,睡觉前又试了下,竟然又能启动了。

更早的文章 更新的文章

© 2025 解惑

本主题由Anders Noren提供向上 ↑