Tuesday, July 11, 2006

FreeBSD ssh server

Edit the file /etc/ssh/sshd_config (192.168.71.61)

Change port to 10022.

Change PermitRootLogin yes.

RUP

随着现代信息产业的蓬勃发展,软件开发已经成为一项浩大繁复的工程。就象是建造一座宏伟的宫殿,从计划、设计到施工,每一个环节都必须严格把关,稍有不慎,整个工程就会失败。据统计,仅在美国,每年就有180,000个信息技术项目,耗资大约$2500亿美元,其中25-30%的项目会流产。由此可见,由于管理不善和设计上的失误所造成的损失是巨大的。现代软件开发的管理和方法论显得比以往任何时候都更为重要。

软件开发的过程由方法论和工具构成(process = methodology + tools)。正如装配电子设备一样,仅有工具就可以胜任装配任务。但为了减少失误和提高效率,人们往往采用流水线作业,流水线作业便是一种应用于电子设备装配中的方法论。目前,信息技术市场流行的方法论有RUP(Rational Unified Process), The Zachman Framework, XP(Extreme Programming)等。在这些方法论中,最流行的要数RUP。RUP是由Rational Software公司首创的。因它与当前流行的JAVA, J2EE技术和面向对象的设计思想(OOAD)紧密的结合在一起,所以在大型的信息技术项目中得到了广泛的应用。在这篇文章中,我们试图对RUP的特点作一个初步的探讨,并且讨论它是如何贯穿在整个软件开发的生命周期之中的。

RUP最重要的它有三大特点:1)软件开发是一个叠代过程,2)软件开发是由Use Case驱动的,3)软件开发是以构架设计(Architectural Design)为中心的。

按照传统的瀑布(Waterfall)开发模式,软件开发大致经历如下几个步骤:商务需求分析(Business Requirement Analysis),系统分析(System Analysis),系统设计(System Design),开发实现(Implementation),测试(Test),发布(Deployment),系统支持(Supporting)和系统变更管理(Change Management)。

传统的瀑布开发模式假定在进行新的开发过程时,上一个过程已经完成,而且不会回到上一个过程。初看起来,这似乎是一个非常合理,高效率的解决方案,但 20多年的实践证明,这个开发模式存在着很大的弊病,原因是软件开发是一个非常复杂的工程,有诸多的因素影响工程的效率和成败。软件开发需要许多不同背景的个人和团队参与。由于这些复杂性,在软件开发的整个生命周期中每一个阶段都有可能留下隐患和错误。如果等到系统已经开发实现完毕,在测试阶段发现了重大问题,这时的返工将会造成人力、物力、财力及时间上的巨大浪费。鉴于以上的考虑,RUP强调软件开发是一个叠代模型(Iterative Model),RUP定义了四个阶段(Phase):开端(Inception),阐述(Elaboration),建造(Construction),过渡(Transition)。其中每个阶段都有可能经历以上所提到的从商务需求分析开始的各个步骤,只是每个步骤的高峰期会发生在相应的阶段。例如开发实现的高峰期是发生在建造阶段。实际上这样的一个开发方法论是一个二维模型。这种叠代模型的实现在很大程度上提供了及早发现隐患和错误的机会,因此被现代大型信息技术项目所采用。

RUP 的另一大特征是Use Case 驱动。Use Case是RUP方法论中一个非常重要的概念。简单地说,一个Use Case就是系统的一个功能。例如在一个基于电子商务的医疗系统中,病人可以坐在家里通过网上浏览器与医生约定看病的时间(Make appointment),这样,“Make appointment”就是系统的一个Use Case。在系统分析和系统设计中,Use Case被用来将一个复杂的庞大系统分割、定义成一个个小的单元,这个小的单元就是Use Case,然后以每个小的单元为对象进行开发。按照RUP, Use Case贯穿整个软件开发的生命周期。在商务需求分析中,客户或用户对Use Case进行描述,在系统分布和系统设计过程中,设计师对Use Case进行分析,在开发实现过程中,开发编程人员对Use Case进行实现,在测试过程中,测试人员对Use Case进行检验。

RUP的第三大特征是它强调软件开发是以构架为中心的。构架设计(Architectural Design)是系统设计的一个重要组成部分。在构架设计过程中,设计师(Architect)必须完成对技术和运行平台的选取,整个项目的基础框架(Framework)的设计,完成对公共组件的设计,如审计(Auditing)系统,日志(Log)系统,错误处理(Exception Handling)系统,安全(Security)系统等。设计师必须对系统的可扩展性(Extensibility),安全性(Security),可维护性(Maintainability),可延拓性(Scalability),可重用性(Reusability)和运行速度(Performance)提出可行的解决方案。

在RUP方法论中,不同的角色可以从不同的侧面来认识同一个项目。RUP定义了“4+1”个场景(View):Use Case场景(Use Case View),逻辑场景(Logic View),进程场景(process View),实现场景(Implementation View)和发布场景(Deployment View)。在Use Case场景中,客户和商务分析员对Use Case进行描述,在逻辑场景中,设计师对系统进行分析和设计,在进程场景中,设计师对系统可能出现的并发性,运行速度和分布特性进行描述。实现场景则反映了程序开发员开发实现的过程。发布场景是描述系统管理员和组装人员实施系统发布和管理的过程。值得强调的是,系统构架的设计是在逻辑场景中描述的。

RUP还定义了4个模型,即Use Case模型(Use Case Model),分析模型(Analysis Model),设计模型(Design Model)和实现模型(Implementation Model)。Use Case模型包含Use Case Diagram和Use Case文档。Use Case模型是其他三个模型的基础,分析模型即是概念模型(Conceptual Model),是系统分析所得到的结果,分析模型包含了类图(Class Diagram),次序图(Sequence Diagram)以及活动图(Activity Diagram)。设计模型则是构架设计和系统设计的结果。当设计模型完成后,开发编程人员便可以进行编程了。设计模型主要包含了类图,次序图和状态图 (State Chart Diagrams)。分析模型和设计模型看起来有许多相似之处,但两者的含义有本质的区别。分析模型强调的是问题的范围,但并不给出解决问题的方案,分析模型并不涉及具体的技术和平台。例如它并不关心是否应用EJB或一般的JAVA BEANS,系统是安装在WebSphere或是在WebLogic。但是与之相反,设计模型要考虑这些细节,而且要提供解决这些问题的全部方案。当然设计模型是建立在分析模型之上的,分析模型中的一个类可直接映射成为设计模型中的类,但这种映射关系一般并不是一一对应的,最后一个模型是实现模型。实现模型包含构件图(Component Diagram),从这个模型出发,开发编程人员可以产生骨架源程序(Skeleton Source Code),也可以从源程序出发更新设计模型。

目前应用于系统分析和设计的工具主要有Rational Rose和Together Software Center(TogetherJ)。JAVA和J2EE的开发工具有IBM Websphere Application Developer(WSAD), Borland Jbuilde和WebGain VisualCafe. WSAD和WebSphere Application Server应用在一起,使得服务器端的排错和系统的发布变得非常的容易。Jbuilder和VisualCafe一般与WebLogic Server紧密结合在一起。目前WebSphere Server和WebLogic Server占据了Application Server市场的66%,其中WebSphere Server占据了37%,成为同类产品的No.1。在单位测试和集成测试中,广泛应用的工具和框架有Junit, JunitPerf和Cactus.。

综上所述,软件开发的方法论已经成为现代软件工程过程中不可缺少的一个重要部分。是目前在Java/J2EE和面向对象的大型项目中广泛被采用的一种方法论。他对整个软件开发的生命周期提供了基础框架和指导。RUP, UML/Rational Rose, Java/J2EE, WSAD, Websphere Application Server和Oracle这样的技术、工具和平台的组合是目前许多公司、政府信息技术项目中采用的方案。因此,RUP的知识和经验也是现在求知是场所需求的热门技能。

用例驱动的需求过程实践

一、需求矛盾
  根据CHAO的权威统计,虽然自"软件危机"提出以来,软件工程方法得到了长足的发展与进步,但在去年的软件项目成功率仍然不足30%,绝大多数的软件项目仍然超进度、超成本。而在这些不成功的项目中,由于需求不清晰、需求不完整等方面的因素,占到了60%左右。
  下面的这幅漫画虽然不乏夸张,但却是能够激起我们的深思:
No038-1.gif
  根据笔者多年来从事软件需求捕获、分析工作的实践经验,认为造成这一现象的根本原因在于客户与开发人员之间的沟通存在障碍,双方都以自己的角度、自己的专业术语进行沟通,这使得大家并不能够很好地就软件需求达成共识。
  由于帮助客户更好地利用信息化工具提高工作效率,是我们软件开发团队的责任,因此我们没有权利让用户理解我们所用的语言,而是反过来,我们有义务去理解用户的语言,站在用户的角度看问题。
  而事实上,许多开发团队经常抱怨"我们的客户连需求都说不清楚"、"我们的客户对计算机了解太少了"。多年以来,大家都习惯从自己的角度来定义、分析问题,这也就造成了软件行业成为了一个最缺乏信任的行业,我们需要改一下习惯了。
二、现代需求实践
  针对这些现象,许多先贤们开始了实践,并且总结出了一系列优秀的需求实践:
