Index: [Article Count Order] [Thread]

Date:  Fri, 22 Sep 2000 14:25:39 +0900
From:  firo <firo@....jp>
Subject:  [XP-jp:00909] Re: VXP タスク3 	--Config
To:  extremeprogramming-jp@....jp (extremeprogramming-jp ML)
Message-Id:  <00Sep22.133130jst.115207@....jp>
References:  <97BA340C0480D411BDA800062939A1890607AA@....jp>
Posted:  Fri, 22 Sep 2000 13:31:28 +0900
X-Mail-Count: 00909

矢崎です。

私も栗原さんをまねて、「#」のところは素モードとします。

tetsuya@....jp さんwrote:

> でも、このまま例外のサブクラスを作成していってしまうと、新しく例外が作成
> されるたびにインタフェースが変わってしまって、管理が大変になってしまうわね。
>
> コンストラクタ部分
> public Config(String nameOfConfigFile) throws xxxxx, xxxxx
>
> みたいに、例外が追加されるとこのクラスを利用しているクラスも更新しないとい
> けなくなるわ。
> パッケージを作成して、そのパッケージの例外クラスを定義し、そのサブクラスを
> 利用するようにすれば、Configクラスを利用するクラスは、スーパークラスの例外
> をキャッチするだけで良くなるわね。
> # どっかで読んだ気がして頭の隅に残っていたのですが、読み返していくうちに
> # 見つかりました。
> # 「リファクタリング」P.64のインタフェースの変更です。
>

#御意、とりあえず、例外に関してはしばらくはこの方向でいきましょう
か?

>
> パッケージ名は、、、太郎さんがいないからとりあえず「system」としておくわ。

(太郎さん)
そうだね。Configファイルなんかは、システムの事前定義等
を管理するものだから、systemというパッケージでいいんじゃ
ないかな。

> これで良いはず。コンパイルは、、、OKね。
> じゃテストするわね、、、あれ、投げられるべき例外が投げられないわね。
> X-ML-Nameなどがないときに投げられるべき例外が投げられてないみたい。
> Configクラスを見直してみると、、、、
>
> while (true) {
>     fileLine = bufIn.readLine();
>     if (fileLine == null)
>         break;
>
>     if (fileLine.startsWith("X-ML-Name:")) {
>         name = fileLine.substring("X-ML-Name:".length()).trim();
>         if (!isValidMLName(name))
>             throw new BadMLNameException();
>     }
>
>     if (fileLine.startsWith("$-MemberList:")) {
>         nameOfMemberListFile = fileLine.substring("$-MemberList:".length()).
> trim();
>         if (!isValidMemberListFileName(nameOfMemberListFile))
>             throw new BadMemberListFileNameException();
>     }
>     if (fileLine.startsWith("X-"))
>         xList.add(fileLine.trim());
> }
>
> なるほど。X-ML-Nameが見つかったら、その値に対してチェックをしているけれど、
> これでは見つからなかったときはチェックが行われないわね。
>

(太郎さん)
すごい!こんなふうに、バグがすぐ発見できるのは、テストを頻繁に
行うことのすごいアドバンテージだよね。コードを直して、前までの
テストが通れば、それは快感だし、また通らなくても、バグがすぐ
発見できて(直した箇所は少ないから、すぐ発見できるというわけ)
、それを直してテストを通す、、このリズム感が本当快感だよ。


>
> それと、コンストラクタ内のIOExceptionとFileNotFoundExceptionの例外を
> どうするかをきちんと決めてないわね。
> IOExceptionのみ(FileNotFoundExceptionはIOExceptionのサブクラス)を
> 投げるようにしておくのもありかもしれないし、SystemExceptionでラップ
> してしまってもいいかもしれないけど、ちょっと私だけでは決められないので
> 太郎さんと相談ね。
>

(太郎さん)
「リファクタリング」P.64の方針に従うなら、両方ともSystemException
あるいはそのサブクラスの例外としてthrowすべきじゃないかな?そ
れと、例外が起きる原因としては、引数で受け取ったファイル名が正
しくなかった場合とか、ファイル名は正しかったけれど、他の理由で
ファイルが読めなかった場合とか、いろいろあるよね。だけれど、ここ
ではあまり細かくリカバリする必要もなさそうだし、あまりクラスも増や
したくないような気がする。とにかくConfigファイルを正常に読めませ
んでした。だから調べてみてね。という意味で1種類のExceptionに
するのでいいと思うのだけれど、花子さんはどう思うかな?

とりあえず、それでいくとして、(もし別のやり方がよければ元に戻っ
てやりなおせばいいんだし)、テストを書きなおすところから始めよう。
ところで今回使う例外は、今ある2つの例外、いやSystemException
をいれて3つだけど、この3つを使うのはちょっと違うよね。新しい例外
を考えなきゃ。。名前は、、、

