乐者为王

Do one thing, and do it well.

Servlet.init()中Log4j不能输出日志

web.xml配置文件:

1
2
3
4
5
6
7
8
9
10
<web-app>
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.example.learning.HelloServlet</servlet-class>
        <init-param>
            <param-name>log4jConfig</param-name>
            <param-value>/WEB-INF/log4j.properties</param-value>
        </init-param>
    </servlet>
</web-app>

log4j.properties配置文件:

1
2
3
4
log4j.rootLogger=ALL, Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%t] %37c %3x - %m%n

HelloServlet.java代码:

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
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class HelloServlet extends HttpServlet {
    private Logger logger = Logger.getLogger(HelloServlet.class);

    public void init() throws ServletException {
        super.init();

        ServletConfig config = getServletConfig();
        ServletContext sc = getServletContext();

        String log4jConfig = config.getInitParameter("log4jConfig");
        System.out.println(log4jConfig);

        if (log4jConfig == null) {
            BasicConfigurator.configure();
        } else {
            PropertyConfigurator.configure(sc.getRealPath(log4jConfig));
        }

        logger.info("This is an info message!");
    }

    public void destroy() {
    }
}

程序运行没有问题,可就是不能在Console视图中输出日志信息,而且使用System.out.println()也不能输出,不过在把private Logger logger行注释掉后System.out.println()就可以输出了。查看TOMCAT_HOME/logs中的日志文件,发现有如下异常:

1
2
3
----- Root Cause -----
java.lang.NoClassDefFoundError: org/apache/log4j/Logger
  at com.example.learning.HelloServlet.<init>(HelloServlet.java:15)

找不到Logger类?是不是WEB-INF/lib目录下没有log4j.jar呢?转到WEB-INF/lib目录,果然没有发现log4j.jar文件。把log4j.jar拷过去再试一下,真的OK了。

JPetStore 4.0.5配置MySQL数据库时遇到的问题

在配置JPetStore 4.0.5时出了一点问题,写此文章记录下解决方法,以便日后查找。

按照教程配置好后运行Tomcat,在点击“Enter the Store”时出现了HTTP 500错误。从日志中的异常记录来看是没有找到MySQL的驱动程序。

1
SimpleDataSource: Error while loading properties. Cause: java.lang.ClassNotFoundException: driver

可是我已经把驱动程序包放到WEB-INF/lib目录下了呀!

查看sql-xml-config.xml文件中dataSource的属性,发现它们的值如下:

1
2
3
4
5
6
7
8
9
10
11
<transactionManager type="JDBC">
    <dataSource type="SIMPLE">
        <property value="${driver}" name="JDBC.Driver" />
        <property value="${url}" name="JDBC.ConnectionURL" />
        <property value="${username}" name="JDBC.Username" />
        <property value="${password}" name="JDBC.Password" />
        <property value="15" name="Pool.MaximumActiveConnections" />
        <property value="15" name="Pool.MaximumIdleConnections" />
        <property value="1000" name="Pool.MaximumWait" />
      </dataSource>
</transactionManager>

而在database.properties中的值分别是:

1
2
3
4
SimpleDriver=org.gjt.mm.mysql.Driver
SimpleUrl=jdbc:mysql://localhost:3306/jpetstore
SimpleUsername=jpetstore
SimplePassword=ibatis

因为dataSource中的属性值是从database.properties文件中读取的,所以要将database.properties中的属性名改成和sql-xml-config.xml中的一致。这样就不会再出现找不到驱动的异常了。改写后的database.properties内容如下:

1
2
3
4
driver=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost:3306/jpetstore
username=jpetstore
password=ibatis

Eclipse中Ant执行JUnit测试的问题(2)

Eclipse 3.0.3 + Ant 1.6.2 + JUnit 3.8.1

构建配置文件build.xml:

1
2
3
4
5
6
7
8
<target name="junit">
    <junit>
        <formatter type="xml" />
        <batchtest todir="${report.dir}">
            <fileset dir="${classes.dir}" includes="**/*Test.class" />
        </batchtest>
    </junit>
</target>

执行任务的时候出现了异常:

1
2
3
4
5
6
7
8
9
10
java.lang.ClassNotFoundException: com.example.learning.HelloTest
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)

网上搜索没有找到答案,到Ant官网上发现 http://ant.apache.org/faq.html#delegating-classloader 这篇文章讲了该问题。只要在junit任务里加入classpath指出要加载类的路径就可以了。修改后的build.xml文件如下:

1
2
3
4
5
6
7
8
9
10
11
<target name="junit">
    <junit>
        <classpath>
            <pathelement location="${classes.dir}" />
        </classpath>
        <formatter type="xml" />
        <batchtest todir="${report.dir}">
            <fileset dir="${classes.dir}" includes="**/*Test.class" />
        </batchtest>
    </junit>
</target>

Eclipse中Ant执行JUnit测试的问题(1)

Eclipse 3.0.3 + Ant 1.6.2 + JUnit 3.8.1