1)Use case:用例分析技术
  鼎鼎大名的RUP是这样总结自己的:用例驱动,以体系结构为中心,迭代、增量的开发过程。Use case也伴随着RUP、UML一起名扬天下。
  用例用来描绘一个系统外在可见的需求情况,是代表系统中各个项目相关人员(风险承担人,Stakeholder)之间就系统的行为所达成的契约。
2)User Story:用户故事、用户素材
  用户故事是Kent Beck在极限编程(XP)方法论中推荐的最佳实践之一。它由客户参与编写,说明他们需要系统为他们做什么,一般用客户的术语写就,三句话左右。
3)Feature:特征
  这是特征驱动开发(FDD)方法论的核心实践之一。一个特征就是一个小的,具有客户价值的功能,通常表示为。
  从上面的定义来看,这三种现代软件工程需求实践无一例外地遵从两个原则:一是站在用户的角度看待系统、定义系统;二是用用户看得懂的语言表达。而在笔者的实践中,鉴于以下两点考虑还是先在团队中应用了"用例分析技术":
1)用户故事略显粗糙,掌握起来需要经验,没有详细的规则用于按部就班,一开始采用容易迷失方向;而用例相对来说更加形式化,易于上手;
2)特征看上去很有吸引力,但毕竟相关的理论还未完整,引入团队实践有些困难。
三、用例分析技术简介
  用例分析技术是Rational三友之一Ivar Jacobson先生于1967年在爱立信公司开发AXE交换机时开始研究,并于1986年总结、发布的一项源于实践的需求分析技术。Ivar先生在加盟 Rational之后,与三友合作提出了UML、完善了RUP,用例分析技术也因此被人广泛了解和关注。
  用例分析技术为软件需求规格化提供了一个基本的元素,而且该元素是可验证、可度量的。用例可以作为项目计划、进度控制、测试等环节的基础。而且用例还可以使开发团队与客户之间的交流更加顺畅。
  许多人是在学习UML的时候接触到Use case,所以许多人都误解其为一种图表,把用例图当作用例分析的全部,其实这是错误的,用例描述才是用例分析技术的核心。下面是一个简单的例子:
No038-2.gif
3.1 参与者,Actor
  参与者,定义了用户在系统交互过程中扮演的角色,其可以是一个人,也可以是另一个相关的系统。
3.2 用例,Use case
  用例实例(场景)是在系统中执行的一系列动作,这些动作将生成特定参与者可见的价值结果,一个用例定义一组用例实例(场景)。
  一个用例应为参与者提供(实现)一个价值。
No038-3.gif
3.3 事件流
  就像类对应于对象一样,一个用例的实例就是使用场景,用例就是对使用场景进行抽象的总结:
  1)前置条件:指在用例启动时,参与者(Actor)与系统应置于什么状态,这个状态应该是系统能够检测到的、可观测的;
  2)后置条件:用例结束时,系统应置于什么状态,这个状态也应该是系统能够检测得到的、可观测的;
  3)基本事件流:基本事件流是对用例中常规、预期路径的描述,也被称为Happy day场景,这时大部分时间所遇到的场景;它将体现系统的核心价值;
  4)扩展事件流:主要是对一些异常情况、选择分支进行描述。
  建议大家在编写事件流时,注意以下几点:
  1)使用简单的语法:主语明确,语义易于理解;
  2)明确写出"谁控制球":也就是在事件流描述中,让读者直观地了解是参与者在控制还是系统在控制;
  3)从俯视的角度来编写:指出参与者的动作,以及系统的响应,也就是第三者的角度;
  4)显示过程向前推移:也就是第一步都有前进的感(例如,用户按下tab键做为一个事件就是不合适的);
  5)显示参与者的意图而非动作(光有动作,让人不容易直接从事件流中理解用例);
  6)包括"合理的活动集"(带数据的请求、系统确认、更改内部、返回结果);
  7)用"确认"而非"检查是否":(如系统确认用户密码正确,而非系统检查用户密码是否正确);
  8)可选择地提及时间限制;
  9)采用"用户让系统A与系统B交互"的习惯用语;
  10)采用"循环执行步骤x到y,直到条件满足"的习惯用语。
四、Alistair Cockburn眼中的用例分析技术
  在使用用例分析技术时,很多人都觉得如何确定用例的粒度是一个难点,而且感觉到用例没有什么规则遵从,甚至有无所适从的感觉。正如Cockburn先生提出的学习用例分析技术的"守、破、离"的三个阶段:
  1)守:练习基本功夫,遵循规则,照章行事;
  2)破:能突破传统,因地制宜地灵活应用; 3)离:超脱任何招式与规则,达到无招胜有招的境界。
  但用例分析技术却让第一阶段的初学者感到无法很快地掌握。而其所著"编写有效用例"则想为用例分析技术补充规则,让大家能够更好地掌握。
  Cockburn先生在Ivar Jacobson的基础上,做了一些补充:
  1)用例是契约,是系统与涉众之间达成的契约。也就是将用例朝着形式化的方向发展;
  2) 将用例分成三级:
  ◆ 概要级:包括多个用户目标(显示用户目标运行的语境,显示相关目标的生命周期、为低层用例提供一个目录表);
  ◆ 用户目标级
  ◆ 子功能级
  不过,对于Cockburn先生的贡献,用例始祖Ivar大师并未做出任何反应。本人在实践中认为,Cockburn先生的思路与理念对于初学用例分析技术的人来说,十分有价值,使得用例分析技术更具操作性,当其同时也有点画地为牢的感觉,也许Cockburn先生也意识到这点,因此第三阶段就是"离 ",没有规则,按需灵活使用。
五、如何在开发过程中应用用例分析技术
  用例分析技术在需求过程中的地位如下图所示:
No038-4.gif
  对于用例分析技术理解上的两个最大的误区是:
  1)用例分析技术包括了整个需求过程:它只是一个需求分析技术,是在传统的需求捕获技术的基础上使用的,并无法替代这些技术;
  2)用例分析技术是分解技术:其实用例分析技术是一种合成技术,将在需求捕获中收集而来的零散的特性合成为用例:
No038-5.gif
5.1 用例分析前的工作
  在用例分析之前,应该完成以下工作:
  1)确定涉众(Stakeholder)和用户类型(命名、简要描述、涉众代表、特征、能力);
  2)确定涉众代表(命名、简要描述、责任、参与);
  3)在项目中加入涉众代表(访谈、问卷、顾问、评审、角色扮演);
  4)创建共同的构想(问题定义、系统范围、用户目标、非功能需求à前景文档);
  5)采用传统的需求捕获技术捕获需求;
  6)组建用例分析队伍(少量、有问题域知识)。
5.2 用例分析过程中的注意事项
  用例分析的过程如下图所示:
No038-6.gif
  在使用中要注意:
  1)用例源于涉众,请不要自己杜撰出用例;
  2)用例的事件流的编写过程中,应充分加入团队的参与;
  3)虽然用例源于涉众,但不要企图向他们直接问"你还有什么用例?这样的问题。

REGULAR EXPRESSIONS IN FIVE MINUTES

As I mentioned above, regular expressions are arguably a complete language. They are comprised of a string of special characters interspersed with sets of characters that are used as a mask against
strings in files and HTML entry fields. The regular expression engine
compares a line of text with your regular expression mask. The
regular expression engine can either simply return a Boolean saying
your text string did not match the mask, or it can update characters
in that string. The following, for instance, is a regular expression
that you can use to compare phone numbers.

/^\(\d\d\d\) \d\d\d-\d\d\d\d$/

That regular expression can be used in JavaScript to test an input
test:

function checkPhoneNumber(phoneNo) {
var phoneRE = /^\(\d\d\d\) \d\d\d-\d\d\d\d$/;
if (phoneNo.match(phoneRE)) {
return true;
} else {
alert("The phone number entered is invalid!");
return false;
}
}

But that regular expression expects a space after the area code (if
given) and a hyphen between the exchange and the four-digit number.
The following accepts an optional area code (with optional
parentheses), a three-digit exchange with one space or no space after
the area code, and a four-digit number with a single space, a hyphen,
or no space between it and the exchange:

/^(\()(\d{3})?(\))( -)(\d{3})( -)(\d{4})$/

Regular expressions have a number of special characters in them to
control how the mask works. The caret (^), for instance, if at the
beginning of the string, says to match the following mask from the
beginning of the string. The dollar sign ($) says to match the
preceding mask from the end of the string. The escape-d, identified
with the forward slash (\) and the lowercase letter d, says to match
a digit. The vertical bar symbol () is the regular expression
Boolean "or" character. The caret control character (^), if not used
at the beginning of the mask, is the Boolean "not" character. The
backward slash (/) is the commonly used delimiter for the complete
mask. It can be replaced with another character if necessary -- say,
for instance, if you are validating a URL, which itself contains back
slashes.

If this is your first exposure to regular expressions, don't be
concerned if I just lost you. Just be aware that regular expressions
are cryptic yet powerful. You could do the same checks with code, but
your code would become lengthy and far more error prone than regular
expressions.

Once I became accustomed to the use of regular expressions, I wanted
a way of globally replacing Java code in all source files of my app.
That's where the Unix sed utility comes into play. The sed utility
takes an input file and runs all its text through a regular
expression. What I do is write a quick shell script that runs files
in a directory (or directories) recursively through sed. I once wrote
a ten-line shell script to convert a client's JavaServer Pages from
the syntax of JSP 0.91 to JSP 1.1.

