Java RMIについて

既存のPOJOインターフェースをRemoteインターフェースとして公開しようとしたときにおもわぬところで問題となったのが”リモートインターフェースメソッドは、throws RemoteExceptionを定義しなければならない"という制約。
RMIでオブジェクトを公開するには、インターフェース”Remote”を継承した"リモートインターフェース"を定義する必要があるのだが、既存のPOJOインターフェースを公開する場合は、MIXIN(インターフェースの多重実装)してやればいいと軽くかんがえていた。しかし、冒頭の制約のせいで、POJOインターフェースのメソッドのthrows句にRemoteExceptionそのものか、RemoteExceptionの親クラスを宣言しなければならず、せっかくのPOJOインターフェースが汚染されてしまう。

解決策としては
リモートインターフェースとして公開したいPOJOインターフェースを薄く
Wrapするような別のインターフェースを定義するぐらいだな。

//POJOインターフェース
public interface Pojo {
    void hoge();
}

//リモートインターフェース(Pojoのラッパー)
public interface RemotePojo extends Remote {
    void hoge() throws RemoteException;
}

//実装クラス
public class RemotePojoImpl implements RemotePojo {
    private Pojo pojo;

    public RemotePojoImpl(Pojo pojo) {
        this.pojo = pojo;
    }

    void hoge() throws RemoteException {
        this.pojo.hoge();
    }
}

冗長すぎる。ふぅ。やだな。やっぱソケットだな。

正規表現でマッチした文字列のハイライトがずれる問題(2)

http://d.hatena.ne.jp/jawagenjin/20080606/1212679738の続き。
前回の例ではJEditorPaneを使ってテキストをハイライトしていたが、JEditorPaneが使っているDefaultEditorKitのAPIドキュメントにあった下記の記述が答えのようだ。

ドキュメントがメモリー内にある間は、ドキュメントがディスク上にある場合の復帰改行がどのように定義されているかにかかわらず、改行の定義に \n 文字が使用されます。したがって、検索時には、常に "\n" を使用するようにしてください。新規ドキュメントが作成され、EndOfLineStringProperty が未定義の場合、ドキュメントの書き出しには System プロパティーが使用されます。

つまり、正規表現のMatcherがマッチした際に返すインデックスは文字列のインデックスそのままだが、Document内では、改行コードは"\n"のみとして認識されており、ポジション指定した際に、"\r"の分だけインデックスがずれていくという事らしい。

改行コードのリプレース(\r\n->\n)とかじゃなくスマートな解決方法を探す。

正規表現でマッチした文字列のハイライトがずれる問題

Highlighterと、HilightPainterを使ってエディタ上の文字列から指定された正規表現にマッチした文字をハイライトする処理を書いてみたが、どうも対象の文字列が\r\n(CRLF)を含む場合にハイライトがずれてしまう現象を確認。
正規表現のMatcherは正確なインデックスを返しているようだが、Hilighter(もしくは、EditorPane)が\r\nを1文字として誤認識しており、\r\nが現れる度に後ろにインデックスが1つずれているような挙動。
今のところ、下のサンプルのように、対象の文字列の\r\nを\nに置換してからマッチとハイライトを行うとずれないが…。すっきりしないのでもう少し調査する。

    //エディタからHighlighterを取得
        Highlighter hilighter = this.sourceEditorPane.getHighlighter();
        hilighter.removeAllHighlights();

        //HighlightPainterを生成
        HighlightPainter painter = 
                new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);
                
        String regexp = this.regExpField.getText();
        if (regexp.length() == 0) {
            return;
        }

        Pattern p = Pattern.compile(regexp, Pattern.MULTILINE);
        
        String source  = this.SourceEditorPane.getText();
        if (source.length() == 0) {
            return;
        }

    //インデックスのずれを回避する為改行コードを置換
    source = soruce.replaceAll("\r\n","\n");

        Matcher m = p.matcher(source);
        while(m.find()) {
            try {
                hilighter.addHighlight(m.start(),m.end(), painter);
            } catch (BadLocationException ex) {
                //なにもしない
            }
        }

Swingで Undo Redo

テキストエディタ等でよくある、Undo(Ctrl-z)とRedo(Ctrl-y)をSwingで実現する。

主な構成要素

javax.swing.undo.UndoableEdit UndoRedoが行える編集作業そのものを表すインターフェース。メソッドundo(),redo()を持つ
javax.swing.event.UndoableEditListener UndoRedoが行える編集作業を監視するオブザーバを表すインターフェース。主な実装クラスとしては、UndoManagerクラスがある
javax.swing.event.UndoableEditEvent 編集作業発生時に、UndoableEditListenerに通知される、イベント。内部にUndoableEditを保持

関係

もう少し具体的な例

  1. GUI構築時に、編集対象であるJEditorPaneDocumentオブジェクトに、UndoableEditListenerの実装クラスであるUndoManagerオブジェクトを追加して、さらにUndoManagerに対してUndo、Redoを行うActionをそれぞれ作成して、ボタン等に割り当てておく。
  2. アプリケーションユーザーがそのJEditorPaneに対して編集を行った際、そのDocumentから、UndoManagerに対してUndoableEditEventが通知される。UndoManagerはUndoableEditEventから、UndoableEditを取得して管理する。
  3. Undoを行うActionが割り当てられたボタン等をアプリケーションユーザーがクリックした時に、UndoMangerへUndoを指示。UndoManager内部では最新のUndoableEditがUndoされる。
  4. Redoを行うActionが割り当てられたボタン等をアプリケーションユーザーがクリックした時に、UndoManagerへRedoを指示。UndoManager内部では直近にUndoされたUndoableEditがRedoされる。