BadConfigFileExceptionでいこう。

じゃあ、ConfigTestを直すね。以下のcatchのところを

・・・
    public void testNoConfigFile() throws SystemException {

        try{
            Config aConfig = new Config("nonconfig");
            fail("Should raise an IllegalArgumentException");
        }catch(IllegalArgumentException e){
            assert(true);
        }

    }

・・・
(太郎さん)
キャッチする例外をIllegalArgumentExceptionからBadConfigFileException
に変えるだけでいいよね。

・・・
        }catch(BadConfigFileException e){

・・・
(太郎さん)
でコンパイルすると、、
BadConfigFileExceptionはまだないから、当然、とおりません。

次にBadConfigFileExceptionをコンパイルが通るレベルで書き
ます。

・・・
/*
 * $Id: BadConfigFileException.java
 */
package XP.jp.co.esm.wiki.extremedomo.system;

public class BadConfigFileException extends SystemException {
}
・・・
(太郎さん)
そして、コンパイル。今度はOK。
次はテスト、、、、
testNoConfigFileが予定どおりとおらなくなった。

で、次にConfigを直すっと。

コンストラクタの中のFileNotFoundExceptionをキャッチしている
ブロックは、その下のブロックにまかせてしまうことでいらなく
なったから、全部削除してしまおう

・・・
(このブロックは削除)
        } catch (FileNotFoundException e) {
            // What is exception handling carried out?
            throw new IllegalArgumentException();
・・・
(太郎さん)
そして、その下のIOExceptionをキャッチしているブロックの中
で、今まで何もしていなかったけれど、ここでBadConfigFileException
を投げるとすればいいんじゃないかな?

・・・
        } catch (IOException e) {
            // What is exception handling carried out?
            throw new BadConfigFileException();
・・・
で、コンパイル、、、

そして、テスト。

はい、全て通りました。


で、ここで本当はCVSにコミットしないといけないけれど、今
壁の中だからできない。今日、自宅に帰ってからやります。
すみません。

さて、太郎としてはConfigはそろそろこの辺でいったん
クロージングして次に進んではどうかなと考えています。
花子さんや、他のメンバー方、どうでしょう?


#最後にソースを全文掲載


/*
 * $Id: ConfigTest.java,v 1.1 2000/09/20 09:01:12 xp Exp $
 */
package XP.jp.co.esm.wiki.extremedomo.system;

import junit.framework.*;

import java.io.*;
import java.util.*;

public class ConfigTest extends TestCase {

    public ConfigTest(String name) {
        super(name);
    }

    public static void main(String[] args) {
        junit.textui.TestRunner.run(ConfigTest.class);
    }
    private void createCorrectConfigFile(String filename) {
        FileOutputStream fo;
        try {
            fo = new FileOutputStream(filename);
        } catch (FileNotFoundException e) {
            throw new RuntimeException("unable to open config file");
        }
        PrintWriter pw = new PrintWriter(fo);
        pw.println("X-ML-Name: extremeprogramming-jp");
        pw.println("Y-ML-Name: extremeprogramming-false");
        pw.println("X-Mail-Count: 00796");
        pw.println("Y-Mail-Count: 00888");
        pw.println("$-MemberList: memberlist");
        pw.println("$$-MemberList: memberrrlist");
        pw.println("X-MLServer: fml [fml 2.1_GAMMA#185](distribute only mode)");

        pw.println("Y-MLServer: fml [fml 2.1_GAMMA#185](not distribute only
mode)");
        pw.println("X-ML-Info: If you have a question, contact with me");
        pw.println("Y-ML-Info: If you have a question, do not contact with me");

        pw.close();
        try {
            fo.close();
        } catch (IOException e) {
            throw new RuntimeException("error on closing  config file");
        }
    }

    public void testCorrectConfig() throws SystemException {
        createCorrectConfigFile("config");

        Config aConfig = new Config("config");

        assertEquals("test1", "extremeprogramming-jp", aConfig.getName());

        Iterator iterator = aConfig.getXInfo();
        assertEquals("test2", "X-ML-Name: extremeprogramming-jp",
iterator.next());
        assertEquals("test3", "X-Mail-Count: 00796", iterator.next());
        assertEquals("test4", "X-MLServer: fml [fml 2.1_GAMMA#185](distribute
only mode)", iterator.next());
        assertEquals("test5", "X-ML-Info: If you have a question, contact with
me", iterator.next());
        assert("test6", !iterator.hasNext());

        assertEquals("test7", "memberlist", aConfig.getMemberListFileName());
    }
    public void testNoConfigFile() throws SystemException {

        try{
            Config aConfig = new Config("nonconfig");
            fail("Should raise an IllegalArgumentException");
        }catch(BadConfigFileException e){
            assert(true);
        }

    }
    public void testNoNameConfig1() throws SystemException {
        FileOutputStream fo;
        try{
            fo = new FileOutputStream("badconfig");
        }catch(FileNotFoundException e){
            throw new RuntimeException("unable to open badconfig file");
        }
        PrintWriter pw = new PrintWriter(fo);
        pw.println("Y-ML-Name: extremeprogramming-false");
        pw.println("X-Mail-Count: 00796");
        pw.println("Y-Mail-Count: 00888");
        pw.println("$-MemberList: memberlist");
        pw.println("$$-MemberList: memberrrlist");
        pw.println("X-MLServer: fml [fml 2.1_GAMMA#185](distribute only mode)");

        pw.println("Y-MLServer: fml [fml 2.1_GAMMA#185](not distribute only
mode)");
        pw.println("X-ML-Info: If you have a question, contact with me");
        pw.println("Y-ML-Info: If you have a question, do not contact with me");

        pw.close();
        try{
            fo.close();
        }catch(IOException e){
            throw new RuntimeException("error on closing badconfig file");
        }

        try{
            Config aConfig = new Config("badconfig");
            fail("Should raise a BadMLNameException");
        }catch(BadMLNameException e){
            assert(true);
        }

    }
    public void testNoNameConfig2() throws SystemException {
        FileOutputStream fo;
        try{
            fo = new FileOutputStream("badconfig");
        }catch(FileNotFoundException e){
            throw new RuntimeException("unable to open badconfig file");
        }
        PrintWriter pw = new PrintWriter(fo);
        pw.println("X-ML-Name:");
        pw.println("X-Mail-Count: 00796");
        pw.println("Y-Mail-Count: 00888");
        pw.println("$-MemberList: memberlist");
        pw.println("$$-MemberList: memberrrlist");
        pw.println("X-MLServer: fml [fml 2.1_GAMMA#185](distribute only mode)");

        pw.println("Y-MLServer: fml [fml 2.1_GAMMA#185](not distribute only
mode)");
        pw.println("X-ML-Info: If you have a question, contact with me");
        pw.println("Y-ML-Info: If you have a question, do not contact with me");

        pw.close();
        try{
            fo.close();
        }catch(IOException e){
            throw new RuntimeException("error on closing badconfig file");

        }

        try{
            Config aConfig = new Config("badconfig");
            fail("Should raise a BadMLNameException");
        }catch(BadMLNameException e){
            assert(true);
        }

    }
    public void testNoNameConfig3() throws SystemException {
        FileOutputStream fo;
        try{
            fo = new FileOutputStream("badconfig");
        }catch(FileNotFoundException e){
            throw new RuntimeException("unable to open badconfig file");
        }
        PrintWriter pw = new PrintWriter(fo);
        pw.println("X-ML-Name:                              ");
        pw.println("X-Mail-Count: 00796");
        pw.println("Y-Mail-Count: 00888");
        pw.println("$-MemberList: memberlist");
        pw.println("$$-MemberList: memberrrlist");
        pw.println("X-MLServer: fml [fml 2.1_GAMMA#185](distribute only mode)");

        pw.println("Y-MLServer: fml [fml 2.1_GAMMA#185](not distribute only
mode)");
        pw.println("X-ML-Info: If you have a question, contact with me");
        pw.println("Y-ML-Info: If you have a question, do not contact with me");

        pw.close();
        try{
            fo.close();
        }catch(IOException e){
            throw new RuntimeException("error on closing badconfig file");

        }

        try{
            Config aConfig = new Config("badconfig");
            fail("Should raise a BadMLNameException");
        }catch(BadMLNameException e){
            assert(true);
        }

    }
    public void testNoMemberListConfig1() throws SystemException {
        FileOutputStream fo;
        try{
            fo = new FileOutputStream("badconfig");
        }catch(FileNotFoundException e){
            throw new RuntimeException("unable to open badconfig file");
        }
        PrintWriter pw = new PrintWriter(fo);
        pw.println("X-ML-Name: extremeprogramming-jp");
        pw.println("Y-ML-Name: extremeprogramming-false");
        pw.println("X-Mail-Count: 00796");
        pw.println("Y-Mail-Count: 00888");
        pw.println("$$-MemberList: memberrrlist");
        pw.println("X-MLServer: fml [fml 2.1_GAMMA#185](distribute only mode)");

        pw.println("Y-MLServer: fml [fml 2.1_GAMMA#185](not distribute only
mode)");
        pw.println("X-ML-Info: If you have a question, contact with me");
        pw.println("Y-ML-Info: If you have a question, do not contact with me");

        pw.close();
        try{
            fo.close();
        }catch(IOException e){
            throw new RuntimeException("error on closing badconfig file");
        }

        try{
            Config aConfig = new Config("badconfig");
            fail("Should raise a BadMemberListFileNameException");
        }catch(BadMemberListFileNameException e){
            assert(true);
        }

    }
    public void testNoMemberListConfig2() throws SystemException {
        FileOutputStream fo;
        try{
            fo = new FileOutputStream("badconfig");
        }catch(FileNotFoundException e){
            throw new RuntimeException("unable to open badconfig file");
        }
        PrintWriter pw = new PrintWriter(fo);
        pw.println("X-ML-Name: extremeprogramming-jp");
        pw.println("Y-ML-Name: extremeprogramming-false");
        pw.println("X-Mail-Count: 00796");
        pw.println("Y-Mail-Count: 00888");
        pw.println("$-MemberList:");
        pw.println("$$-MemberList: memberrrlist");
        pw.println("X-MLServer: fml [fml 2.1_GAMMA#185](distribute only mode)");

        pw.println("Y-MLServer: fml [fml 2.1_GAMMA#185](not distribute only
mode)");
        pw.println("X-ML-Info: If you have a question, contact with me");
        pw.println("Y-ML-Info: If you have a question, do not contact with me");

        pw.close();
        try{
            fo.close();
        }catch(IOException e){
            throw new RuntimeException("error on closing badconfig file");
        }

        try{
            Config aConfig = new Config("badconfig");
            fail("Should raise a BadMemberListFileNameException");
        }catch(BadMemberListFileNameException e){
            assert(true);
        }

    }
    public void testNoMemberListConfig3() throws SystemException {
        FileOutputStream fo;
        try{
            fo = new FileOutputStream("badconfig");
        }catch(FileNotFoundException e){
            throw new RuntimeException("unable to open badconfig file");
        }
        PrintWriter pw = new PrintWriter(fo);
        pw.println("X-ML-Name: extremeprogramming-jp");
        pw.println("Y-ML-Name: extremeprogramming-false");
        pw.println("X-Mail-Count: 00796");
        pw.println("Y-Mail-Count: 00888");
        pw.println("$-MemberList:                       ");
        pw.println("$$-MemberList: memberrrlist");
        pw.println("X-MLServer: fml [fml 2.1_GAMMA#185](distribute only mode)");

        pw.println("Y-MLServer: fml [fml 2.1_GAMMA#185](not distribute only
mode)");
        pw.println("X-ML-Info: If you have a question, contact with me");
        pw.println("Y-ML-Info: If you have a question, do not contact with me");

        pw.close();
        try{
            fo.close();
        }catch(IOException e){
            throw new RuntimeException("error on closing badconfig file");
        }

        try{
            Config aConfig = new Config("badconfig");
            fail("Should raise a BadMemberListFileNameException");
        }catch(BadMemberListFileNameException e){
            assert(true);
        }

    }
    protected void setUp() {
    }

    protected void tearDown(){
    }
}


/*
 * $Id: Config.java,v 1.1 2000/09/20 09:01:12 xp Exp $
 */
package XP.jp.co.esm.wiki.extremedomo.system;

import java.util.*;
import java.io.*;

public class Config {
    public Config(String nameOfConfigFile) throws SystemException {
        BufferedReader bufIn = null;
        try {
            bufIn = new BufferedReader(new FileReader(nameOfConfigFile));

            String fileLine;

            while (true) {
                fileLine = bufIn.readLine();
                if (fileLine == null)
                    break;

                if (fileLine.startsWith("X-ML-Name:")) {
                    name = fileLine.substring("X-ML-Name:".length()).trim();
                }
                if (fileLine.startsWith("$-MemberList:")) {
                    nameOfMemberListFile =
fileLine.substring("$-MemberList:".length()).trim();
                }
                if (fileLine.startsWith("X-"))
                    xList.add(fileLine.trim());
            }
        } catch (IOException e) {
            throw new BadConfigFileException();
        } finally {
            try {
                if (bufIn != null)
                    bufIn.close();
            } catch (Exception e) {
            }
        }
        checkMLName();
        checkMemberListFileName();
    }
    public String getName() {
        return name;
    }
    public Iterator getXInfo() {
        return xList.iterator();
    }
    public String getMemberListFileName(){
        return nameOfMemberListFile;
    }
    private boolean isEmptyString(String str) {
        return str == null || str.length() == 0;
    }
    private void checkMLName() throws BadMLNameException {
        if (isEmptyString(name))
            throw new BadMLNameException();
    }
    private void checkMemberListFileName()
        throws BadMemberListFileNameException {

        if (isEmptyString(nameOfMemberListFile))
            throw new BadMemberListFileNameException();
    }

    private String name;
    private List xList = new ArrayList();
    private String nameOfMemberListFile;
}


/*
 * $Id: BadConfigFileException.java
 */
package XP.jp.co.esm.wiki.extremedomo.system;

public class BadConfigFileException extends SystemException {
}

--
矢崎博英  firo@....jp