An alternatve to Sed is Perl. The Perl programming language is
probably 80-to-90 percent regular expressions. And now, with EPIC's
Perl plug-in, you can develop and run your Perl scripts in Eclipse.

I've been using regular expressions in JavaScript for a while, but
with the advent of Struts 1.1, I now use them in my server-side Java
Web applications. Struts 1.1 added the ability to use declarative
edits for HTML input fields. The declarations are placed in an XML
file called validator.xml. The following is a validator.xml snippet
that declares edits for the input form called visits:

<form name="visit">
<field property="sendToCopy" depends="required,mask">
<arg0 key="form.visit.sendToCopy"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*$</var-value>
</var>
</field>
<field property="contactPhone" depends="required,mask">
<arg0 key="form.visit.contactPhone"/>
<var>
<var-name>mask</var-name>
<var-value>^(\()(\d{3})?(\))( -)(\d{3})( -)(\d{4})$</var-value>
</var>
</field>
<field property="contactEmail" depends="mask">
<arg0 key="form.visit.contactEmail"/>
<var>
<var-name>mask</var-name>
<var-value>^.+@.+\..{2,3}$</var-value>
</var>
</field>
</form>

Note that Struts will automatically edit the qualified fields on the
server. Struts will also add JavaScript code in the JSP input form
that performs the same regular expression edits that are performed on
the server via Java. By selecting that client-side edit option,
performance is enhanced because there isn't a roundtrip to the
server. And you didn't even have to write the JavaScript code.

As I said earlier, regular expressions are directly supported in
JDK1.4. But don't wait until you are using JDK1.4. You can use
Jakarta's ORO package today with JDK1.2 and 1.3. Jakarta's ORO
package provides a dozen or so different mechanisms for running
regular expressions (while the Java 1.4 API has only
java.util.regex.Matcher and java.util.regex.Pattern). My favorite ORO
API is the org.apache.oro.text.perl.Perl5Util class. As its name
suggests, the Perl5Util class adds Perl-like behavior to the
org.apache.oro.text.regex class. The following is a sample Singleton
class that converts 8-digit BigDecimal date values to java.sql.Date
objects:

package com.vpia.utils;

import java.math.BigDecimal;
import java.sql.Date;
import org.apache.oro.text.perl.Perl5Util;

+public class ObjectConverter {

// other converter methods omitted
public static Date toDate(String obj) {
return ObjectConverter.toDate( new BigDecimal(obj));
}

public static Date toDate(BigDecimal obj) {
BigDecimal dec = (BigDecimal) obj;
String str = Integer.toString(dec.intValue());
Perl5Util util = new Perl5Util();
str = util.substitute("s/([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])/$1-$2-$3/", str);
return Date.valueOf(str);
}
}

If you want to learn more about regular expressions, try the
following books. The first two have several chapters on regular
expressions, and the last is considered to be the definitive guide to
regular expressions.

  • "JavaScript: The Definitive Guide," 4th Edition by David Flanagan,
    O'Reilly
  • "Learning Perl," 3rd Edition by Randal Schwartz and Tom Phoenix,
    O'Reilly
  • "Mastering Regular Expressions,", 2nd Edition by Jeffrey Friedl,
    O'Reilly

Eclipse CVS - Remove Sticky Tag

I had a file index.html with sticky tag. Any changes of index.html would be committed to CVS server because of that sticky tag.

To get rid of this sticky tag, cd to the CVS directory next to index.html file. Edit the entry

/index.html/1.22/Wed Mar 9 21:46:39 2005//Txxx

remove Txxx at the end.

Then remove Base directory and baserev file.

Done.

Struts titleKey

在FireFox中,html:link中的titleKey优先于html:img中的titleKey。而IE中,html:img中的titleKey和altKey都优先。

因此,为了避免titleKey在FireFox和IE中的行为不一致,当LINK在IMAGE之上时,只使用html:link中的titleKey。

Struts LookupDispatchAction html:image

在STRUTS体系结构中,如果用LookupDispatchAction类来处理表单,用html:image定义的图标来提交表单,实现方法如下:

1、将toaddnew和toupdate所需要的准备程序归到一个ACTION类中,如CornerKickLinkAction,它是 DispatchAction的一个子类,当然,在我的实现中,由于需要继承许多共享protected方法,CornerKickLinkAction 是ExtendedDispatchAction的子类,ExtendedDispatchAction是DispatchAction的一个子类,DA 是STRUTS的类,EDA只处理和SESSION、DATABASE CONNECTION有关的纯系统逻辑,CKLA则专责具体的CornerKick也就是说用户逻辑。如果有需要,诸如tolist或todelete所需要的程序也应该归到此类中。其余事项请参考STRUTS中有关DispatchAction的文献。

2、将doaddnew和doupdate、甚至dodelete和doaddasnew所需要的程序归到一个ACTION类中,如 CornerKickFormAction。它是LookupDispatchAction的一个子类。我的实现中, ExtendedLookupDispatchAction继承LookupDispatchAction,处理和session及database connection有关的逻辑,EventFormAction继承ELDA,共享的cancel处理和cursor处理写在这个类中,CKFA专责只和CornerKick添加和修改有关的逻辑。

3、html:image的定义中,property="method"必须和其余html:submit的property定义相同,这是为了兼容IE和FireFox的不同行为,在IE中,html:image所提交的request.getParameter("method")是null,而FireFox中会把html:image中定义的value随request送到服务器。因此,在服务器的DFA处理中,若method为null,那么可以肯定不是html:submit所提交的,而且很可能是IE,若method为html:image中的value,那么可以肯定是html: image所提交的,而且可能是FireFox。

4、注意,CANCEL键所提交的request.getParameter("method")也是null,因此必须在处理html:image的逻辑之前处理isCancelled(request)。

Cewolf 汉字

如果服务器没有汉字支持,CEWOLF所生成的图表中汉字不能正确显示。

Solaris X-terminal X-Deep

Install X-Deep on a Windows workstation, e.g. 192.168.71.115.

X-Deep can be obtained from download.com.

Start XServer on 192.168.71.115. Go to options, at the XDMCP panel, totally uncheck everything, basically we don't want to have XDMCP run. at the security penal, add 192.168.71.73 and 192.168.71.74 to trusted hosts.

In the ssh or telnet terminal of 192.168.71.74, do

$DISPLAY=192.168.71.115:0
$export DISPLAY

$xclock

You see a graphic clock on 192.168.71.115, smile.

SuSE 9.2 mini installation

Download and have the mini installation iso burn into a CD.

Start the computer with that CD.

Select Manual Installation.

Have the network card module loaded. (Find out the driver before installation, e.g. e100 for Intel Pro 100 Ethernet Card.)

Select Network/FTP installation.

195.135.221.132 /pub/suse/i386/9.2

or 141.43.99.5 /.mirror/ftp.suse.com/suse/i386/9.2

Bugzilla on FreeBSD

起先,我试着在RedHat的Fodera Core 3上装Bugzilla,其中的perl-GD和perl-Templete总过不去,其中最可能的原因就是RedHat所带的gd库和这两个perl所要求的gd不兼容。其间用时约一个星期。

于是我试着找SuSE安装盘,但是SuSE现在只发布DVD版了,我所有的机器只有CD-ROM,所以就试着用它的mini安装盘,用FTP的方式安装,大约试了两个星期,未能成功。

那么我想也许slackware可能不错,安装过程倒是不难,但安装之后起动时,在grub>的提示符下,有好几个参数基本上属于高高专业级的人才可能明白,于是只好放弃。用时两天。

最后我决定用FreeBSD 5.3,安装比较简单,注意,一定要选ports,不然的话安装MySQL呀,Apache呀等等会很难。起动也没我什么麻烦,三个麻烦,记录如下。

一是如何让root用户通过ssh登录。

解决方案是编辑/etc/ssh/sshd_config文件,找到了这个关键,其余就简单了,就不多说了。

二是MySQL的安装所选的数据库存储目录是/var/db/mysql,FreeBSD的默认安装只给/var文件系统250MB左右,所以必须要指定一个/usr的目录,比如说/usr/home/msyql/dbs。这里要注意的是,这个目录要先创建好,并把权限设成777,安装后再改得安全点就可以了。

按MySQL安装的说明书,用指定DB_DIR参数的方法是不行的,我用修改Makefile的方法通过了,应该说这种方法不规范,不过它WORK呀。具体办法就是在Makefile中把DB_DIR改成我所需要的目录。

三是Apache的配置文件和bugzilla目录下的所有关系。其关键如下,

#cd /usr/local/www/data-dist/bugzilla
#find ./ -type d -exec chown www:www {} \; //设置web server属主对该目录下所有目录的权限
#find ./ -type f -exec chown www:www {} \; //设置web server属主对该目录下所有文件的权限

在我的这次安装中Apache的用户是www,用户组也是www,检查httpd.conf文件便知。

在httpd.conf文件中,加入,

AllowOverride Limit
Options ExecCGI

去掉#AddHandler cgi-script .cgi句首的#。

还有,记住在/etc/rc.conf中激活apache和sendmail。

apache_enable="YES"
sendmail_enable="YES"

嗯,就这么着,Bugzilla工作了,用时五天。

Install JDK 1.4 on FreeBSD

Do not run 'make clean', but edit /usr/local/ports/java/jdk14/work/control/build/
bsd-i586/gensrc/java/util/CurrencyData.java, remove the first line and run 'make' again.

