乐者为王

Do one thing, and do it well.

Ant系列之用EMMA测量测试覆盖率的问题

EMMA是一个coverage工具,有on-the-fly和offline两种使用方式,在Ant里通常采用offline方式。

到sourceforge下载了2.0版本的EMMA下来,由于将EMMA的生成文件做了重定向,因此遇到了些问题,比如出现以下错误:

1
nothing to do: no runtime coverage data found in any of the data files

查找EMMA的FAQ 3.7节,只是告诉你可能少了metadata和runtime coverate date(对Ant用户来说一般是少了runtime coveraget date,它的后缀名默认是ec)。

由FAQ 3.15节可以知道runtime coverage data文件默认是生成在user.dir目录下的(即build.xml中的basedir目录下),而由instr指令生成的metadata文件(后缀名默认为em)则已经被重定向到另外的目录(用来生成coverage report的地方),所以必须重新设置coverage.out.file的值,用来重定向生成的runtime coverage data。因为runtime coverage data是在junit任务执行时产生的,所以我们可以在junit任务中添加一行代码:

1
<sysproperty key="emma.coverage.out.file" value="${coverage.dir}/coverage.emma" />

注意:

  1. metadata和runtime文件的后缀名最好设置相同;
  2. 一定要将junit任务的fork属性设置为true,这是因为EMMA 2.0的runtime coverage data是在JVM退出后生成的;
  3. instrumented classes必须是第一个被JVM执行的,所以instrumented classes目录必须处在junit任务的classpath的第一行,具体原因不明,如果谁知道还请告知下。

其实EMMA附带的examples目录下的build-offline.xml里已经说明的很详细了,只不过下载后没有仔细看,才遇到了一些问题。下面是build.xml的部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<path id="classpath">
  <pathelement location="${instrumentedclasses}" />
  <pathelement location="${classes}" />
  <pathelement location="${testclasses}" />
  <fileset dir="${lib}" includes="**/*.jar" />
</path>

<target name="compile" depends="prepare">
  <javac srcdir="${src}" destdir="${classes}" debug="on">
    <classpath refid="classpath" />
  </javac>
  <javac srcdir="${test}" destdir="${testclasses}" debug="on">
    <classpath refid="classpath" />
  </javac>
</target>

<target name="coverage.instrument" depends="compile">
  <emma enabled="yes">
    <instr instrpath="${classes}" destdir="${instrumentedclasses}"
        metadatafile="{coveragereports}/metadata.emma" merge="true">
    </instr>
  </emma>
</target>

<target name="junit" depends="coverage.instrument">
  <junit printsummary="yes" haltonfailure="no" fork="true">
    <sysproperty key="emma.coverage.out.file" value="${coveragereports}/coverage.emma" />
    <classpath refid="classpath" />

    <formatter type="xml" />

    <batchtest fork="yes" todir="${junitreports}">
      <fileset dir="${test}">
        <include name="**/*Test*.java" />
      </fileset>
    </batchtest>
  </junit>
</target>

<target name="coverage.report" depends="test">
  <emma enabled="yes">
    <report sourcepath="${src}">
      <fileset dir="${coveragereports}">
        <include name="*.emma" />
      </fileset>

      <html outfile="${coveragereports}/coverage.html" depth="method" />
    </report>
  </emma>
</target>

修复CheckStyle报告中Summary部分文件数目错误问题

在使用CheckStyle时用了它提供的checkstyle-frames.xsl作为样式文件,不过checkstyle-frames.xsl生成报告时有些问题,主要是统计数据有点问题,Summary中报告的文件数目比真实的多,所以对xsl文件的summary模板作了小小的一些修改,解决了这个问题,且添加了一个统计有错误的文件个数的功能。

原来的xsl内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<xsl:template match="checkstyle" mode="summary">
    <h3>Summary</h3>
    <xsl:variable name="fileCount" select="count(file)"/>
    <xsl:variable name="errorCount" select="count(file/error)"/>
    <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
        <tr>
            <th>Files</th>
            <th>Errors</th>
        </tr>
        <tr>
            <xsl:call-template name="alternated-row"/>
            <td><xsl:value-of select="$fileCount"/></td>
            <td><xsl:value-of select="$errorCount"/></td>
        </tr>
    </table>