サンプル

  //UndoMangerを保持するプロパティを宣言
  private UndoManager undomanager = new UndoManager();
  
  //このコードをGUI構築時に実行
  this.editorPane.getDocument().addUndoableEditListener(this.undomanager);

  //Undoのアクション/イベント処理に記述
  if (this.undomanager.canUndo()) this.undomanager.undo();

  //Redoのアクションイベント処理に記述
  if (this.undomanager.canRedo()) this.undomanager.redo();

Javaで使える正規表現メタ文字まとめ(未完成)

Javaで使える正規表現のメタ文字をメモ。

文字クラス

.	任意の一文字
[abc]	abcのどれか1文字
[^abc]	否定(どれにもあてはまらない、他の文字。空白行にはマッチしない。)
[a-z]	範囲指定("-"は先頭であればリテラル、先頭でなければ範囲指定子となる)

量指定子(直前の文字およびグループが現れる量を指定できる)

欲張り量指定(最長マッチ)
?	0...1
+	1...n
*	0...n
{n}	n
{n1,n2}	n1...n2
非欲張り量指定(最短マッチ)
??		0...1
+?		1...n
*?		0...n
{n}?		n
{n1,n2}?	n1...n2

文字クラス略記

1文字を表すクラス
\s	空白1文字をあらわす文字クラス
\S	\s以外のもの[^\s]と同意
\t	タブ1文字をあらわす文字クラス
\r	キャリッジリターンを表す文字クラス
\n	改行を表す文字クラス
\d	1桁の数字
\D	[^\d]と同意
単語等複数文字を表すクラス
\w	英語と数字の組み合わせの単語
\W	[^\w]と同意
文字そのものではなく位置を表すクラス
\b	単語境界をあらわす(\bregex\b は " regex "にマッチするが"aregex"にマッチしない)
^	行および文字列の先頭
$	行および文字列の末尾

文字クラス同士の集合演算

&&	and(例:[[a-z]&&[^g]] gを除く小文字アルファベット)
	or(例:[[a-z]0] 小文字アルファベットもしくは0)

論理

|      例:ebc|def abcもしくはdefと一致

グループ

(abc|def)ghi	|の適用範囲を限定。abcghiもしくはdefghiのどちらかと一致する。
(abc)?		量指定子の適用範囲をグルーピング"abc"という文字列の繰り返し制御。
(abc)\1	戻り参照(\1は、直前()内で一致したものと同じもの、つまりabcabcという意味となる)
(a(b))(c)	abが\1 bが\2 cが\3として参照できる。"("が現れた順に、戻り参照番号が振られる。
(?:...)	"?:"で戻り参照なしのグループを定義できる。戻り参照番号が振られない。
(?=...)	"?="先読み。以降に指定した正規表現のマッチ部分の前の位置を表す。
(?!...)	"?!"否定先読み。以降に指定した正規表現にマッチしない部分の前の位置を表す。
(?>=...)	"?>=..." 戻り読み。以降に指定した正規表現のマッチ部分の後ろの位置をあらわす。
(?<!...)	"?<!..."否定戻り読み。以降に指定した正規表現にマッチしない部分の後ろの位置を表す。
(?<...)	"?<..."アトミックグループ。このグループにマッチした文字列は固定され、
		あとに続く正規表現はこのグループのマッチが終了した部分から再度マッチ処理を開始する。

エスケープ文字

\	各種メタ文字の前に記述することで、その意味を殺す

Javaの置換で使える戻り参照文字

$n	グループでキャプチャした文字の参照

Javaで正規表現を使って置換

ほとんどAPIドキュメントのままだが…
置換文字列に戻り読み指定の$1とか、$2がそのまま使えるのはありがたいな。

        //置換元文字列
    String source = "Javaで正規表現"
                         + "\nJavaなんかよりもPerlで正規表現"
                         + "\nJavaなんかよりもRubyで正規表現";
        //行頭の"Javaなんかよりも..."を"Javaなんか"で置換
        String regexp = "(^Javaなんか)よりも(?:Perl|Ruby)"; //正規表現
        String replacement = "$1"; //置換文字列:直前にマッチしたグループの1つ目の文字列

        //行に対するマッチ処理を実行するため、Pettern.MULTILINEを設定
        Pattern p = Pattern.compile(regexp, Pattern.MULTILINE);
        Matcher m = p.matcher(source);
        
        //置換結果を収集するためのバッファ
        StringBuffer sb = new StringBuffer();
        while(m.find()) {
      //マッチ直前までの文字列と、置換文字を結合
            m.appendReplacement(sb, replacement);
        }
        m.appendTail(sb);//以降の文字をすべて結合

        System.out.println(sb.toString());
        //結果
        //Javaで正規表現
        //Javaなんかで正規表現
        //Javaなんかで正規表現

結局Haskell

関数型言語を勉強しようとおもってSchemeをやろうかと思ってたけど、結局Haskellになった。今読んでる。全然違うパラダイムの言語を覚えるのは、刺激的でいい。

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門


いっちょ正規表現を本格的に覚えるか。と思ってこれも読んでる。第2版だけど。買ったらすぐに3版が出たTT。
詳説 正規表現 第3版

詳説 正規表現 第3版


あと
Jythonプログラミング

Jythonプログラミング



ビューティフルコード (THEORY/IN/PRACTICE)

ビューティフルコード (THEORY/IN/PRACTICE)


を発注。
久しぶりのエントリなのにこんだけだorz.