For some reason (I don't know what) the first line of this file gets corrupted sometimes.

> Java HotSpot(TM) Client VM warning: Can't detect initial thread stack
> location
> /usr/local/ports/java/jdk14/work/control/build/
bsd-i586/gensrc/java/util/CurrencyData.java:1:
> 'class' or 'in terface' expected
> Java HotSpot(TM) Client VM warning: Can't detect initial thread stack
> location
> ^
> /usr/local/ports/java/jdk14/work/control/build/
bsd-i586/gensrc/java/util/CurrencyData.java:1:
> unclosed chara cter literal
> Java HotSpot(TM) Client VM warning: Can't detect initial thread stack
> location
> ^
> 2 errors
> gmake[4]: *** [.compile.classlist] Error 1
> gmake[4]: Leaving directory
> `/usr/local/ports/java/jdk14/work/j2se/make/java/java'
> gmake[3]: *** [optimized] Error 2
> gmake[3]: Leaving directory
> `/usr/local/ports/java/jdk14/work/j2se/make/java/java'
> gmake[2]: *** [all] Error 1
> gmake[2]: Leaving directory
> `/usr/local/ports/java/jdk14/work/j2se/make/java'
> gmake[1]: *** [all] Error 1
> gmake[1]: Leaving directory `/usr/local/ports/java/jdk14/work/j2se/make'
> gmake: *** [j2se-build] Error 2
> *** Error code 2
>
> Stop in /usr/local/ports/java/jdk14.

Postgresql 7.3 on FreeBSD

To enable remote access of Postgresql server, edit the file

~pgsql/data/postgresql.conf e.g. /usr/local/pgsql/data/postgresql.conf

and update TCPIP_SOCKET = true.

# /usr/local/etc/rc.d/010.pgsql.sh stop
# /usr/local/etc/rc.d/010.pgsql.sh start

OK. Postgresql is listening at port 5432 now.

db2_kill

db2_kill runs on Unix to kill DB2 instance immediately. Thus it simulates DB2 failure.

If you got SQL1072C message when db2start not work after db2_kill, probably you have a db2bp command line database connection not terminated before db2_kill.

Try db2terminate, or just run ps -ef | grep and then kill -9 processes related to this instance.

It works for me.

DB2 Grant User Permissions

This is just an example.

We need to have an user called apsuite to access all instances, e.g. db2inst1 and db2inst3. All DB2 installations are 8.2.

$db2 connect to aps6331
$db2 grant bindadd, connect, createtab on database to user apsuite
$db2 connect reset

Do these three steps for all participated databases on all instances.

Done!

SSH installation for Solaris 8

Introduction:

Secure shell (SSH) is a protocol that provides a secure, remote connection to any device with ssh support. SSH is a substitute to Berkeley r-tools like telnet, rlogin, rsh and rcp which are not secure. SSH provides more security to any data that is being transported to the Internet by providing more authentication, encryption and authorization procedures. There are currently two versions of SSH available, SSH Version 1 and SSH Version 2.

Required packages:

All of the required packages of this tutorial is available from http://www.sunfreeware.com/

openssh
openssl (SSL)
prngd (Psuedo Random Generator Daemon)
zlib (Z library)

Installation:

#pkgadd -d openssl-0.9.6c-sol8-sparc-local

The following packages are available:

1 SMCosslc openssl (sparc) 0.9.6c

Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]:

#pkgadd -d prngd-0.9.23-sol8-sparc-local

The following packages are available: 1 SMCprngd prngd (sparc) 0.9.23

Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]:

#pkgadd -d zlib-1.1.4-sol8-sparc-local

The following packages are available: 1 SMCzlib zlib (sparc) 1.1.4

Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]:

#pkgadd -d openssh-3.1p1-sol8-sparc-local

The following packages are available: 1 SMCossh openssh (sparc) 3.1p1

Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]:

Startup Scripts:

Create a startup script for the ssh daemon.

/etc/init.d/ssh

#! /bin/sh
#
# start/stop the secure shell daemon

case "$1" in
'start')
# Start the ssh daemon
if [ -f /usr/local/sbin/sshd ]; then
echo "starting SSHD daemon"
/usr/local/sbin/sshd &
fi
;;
'stop')
# Stop the ssh deamon
PID=`/usr/bin/ps -e -u 0 /usr/bin/fgrep sshd /usr/bin/awk '{print $1}'`
if [ ! -z "$PID" ] ; then
/usr/bin/kill ${PID} >/dev/null 2>&1
fi
;;
*)
echo "usage: /etc/init.d/sshd {startstop}"
;;
esac

Make the script executable and create a startup script on run level 2.

#chmod +x /etc/init.d/sshd
#ln –s /etc/init.d/sshd /etc/rc2.d/S99sshd

Create a startup script for the pseudo random generator daemon.

/etc/init.d/prngd

#! /bin/sh
#
# start/stop the pseudo random generator daemon

case "$1" in

'start')
# Start the ssh daemon
if [ -f /usr/local/bin/prngd ]; then
echo "starting PRNG daemon"
/usr/local/bin/prngd /var/spool/prngd/pool&
fi
;;

'stop')
# Stop the ssh deamon
PID=`/usr/bin/ps -e -u 0 /usr/bin/fgrep prngd /usr/bin/awk '{print $1}'`
if [ ! -z "$PID" ] ; then
/usr/bin/kill ${PID} >/dev/null 2>&1
fi
;;

*)
echo "usage: /etc/init.d/prngd {startstop}"
;;

esac
Make the script executable and create a startup script on run level 2.

#chmod +x /etc/init.d/prngd
#ln –s /etc/init.d/prngd /etc/rc2.d/S99prngd

# /etc/init.d/prngd start

starting PRNG daemon

Info: Random pool not (yet) seeded
Could not bind socket to /var/spool/prngd/pool: No such file or directory

# mkdir -p /var/spool/prngd
#/etc/init.d/prngd start

starting PRNG daemon
# Info: Random pool not (yet) seeded
#

Next is to start the actual ssh daemon,

# /etc/init.d/sshd start
starting SSHD daemon

Could not load host key: /usr/local/etc/ssh_host_key
Could not load host key: /usr/local/etc/ssh_host_rsa_key
Could not load host key: /usr/local/etc/ssh_host_dsa_key

Disabling protocol version 1. Could not load host key
Disabling protocol version 2. Could not load host key
sshd: no hostkeys available -- exiting.
#

The errors above are due to the fact that we didn't
create any key pairs for our ssh server.

Create a public key pair to support the new, DSA-based version
2 protocol

# /usr/local/bin/ssh-keygen -d -f /usr/local/etc/ssh_host_dsa_key -N ""

Generating public/private dsa key pair.

Your identification has been saved in /usr/local/etc/ssh_host_dsa_key.

Your public key has been saved in /usr/local/etc/ssh_host_dsa_key.pub.

The key fingerprint is:

00:91:f5:8a:55:7c:ac:ff:b7:08:1f:ce:23:aa:f2:79 root@solaris8

Create a public key pair to support the old, RSA-based version
1 protocol

# /usr/local/bin/ssh-keygen -b 1024 -f /usr/local/etc/ssh_host_rsa_key -t rsa -N ""

Generating public/private rsa1 key pair.

Your identification has been saved in /usr/local/etc/ssh_host_rsa_key.

Your public key has been saved in /usr/local/etc/ssh_host_rsa_key.pub.

The key fingerprint is:

8e:b0:1d:8a:22:f2:d2:37:1f:92:96:02:e8:74:ca:ea root@solaris8
Edit ssh daemon configuration file /usr/local/etc/sshd_config, enable protocol
2 and 1

Uncomment the line, that says

protocol 2,1

# /etc/init.d//sshd start

starting SSHD daemon

#

Your ssh server is now ready to accept a ssh session.
You will also need to perform following steps for openssh-3.9p1

# mkdir /var/empty
# chown root:sys /var/empty
# chmod 755 /var/empty
# groupadd sshd
# useradd -g sshd -c 'sshd privsep' -d /var/empty -s

/bin/false sshd

/var/empty should not contain any files.

It's described here http://www.sunfreeware.com/README.privsep.

Delete Unwanted CVS Version

To delete unwanted CVS version, e.g. a version called v3-2-20050105 of project apSuiteConsole, do the following,

1. on CVS server, run

#cd /usr/local/cvsroot
#cvs rtag -R -d v3-2-20050105 apSuiteConsole

2. on Eclipse CVS repository view, configure branches and versions, select the v3-2-20050105, click Remove.

done.

US Patent US 6,813,633 B2

Dynamic Multi-level Cache Manager

Inventors: Frankie Chibun Wong, Thomas Tieping Liu (in the document it is Teiping Liu)

Assignee: Foedero Technololgies, Inc.

Appl. No.: 10/173,614

Filed: Jun. 19, 2003

Date of Patent: Nov. 2, 2004

Juniper NetScreen VIP

To open a port for external access, e.g. 192.168.71.61 is running a web service at port 80, and we want external access at 69.159.201.113 which is the public address.

Login NetScreen Administration WebUI,

1. update NetScreen WebUI port from 80 to 10000

a. Configuration > Admin > Management, update HTTP Port to be 10000.
b. click Apply

2. create VIP service

a. Network > Interfaces (List), click Edit (ethernet4)
b. click VIP, Network > Interface > Edit > VIP/VIP Services
c. click New VIP Service
d. select HTTP at the Map to Service, enter 192.168.71.61 at Map to IP
e. click OK