</xsl:template>

修改后的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<xsl:template match="checkstyle" mode="summary">
    <h3>Summary</h3>
    <xsl:variable name="fileCount">
        <xsl:value-of select="count(file[not(./@name = preceding-sibling::file/@name)])" />
    </xsl:variable>
    <xsl:variable name="fileErrorCount" select="count(file[count(error) > 0])" />
    <xsl:variable name="errorCount" select="count(file/error)" />
    <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
        <tr>
            <th>Total Files</th>
            <th>Files With Errors</th>
            <th>Errors</th>
        </tr>
        <tr>
            <xsl:call-template name="alternated-row" />
            <td><xsl:value-of select="$fileCount" /></td>
            <td><xsl:value-of select="$fileErrorCount" /></td>
            <td><xsl:value-of select="$errorCount" /></td>
        </tr>
    </table>
</xsl:template>
  • following-sibling 按文档顺序选择文档中此后出现的当前节点的所有兄弟节点。
  • preceding-silbling 按与文档顺序相反的方向选择文档中此前出现的当前节点的所有兄弟节点。
  • following 除当前节点的所有后代节点外,按顺序选择文档中当前节点之后出现的所有节点,不包括属性节点或名称空间节点。
  • preceding 按与文档方向顺序相反的方向选择文档中在当前节点之前出现的所有节点。

Ant系列之用JDepend生成包依赖性度量的问题

首先获取JDepend的最新jar文件jdepend-2.9.jar,把它添加到ANT_HOME/lib目录里。

在build.xml中添加:

1
2
3
4
5
6
7
<target name="jdepend" description="Generate dependency metrics for each package">
    <jdepend format="xml" outputfile="${jdepend.dir}/jdepend-report.xml">
        <classpath>
            <pathelement path="classes" />
        </classpath>
    </jdepend>
</target>

运行任务后出现如下的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
BUILD FAILED
build.xml:59: Missing classespath required argument
    at org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask.execute(JDependTask.java:397)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275)
    at org.apache.tools.ant.Task.perform(Task.java:364)
    at org.apache.tools.ant.Target.execute(Target.java:341)
    at org.apache.tools.ant.Target.performTasks(Target.java:369)
    at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1216)
    at org.apache.tools.ant.Project.executeTarget(Project.java:1185)
    at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:40)
    at org.eclipse.ant.internal.ui.antsupport.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
    at org.apache.tools.ant.Project.executeTargets(Project.java:1068)
    at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.run(InternalAntRunner.java:423)
    at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.main(InternalAntRunner.java:137)

查看JDependTask.java文件的397行:

1
2
3
4
5
6
if (getSourcespath() == null && getClassespath() == null) {
    throw new BuildException("Missing classespath required argument");
} else if (getClassespath() == null) {
    String msg = "sourcespath is deprecated in JDepend >= 2.5 - please convert to classespath";
    log(msg);
}

发现是getClassespath() == null了,跳到221行:

1
2
3
public Path getClassespath() {
    return classesPath;
}

不是写了classpath吗?怎么classesPath的值会等于null呢?结果发现在247行有:

1
2
3
4
5
6
7
public void setClasspath(Path classpath) {
    if (compileClasspath == null) {
        compileClasspath = classpath;
    } else {
        compileClasspath.append(classpath);
    }
}

原来是在build.xml中把classespath错写成classpath了,那样当然有问题啦。改过来,再运行就可以了。

Ant系列之用Checkstyle检查代码规范的问题

首先将checkstyle-all-4.1.jar文件拷贝到项目的lib目录下,并建立CheckStyle配置文件。

然后在build.xml文件中声明CheckStyle任务:

1
<taskdef resource="checkstyletask.properties" classpath="${lib.dir}/checkstyle-all-4.1.jar" />

接着是建立CheckStyle任务:

