• 最近在工作中遇到一个问题,有一个jsp很大,其中包括了有300多个tag,反应是无法编译(在有的服务器上可以编译,但无法加载),打开生成的java文件,发现在jspService中有超过5000行的代码,其生成的class的code属性的长度超过了65535这个限制,jvm加载的时候认为是无效的class文件,抛出异常。必须给它减肥了,再就是把文件的内容分成两个文件来存放,分别编译,解决问题。

    今天突然又想起这个问题了,想看看Tapestry是如何应对这种情况的呢,另外今天开始学习asp.net,也想看看它的反应如何,由于写了一个变态的测试程序,生成所需要的测试文件。

    下面是python脚本:


    #生成taspstry的测试文件, 生成20000个tagestry 标记
    f=open("t.html","w")
    s0="""<span jwcid="$content$">"""
    s1="""<div><span jwcid="@Insert" value="ognl:msg" raw="true"/></div>"""
    s2="</span>"
    f.write(s0)
    i = 0
    while i<20000:
     f.write(s1+"\n")
     i=i+1
    f.write(s2)
    f.close()

    #生成jsp的测试文件, 生成2000个jsp tag标记
    f=open("t1.jsp","w")
    s0="""<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>"""
    s1="""<div><c:out value="test"/></div>"""
    f.write(s0)
    i = 0
    while i<2000:
     f.write(s1+"\n")
     i=i+1
    f.close()

    #生成asp.net的测试文件, 生成20000个Label组件
    s0="""<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title>Untitled Page</title>
    </head>
    <body>"""

    s1 = """<asp:Label ID="Label%d" runat="server" Height="32px" Width="72px"/> """
    s2="""</body>
    </html>"""

    f=open("t1.aspx","w")
    f.write(s0)
    i = 0
    while i<20000:
     f.write(s1%(i)+"\n")
     i=i+1
    f.write(s2)
    f.close()
     

  • 最近的总结

    2006-01-24

    又是一个多月没有写日志了,总是在瞎忙,今天就把最近的情况总结一下。

    1.Linux

    取得Shell运行时所在的目录

    功能:主要取得了当前运行脚本的绝对目录和参数,这个脚本是晚上帮朋友写的,以前也想写一个类似的脚本,一直没有动手,效果还不错。
    #! /bin/sh
    name=$0
    args=$*
    name=`echo $name|sed 's/^\.\{1,2\}\/\{1,\}//'`
    if [ ! $(echo $name | grep  '^/' - ) ]; then
        if [ `pwd` == '/' ]; then
            name=/$name
        else
            name=`pwd`/$name
        fi
    fi
    script=`/bin/ls -l $name | awk '{ print $NF; }'`
    while test -h "$script"
    do
      script=`/bin/ls -l $script | awk '{ print $NF; }'`
    done
    bindir=`dirname $script`
    echo "BaseDir:$bindir Args:$args"

    在两台机子之间拷贝文件

    cat <file0> | ssh  <host> "cat > /destfilepath"

    这个脚本需要在两台机子之间配置ssh,有可能需要输入密码,很是方便。

    2.Tagpstry

    换了新的工作,对一些j2ee的框架接触的少了许多,最近在用tapestry(tacos)+spring+hibernate做一个东西,另外用了jdk5.0,用了其中的泛型和annotation的功能,最喜欢String.fromat这个功能了,强。

    有时用tapestry进行一些特殊功能的实现,不是太灵活,特别是在基于tacos时,例如当提交form的时候,想要为用户提供一个确认的窗口,直接使用tacos的时候,是很难办到的,我找了它的好些component也没有找到类似的功能,用了一个比较别扭的办法:

    <form jwcid="pageForm">
        <div> 
            <label>
            <span key="title">标题:</span>     </label>
            <input name="title" type="text"  size="60" value="ognl:document.pageTitle" jwcid="title@TextField"/>
           </div>
          <div>
    <a jwcid="@tacos:AjaxDirectLink" name="dp" id="dp" listener="ognl:listeners.deletePageData" parameters="ognl:{pageDataId}" updateComponents="ognl:{'auditResult'}"/>

    <!--在这个a tag中触发jwcid dp的click事件-->

    <a href="javaScript:var ok = window.confirm('confirm?');if(ok){did.style.display='none';document.all.dp.click()}"><span key="deletePageData">删除此记录</span></a>
        </div>
      </form>

    使用Tapestry最大的感触是刚开始的时候有些不大适应,用的习惯后就对它强大的功能很是佩服,而且在DW中设计页面正如它所声明的一样,基本上不影响整体页面的效果。

    3.Java

    说起来实在是不好意思,最近才明白了String.replace和String.replaceAll之间的区别,前者不使用正则表达式,而后者使用正则表达式来执行替换操作。

    Jrockit是一个很强大的jvm,利用它提供的工具,可以动态的监视jvm中内存使用的状态,从Bea的文档上知道了Jrockit5.0有内存泄漏检测的工具,令人郁闷的是一直也没有成功的使用这个功能,不知道是否是由于License的限制。Jrockit的性能通过调整jvm的参数可以有很大的提升,公司有一台服务器,双CPU,把Jrockit的垃圾收集改为parallele,同时把-Xmx设为1000M,系统的响应速度得到了很大的提升,呵呵。

    Hibernate删除的时候,可以通过它来删除Object,但如果对象的个数多于一个,还是用sql来删除的好,不要猜测数据的多少,因为我们不好预测到所有可能发生的情况,在sql server使用Hibernate的delete方法的时候,按照hibernate的做法,它会先找到所有要删除的对象,之后才删除,我在测试一个程序的时候,发现sql server的后台进程阻塞了好几个,全是由于事先认为数据量不大,使用Hibernate删除不会有太多的影响,就懒得用jdbc来直接删除,其实通过spring的JdbcTemplate非常方便。

    4.Python

    前些日子用Python写了个程序,先在windows上写,后传到Linux上运行,发现总是不对,在网上搜索了一下,有高人说可能是由于windows和Linux之间换行符的不同赞成的,可以用dos2unix命令解决,不过这个命令不是在所有的Linux发行版上都有的。

    5.其它

    最近GCT考试结果出来了,还好被录取了,又要上学了,呵呵。今天上午把亲爱的GF送上火车了,心里的一块石头总算落下来了,不过又要给自己找火票了,晚上有同学打过电话来说,回大同的票已经没有了,郁闷,该怎么回家呢?明天再说吧。

  • Python TcpTunnel

    2005-09-01

    昨天工作中突然要用到Apache Soap中的一个叫做TcpTunnel工具,找了半天才找到,用得时候还是比较好的,就是感觉有时需要保存下来,很不方便,一大堆的输出全在文本框里了,晚上要加班,等频道那边填数据的空隙,就用Python写了一个简单的实现,还是比较好用地:)我把每次请求和响应顺序地写到对应的文件里,什么Cookie啊,JESSIONID啊,全能得到,呵呵:)

    下面就是代码:

    # -*- coding: cp936 -*-
    import socket
    import thread
    import threading
    """
    类似于apache soap TcuTunnle工具的Python实现
    """
    class TcpTunnel(object):
        def __init__(self,host,port,destHost,destPort):
            self.host = host
            self.port = port
            self.destHost = destHost
            self.destPort = destPort
        def run(self):
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.bind((self.host,self.port))
            s.settimeout(1)
            s.listen(1)
            i = 0
            while True:
                try:
                    conn,addr = s.accept()
                    rq_o = open(requestOut+"."+str(i),'w')
                    rp_o = open(responseOut+"."+str(i),'w')
                    dest = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    dest.connect((self.destHost,self.destPort))
                    request = Request(conn,dest,rq_o)
                    response = Response(conn,dest,rp_o)
                    request.start()
                    response.start()           
                    print 'Connected by', addr
                    i = i+1
                except socket.timeout,msg:
                    pass               

    class Request(threading.Thread):
        def __init__(self,local,remote,rq_o):
            threading.Thread.__init__(self)
            self.local = local
            self.remote = remote
            self.rq_o = rq_o

        def run (self):
            while True:
                try:
                    data = self.local.recv(1024)               
                    if not data:
                        self.remote.shutdown(socket.SHUT_WR)
                        break
                    self.rq_o.write(data)
                    self.remote.send(data)
                except socket.error, msg:
                    self.remote.shutdown(socket.SHUT_WR)
                    break               
            self.local.shutdown(socket.SHUT_RD)
            self.rq_o.close()

    class Response(threading.Thread):
        def __init__(self,local,remote,rp_o):
            threading.Thread.__init__(self)
            self.local = local
            self.remote = remote
            self.rp_o=rp_o

        def run (self):
            while True:
                try:
                    data = self.remote.recv(1024)
                    if not data:
                        self.local.shutdown(socket.SHUT_WR)
                        break
                    self.rp_o.write(data)
                    self.local.send(data)
                except socket.error, msg:
                    self.local.shutdown(socket.SHUT_WR)
                    break               
            self.remote.shutdown(socket.SHUT_RD)
            self.rp_o.close()
    requestOut = "request.out"
    responseOut = "response.out"

    tcp = TcpTunnel("localhost",8080,"www.google.com",80)
    tcp.run()

    BTW:最近心情很不好,可以说是非常地糟,刚才在写这个程序的时候发现自己竟然可以不再想那些烦恼,好像已经完全地忘掉它们了, 随意地实现自己的想法,这时我终于认识到了,我是程序员了已经:)   

    事情终究要解决的,终究是要有结果的,可是用什么方式结束是个未知数,我希望有好的结果,老天保佑。

  • 最近刚换了工作,提起换工作,我都不好意思了,二年换了四家,惭愧,这回要认真的体会一家公司了。

    前段时间做测试,需要大量的身份证号和姓名,一时手头上又没有那么多,用GOOGLE搜了一下,还真找到一个网页,上面有不少信息,可是不方便提取出来,我想了一个简单的办法,先把这个文件保存下来,再写一个PYTHON小程序,用正则表达式从HTML文件里抽取出想要的数据,调用的时候把输出重定义向到一个文件中,就取到了里面想要的数据。下面是这个小程序,比起JAVA来,代码少了很多。

    # -*- coding: cp936 -*-
    import sys
    import os
    import re
    import time

    filepattern ="""姓名:(.*)身份证:(.*)"""
    filep = re.compile(filepattern)
    if __name__ == "__main__":
    if(len(sys.argv)<2):
    print '缺少参数'
    sys.exit(0)

    dump = open(sys.argv[1],'r')
    data = dump.read()
    result = filep.findall(data)
    if(result!=None):

    for group in result:
    name = group[0].strip(' ')
    cid = group[1].strip(' ')
    if (len(name)>0 and len(cid)>0 and (len(cid)==18 or len(cid)==15)):
    print cid+"/"+name+"\r\n",
    dump.close()
    sys.exit(0)

  •  前段时间,websphere总是当机,其实也不是当,就是响应特别的慢,几乎没有响应了。实在没有办法只好生成javacore,看一看线程的情况。他们是每隔10分左右生成一个javacore,在websphere中,生成的内容全部在native_stdout.log中,开始看的时候发现有很多线程的调用栈中都有

    - locked <0xc2527c58> (a oracle.jdbc.ttc7.TTC7Protocol)

    我怀疑可能是这里的问题,用眼看那些日志可真够受的了,也得不到什么有用的信息。就用python写了一个分析程序,把这些locked全找出来,于是就写了下面这个小程序:

    # -*- coding: cp936 -*-
    import sys
    import re
    pattern = '[\s*]- locked <0x(.*)>.*
    \\(a oracle.jdbc.*\\)'
    prog = re.compile(pattern)
    lockMap = {}
    lineMap = {}
    if __name__ == "__main__":
        if(len(sys.argv)<2):
            print '缺少参数'
        print sys.argv[1]
        print '行数','地址','内容'
        dump = open(sys.argv[1],'rb')
        line=dump.readline()
        ln = 1
        lock = 0
        crash = 0
        while line!='':
            #print line       
            result = prog.match(line)
            #print result
            if(result != None):
                lock = lock +1
                objectref = result.group(1)
               
                if lockMap.has_key(objectref):
                    crash = crash + 1
                    lockMap[objectref].append(ln)
                else:
                    lockMap[objectref]=[ln]

                lineMap[ln] = result.group(0)
                print str(ln),objectref,result.group(0)
            line = dump.readline()
            ln = ln+1
        print '共有'+str(lock)+'个锁对象出现'

        lockkeys = lockMap.keys()
        print '\n'+str(crash)+'个锁被两个或两个以上的线程取得\n'
        print '锁对象\t在log中出现的行数'
        for key in lockkeys:
            print str(key)
            for lc in lockMap[key]:
                print '\t'+str(lc)+str(lineMap[lc])
        #print lockMap
        sys.exit(0)

    通过对native_stdout.log运行这个程序,得出的结果就是:

    ......

    共有288个锁对象出现

    144个锁被两个或两个以上的线程取得

    锁对象 在log中出现的行数
    c0e6aef0
     2562 - locked <0xc0e6aef0> (a oracle.jdbc.ttc7.TTC7Protocol)
     5995 - locked <0xc0e6aef0> (a oracle.jdbc.ttc7.TTC7Protocol)
    c04e1ae8
     2990 - locked <0xc04e1ae8> (a oracle.jdbc.driver.OracleConnection)
     6423 - locked <0xc04e1ae8> (a oracle.jdbc.driver.OracleConnection)
    c1da32c8
     2019 - locked <0xc1da32c8> (a oracle.jdbc.driver.OraclePreparedStatement)
     5452 - locked <0xc1da32c8> (a oracle.jdbc.driver.OraclePreparedStatement)

    ..............

    由这个结果可以知道,144个锁在线程中被引用,通过结果中显示的行数,locked后面的对象锁始终是被同一个线程持有,比如:

    2019 - locked <0xc1da32c8> (a oracle.jdbc.driver.OraclePreparedStatement)
     5452 - locked <0xc1da32c8> (a oracle.jdbc.driver.OraclePreparedStatement)

    这里有一个对象<0xc1da32c8>在同步块里,而在2019和5452这两行上,找到它们的线程号,是同一个,其余的也是一样的结果。这就排除了死锁的可能,也初步排除了程序造成死锁的可能。

    而在每个这样的输出中,都有下面的内容:

    at java.net.SocketInputStream.socketRead0(Native Method)
     at java.net.SocketInputStream.read(SocketInputStream.java:129)
     at oracle.net.ns.Packet.receive(Unknown Source)

    就是由于在读数据的时候线程被阻塞了,导致很多的线程被挂起,在这里是77个线程被挂起了。

    我怀疑是oracle的jdbc驱动的问题,于是在网上找资料,果然有相似的问题。于是就按照oracle metalink上所说的,下了一个10g的驱动来用,(忘记说了,我们用的是9.2.0.5那一个驱动),在本地测试了一下,问题没有再现,把服务器上的驱动换掉,现在已经是第3天了,一直没有当机,而且连接也很正常。:)

    9.2.0.5的驱动有严重的bug,它可能会导致server当机:(

    另外,要避免这个问题发生,还可以通过设置查询超时来避免,不至于把server弄当了。

  • python小应用 2

    2005-03-22

    python小应用可以帮助我们解决一些不大容易的问题。

    今天收到了一个邮件,不知道为什么,在gmail里有的邮件总是乱码,点击original message,看到了base64的编码,是gbk,而手边又没有适合的工具来转换编码,用pythong很方便就可以了:)

    打开python shell,输入

    import base64

    msg = base64.decodestring("""base64的编码拷到这里""")

    print msg

    就可以看到邮件的文本内容了。

    由于base64的编码长度一般比较长,所以用"""和"""来括起来这些内容是个不错的选择:)

  • 上周买了一个MP3播放器,挺好的。昨天下了一些Queen的MP3,拷贝到了MP3里面,在路上一听,才发现格式错误。回到家里到电脑上放,可以的啊。仔细的检查了一下文件,发现这次下的MP3里都有一张Queen专缉的图片,这就导致了我的MP3无法播放这些MP3了。

    今天到公司,正好上网找了一下MP3的格式,顺便用python写了一个程序,修改MP3,把那些信息都删除,MP3就可以正常播放了,程序见下面:

    # -*- coding: cp936 -*-
    """
    将MP3文件中的ID3V2.3部分去掉,以便在MP3机上播放
    用法:mp3lcear [源mp3目录] [生成的mp3目录]
    """
    import sys
    import os
    import string
    import shutil
    import struct
    import thread
    import threading
    import time

    mp3suffix = 'mp3'

    class Process(threading.Thread):
    """
    简单地在运行的过程中显示进度
    """
    def __init__(self,msg,sleepTime):
    threading.Thread.__init__(self)
    self.msg = msg
    self.running = True
    self.sleepTime = sleepTime
    def setPause(self,pause):
    self.pause = pause
    def setRunning(self,running):
    self.running = running
    def run (self):
    while(self.running):
    self.pause.wait()
    print self.msg,
    time.sleep(self.sleepTime)

    def usage(code, msg=''):
    """
    程序的使用方法
    """
    print >> sys.stderr, __doc__
    if msg:
    print >> sys.stderr, msg
    sys.exit(code)

    def checkDir(argDir,create=False):
    """
    检查目录是否存在,如果create为Ture,则新建一个目录
    """
    tempDir = None
    if(not os.path.isdir(argDir)):
    currentDir = os.path.abspath(os.curdir)
    tempDir = os.path.join(currentDir,argDir)
    if(not os.path.isdir(tempDir) and create):
    os.mkdir(tempDir)
    else:
    usage(1,"目录"+argDir+"不存在")
    else:
    tempDir = os.path.abspath(argDir)
    return tempDir

    def clearMp3(srcFile,destFile):
    """
    修改mp3文件,并将其创建到destFile所指定的地址
    """
    global process
    srcfp = None
    filesize = os.path.getsize(srcFile)
    try:
    srcfp = open(srcFile,'rb')
    head = srcfp.read(3)
    if(head=='ID3'):
    srcfp.seek(3,1)
    size = srcfp.read(4)
    if(not len(size)==4):
    print srcFile+'文件格式错误'
    else:
    size0 = struct.unpack('b',size[0])[0]
    size1 = struct.unpack('b',size[1])[0]
    size2 = struct.unpack('b',size[2])[0]
    size3 = struct.unpack('b',size[3])[0]
    headSize =(((size0&0x7f)<<21) | ((size1&0x7f)<<14) | ((size2&0x7f)<<7) | (size3&0x7f))
    filesize = filesize - headSize
    destfp = None
    try:
    dataLen = 0
    destfp = open(destFile,'wb')
    srcfp.seek(headSize,1)
    data=srcfp.read(1024)
    while (data!= ''):
    destfp.write(data)
    data=srcfp.read(1024)
    except Exception,e:
    print '创建文件'+destFile+'错误',e
    try:
    if (destfp != None):
    destfp.close
    except Exception,de:
    print de
    else:
    print srcFile+'不需要修改 拷贝',
    try:
    shutil.copyfile(srcFile,destFile)
    except Exception, ce:
    print ce
    except Exception,oe:
    print '修改中出错',oe
    try:
    if (srcfp != None):
    srcfp.close()
    except Exception,se:
    print de

     

    if __name__ == "__main__":
    if(len(sys.argv)<3):
    usage(1)
    global process

    sourceDir = checkDir(sys.argv[1])
    destDir = checkDir(sys.argv[2],True)

    print 'Mp3源目录',sourceDir
    print 'Mp3目的目录',destDir

    process = Process('...',1)
    pause = threading.Event()
    process.setPause(pause)

    process.start()

    for filename in os.listdir(sourceDir):
    srcPath = os.path.join(sourceDir, filename)
    destPath = os.path.join(destDir, filename)
    if os.path.isfile(srcPath):
    print '开始处理 '+filename,
    tempfilename = filename.lower()
    if(not tempfilename.endswith(mp3suffix)):
    print filename+'不是一个mp3文件\n'
    else:
    pause.set()
    clearMp3(srcPath,destPath)
    pause.clear()
    print '结束 \n'
    pause.set()
    process.running = False
    sys.exit(0)

    用这个程序修改后的MP3比原来要小一些了,因为一张图片被删除了,起到了给MP3"瘦身"的作用。在那些mp3中,每个都有一张400多K的图片,10几个MP3,就相当一个普通MP3文件的大小了。python写一些小工具很是方便:)

    刚才才知道师姐是今天走,我还以为是明天晚上的车。回想一下,从认识到现在,都快三年了也,我,她和她老公经常在一起玩,现在要走了,还不知道什么时候才能再见,不过以后经常被她宰的机会也少了许多,正所谓那什么,哈。。。。祝她一路顺风,一路平安^_^

  • 刚用jython测试了一下今天的程序,新的程序使用NIO,用jython交互式的运行方式,可以很方便地测试这种程序,可以手动连接到服务器上,然后向它发数据,像一个功能更加强大的Telnet,同时呢,可以观察服务器的反应,输入特定的数据,看其效果,更容易debug和查看程序的逻辑,比较不好地是它需要我们手动地连接,如果测试量较大很不方便,在今后几天想一想有没有更好的方法:)
  • Jython,一听这名字我就下决心要学习它,与Java的集成可以说是做到了完美,你几乎不用学Jython的函数库或它的类库,会使Java的类库就可以了。但是与CPython相比,它的严谨性会差一点,上午写了一个py,在文件里调用了一个方法"".jion("a"),在用jython调用没有报错,但是我感觉结果不对,于是在CPython的运行这个文件,它马上检查出了这个错误,这是Jython特有的吗?
  • 昨天回家试了一下运行jython,发生它的报错是org.python.core.PyObject类的格式错误,只好重新编译一下,还好,它可以单独编译。重新打包jython.jar用jdk1.5试运行,正常。现在在Red Hat Linux中使用Jython,还不错,它的命令窗口还以是透明的,这样就能随时看到我桌面上设的陈慧琳了。惟一感觉不好的是一旦进入Jython的交互环境,方向键就变得很难用了,惟一能用的就是退格键,一敲方向键,打出的不知是什么字符,感觉好像还是Unicode字符:)太郁闷了。