雑記帳 2010年 5月第4週

2010/05/16 Sun.

今日も物件の下見です。14時くらいに不動産屋に行って、そこから車で向かうことに。駅から徒歩12分の距離なら許容範囲だ。
昨日の下見のせいか、見るべき観点が整理されていて、それほど時間は食わなかった。うーん、こっちの物件も悪くないな。
とりあえず「こっち」と「こっち」の2つに絞れた感じ。前者はちょっとばかりお高いんですよね。予算の限界値ギリギリだ。

2010/05/23 修正
「こっち」と書いてある箇所のリンクを削除。

66,000円、共営費2,000円 59,000円、共営費3,000円
1K 1K
京王多摩センター 徒歩4分、実測6分 京王多摩センター 徒歩9分、実測12分
マンション/鉄骨造 マンション/鉄骨造
1988年3月築(築22年) 1992年3月築(築18年)
フローリング7畳、占有面積25.6㎡ フローリング6畳、占有面積23.49㎡
風呂・トイレ別 風呂・トイレ別
5階建ての3階・角部屋 4階建ての2階・角部屋
東京電力・公営水道 東京電力・公営水道
プロパンガス・Bフレッツ プロパンガス・Bフレッツ
照明設備なし 照明設備あり
ガスコンロなし 一口ガスコンロあり
エアコンあり エアコンあり

前者と後者の大きな違いは、6畳か7畳か、独立洗面台の配置場所、基本設備の有無。うああ、かなり悩ましいところ。
両方とも角部屋だから窓はベランダ側とは別にもう一つあるんだけど、前者の方が大きい窓な上に見栄えがいい感じ。
絶対譲れない点としては独立洗面台だけど、そもそも多摩センだと独立洗面台の条件で探すと上記2つしか出てこない。
次は何で選ぶかとなると、やはり家賃と共営費。前者が68,000円になることを考えると、残業無しの月の手取りの44.4%になる。
電気代8,000円、ガス代10,000円、水道代3,000円、携帯代6,000円、ネットで5,000円と考えると、余裕が皆無に近くなる。
ガス代を高く見積もりすぎかと思うけど、今日職場の先輩に聞いたら「プロパンだとそれくらいはなるかも」ってことだし。
今は保険に何も入ってないから、安めの都民共済あたりで5,000円程度、煙草代が4,000円となると、食費はいくら残るんだ?
月あたりの家賃で6,000円の差ってのは誤差で済むかと思ったけど、一歩間違えたら貯蓄の切り崩し生活に陥るだろうな。

前者はアレなんだよね、縦長に7畳になっているから、見た感じの広さが随分違う。後者だとちょっと狭いと感じちゃったし。
ただし、前者は目の前がニュータウン通り、後者は一本入ったトコ。交通騒音の聞こえ方も随分違った。静かに越したことない。
でも後者は横長に6畳になっているせいで、キッチン付近の広さに余裕を感じた。あーもう、多摩センだと探すのにも限界がある。

2010/05/17 Mon.

今日もStrutsと格闘です。一つのActionに対して、渡すFormBeanって基本的には1種類?複数書いたらおかしな事になった。
struts-configにActionを定義して、同じActionに対して複数のFormBeanを定義したら、一番最後の記述のが適用されてた。
例えばログアウト処理のActionは複数の画面から呼ばれるから、その数だけFormBeanを定義すると思ったんだけど。勘違い?
全ての画面のFormBeanは共通のFormBeanを継承して作ってるから、結局共通のBeanで渡すようにせざるを得なかった。
後はLoggingInterceptorをこねくり回す。BeanクラスにはApacheのPropertyUtilを使ってるけど、一部が想定通りに動かない。
あれ、スーパークラスでtoString()をオーバーライドして、サブクラスからtoString()をすると、継承元の情報って出せないの?
Class<T>#getDeclaredFields」は「継承フィールドは含まれません」なんて書いてありやがる。マジかよ、知らなかった。
かと言って、「Class<T>#getFields」だと「アクセス可能なpublicフィールドをリフレクト」なんて書いてある。さて、どうやろうか。

Strutsも覚えたいし、Springもやりたいし、Hibernateも詳しくなりたいし、引っ越し先も決めたい。色々やりたいぞー。

2010/05/18 Tue.

以前のLoggingInterceptorをちょっと変更して「こんな感じ」に直してみる。見た目はこっちの方が綺麗かもしれない。

昨日の話、データ保持用のBean系でスーパークラスの情報を取れなかった件、あっさり解決しました。やってみるモンだな。

package test.logging.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.PropertyUtils;

