2009年4月30日星期四

当卸载symantec客户端需要密码时

忘记symantec病毒防护中心密码的情况下卸载symantec客户端的方法:
1.) Norton Symantec AntiVirus 8.0卸载的通用密码:symantec
2.) Norton Symantec AntiVirus 9.0无通用密码,不过可以采取以下方式来去除卸载密码,修改注册表
HKEY_LOCAL_MACHINE\SOFTWARE\INTEL\LANDesk\VirusProtect6\CurrentVersion\AdministratorOnly\Security
修改UseVPUninstallPassword键值为0,即可无需密码卸载
3.) Norton Symantec AntiVirus 10.0可同样使用方法2。

2009年4月27日星期一

面向接口编程

在类A中发现如下代码:

public TestStepExecuteResult deviceCommand(final String command,
final Vector inputParams, final Vector outputParams) {
... ...
AbcCommandExecutor executor = AbcExecutorSessions.getInstance()
.getExecutor(AbcExecutorType.CASE_EXECUTOR);
if (command.equals("TspStatusCheck")) {
testStep = new TspSysStatusCheck();
return (testStep.testStepRun(inputParams, outputParams, executor));
} else if (command.equals("TspCreateVlan")) {
testStep = new TspVlanCreateVLAN();
return (testStep.testStepRun(inputParams, outputParams, executor));
} else if (command.equals("TspCreateDhcpProvider")) {
testStep = new TspDhcpCreateDhcpProvider();
return (testStep.testStepRun(inputParams, outputParams, executor));
} else if .....
.....// 省略n多行。
} else {... ...
}
....
}

显然,可以重构,很简单。
  1. 找到testStep对应的父类或接口,假如是ITestStep。
  2. 修改deviceCommand()签名,
    public TestStepExecuteResult deviceCommand(ITestStep testStep,
    final Vector inputParams, final Vector outputParams) 。
  3. 把诸如 new TspSysStatusCheck() 的代码,移到方法调用前的某个合适位置(也许需要利用反射)。
  4. 修改臭味部分,把n多行的if-else if -else if替换为一行:
    return testStep.testStepRun(inputParams, outputParams, executor);

实际上,inputParams, outputParams也是可以/应该放到ITestStep中的。因为,本来这些数据的属主也是ITestStep。

2009年4月23日星期四

用tclBlend 执行tcl脚本

void eval(String str)
void evalFile(String fileName)

eval("source C:/tclScript/test.tcl");
evalFile("C:/tclScript/test.tcl");
上面这两种调用的效果是一样的。值得注意的是目录分割符是"/",而不是"\"。TclBlend会把"\"当作转义符。

2009年4月21日星期二

安装Perl模块

类似于Net-Server-0.97.tar.gz这样的模块,只要解压后按照:
perl Makefile.PL
[configurate]
make
make test
make install
这样的步骤就可以把模块安装到perl的运行环境中了。

另:
POE: Perl Object Environment
POE is a framework for creating event-driven cooperative multitasking programs in Perl.

2009年4月16日星期四

在Blogger中让代码着色

Google code prettify用于web页面code着色显示。
http://google-code-prettify.googlecode.com/svn/trunk/README.html