3. create a policy

a. click Policies
b. select from Untrust to Global, and click New
c. at the Destination Address, select VIP::1
d. at the Service, select HTTP
e. check Position at Top
f. click OK

4. verify the setting

a. in a browser, visit http://69.159.201.113

Change IP Address on Solaris

/etc/hosts, here you have to put the ip and the name.

/etc/hostname.eri0, here the interface file, it varies

/etc/defaultrouter, your new gateway
/etc/defaultdomain, if you will change of domain.
/etc/nodename, you host name

you have to change the mask with ifconfig:
ifconfig eri0 down
ifconfig eri0 a.b.c.d netmask 255.255.255.XXX
ifconfig eri0 up

then you have to restart the server

rmiregistry

On Linux, sometime rmiregistry is found default at /usr/bin/rmiregistry.

That may cause some problem, the rmistart.sh should specify the rmiregistry to $JAVA_HOME/bin/rmiregistry.

Windows Domain

当有两个网段,如192.168.70和192.168.71,需要安装WINS才能通过网络邻居找到周围的机器,否则可以定义LMHOSTS(under winnt\system32\drivers\etc)来达到效果。如下例所示:

192.168.70.106 user9
192.168.70.99 user1
192.168.70.18 user18
192.168.70.108 user004
192.168.70.109 user007
192.168.71.90 user21

192.168.71.91 domainc #PRE #DOM:nsm #net group's DC

Postgresql 7.4 Startup Configuration

If the postgresql -D points to /var/lib/pgsql, under /var/lib/pgsql/data, the file postgresql.conf is used to controll the startup parameters.

To uncomment the tcpip_socket entry and set it to be true to enable Postgresql 7.4 to listen on port 5432 when it starts up.

# tcpip_socket = falsetcpip_socket = true

Enable 8080 on iptables

On Linux, if iptables is deployed, to enable access to port 8080, do the following,
#service iptables stop
#vi /etc/sysconfig/iptables
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 21 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT

Notes: the above last line is added and will enable access to port 8080.
#service iptables start

Done!

crontab -e

As user root, run

#crontab -e
0 0 1,15 * 1 /mydir/myprogram

#crontab -l

The cron daemon would run the program myprogram in the mydir directory on the first and fifteenth of each month, as well as on every Monday.

----
For commands that need to be executed repeatedly (e.g., hourly, daily, or weekly), you can use the crontab command. The crontab command creates a crontab file containing commands and instructions for the cron daemon to execute.

You can use the crontab command with the following options:

crontab -a filename
Install filename as your crontab file. On many systems, this command is executed simply as crontab filename (i.e., without the -a option).

crontab -e
Edit your crontab file, or create one if it doesn't already exist.

crontab -l
Display your crontab file.

crontab -r
Remove your crontab file.

crontab -v
Display the last time you edited your crontab file. (This option is available on only a few systems.)

crontab -u user
Used in conjunction with other options, this option allows you to modify or view the crontab file of user. When available, only administrators can use this option.

Each entry in a crontab file consists of six fields, specifying in the following order:

minute(s) hour(s) day(s) month(s) weekday(s) command(s)

The fields are separated by spaces or tabs. The first five are integer patterns and the sixth is the command to execute. The following table briefly describes each of the fields:

Field Value Description minute 0-59 The exact minute that the command sequence executeshour 0-23 The hour of the day that the command sequence executesday 1-31 The day of the month that the command sequence executesmonth 1-12 The month of the year that the command sequence executesweekday 0-6 The day of the week that the command sequence executes (Sunday = 0, Monday = 1, Tuesday = 2, and so forth)command Special The complete sequence of commands to execute.

The command string must conform to Bourne shell syntax. Commands, executables (such as scripts), or combinations are acceptable.

Each of the patterns from the first five fields may be either * (an asterisk), meaning all legal values, or a list of elements separated by commas. An element is either a number or an inclusive range, indicated by two numbers separated by a minus sign (e.g., 10-12). You can specify days with two fields: day of the month and day of the week. If you specify both of them as a list of elements, cron will observe both of them, for example:

0 0 1,15 * 1 /mydir/myprogram

The cron daemon would run the program myprogram in the mydir directory on the first and fifteenth of each month, as well as on every Monday. To specify days by only one field, the other field should be set to * , for example:

0 0 * * 1 /mydir/myprogram

In the above example, the program would run only on Mondays.

实践——如何在STRUTS中实现多语言支持

首先,要准备多语言的properties文件,作为application resources。

我的实践是在src目录下创建一个resources目录,JAVA会把它看成是一个package。在这个目录下创建各个properties文件,然后再复制并加上_zh_CN或者_en_US作为各locale所需的resources。注意,需要用PropertiesEditor,一个配合eclipse的插件,来编辑中文文件,还要特别注意在preview后再存,同时覆盖原_zh_CN文件。

在JSP的中加入locale=true,就成了。意思是根据用户的流览器的首选locale来决定页面和session中的locale。在IE的语言选项中可以选择所需的locale以调试。

在struts的struts-conf.xml中定义controller的contentType为text/html; charset="UTF-8"。在每个JSP文件的头加上contentType定义,在每个
html的文件的head中加contenType定义。

%@ page contentType="text/html;charset=UTF-8" %
%@ taglib uri="/WEB-INF/taglib/struts-html.tld" prefix="html" %
%@ taglib uri="/WEB-INF/taglib/struts-bean.tld" prefix="bean" %
%@ taglib uri="/WEB-INF/taglib/struts-tiles.tld" prefix="tiles" %

html:html locale="true"
head
meta http-equiv="Content-Type" content="text/html;charset=UTF-8"
title bean:message bundle="TITLES" key="title.window.default" / /title
html:base/
link rel="stylesheet" type="text/css" href="html:rewrite forward='DefaultStyleSheet'/"
/head

表格中的多语言支持可以用一个Filter来完成,

/*
* Created on 9-Aug-2004
*/
package com.cm.soccer.impl;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* @author thomas
*
* Filter that sets the character encoding to be used in parsing the
* incoming request, either unconditionally or only if the client did not
* specify a character encoding. Configuration of this filter is based on
* the following initialization parameters:
*
* encoding - The character encoding to be configured
* for this request, either conditionally or unconditionally based on
* the ignore initialization parameter. This parameter
* is required, so there is no default.
* ignore - If set to "true", any character encoding
* specified by the client is ignored, and the value returned by the
* selectEncoding() method is set. If set to "false,
* selectEncoding() is called only if the
* client has not already specified an encoding. By default, this
* parameter is set to "true".
* Although this filter can be used unchanged, it is also easy to
* subclass it and make the selectEncoding() method more
* intelligent about what encoding to choose, based on characteristics of
* the incoming request (such as the values of the Accept-Language
* and User-Agent headers, or a value stashed in the current
* user's session.
*/

public class EncodeFilter implements Filter {

// ----------------- Instance Variables
/**
* The default character encoding to set for requests that pass through
* this filter.
*/
protected String encoding = null;

/**
* The filter configuration object we are associated with. If this value
* is null, this filter instance is not currently configured.
*/
protected FilterConfig filterConfig = null;

/**
* Should a character encoding specified by the client be ignored?
*/
protected boolean ignore = true;

// ----------------- Public Methods
/**
* Place this filter into service.
*
* @param filterConfig The filter configuration object
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}

/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {

String encoding = selectEncoding(request);
// One way to ensure response set to be UTF-8 is to wrap the response here.
// But we don't go this way in this implementation.
// We have put contentType setting in every JSPs.
// response =
// new ResponseWrapper((HttpServletResponse) response, encoding);
// Conditionally select and set the character encoding to be used
if (ignore (request.getCharacterEncoding() == null)) {
if (encoding != null)
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}

/**
* Take this filter out of service.
*/
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}

// ----------------- Protected Methods
/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* null.
* The default implementation unconditionally returns the value configured
* by the encoding initialization parameter for this
* filter.
*
* @param request The servlet request we are processing
*/
protected String selectEncoding(ServletRequest request) {
return (this.encoding);
}
}


在web.xml中定义,

EncodeFilter
com.cm.soccer.impl.EncodeFilter

encoding
UTF-8

ignore
false

EncodeFilter
cmss

Struts中如何写多参数链接

在View类的Class中准备一个返回HashMap的Method,例如:

public HashMap getRemoveLinkParams() {
HashMap map = new HashMap();
map.put("id", getId());
map.put("symbol", getSymbol());
return map;
}

在JSP中的链接写成:

<bean:define id="rlps" name="teamview" property="removeLinkParams"/>

<html:link action="/rosters/team/links?method=toremove" name="rlps">
remove
</html:link>

如果teamview中的id是42,symbol是“Jack London”,则出现在实际页面中的链接是:

/rosters/team/links?method=toremove&id=2&symbol=Jack London

(完)

DynaValidatorForm中验证输入

在Struts中,采用org.apache.struts.validator.DynaValidatorForm可以帮助自动验证用户从流览器的输入是否正确。例如:
<form-bean name="PlayerForm" type="....DynaValidatorForm">
<form-property name="name" type="java.lang.String"/>
<form-property name="sex" type="java.lang.Integer"/>
<form-property name="birthdate" type="java.lang.String"/>
<form-property name="height" type="java.lang.String"/>
<form-property name="weight" type="java.lang.String"/>

