Lunuo Plugin开发总结(一)
作为新手入行开发eclipse插件,到现在为止初步了解了eclipse,osgi,RCP,SWT/JFace等一些知识。在这过程中,给我最大的帮助的是这本《Contributing to eclipse Principle, Patterns, and Plug-Ins》,这本书的作者是大名鼎鼎的Erich Gamma,JUnit的开发者,在书中demo的开发就是JUnit-Plugin的开发,作者用了Test Driven Development 和Pattern Design的观点和方法。让我在学习的过程中深深为精彩的开发过程吸引。还有《eclipse Building Commercial-Quality Plug-Ins》,这本书在介绍eclipse plugin上有更加详细的细节,但是整本书读起来就不像前本这么朗朗上口了。
本个月开期的半个月,花费精力在验证Fault Automatical Location上了,需要用到Program Dependence Graph of java program。根据图来算出rank最大的点离真正错误的点的距离,来统计的判断location的方法效率。通过查找资料发现indus可以提供现有的功能,但是由于缺乏文档,并且PDG的方法就存在很多问题等其他原因我并没有深入。而是在一位博士的指点下,改成用cost来计算。这种方法就简单多了。也不需要其他信息,在现有基础上就可完成了。
于是下半个月开始开发eclipse插件。希望可以完成基础的eclipse插件框架和整体构想。在开发途中遇到最大的困难便是Soot在eclipse插件里时,整个classloader产生变化,导致找不到类,soot反复告知我要正确设置classpath。于是我开始研究起了java的classloader机制,我搜集了网上很多的关于介绍java的classloader和eclipse框架的classloader的文章,已收集在这个blog中了。但是最后我还是没有解决这个问题。我大致了解了整个机制,但是却对于soot的classloader望而却步,soot有3万多行高质量的代码,简直令我望而生畏了。于是我采用了JUnit开发时使用的通过eclipse新启动一个VM的方法来运行程序,这样就好比完全使用soot在命令行运行类似了。由于启动的关闭VM需要消耗时间长,造成eclipseUI类似停顿的现象出现。而由于我在plugin开发时使用的是类似auto incremental builder,我希望整个instrument的过程能无缝的结合到eclipse中,只要修改了java程序,就会自动的开始instrument,类似jdt中的javabuilder。但是这样的话就需要频繁的启动的关闭新的VM来运行soot,这样造成eclipseUI停顿是不可接受了。我无法搞清楚UI停顿的问题,起码尝试了5,6种方法也没有解决。反而是通过自己试的过程中解决了这个问题。在调试过程时,我一直好奇为什么我另开线程也仍然解决不了这个问题。似乎只有在UI线程调用非UI线程才不会等在非UI线程完成。但是由于autobuilder自然是在非UI线程,于是我发现通过启动线程后sleep线程,那么autobuilder线程就会自己返回了。这是我想到线程的知识时尝试的方法。但是VM的启动和关闭仍然会是一个不好的体验。因此我认为可以让此VM持续开着,设立成C/S模型来运行Instrument会是一个很好的选择,并且通过这样可以远程部署和运行大量的测试案例。这样多个开发人员可以同时使用服务器端高性能的机器来跑繁重的test过程。因为我认为这个工具的意义在于测试代码量巨大的Application,通过手工查找是不现实的。当然最终我是需要跟JUnit结合的。自然也是要支持很好的单元测试了。
关于eclipse的远程调试,eclipse支持远程调试,在eclipse的launch框架中,可以launch新的vm运行在debug模式在,再通过socket能把调试信息推回到eclipse。由于我开发时就涉及到这个问题,所以我查找的资料来实现这个过程。但是至今我没运行成功。
在完成通过新启动VM来运行soot后,我不死心的跟soot作者 Eric联系了一下。当Eric肯定了soot是通过URLClassLoader来载入类和需要设置sootclasspath时,我恍然大悟明白了soot的载入过程。而sootplugin里用到的方法简直迷惑了我,我一直认为Threadcontextclassloader的作用是被sootclassloader当作parent的但是事实上是不是的。soot可能自己构建了classloader继承体系。只要设置sootclassloader后即可。我在原先的尝试过程中使用过,但是我忘了设置了jre/lib和jre/lib/ext的的路径,本来这个是通过systemclassloader来装载的,但是在soot调用过程中soot可能区分这个模式,也需要自己来装载。我十分懊恼我忽视了soot的exception中can't find class ,一种是我自己的类,一种的系统类的错误。这造成了我花费了大量精力去学习了javaclassloader,而实际上,soot调用和设置很简单能完成。可能是我太自信自己能解决问题吧,我直到最后通过别的方法解决后才不死心的给Eric发了我的代码,而他从他的角度帮我否定了一些可能性后,我们短短交流了一会就解决了这个问题。当然通过线程的方式启动soot可以很好的避免vm启动的时间。但是使用C/S模式也有一定的用处,所以我决定把这个功能也集成到己开发框架了。这需要大量的关于socket和classloader,线程的知识,大致想法是模仿tomcat,jboss之类的服务器,采用同样的方法来支持class的hot swap。