按照这篇文章(http://sls.weco.net/blog/rjrsjajawhu/26-dec-2008/11929)的讲述,
三步就可以让blogger中发布的code获得语法着色功能。
package com.dh.tcl;

public class TclTest {

private Thread t;
private Thread t2;

private EventProcessingThread ep;
private EventProcessingThread ep2;

public TclTest() {
startEventProcessThread();
}


private void startEventProcessThread() {
ep = new EventProcessingThread();
t = new Thread(ep);
t.setDaemon(true);
t.start();

ep2 = new EventProcessingThread();
t2 = new Thread(ep2);
t2.setDaemon(true);
t2.start();

// Wait for other Thread to get ready
while (ep.interp == null || ep.interp2 == null
|| ep2.interp == null || ep2.interp2 == null) {
try {Thread.sleep(10);} catch (InterruptedException e) {}
}

}

public void printInfo() {
System.out.println(ep.interp.getNotifier());
System.out.println(ep.interp2.getNotifier());

System.out.println(ep2.interp.getNotifier());
System.out.println(ep2.interp2.getNotifier());
}


public static void main(String[] args) {
TclTest test = new TclTest();
test.printInfo();
}

}
程序输出:
tcl.lang.Notifier@dd5b
tcl.lang.Notifier@dd5b
tcl.lang.Notifier@c4bcdc
tcl.lang.Notifier@c4bcdc
可见,在不同线程中创建的Interp对象所对应的Notifier对象是不同的。
但是同一线程中Interp对象的notifier对象是相同的。

2009年4月15日星期三

Tcl Blend中的线程和event处理

Jacle和Tcl Blend中的tcl.lang.Notifier实现了事件循环处理功能。 一个线程可以包含N个Tcl解释器,在同一个线程中创建的解释器Interp共享同一个Notifer。也就是Notifier是和绑定创建Interp时的线程对应在一起的。最简单的情况,一个线程包含一个Tcl解释器和一个Notifier对象。
看看Interp的构造函数的定义就清楚了:

cThread = Thread.currentThread();
notifier = Notifier.getNotifierForThread(cThread);
notifier.preserve();

Notifier.getNotifierForThread()定义是:

public static synchronized Notifier getNotifierForThread( Thread thread)
{
Notifier notifier = (Notifier) notifierTable.get(thread);
if (notifier == null) {
notifier = new Notifier(thread);
notifierTable.put(thread, notifier);
}

return notifier;
}



通常,事件是在一个循环中通过不断的调用doOneEvent()方法得到处理。
而TclBlend的Event包含了你要完成的逻辑。如果事件队列中没有event,则doOneEvent()会被阻塞,直到获得新的事件。所以,一般创建一个独立的线程来运行Notifier.doOneEvent()。而tcl event都是在其它的线程中创建并通过interp.getNotifier().queueEvent(event, TCL.QUEUE_TAIL) 放到event query中。

调用event.sync(); 会阻塞,直到这个event被处理完毕。

从不是运行doOneEvent()的线程中调用interp.eval()是不合法的,通常导致crash和随机的错误。

If you want to use the tclblend in your java project, you need not only the tclBlend libraries but also the jacl libraries. You should copy the tclBlend and jacl jar files into the same directory otherwise tclBlend it can not work rightly.

2009年4月14日星期二

对单例的另一点体会。

单例的核心是保证类的实例只有一个。

你可以在编程中为你的应用很小心地只为某个类创建一个实例,并小心翼翼的保证只有一个实例。
但这太累了,需要把这用保证集中起来,最好的地方当然就是这个类自己了。

单例把这种保证是放在了该类自己的代码中。所以,单例虽然很简单,却很漂亮。

eclipse plugin的误用

现在的项目,根据设备的不同而构建了不同的plugin。而每次程序发布时都需要重新编译所有代码,一起同步发布。
个人感觉eclipse plugin应该用于更宽松的耦合。就是,需要可以在不知道你的app的情况下,直接把plugin拷贝到规定目录,就能run起来,提供服务。
而现在的项目,plugin甚至是依赖于base app某些包的。所以个人感觉完全没必要把device实现为plugin。

构建应用:业务知识、编程知识、需求分析能力、设计能力

工作的时候应该不断积累“业务知识、编程知识、需求分析能力、设计能力”。

业务知识,编程知识都是最低级的。它不需要你太多的拓展,你只要理解、记住这些知识本身就足够了。比如,dslam的命令行使用(及其含义)、协议规范(如SIP的呼叫流程)、java多线程编程的注意事项及惯用法、socket编程... ... 这些知识有的很简单,有的相当复杂,但总的来说,是比较易懂易学的。
难的是,根据业务知识结合编程知识,进行需求分析,进行系统设计。分析和设计需要更高一点的抽象处理,是需要全盘考虑的,甚至是要进行平衡取舍处理。

哪种知识都很重要,哪种能力都很关键。在工作中多思考、多实践,应该就会不断进步吧。

资源的生命期

在C++ 语言中,特别注意对资源的管理。写构造函数、析构函数时都要仔细考虑类中各种资源的初始化和释放的问题。
什么是资源?任何一个对象的实例也可以理解为资源,因为它至少占用了内存。我想说的资源是诸如:数据库连接、socket连接 这样的对象、线程对象、文件句柄、IO端口... ...这种资源不仅占据本程序的资源(内存、CPU运算)而且还占用外部系统的能力,而这些外部系统的能力了往往并不是无限的。是资源的东西,同时也意味着被动的东西。资源天生就是被用来管理、使用的。

在Java的项目中,因为java的垃圾回收机制,在类的级别我们确实不用操心太多。但是,就程序的结构上,我们必须要确切的知道我的程序中到底有哪些资源。一般情况下我们必然会有对某种资源的管理类。这个类负责资源的生命期。有些资源根据某些策略也许需要lazy-initialization,有些需要提前的hungry-initialization。但是如论如何,在程序的任何运行阶段我们要对这种资源的使用心里有数。我们可以构建ResourceManager来管理程序中的所有资源。
这样,当我们按下“暂停”“停止”“restart”这样的按钮时就可以很容易的通过resource manager来对资源进行管理。
当然,如果你的程序不是关键应用,可以不断重启,那么不必太关心resource。但是,这样的程序会给以后的维护和修改设置障碍。

这个看似简单的论述,如果不能再设计阶段进行考虑的话,也会带来混乱。相反,程序就很好维护、易懂。

2009年4月2日星期四

telnet中的颜色控制字符

十六进制
1b 5b 30 30 6d 1b 5b 30 30 6d ###### 1b 5b 30 30 6d 20
. [ 0 0 m . [ 0 0 m ###### . [ 0 0 m
其中###表示字符串。

.[00m.[00m 第一个.[00m表示颜色开始,第二个.[00m表示白色。
.[00m 表示颜色设置结束。
.[00m.[34m 第一个.[00m表示颜色开始,第二个.[34m表示蓝色。
.[00m 表示颜色设置结束。

.[00m.[00manaconda-ks.cfg.[00m .[01;34mDesktop.[00m .[00minstall.log.[00m .[01;34mpackages.[00m
manaconda-ks.cfg和 install.log是白色,Desktop和packages是蓝色。


下面的定义摘自:
http://www.linuxselfhelp.com/howtos/Bash-Prompt/Bash-Prompt-HOWTO-12.html,可见telnet与unix的渊源很深。
local BLUE="\[\033[0;34m\]"
local LIGHT_GRAY="\[\033[0;37m\]"
local LIGHT_GREEN="\[\033[1;32m\]"
local LIGHT_BLUE="\[\033[1;34m\]"
local LIGHT_CYAN="\[\033[1;36m\]"
local YELLOW="\[\033[1;33m\]"
local WHITE="\[\033[1;37m\]"
local RED="\[\033[0;31m\]"
local NO_COLOUR="\[\033[0m\]"

建模,也是一种分类。

写telnet connection的时候用到一些常量。比如login的提示符“login: ”,支持的命令“dir”、“list”。这些刚开始都是写到telnetConnection的类里作为常量。但是,当试图支持Linux和XP两种OS上的telnet server时发现这是错误的。
新的想法是:创建一个Device类,这个类包含IP, Name之类, Device类中再包含一个TelnetServer类。TelnetServer有两个子类分别对应Linux, XP或者其它server软件(比如dslam)。把“login: ”这样的东西放到TelnetServer中是合适的。
而dir, list这样的命令放在OsCommandSet类中也许比较合适。
这样就成了:

Device
|
|------>TelnetServer
|------->OsCommandSet


而 TelnetConnection<---Device

分类就是把数据、方法放到合适的类里。分类正确了,代码逻辑就清楚,同时维护就容易。

Windows Telnet server设置

通过CLTF连接windowsXP的telnet server时,输入用户名、密码之后,会出现诸如:“
[5;1H [K [6;1H [K [7;1H [K [8;1H [K [9;1H [K [10;1H [K [11;1H [K [12;1H [K [13;1H [
”的字符。实际上这些都是光标定位用的信息。通过执行tlntadmn localhost config mode=stream,把server设置为stream模式,就可以去除这些“乱码”了。
[参考:http://mail-archives.apache.org/mod_mbox/commons-user/200806.mbox/%3C23ec93be0806070251y39b0b175m89bbdb6c9f16ab0a@mail.gmail.com%3E]

tlntadmn的详细用法:
C:\Documents and Settings\Dahui>tlntadmn -?
用法: tlntadmn [computer name] [common_options] start | stop | pause | continue
| -s | -k | -m | config config_options
所有会话用 'all'。
-s sessionid 列出会话的信息。
-k sessionid 终止会话。
-m sessionid 发送消息到会话。

config 配置 telnet 服务器参数。

common_options 为:
-u user 指定要使用其凭据的用户
-p password 用户密码

config_options 为:
dom = domain 设定用户的默认域
ctrlakeymap = yes|no 设定 ALT 键的映射
timeout = hh:mm:ss 设定空闲会话超时值
timeoutactive = yes|no 启用空闲会话。
maxfail = attempts 设定断开前失败的登录企图数。
maxconn = connections 设定最大连接数。
port = number 设定 telnet 端口。
sec = [+/-]NTLM [+/-]passwd
设定身份验证机构
mode = console|stream 指定操作模式。


1)还发现了windows telnet server和Linux telnet server的一个不同:当提示口令时,linux是“password: ” 而windows是“Password: ”。

2)Windows是中文操作系统时,通过inputStream得到的byte[]转为String是需要GBK编码。

2009年4月1日星期三

配置管理的基础环境

项目越大越复杂,对CM(配置管理)的要求就越高。源码管理、版本管理、build管理,发布管理,项目branch, patch的管理、甚至用户的管理。

CM在项目中的发展也是渐进的、迭代的,是根据开发中的需求变化的。当然前期的高瞻可以解决不少问题。前期的错误决策也会给CM的管理员(甚至开发人员、测试人员)带来痛苦。

我遇到的最“愚蠢的”,似乎也是最常见的错误是:“目标环境是windows(或是其它比如mobile), 开发环境是windows,而version control和CI(Continuous Integration)的环境却是linux”。要知道,有时候你的脚本会因为处理OS的差异而变得丑陋,付出很多而得不偿失。
我真的不明白为什么要把环境人为的差异化。用linux稳定?还是显得水平高?