<form-property name="goals" type="java.lang.String"/>
</form-bean>

以上在struts-config.xml中定义。其中我们希望name,birthdate和goals必输入,name长度不能超过40,birthdate的格式必须是日期,height和weight是浮点数,goals是整数而且必须大于0小于2000,sex在FORM中是选择项,因此可以不验证。则在validation.xml中定义如下:
<form name="PlayerForm">
<field property="name" depends="required,maxlength">
<arg0 key="label.player.name"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>

<var-value>40</var-value>
</var>
</field>
<field property="birthdate" depends="required,date">
<arg0 key="label.player.birthdate"/>

</field>
<field property="height" depends="float">
<arg0 key="label.player.height"/>
</field>
<field property="weight" depends="float">
<arg0 key="label.player.weight"/>

</field>
<field property="goals" depends="required,integer,intRange">
<arg0 key="label.player.goals"/>
<arg1 name="intRange" key="${var:min}" resource="false"/>
<arg2 name="intRange" key="${var:max}" resource="false"/>
<var>

<var-name>min</var-name>
<var-value>0</var-value>
</var>
<var>
<var-name>max</var-name>

<var-value>2000</var-value>
</var>
</field>
</form>

注意,birthdate、height、weight、goals等值是字符串型,在Action类Class中需转换成各自目标的类型,而sex则不用转换。

Hibernate Delete Sample

In Hibernate, you can make use of session.delete(COMMAND, values, types) like this.

String COMMAND="from com.any.BookItem item "
+ "where item.bookpk.code=? "
+ "and item.bookpk.title=?";
Object[] values = { new Integer(2), "JSP banza" };
Type[] types = { Hibernate.INTEGER, Hibernate.STRING };

session.delete(COMMAND, values, types);

HOW TO: vsftpd, linux and linksys router

Recently I've got vsftpd running from behind my BEFSX41 both in PORT and PASV modes so I thought that I share my set-up since FTP servers are quite a hot topic here ;)

My config:
BEFSX41 1.43.4 (any BEFSx should be OK)
vsftpd 1.1.1 (1.1.0 and up supports PASV from behind NAT, get it here: vsftpd.beasts.org )
RedHat 7.3 (any linux should be fine)

Router set-up:
Forward port 21 TCP on UPnP Forwarding page
Forward ports 65000~65534 TCP on Port Range Forwarding Page (any range, it's up to you)

vsftpd.conf set-up:
pasv_enable=YES
pasv_min_port=65000 (same range as on router)
pasv_max_port=65534
pasv_address=100.100.100.100 (here comes your WAN IP)
...all other variables are set to default values

And since I have dynamic WAN IP from my ISP here's a little script running from cron to update vsftpd.conf with current IP (I use free dynamic DNS service www.dynu.com )

code:

#!/bin/sh
#vsftpd.conf IP update by Beaujolais
vsftpd_conf=/etc/vsftpd.conf
vsftpd_log=/var/log/vsftpd.log
#change to your domain name in next line
my_ip=`host your_host.dynu.com | cut -f4 -d" "`
vsftpd_ip=`grep pasv_address $vsftpd_conf | cut -f2 -d=`

if [ "$my_ip" != "$vsftpd_ip" ] ; then
( echo ",s/$vsftpd_ip/$my_ip/g" && echo w ) | ed - $vsftpd_conf
echo `date` "$vsftpd_conf updated with $my_ip IP address" >> $vsftpd_log
fi


...hope this helps to somebody :)

Real Case - CVS Eclipse Implementation

Set up the CVS server,

1. check cvs package, or install it

#rpm -qa | grep cvs
cvs-1.11.2-5

2. user, CVSROOT and protocol

in this case, we run cvs under root, CVSROOT is /usr/local/cvsroot, protocol is pserver with default port 2401.

edit the .bash_profile to set CVSROOT=/usr/local/cvsroot and export it.

3. init cvs repository

create the CVSROOT directory,
#cd /usr/local
#mkdir -p cvsroot

run cvs init to create repository
#cvs -d /usr/local/cvsroot init

4. configure xinetd to start cvspserver

create a cvspserver file under /etc/xinetd.d directory

# default: on
# description: the cvs pserver daemon
service cvspserver
{
disable = no
socket_type = stream
wait = no
user = root
group = root
server = /usr/bin/cvs
protocol = tcp
port = 2401
log_on_failure += USERID
log_type = FILE /var/log/cvspserver
server_args = -f --allow-root=/home/orchid/cvsroot pserver
}

restart xinetd
#service xinetd restart

check if cvspserver is started
#netstat -nap | grep 2401

Set up users

1. create the passwd file under $CVSROOT/CVSROOT

#cd $CVSROOT/CVSROOT
#touch passwd

2. create the cvs operation user

#useradd -g users cvsuser
#chown -R cvsuser:users $CVSROOT

3. prepare the passwd perl script

#!/usr/bin/perl
# Usage
# ./cvspasswd.sh
# then copy/paste to the $CVSROOT/CVSROOT/passwd file.
#
$saltchars = 'abcdefghijklmnopgrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./';
while (<>) {
chomp $_;
my ($salt) = substr($saltchars, rand(64), 1).substr($saltchars, rand(64), 1);
my ($c) = crypt($_, $salt);
print "'$_' => '$c'\n";
}

4. add entries to the passwd file

thomas:Encrypted Password:cvsuser
...more entries

Hotel California

On a dark desert highway, cool wind in my hair
Warm smell of colitas, rising up through the air
Up ahead in the distance, I saw a shimmering light
My head grew heavy and my sight grew dim
I had to stop for the night
There she stood in the doorway;
I heard the mission bell
And I was thinking to myself,
'This could be Heaven or this could be Hell'
Then she lit up a candle and she showed me the way
There were voices down the corridor,
I thought I heard them say...

Welcome to the Hotel California
Such a lovely place
Such a lovely face
Plenty of room at the Hotel California
Any time of year, you can find it here

Her mind is Tiffany-twisted, she got the Mercedes Benz
She got a lot of pretty, pretty boys, that she calls friends
How they dance in the courtyard, sweet summer sweat.
Some dance to remember, some dance to forget

So I called up the Captain,
'Please bring me my wine'
He said, 'We haven't had that spirit here since nineteen sixty nine'
And still those voices are calling from far away,
Wake you up in the middle of the night
Just to hear them say...

Welcome to the Hotel California
Such a lovely place
Such a lovely face
They livin' it up at the Hotel California
What a nice surprise, bring your alibis

Mirrors on the ceiling,
The pink champagne on ice
And she said 'We are all just prisoners here, of our own device'
And in the master's chambers,
They gathered for the feast
They stab it with their steely knives,
But they just can't kill the beast

Last thing I remember, I was
Running for the door
I had to find the passage back
To the place I was before
'Relax,' said the night man,
We are programmed to receive.
You can checkout any time you like,
but you can never leave!

6/16记,歌词中colitas是little buds的意思。此歌是Eagles于1976/12/15发行的。

测试项目的方法论

May 03, 2004

最近我在客户的一次门户概念原型测试中完成得很好,客户很满意,我认为主要就是准备工作做得仔细吧,不过一班闲人就将其拔高到方法论的高度,让我总结一下。

说实在的,我觉得方法论当然是个好东西,不过从所谓的性能测试和概念原型测试中总结出方法论来,不免让人觉得好笑。我想其实大家都不傻,这又何必呢?可是你就得做得有板有眼。

很多事情不是书上指导了就能做好的,用心学习积累经验比什么都强。写个方法论,除了指导自己和与自己差不多水平的人以外,还能指导谁呢?

首先要明确测试的目的。目的拟不出来,理解不了,或者总想着东西兼顾,乃测试大忌。有些人很重视某些小技巧和小方法,觉得那就是生存的根本,这就是所谓的只见树木,不见森林,方向都没确定呢,只记得那条路上有狼,那条路上有虎,又有什么用呢。明确目的,听起来再简单不过了,但领悟的人能有几个?

比方说这次门户测试吧,目的就是证明我们的产品将客户的交易重写在另一个数据库上了,而且此类重写需要在各种情况下都能完成。很简单,就一条,这就是目的。所谓易用性、压力测试、性能提升等等,可以说得象回事,但主测的人真要去做,那就是昏了头了,可是事实上真有很多人昏头。

目的是怎么定下来的?这就需要你懂销售和客户,还要懂当时的情形,明白什么是关键。经验积累是一回事,沟通客户,理解客户当前紧要任务是另一回事,然后将客户的任务转成自己产品的作用是第三件事。

所以第一条的第一款是了解背景资料,包括客户信息、项目信息。第二款是约见客户项目经理和设计师,可以分开来见,也可以一起见,关键是要知道问那些问题,确认自己的方向,并快速构思出测试目的,当然你若对产品了解足够多,当时你就知道目的能不能达到,从而拟出对自己有利的方向,这就是所谓的谋事在人了。第三款是和客户确认目的,这时候要很认真,也一定要让客户知道你是很认真的,确认下目的,客户可能会想着多个目的,但你要归到一点上来,若不能归到一点,则说服客户将测试分成多个阶段。

然后就可以做测试可行性研究了,算是第二条吧。有经验的测试设计师在沟通确认目的的时候就大体知道可行性了,而没经验的则胡乱答应,结果做不了,公司为什么要给设计师高薪呢,原因就在这里了,成功的设计师从来只有可行的可行性研究报告。