1
2
3
4
5
6
7
8
9
10
<target name="checkstyle" description="Generates a report of code convention violations.">
    <checkstyle config="${docs.dir}/checkstyle_checks.xml" failOnViolation="false">
        <fileset dir="${src.dir}" includes="**/*.java" />
        <formatter type="xml" toFile="${checkstyle.dir}/checkstyle_report.xml" />
    </checkstyle>
    <xslt basedir="${checkstyle.dir}" destdir="${checkstyle.dir}/html" extension=".html"
            style="${docs.dir}/checkstyle-frames.xsl">
        <param name="output.dir" expression="${checkstyle.dir}/html" />
    </xslt>
</target>

其中output.dir是checkstyle-frames.xsl中的参数:

1
<xsl:param name="output.dir" />

在运行任务时可能会出现如下异常:

1
javax.xml.transform.TransformerException: java.lang.RuntimeException: Unrecognized XSLTC extension 'org.apache.xalan.xslt.extensions.Redirect:write'

可以将checkstyle-frames.xsl中的:

1
xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"

改成下面的内容:

1
xmlns:redirect="http://xml.apache.org/xalan/redirect"

如果出现这样的异常:

1
Got an exception - java.lang.RuntimeException: Unable to get class information for

可以修改对抛出异常的限制:允许抛出非检查型异常异常和抛出另一个已声明异常的子类。

1
2
3
4
<module name="RedundantThrows">
    <property name="allowUnchecked" value="true" />
    <property name="allowSubclasses" value="true" />
</module>

WebWork中如何实现i18n

ognl-2.6.5.jar + oscore-2.2.4.jar + webwork-2.1.7.jar + xwork-1.0.5.jar

web.xml配置文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <display-name>i18n</display-name>

    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>com.opensymphony.webwork.dispatcher.ServletDispatcher</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

    <taglib>
        <taglib-uri>webwork</taglib-uri>
        <taglib-location>/WEB-INF/webwork.tld</taglib-location>
    </taglib>
</web-app>

webwork.properties配置文件:

1
2
3
4
5
6
7
### This can be used to set your locale and encoding scheme
#webwork.locale=en_US    <- 这行一定要注释掉,因为WebWork首先判断webwork.locale有没有被设置,
                            如有则始终以该locale为准,忽略浏览器的locale
webwork.i18n.encoding=utf-8

### Load custom default resource bundles
webwork.custom.i18n.resources=ApplicationResources

xwork.xml配置文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xwork PUBLIC
    "-//OpenSymphony Group//XWork 1.0//EN"
    "http://www.opensymphony.com/xwork/xwork-1.0.dtd">

<xwork>
    <include file="webwork-default.xml" />

    <package name="default" extends="webwork-default">
        <action name="hello" class="com.codemany.i18n.action.HelloAction">
            <result name="success" type="dispatcher">/i18n.jsp</result>
        </action>
    </package>
</xwork>

HelloAction.java实现代码:

1
2
3
4
5
6
7
8
import com.opensymphony.xwork.ActionSupport;

public class HelloAction extends ActionSupport {

    public String execute() throws Exception {
        return SUCCESS;
    }
}

i18n.jsp的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %>

<%@ taglib uri="webwork" prefix="ww" %>

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

<body>
    <ww:property value="getText('i18n.value')" />
</body>
</html>

ApplicationResources_zh_CN.properties的内容:

1
i18n.value=国际化

ApplicationResources_en_US.properties的内容:

1
i18n.value=internationalization

练习破解'Crackme2 - by CoSH'

Crackme2程序

  1. 用PEiD查看,程序没有加壳;
  2. 首先找到注册错误提示信息“One of the Details you entered was wrong”;
  3. 用W32Dasm反汇编,利用String Data References找到上述字符串,双击它,看到以下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
* Reference To: MFC42.Ordinal:0F24, Ord:0F24h
|
:004014EB E85A030000              call 0040184A
:004014F0 83F805                  cmp eax, 00000005                 -> 比较Name的长度是否不大于5
:004014F3 7E41                    jle 00401536                      -> 如果是就跳到出错信息处
:004014F5 8D86E0000000            lea eax, dword ptr [esi+000000E0] -> Name字符串的地址
:004014FB 8BCF                    mov ecx, edi
:004014FD 50                      push eax