构建配置文件build.xml:

1
2
3
4
5
6
7
8
<target name="junit">
    <junit>
        <formatter type="xml" />
        <batchtest todir="${report.dir}">
            <fileset dir="${classes.dir}" includes="**/*Test.class" />
        </batchtest>
    </junit>
</target>

在执行时出现了以下问题:

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
BUILD FAILED: build.xml:44: Could not create task or type of type: junit.

Ant could not find the task or a class this task relies upon.

This is common and has a number of causes; the usual
solutions are to read the manual pages then download and
install needed JAR files, or fix the build file:
 - You have misspelt 'junit'.
   Fix: check your spelling.
 - The task needs an external JAR file to execute
     and this is not found at the right place in the classpath.
   Fix: check the documentation for dependencies.
   Fix: declare the task.
 - The task is an Ant optional task and the JAR file and/or libraries
     implementing the functionality were not found at the time you
     yourself built your installation of Ant from the Ant sources.
   Fix: Look in the ANT_HOME/lib for the 'ant-' JAR corresponding to the
     task and make sure it contains more than merely a META-INF/MANIFEST.MF.
     If all it contains is the manifest, then rebuild Ant with the needed
     libraries present in ${ant.home}/lib/optional/, or alternatively,
     download a pre-built release version from apache.org
 - The build file was written for a later version of Ant
   Fix: upgrade to at least the latest release version of Ant
 - The task is not an Ant core or optional task
     and needs to be declared using <taskdef>.
 - You are attempting to use a task defined using
    <presetdef> or <macrodef> but have spelt wrong or not
   defined it at the point of use

Remember that for JAR files to be visible to Ant tasks implemented
in ANT_HOME/lib, the files must be in the same directory or on the
classpath

Please neither file bug reports on this problem, nor email the
Ant mailing lists, until all of these causes have been explored,
as this is not an Ant bug.

产生上面错误的原因是Ant在执行junit任务时没有找到junit.jar这个文件。将junit.jar放到ANT_HOME/lib目录下,再次执行,这下该OK了吧!

有没有搞错,还产生同样的错误!到命令行下试试。打入命令ant junit,然后出现:

1
2
3
4
5
6
Buildfile: build.xml

junit:

BUILD SUCCESSFUL
Total time: 1 second

怎么会这样?命令行下可以,Eclipse中就不行了?

到Preferences -> Ant -> Runtime -> Classpath下设置一下junit.jar的路径,再次执行junit任务,终于在Console视图中看到了成功的消息。

操作系统分区类型大全

大概是最全的操作系统分区类型列表了:)

分区类型 操作系统 分区类型 操作系统
0x0 UNUSED 0x80 Old Minix
0x1 DOS FAT12 0x81 Minix/Old Linux
0x2 Xenix root 0x82 Linux Swap
0x3 Xenix user 0x83 Linux EXT2
0x4 DOS FAT16 < 32MB 0x84
0x5 DOS Extended 0x85 Linux EXT
0x6 DOS FAT16 >= 32M 0x86
0x7 HPFS/NTFS 0x87
0x8 AIX 0x88
0x9 AIX bootable 0x89
0xA OS/2 boot manager 0x8A
0xB OS FAT32 0x8B
0xC DOS FAT Cyl > 1024 0x8C
0xE DOS FAT system 0x8E
0xF DOS big Extended 0x8F
0x13 0x93 Amoeba
0x14 0x94 Amoeba BBT
0x25 0xA5 FreeBSD
0x26 [Hidden] 0xA6 OpenBSD
0x27 0xA7 NeXT STEP
0x29 0xA9 NetBSD
0x37 0xB7 BSDI
0x38 0xB8 BSDI Swap
0x40 Venix 80286 0xC0
0x41 PPC PReP boot 0xC1
0x47 0xC7 Syrinx
0x51 Novell ? 0xD1
0x52 MicroPort 0xD2
0x5B 0xDB CP/M
0x61 0xE1 DOS access
0x63 GNU hurd 0xE3 DOS R/0
0x64 Novell NetWare 0xE4
0x65 Novell NetWare 0xE5
0x6B 0xEB BeOS
0x72 0xF2 DOS secondary
0x75 PC/IX 0xF5
0x7F 0xFF BBT

JSP中怎样输出\r\n到textarea中

测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%
    String str = "first line\r\nsecond line";
%>

<body>
    <textarea id="editor" name="editor"></textarea>;
</body>

<script type="text/javascript">
<!–-
    var editor = document.getElementById('editor');
    editor.value = '<%= str.replaceAll("\r\n", "\\\\r\\\\n") %>';
//-–>
</script>

忘记Linux的root密码后

一不小心忘记了Linux的root密码,只能以普通用户zer0ne的身份进入系统了。

找到Linux的DISC 1安装光盘,从光盘启动,出现boot:引导符后输入(其中,/dev/hda3是Linux系统所在的分区):

1
linux single root=/dev/hda3 initrd=