如果研究的结果是不可行,则必须回到第一条,重新确定测试目标,这一点很重要,任何人都有出错的时候,百密一疏,错了就赶紧回头,别心存侥幸。当然,也有不得已不得不上的时候,那就要知己知彼而百战不殆了。

可行性研究之后,便需要制定详细的测试计划。

制定计划的第一步就是收集测试环境资料。不同的产品、不同的项目所需要的资料是不同的,从这一点上也体现出设计师的价值。当然收集此类不需要面谈,最好是通过电话商量,通过电子邮件提出问题。通常客户对此类资料掌握得也不完整,所以应该计划好一个星期的时间让客户能准备好答案。

第二步是撰写浮出水面的测试计划书。计划书务求详尽,对各种情况要考虑周到,因为客户多半不熟悉自己的产品,而且测试过程中对出现的问题再求答案,则大大影响测试的效果,即使测试完成了,客户的印象分却丢了。

计划书应该有四部分的内容。一是安装和配置指南,二是理想配置样板,三是测试内容祥解,四是任务人员进度表。

通常客户很关心安装和配置指南,因此在写的时候要从客户的角度来衡量,要达到的效果是,客户看完指南后对测试就放心了。朴实无华地写出详细步骤就好了,切忌再宣传产品的优点和功能。

理想配置样板是为了配置的时候有个参考,应该运用收集到的测试环境资料来准备,最大限度地追求与实际测试时参数一致,由于篇幅巨大,客户虽无心细观,亦觉得设计书详尽有力。

由于真正测试时变化的因素很多,测试通常不能按照测试内容祥解完全地执行。这一部分是为了提醒要测的内容,定个方向而已。

任务人员进度表很重要,无论是客户还是测试一方,都应该按照此表安排人员的时间,而且在测试过程中,所有参与人员可以依据此表对测试的进度和自己当前的任务心中有数。

计划书完成后要与客户的项目经理和设计师沟通,确定他们对测试的内容和人员安排已经知道并认可。然后就可以定下时间,开始测试了。

即使准备十分周详,测试过程中依然会出一些问题,有些是环境的问题,对于此类问题,应该使得客户明白是环境问题,调动力量解决,解决过程中,只能耐心等待,沉默是金。而有些问题出在产品上,态度要诚恳,不要将责任推到开发人员身上,也不要对问题喋喋不休,静下心来迅速找到绕道的方案,然后承诺解决并定下一个汇报解决结果的时间。

测试结束后,别忘记和客户现场总结测试的结果,并定下下一步销售会议的时间。

Postgresql Installation on Windows XP

March 18, 2004

Preliminary Work

Create a new Windows user account with password and ensure that it has administrative rights. This account will be the PostgreSQL Superuser account. Once the installation process terminated, this account can be deleted.

Log in under the new account.

Cygwin installation

For a first-time install, go to http://cygwin.com/ and click on the "Install or update now" icon.

Download and start the setup program.

The only choices you should have to make are:
that you want to install from the internet
where to install it on your machine (Root install Directory. e.g. C:\cygwin)
where to find the installation packages (Local Package Directory. e.g. C:\cygwin\install)
whether to use IE5, a direct connection, or a proxy to access the internet.
which download site you select

Please ensure that the following files(some of them not in the default list) are included in the download list:

PostgreSQL
cygwin
readline
libreadline
zlib
crypt
bzip2
cygrunsrv
cygutils
cygipc

Finally you can accept to create an icon on the desktop and to add an icon to the start menu.

Testing the Cygwin shell

Run the Cygwin bash shell and type the following commands:
cd /
Change to the root directory as defined during setup (C:\cygwin)

ls

Similar to the DOS 'DIR' command. Lists the content of the root directory. This root directory contents the following directories: bin, etc, home, lib, temp, tmp, usr, var..

Installing and starting CygIPC, the IPC-Manager

Using the windows file manager, copy cygipc-version.tar.bz2 from the local package directory (C:\cygwin\install/...\release\cygipc) into the root directory (C:\cygwin).

The ls command in the cygwin bash shell must confirm the presence of cygipc-version.tar.bz2

Unpack the archive by typing: bunzip2 -c /cygipc-version.tar.bz2 | tar xv

The directory /bin contains now the IPC-Manager ipc-daemon2.exe and a documentation has been installed into the directory /usr/share/doc/cygipc-version.

Test the IPC daemon by typing ipc-daemon2 & in the cygwin bash shell. The process number will be returned, eg. [1] 3480.

PostgreSQL initialisation

Do not forget to start the IPC-Manager before continuing!!

Type the following command in the cygwin bash shell: initdb -D /usr/share/postgresql/data -W

During the initialisation, you will be prompted for the superuser password. Enter the same password than for the windows account password.

The data directory will be created in /usr/share/postgresql/data.

Starting aund stopping the Database

Start the Database with: pg_ctl start -D /usr/share/postgresql/data -o "-i"
and stop it with: pg_ctl stop -D /usr/share/postgresql/data

Installing the IPC-Daemon as a Windows service

The IPC-daemon does not need to run during this step.

Run the Cygwin bash shell and type the following command:
cd /
ipc-daemon2 --install-as-service

After rebooting the system you can verify the presence of the new service called Cygwin IPC Daemon 2 (Control Panel -> Performance and Maintenance -> Administrative Tools -> Services)

Installing PostgreSQL as a Windows service

The IPC-Daemon must be started before continuing.

Run the Cygwin bash shell and type the following commands:
cd /
cygrunsrv --install postmaster --path /bin/postmaster --args "-D /usr/share/postgresql/data -i" --dep ipc-daemon2 --termsig INT --shutdown
Now the Database will be available at each Windows start.

After rebooting the system you can verify the presence of the new service called postmaster (Control Panel -> Performance and Maintenance -> Administrative Tools -> Services)

Post installation

Reboot your system, log in as user with administrative rights and delete the temporary account.

Create 2nd DB2 Instance

To create the second instance on DB2 server(version 8.1), do the following steps,

1. as root

#useradd -g db2grp1 db2inst2
#passwd db2inst2
(give a password, e.g. passw0rd)

2. as root (take DB2 default installation on Linux as example)

#/opt/IBM/db2/V8.1/instance/db2icrt -a SERVER -p 50001 -u db2fenc1 db2inst2

or

add an entry at the bottom of /etc/services file, "db2c_db2inst2 50001/tcp"
#/opt/IBM/db2/V8.1/instance/db2icrt -a SERVER -p db2c_db2inst2 -u db2fenc1 db2inst2

or
add an entry at the bottom of /etc/services file, "db2c_db2inst2 50001/tcp"
#/opt/IBM/db2/V8.1/instance/db2icrt -a SERVER -u db2fenc1 db2inst2
#su - db2inst2
$db2set DB2COMM=tcpip -i db2inst2
$db2 update dbm cfg using SVCENAME db2c_db2inst2

3. new DB2 instance db2inst2 is ready.

Start OpenOffice as Service

To start OpenOffice as service, run

./soffice "-accept=socket,port=8100;urp" -invisible

DB2 License Control

DB2 license files usually have .lic as the end. License for workgroup or express edition are different.

To show license status,

$db2licm -l

To add a license,

$db2licm -a

Struts - File Locations

1. Images, Javascript libraries, CSS files, etc. cannot go under
WEB-INF because they cannot be seen from the client
2. JSPs can go under WEB-INF because they are always called from
Struts actions
3. JSPs that refer to images, JavaScript libraries, CSS, etc. MUST use
the Struts tag to make the reference work correctly.

Movable Type - Chinese

作为最优秀的blog工具,MT应该是首选。不过对于东方文字,需要一些特别的考虑。
在默认安装情况下,你输入的中文都会被编码,这虽然不影响发布以后的浏览,但是作为作者,当你需要修改的时候,你会无从下手。
从MT论坛得到解决方案,需做一下修改:(此处以MT 2.50为准,不过以前版本或者以后版本可以照此,只是所涉及到的修改的源代码的位置可能不同):

1. CGI.pm - line 376

$self->charset('ISO-8859-1');
修改为:
$self->charset('GB2312');

2. 模板的修改(template):
通过 blog 管理的 TEMPLATES界面,将所有模板文件中的

改为

3. mt.cfg

找到
#NoHTMLEntities 1
将前面的注释符号#去掉,变成
NoHTMLEntities 1

经过以上步骤,中文的正确处理就没有问题了。

【小技巧】自由控制首页显示文章的数量

在MT Blog系统中,经常更新的Blog首页往往会呈现很多文章条目,页面会拉的很长;而不经常更新的Blog,在偶尔更新Blog的时候会发现只显示一篇文章,与侧面的导航条极不相称,其实只要在Index模板中简单设定一些参数即可自由控制首页显示文章的数量...

默认状况下是首页显示最近7天以内的更新内容,这是在MT参数设定里定义的。我们可以在MT的Index模板中设置一个参数来调整Blog首页显示文章的数量,具体做法如下:

在模板中找到控制文章显示的情景标签,在这个标签中增加一个lastn="X"参数,"X"就是你想定义首页要显示文章的数量,例如:,那么你的Blog首页文章将总会显示最新更新的8条文章,这样你的Blog首页文章就不会因更新频率的原因被拉的过长或过短。

My Experience Install Movable Type