* Reference To: MFC42.Ordinal:0F22, Ord:0F22h
|
:004014FE E841030000              call 00401844
:00401503 8DBEE4000000            lea edi, dword ptr [esi+000000E4] -> Serial字符串的地址
:00401509 8BCD                    mov ecx, ebp
:0040150B 57                      push edi

从004014F0到004014F3可以知道Name必须大于5个字符,且和Serial无关。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
* Reference To: MFC42.Ordinal:0F22, Ord:0F22h
|
:0040150C E833030000              call 00401844
:00401511 8B07                    mov eax, dword ptr [edi]
:00401513 803836                  cmp byte ptr [eax], 36
:00401516 751E                    jne 00401536                      -> 跳到出错信息处
:00401518 80780132                cmp byte ptr [eax+01], 32
:0040151C 7518                    jne 00401536                      -> 跳到出错信息处
:0040151E 80780238                cmp byte ptr [eax+02], 38
:00401522 7512                    jne 00401536                      -> 跳到出错信息处
:00401524 80780337                cmp byte ptr [eax+03], 37
:00401528 750C                    jne 00401536                      -> 跳到出错信息处
:0040152A 8078042D                cmp byte ptr [eax+04], 2D
:0040152E 7506                    jne 00401536                      -> 跳到出错信息处
:00401530 80780541                cmp byte ptr [eax+05], 41
:00401534 7417                    je 0040154D                       -> 跳到正确信息处

由上面的比较代码可以得到:

1
2
3
4
5
6
36(hex) = 6
32(hex) = 2
38(hex) = 8
37(hex) = 7
2D(hex) = -
41(hex) = A

所以Serial是:6287-A

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004014E4(C), :004014F3(C), :00401516(C), :0040151C(C), :00401522(C)
|:00401528(C), :0040152E(C)
|
:00401536 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"ERROR"
|
:00401538 6864304000              push 00403064

* Possible StringData Ref from Data Obj ->"One of the Details you entered was wrong"
|
:0040153D 6838304000              push 00403038
:00401542 8BCE                    mov ecx, esi

* Reference To: MFC42.Ordinal:1080, Ord:1080h
|
:00401544 E8F5020000              Call 0040183E
:00401549 6A00                    push 00000000
:0040154B FFD3                    call ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401534(C)
|
:0040154D 8D8EE0000000            lea ecx, dword ptr [esi+000000E0]
:00401553 8D542414                lea edx, dword ptr [esp+14]
:00401557 51                      push ecx

* Possible StringData Ref from Data Obj ->"Well done,"
|
:00401558 682C304000              push 0040302C
:0040155D 52                      push edx

* Reference To: MFC42.Ordinal:039E, Ord:039Eh
|
:0040155E E8D5020000              Call 00401838
:00401563 683C314000              push 0040313C
:00401568 50                      push eax
:00401569 8D442418                lea eax, dword ptr [esp+18]
:0040156D C744242800000000        mov [esp+28], 00000000
:00401575 50                      push eax

* Reference To: MFC42.Ordinal:039C, Ord:039Ch
|
:00401576 E8B7020000              Call 00401832
:0040157B 8B00                    mov eax, dword ptr [eax]
:0040157D 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"YOU DID IT"
|
:0040157F 6820304000              push 00403020
:00401584 50                      push eax
:00401585 8BCE                    mov ecx, esi
:00401587 C644242C01              mov [esp+2C], 01

整理后得到:Name的长度必须大于5个字符,且和Serial无关。

小技巧:如何截取W32Dasm中的汇编代码呢?很简单,在W32Dasm中点击其最左边,会有一红点,再按Shift键,点击另一处,选中所需范围,按Ctrl+C复制到剪贴版,剩下的事就是粘贴了。

去除退出中国游戏中心时弹出的IE窗口