进入系统,把/etc目录下的shadow和passwd文件复制到/home/zer0ne目录下,修改shadow文件的属性。再到 http://www.openwall.com/john/ 下载一个John the Ripper,编译安装好后输入:

1
./unshadow passwd shadow > passwd.1

接着运行破解:

1
john passwd.1

这样,过了半个多小时我的root密码就回来了。

Linux下JDK 1.5.0的安装和配置

先是在网上找了两篇在Linux上安装JDK的文章:http://www.cnblogs.com/sirsunny/archive/2004/11/22/67029.htmlhttp://dev.csdn.net/article/46/article/46/46877.shtm

觉得后者写的比较详细,就照着它来了。步骤1、2、3没问题,把JDK安装好了,现在要配置环境变量了,有三种方法,哪种好呢?第1种不方便,换个shell登陆就不行了,第3种也不好,所有登陆用户都能用,那就只能选择第2种方法了。用vi打开.bashrc文件,在文件末尾添加以下内容:

1
2
3
4
5
6
set JAVA_HOME=/usr/java/jdk1.5.0
export JAVA_HOME
set PATH=$PATH:$JAVA_HOME/bin
export PATH
set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export CLASSPATH

现在文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# .bashrc
# User specific aliases and functions

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

set JAVA_HOME=/usr/java/jdk1.5.0
export JAVA_HOME
set PATH=$PATH:$JAVA_HOME/bin
export PATH
set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export CLASSPATH

然后重新登陆,用echo $JAVA_HOME查看环境变量,咦,怎么是空的呢?肯定有什么地方出错了,是不是不要什么set啊,试试把它去掉看看,修改后的.bashrc文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# .bashrc
# User specific aliases and functions

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

JAVA_HOME=/usr/java/j2sdk1.5.0
export JAVA_HOME
PATH=$PATH:$JAVA_HOME/bin
export PATH
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export CLASSPATH

再执行echo $JAVA_HOME命令:

1
/usr/java/jdk1.5.0/

果然,去掉set后环境变量就正确了。

Inside Protected Mode

以下所说的书指的是杨季文的《80X86汇编语言程序设计教程》。

在380页,他说是“在实方式下被预取,在保护方式下被执行”。这个说法不太正确。现在就来说说在进/出保护模式时究竟发生了什么?

在实模式时,通过指令lgdt fword ptr vgdtr把vgdtr处6个字节的内容装入GDTR中(记住,仅仅只是装入)。然后打开A20地址线(打开A20地址线是为了能存取1M以上的内存,和进不进保护模式其实没有必然的联系,也就是说不打开A20也能进入保护模式,只不过这时在保护模式下就不能存取1M以上的内存了)。然后把CR0寄存器的PE位置1,这是告诉CPU开启保护模式。

讲到这里,就要先来说说shadow cache了。shadow cache的layout可以看388页。在实模式下的时候有些位是只读的。大家还记的实模式下取址的方法吗?对,段寄存器值 * 16 + offset。是直接由MMU这样做然后再取址的吗?不是,实际上是:当你往段寄存器(比如说CS)送值后,MMU同时会把CS * 16的值放入到CS的shadow cache中。这样以后只要不改变CS的值,那么,在同一段代码段中的寻址将是offset加上shadow cache中的段基址部分。明白了吗?好,我们再回过来讲。

1
2
3
mov eax, cr0
or eax, 1
mov cr0, eax

这段代码究竟做了什么呢?其实它做的是开放段寄存器shadow cache的每个位(也就是每个位的值都能修改了,而在实模式下有些位是只读的)。还有就是告诉CPU开启保护模式。记住,这时候在shadow cache中的内容还没有变,还是原来实模式下的地址值。

现在再来谈谈保护模式下的寻址。在386以后的机器,保护模式下的寻址其实和在实模式下的寻址是一样的,也是offset加上shadow cache中的段基址部分。这样就可以理解为什么把CR0的PE位置1后还能执行后面的指令了。因为把CR0的PE位置1虽然使系统进入了保护模式。但因为在shadow cache中的内容还是实模式下的内容,所以才能在保护模式下执行实地址处的指令。然后呢!看看jump指令做了什么?

1
jump selector, offset

这个指令做了什么?它的意思是要跳到选择子为selector的段的偏移为offset处,执行那里的指令。这时CPU究竟做了什么呢?因为是段间跳转(就是带selector的跳转啦)。又因为现在是在保护模式下,所以MMU根据selector从GDT(知道LDGT的作用了吧)来找到段的真实段基址,然后再把它放入到相应段的shadow cache中。接着MMU再把offset和(shadow cache中的段基址部分)相加。这样就得到了下一个指令的地址。同样的道理,从保护模式出来时用

1
2
3
mov eax,cr0
and eax,0xffffffff
mov cr0,eax

使各段的shadow cache中一部分位固定,并且宣告进入实模式,即以后的寻址将采用实模式方式。然后通过执行jump cs, offset来把CS * 16的值装入shadow cache中。