public class AbstractBean {
    public String toString() {
        StringBuffer buf = new StringBuffer();

        Field[] fields = this.getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if (i > 0) {
                buf.append(", ");
            }
            String fieldName = fields[i].getName();
            buf.append(fieldName).append("=");
            try {
                buf.append(PropertyUtils.getSimpleProperty(this, fieldName).toString());
            } catch (IllegalAccessException e) {
                buf.append("[プロパティへのアクセスが許可されていません。]");
            } catch (InvocationTargetException e) {
                buf.append("[メソッド呼び出し時に問題が発生しました。]");
            } catch (NoSuchMethodException e) {
                buf.append("[プロパティ取得用のメソッドが存在しません。]");
            } catch (NullPointerException e) {
                buf.append("null");
            }
        }

        // 継承元の情報も出力する
        Class<?> clazz = this.getClass().getSuperclass();
        // 2010/05/30 add start
        boolean isFirst = true;
        // 2010/05/30 add end
        while (true) {
            if (Object.class == clazz) {
                break;
            }
            Field[] fields_ = clazz.getDeclaredFields();
            for (int i = 0; i < fields_.length; i++) {
                // 2010/05/30 add start
                if (isFirst) {
                    if (fields.length > 0) {
                        buf.append(", ");
                    }
                    isFirst = false;
                }
                // 2010/05/30 add end
                if (i > 0) {
                    buf.append(", ");
                }
                String fieldName = fields_[i].getName();
                buf.append(fieldName).append("=");
                try {
                    buf.append(PropertyUtils.getSimpleProperty(this, fieldName).toString());
                } catch (IllegalAccessException e) {
                    buf.append("[プロパティへのアクセスが許可されていません。]");
                } catch (InvocationTargetException e) {
                    buf.append("[メソッド呼び出し時に問題が発生しました。]");
                } catch (NoSuchMethodException e) {
                    buf.append("[プロパティ取得用のメソッドが存在しません。]");
                } catch (NullPointerException e) {
                    buf.append("null");
                }
            }
            clazz = clazz.getSuperclass();
        }

        return buf.toString();
    }
}

まあ、このまま使っちゃうとスーパークラスがObjectになるまで遡っちゃうけど。遡りを止めるクラスを決めておいた方がいいな。
前述のLoggingInterceptorと合わせてみて、意外にいい感じのロギングになった。後はAdvisorも手を加えたいってトコか。
他に作りたいのが、同じMethodInterceptorの実装で、DBのマスタ系に対してselectされたものをキャッシングしておくもの。
対象クラスと対象メソッドと呼び出しパラメータが完全に一致したらキャッシュから引っ張り出すヤツ。ってか、どっかにありそう。
Seasar2の「S2Caching」、これのSpring版ってあるのかな?「org.springframework.cache.ehcache」とかは違うのかな。
つーか、以前にSeasarでやってた時は、自分でキャッシングを書いたっけ。どんな理由で「S2Caching」を放置したんだっけか?

明日もStrutsと格闘します。今のプロトタイプが全てActionを使ってるので、これを全部DispatchActionに変更したいんだよね。
やっぱり一つの画面でフォームをやたらと複数持たせたくないし、パラメータ違いで別のメソッドを叩けるようにした方がいい。
後は、ログイン制御が超適当なのを直そう。SessionにUserBeanみたいなのを突っ込んでるだけだし、流石に手抜きすぎるか。

2010/05/19 Wed.

昨日の「LoggingInterceptor」を改良していくうちに、ちょっと気になる点が出てきた。ロギングの方針としてはどうなんだろう。

package test.hibernate.dao;

import java.io.Serializable;

public interface GenericDao<T, PK extends Serializable> {
    PK create(T entity);

    T read(PK obj);

    void update(T entity);

    void delete(T entity);
}
package test.hibernate.dao;

import test.hibernate.entity.TblTest;

public interface TblTestDao extends GenericDao<TblTest, String> {
}

例えばだけど、こんなのがあるとするじゃん。あ、GenericDaoGenericDaoHibernateImplみたいなので実装する前提で。
LoggingInterceptorをSpringのBeanNameAutoProxyCreatorとかでDaoに対して挟み込んでみると、こんなのが出たりする。

DEBUG test.hibernate.dao.impl.TblTestDaoImpl#read params(Serializable[junmix])
DEBUG test.hibernate.dao.impl.TblTestDaoImpl#read return(Object[userId=junmix, password=pass])