这次破解的版本是0.8.011.4。

中国游戏中心退出时弹出的IE窗口很烦人,决定做个补丁把它去除掉。

省略无数次尝试……确定退出中国游戏中心后打开的网页地址是 http://www.chinagames.net/PlazaJump/open 。用W32Dasm反汇编iGame.exe,通过String Data References找到网址字符串,双击该字符串,看到以下程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
:0043397A 90                nop
:0043397B 90                nop
:0043397C 90                nop
:0043397D 90                nop
:0043397E 90                nop
:0043397F 90                nop
:00433980 A1A2034800        mov eax, dword ptr [004803A2]
:00433985 56                push esi
:00433986 85C0              test eax, eax
:00433988 8BF1              mov esi, ecx
:0043398A 7411              je 0043399D               -> 判断是否要打开IE窗口
:0043398C 6A00              push 00000000

* Possible StringData Ref from Data Obj ->"http://www.chinagames.net/PlazaJump/open/"
|
:0043398E 6860D84700        push 0047D860
:00433993 B9D0FC4700        mov ecx, 0047FCD0
:00433998 E8B3D2FFFF        call 00430C50             -> 打开IE窗口

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0043398A(C)
|
:0043399D 8BCE              mov ecx, esi

从上面可以知道,只要将0043398A处的je指令改成jmp指令就可以避免退出时弹出的IE窗口了。

现在使用CodeFusion来制作一个文件补丁。它有三种制作补丁的方案,这里使用Find&Replace方法。将0043397A到00433998段的数据作为查找匹配数据,并将0043398A处的74(je指令)改成eb(jmp指令),然后按照步骤生成补丁文件就可以了。

2008/3/19更新

应ls的要求制作了一个针对最新版本(0.8.011.10)的补丁,和原来的补丁放在一起提供下载。

补丁文件

C语言的扬声器发声程序

计算机的主板通常装有8253/8254定时与计数器芯片和8255可编程并行接口芯片,由它们组成的硬件电路可用来产生扬声器的声音。目前的计算机由于采用了超大规模集成电路,因而看不到这些芯片,它们均集成在外围电路芯片中。以下是扬声器的电路图:

使用程序对这些电路编程可以控制声音的长短和音调的高低。在扬声器电路中,定时器的频率决定了扬声器发音的频率,所以可通过设定定时器电路的频率来使扬声器发出不同的声音。对定时器电路进行频率设定时,首先对其命令寄存器端口地址0x43写命令来选择定时器的通道,接着向计数寄存器端口地址0x42发送频率计数值,先送低8位,后送高8位。通过这两步使定时器电路产生一系列的方波信号,此信号能否推动扬声器发音,还要看由8255产生的送数信号和门控信号是否为1,而它们也是可以编程的,端口地址为0x61。以下是完整的实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <dos.h>
#include <conio.h>

#define FREQ 1193180.0

unsigned long getticks()
{
    union REGS regs;

    regs.h.ah = 0x00;
    int86(0x1a, ®s, ®s);
    return ((unsigned long)regs.x.cx << 16) + regs.x.dx;
}

void beep(int tone)
{
    unsigned long ticks;
    unsigned char bits;
    unsigned short count;

    count = FREQ / tone;
    outportb(0x43, 0xb6);    /* 选择定时器的某个通道 */
    outportb(0x42, (unsigned char)(count & 0xff));    /* 发声频率计数值的低8位 */
    outportb(0x42, (unsigned char)(count >> 8));    /* 发声频率计数值的高8位 */

    ticks = getticks();
    while (ticks == getticks())
        ;

    /*
     * 当8255的PB端口的第0位和第1位为1时,表示允许发声;
     * 为0时,表示禁止发声。
     */
    bits = inportb(0x61);
    outportb(0x61, bits | 3);    /* 允许发声 */
    ticks += 2;
    while (getticks() < ticks)
        ;
    outportb(0x61, bits & 0xfc);    /* 禁止发声 */
}

void main()
{
    do
    {
        beep(1046.50);
    } while (!kbhit());
}