1. Download Movable Type(MT) 2.64 from www.movabletype.org
2. mkdir mt-2.64 under /var/www/cgi-bin
3. unpack MT 2.64 files to /var/www/cgi-bin/mt-2.64
4. back up mt.cfg to mt.cfg.0, edit mt.cfg file under /var/www/cgi-bin/mt-2.64

#CGIPath http://WWW.YOUR-SITE.COM/PATH/TO/MT/
CGIPath http://raccoon.cymbalsman.com:6999/cgi-bin/mt-2.64/

#DataSource ./db
ObjectDriver DBI::mysql
Database ******
DBUser ******
DBSocket /var/lib/mysql/mysql.sock
DBPort ****

# StaticWebPath /path/to/static-files/
StaticWebPath /mt-2.64-static/

# NoHTMLEntities 1
NoHTMLEntities 1

# PublishCharset Shift_JIS
# PublishCharset GB2312
PublishCharset UTF-8

5. edit mt-db-pass.cgi file, to put password to access MySQL
******

6. run mt-load.cgi
7. mv mt-load.cgi mt-load.cgi.0
8. edit mt-view.cgi file, add a line for UTF-8
$app->{cgi_headers}{-charset} = 'UTF-8';
$app->run;

9. edit extlib/CGI.pm file
#$self->charset('ISO-8859-1');
$self->charset('UTF-8');
#$self->charset('GB2312');

10. cd /var/www/html, mkdir mt-2.64-static, copy images, docs, index.html, style.css from /var/www/cgi-bin/mt-2.64

11. mkdir oureden under /var/www/html, chown -R apache:apache oureden.

12. edit /etc/httpd/conf/httpd.conf file
#AddDefaultCharset ISO-8859-1
AddDefaultCharset UTF-8

13. restart httpd
/etc/rc.d/init.d/httpd stop
/etc/rc.d/init.d/httpd start

14. Done!

PostgreSQL Installation

as user "cubs"

From PostgreSQL source code, after tar -zxvf the tar.gz file.

./configure --prefix $HOME/pgsql/system --with-pgport=6932 --with-java

To have a none system PostgreSQL installation and change the port to 6932.

make
make install

cd $HOME/pgsql/system/bin
./initdb -D $HOME/pgsql/data

cd $HOME
mkdir bin
create a file "startcubs.sh" contains

#!/bin/sh

# to start up postgresql for cubs

$HOME/pgsql/system/bin/postmaster -i -D $HOME/pgsql/data > $HOME/pgsql/logs/pgsql.log 2> $HOME/pgsql /logs/pgsql-errors.log &

create a file "stopcubs.sh" contains

#!/bin/sh
# to shutdown postgresql for cubs
kill -INT `head -1 $HOME/pgsql/data/postmaster.pid`

create a database named "cubs" with encoding UTF-8

createdb -d cubs --encoding="UNICODE"

PostgreSQL backup and restore

Senario: Backup database dz-demo on 192.168.1.112 owner postgres to dz-enx-3 on 192.168.1.72 owner doczadm.

(192.168.1.112)
#su - postgres
$pg_dump -Ft --blobs --oids dz-demo | gzip > /tmp/dz.tar.gz
or
$pg_dump -Ft -b -o dz-demo | gzip > /tmp/dz.tar.gz

ftp dz.tar.gz to /tmp of 192.168.1.72
#gunzip /tmp/dz.tar.gz
(192.168.1.72)
#su - doczadm
$dropdb dz-enx-3
$createdb dz-enx-3
$pg_restore -d dz-enx-3 -O -U doczadm -x /tmp/dz.tar

Done.

DB2 Solaris System Parameters

Solaris Kernel Configuration Parameters

Note: You must reboot your machine after updating any kernel configuration parameters.

*
* Recommended kernel parameters for "DB2 for Solaris"
* for systems with more than 512MB to 1GB of physical memory
*
set msgsys:msginfo_msgmax = 65535
set msgsys:msginfo_msgmnb = 65535
set msgsys:msginfo_msgmap = 514
set msgsys:msginfo_msgmni = 512
set msgsys:msginfo_msgssz = 16
set msgsys:msginfo_msgtql = 1024
set msgsys:msginfo_msgseg = 32767
*
set shmsys:shminfo_shmmax = 966367641
set shmsys:shminfo_shmseg = 50
set shmsys:shminfo_shmmni = 300
*
set semsys:seminfo_semmni = 1024
set semsys:seminfo_semmap = 1026
set semsys:seminfo_semmns = 2048
set semsys:seminfo_semmnu = 2048
set semsys:seminfo_semume = 50

Notes: Parameters msgsys:msginfo_msgmnb and msgsys:msginfo_msgmax must be set to 65535 or higher.

To set a kernel parameter, add a line at the end of the /etc/system file as follows:

set parameter_name = value

where parameter_name represents the parameter you want to change.

For example, to set the value of parameter msgsys:msginfo_msgmax, add the following line to the end of the /etc/system file:

set msgsys:msginfo_msgmax = 65535

After you have updated your kernel parameters, go to Installing Your DB2 to continue with the installation.

Solaris Shutdown and Power off

shutdown -i 5 -g 0 -y

DB2 Solaris db2profile and usejdbc2

e.g. DB2 instance db2inst1

To use JDBC 2.0, in the /export/home/db2inst1/.profile

add ". /export/home/db2inst1/sqllib/java12/usejdbc2".

the usejdbc2 script has some bug, remove these lines related to AIX and HP-UX.

For user "replica" to connect to db2 databases via JDBC, in the /export/home/replica/.profile, add

# The following three lines have been added by UDB DB2.
if [ -f /export/home/db2inst1/sqllib/db2profile ]; then
. /export/home/db2inst1/sqllib/db2profile
. /export/home/db2inst1/sqllib/java12/usejdbc2
fi

DB2 Create Instance

as root, for Solaris

#cd /opt/IBMdb2/V7.1/instance
#./db2icrt -u db2inst1 db2inst1
#./db2ilist

PostgreSQL List Tables

$pgsql

#select tablename from pg_tables where tablename not like '%pg_%';

will list all tables.

Internet Explore Gateway Timeout Error

When you get the Gateway Timeout error message at IE, try to uncheck the "automatically detect settings".

Tools-Internet Options-Connections-LAN Settings-Automatically detect settings

Virtual Hosts On Orion

Setup up multiple domains using a single IP address.
That the client browser is HTTP 1.1 compliant.
The domain names point to the servers single IP address.
Example Domains: www.example1.com, www.example2.com
Example IP Address: 127.0.0.1

Objective

Setup up multiple domains using a single IP address.

Requirements

That the client browser is HTTP 1.1 compliant.
The domain names point to the servers single IP address.

Limitations

This is a very basic example, it does not take into account using shared applications or event the use of .war or .ear files. This is left as an exercise for the reader.
Example Domains: www.example1.com, www.example2.com
Example IP Address: 127.0.0.1

Steps

Create directories under $ORION_HOME\applications\ for each domain.
mkdir $ORION_HOME\applications\example1
mkdir $ORION_HOME\applications\example2

Each directory should contain a index.html file.
Contents of $ORION_HOME\applications\example1\index.html:

<html><head><title>www.example1.com</title></head>
<body bgcolor="#FFFFFF">
<h2>www.example1.com</h2>
</body>
</html>

Contents of $ORION_HOME\applications\example2\index.html:

<html><head><title>www.example2.com</title></head>
<body bgcolor="#FFFFFF">
<h2>www.example2.com</h2>
</body>
</html>

Create WEB-INF directories for the domains.

mkdir $ORION_HOME\applications\example1\WEB-INF
mkdir $ORION_HOME\applications\example2\WEB-INF

Each WEB-INF directory should contain a web.xml file.
Contents of $ORION_HOME\applications\example1\WEB-INF\web.xml

<web-app>
<display-name>Example 1</display-name>
<description>
example1
</description>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
Contents of $ORION_HOME\applications\example2\WEB-INF\web.xml

<web-app>
<display-name>Example 2</display-name>
<description>
example2
</description>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>

Create web-site XML file for each domain.
Contents of $ORION_HOME\config\example1-web-site.xml:

<web-site host="127.0.0.1" port="80" display-name="Example 1" virtual-hosts="www.example1.com">
<!-- The default web-app for this site, bound to the root -->
<default-web-app application="default" name="example1" />
<access-log path="../log/example1-web-access.log" />
</web-site>
Contents of $ORION_HOME\config\example2-web-site.xml:

<web-site host="127.0.0.1" port="80" display-name="Example 2" virtual-hosts="www.example2.com">
<!-- The default web-app for this site, bound to the root -->
<default-web-app application="default" name="example2" />
<access-log path="../log/example2-web-access.log" />
</web-site>
Edit $ORION_HOME\config\application.xml. Add the following lines:

<web-module id="example1" path="../applications/example1" />
<web-module id="example2" path="../applications/example2" />
Edit $ORION_HOME\config\server.xml. Add the following lines:

<web-site path="./example1-web-site.xml" />
<web-site path="./example2-web-site.xml" />


Restart Orion and test.

(OrionSupport Author's note: if you'd like the machine's IP to be usable for direct access, you'll want to add the IP as a virtual host on one of the web site configuration files, too.)

Monday, July 10, 2006

It is the time to move my personal Movable Type to a public service provider. Here I choose the BLOGGER.com.