超手抜きのTestというテーブルに対して、キーを指定してentityを取得。パラメータと戻り値の内容を出力(不要部分は省略)。
呼び出し元としてはキーはStringで渡しているんだけど、LoggingInterceptorによるログ上にはSerializableと出力している。
DaoのinterfaceにPK extends Serializableと書いているため、DaoとしてはSerializableで受け取っているという認識になる。
で、呼び出し元としてはTestテーブルのentityであるTblTestという型で受け取っているのに、戻り値にはObjectと出ている。
昨日の「LoggingInterceptor」の40行目と67行目、この場合だとDaoのメソッド定義から型を取っているから当然なんだけど。
でも、実際に渡しているクラスがスーパークラスやinterfaceで見えなくなっちゃうってのは、使い勝手としてどうなんだろう。
だったら、メソッド定義から型を取らずに、MethodInvocation#getArguments()で取った各Objectの型を出すのはどうか?

ここで考えたんだけど、AOPのロギングが行われる前って、一般的にはメソッドの開始・終了部にロギングを書いてたと思う。
要するに、意識するべきは「呼び出し対象メソッドとして、どのような値が渡ってきて、どのような値を返すのか」に尽きるかと。
逆に「呼び出し元から渡すパラメータと返ってきた戻り値」をロギングしていた例は、あまり一般的じゃないのかもしれない。
だったら、この場合だと、パラメータがStringだろうが、出力するべきログとしてはSerializableであるのが適切なんじゃないの?

とは思うものの、StringやTblTestとかって出力された方が見た目は良いよなー、戻り値Objectじゃ瞬時に判断つかないし。
かと言って、例えば戻り値がintのものがあったとして、戻り値の型を使ってログを出力するとIntegerと出てしまうから困る。
まあ、MethodInvocation#proceed()の戻り値がObjectだからラップされるのはしょうがないんだろうけど。何とかならないの?

2010/05/20 Thu.

「物件A」と「物件B」、プロパンガスの使用料金を考えたら4,000円程度の差額になった。これは誤差の範囲としていいのか?

2010/05/23 修正
「物件A」と「物件B」と書いてある箇所のリンクを削除。

ただし、前者だと5月16日の雑記にも書いたように、照明器具やガスコンロとかが追加で必要となって来るんだよな。
自分がインテリアに興味があるとは思えないし、照明器具は適当なので済ませる。一口ガスコンロも安けりゃ5,000円程度。
その他の初期投資は、どっちの物件も変わらないだろう。後は環境面と立地の利便性で考えるしかないんだろうな。
ニュータウン通り沿いで交通騒音が目立つが、駅まで徒歩6分。ニュータウン通りから一本入ったとこで、駅まで徒歩12分。
後者は一本入ったトコなのに、意外に車が通る。周辺住人だろうけどさ。騒音がキツけりゃ防音カーテンだ。安くはなさそう。
でも、防音カーテンは高い周波数帯には効くけど、低周波数帯は効果が怪しいらしい。費用対効果は微妙なトコなんだろうな。

あー、約4,000円の差。駅まで徒歩6分の差、往復12分の差、31日で372分の差。月あたり6時間の移動距離削減が4,000円。
いや、待てよ。後者の物件の徒歩12分、これは絶対に一服しながら移動するはず。よって、一ヶ月で煙草3箱の出費がある。
値上がり後の値段を考えて1,230円と試算しても、差額は2,770円。他に前者の物件が有利な点は何だ?6畳と7畳の違いか。
部屋の広さにはこだわらないと思うんだけど、前者の物件の方が体感的に広く感じる。縦長の作りになってるからかな。
まだあった、前者の物件は30Aだった。そんなに使うとも思えないけど。東京電力だと、契約を10A下げると月で273円変わる。
残り2,500円、これが1畳分の広さと、完全に独立した洗面台の正体か。やっぱり前者の物件にしよっかなー。まだ迷う。

2010/05/21 Fri.

何事も無く落ち着いた一日。何も無さ過ぎて困ったので、物件が決まっていないけど、部屋のレイアウトを考えてみたり。
まあ、妄想するだけならタダなんです。で、実際に家具を配置したら妄想と現実のギャップに悩む、と。お決まりだろうな。
ぶっちゃけ、候補が二つある物件のうち、駅から徒歩6分のお高い方で決まりなんじゃないかな。最初から気に入ってたし。

2010/05/22 Sat.

週末は不動産屋へと通います。で、現時点での気持ちを伝えた上で、とりあえず入居申込書を頂く。記入欄多いな。
連帯保証人が必要だったので、親父に頭を下げてお願いする。自分の年収額を記述する欄が非常に悩ましいんですが。
審査用に持ち込む書類は源泉徴収票になるか。直近3ヶ月の給与明細でも可らしいけど、そっちだと蹴られるんじゃないか?
残業が年間で1,000時間くらいあれば、見た目はまともな年収になるんだろうけど、今年は一体どうなることやら……。