一步一步整合WebWork和Spring

把webwork-2.1.7.jar、spring-1.2.1.jar以及webwork2-srping.jar复制到WEB-INF/lib目录下。

添加以下内容到web.xml文件中:

1
2
3
4
5
6
7
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<listener>
    <listener-class>com.atlassian.xwork.ext.ResolverSetupServletContextListener</listener-class>
</listener>

applicationContext.xml中的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<beans>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
    </bean>

    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="/WEB-INF/sql-map-config.xml" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="userManager" class="com.codemany.netlink.service.impl.UserManagerImpl" singleton="true">
        <property name="sqlMapClient" ref="sqlMapClient" />
    </bean>
</beans>

配置文件sql-map-config.xml中的内容如下:

1
2
3
<sqlMapConfig>
    <sqlMap resource="com/codemany/netlink/dao/impl/User.xml" />
</sqlMapConfig>

在xwork.xml中添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<package name="default" extends="webwork-default"
        externalReferenceResolver="com.atlassian.xwork.ext.SpringServletContextReferenceResolver">

    <interceptors>
        <interceptor name="reference-resolver"
                class="com.opensymphony.xwork.interceptor.ExternalReferencesInterceptor" />

        <interceptor-stack name="interceptors">
            <interceptor-ref name="params" />
            <interceptor-ref name="reference-resolver" />
        </interceptor-stack>
    </interceptors>

    <default-interceptor-ref name="default-interceptor" />

    <action name="login" class="com.codemany.netlink.action.LoginAction">
        <external-ref name="userManager">userManager</external-ref>
        <result name="success" type="dispatcher">/success.jsp</result>
        <result name="error" type="dispatcher">/error.jsp</result>
    </action>
</package>

在LoginAction.java中添加代码:

1
2
3
4
private UserManager userManager = null;

public void setUserManager(UserManager userManager) {
    this.userManager = userManager;

建立UserManager.java接口文件:

1
2
3
public interface UserManager {
    public User login(String username, String password) throws UserLoginException;
}

UserManagerImpl.java实现代码:

1
2
3
4
5
6
public class UserManagerImpl extends SqlMapClientDaoSupport implements UserManager {

    public User login(String username, String password) throws UserLoginException {
        // do something
    }
}

系统I/O地址表

PC机中仅使用A[0]-A[9]地址位来表示I/O地址,即可有1024个地址。前512个供系统电路使用,后512个供扩充插槽使用。当A[9]=0时表示为系统板上的I/O地址;A[9]=1时表示为扩充插槽接口卡上的地址。

系统I/O地址使用情况:

I/O地址范围 用途 I/O地址范围 用途
0000-001F 8237A DMA控制器1 00E0-00EF
0020-003F 8259A中断控制器1 00F0 重置协处理器总线
0040-005F 8253/8254定时/计数器(PIT) 00F1 设置协处理器总线
0060-006F 8042键盘控制器(AT) 00F2-00F7
0070-007F CMOS RAM与NMI屏蔽寄存器(AT) 00F8-00FF 协处理器
0080-009F DMA页寄存器 0100-01EF
00A0-00BF 8259A中断控制器2 01F0-01F7 硬盘
00C0-00DF 8237A DMA控制器2 01F8-01FF

扩充插槽I/O地址使用情况:

I/O地址范围 用途 I/O地址范围 用途
0200-0207 游戏卡I/O 0360-036F 保留
0208-020F 0370-0377
0210-0217 扩展部件(仅XT用) 0378-037F 并行口打印机1
0218-021F 0380-038F SDLC 通信及同步通信1
0220-024F 保留 0390-039F
0250-0277 03A0-03AF 同步通信2
0278-027F 并行口打印机2 03B0-03BF MDA 单色显示器
0280-02EF 03C0-03CF 保留
02F0-02F7 保留 03D0-03DF 彩色图形适配器
02F8-02FF 串行口2 03E0-03EF
0300-031F 试验卡 03F0-03F7 软盘适配器
0320-032F 硬盘适配器 03F8-03FF 串行口1
0330-035F