pointcut に関して高い記述力を持つ アスペクト指向言語 Josh 東京工業大学 中川 清志 千葉 滋 SPA 2003, Hakone
アスペクト指向(AOP) オブジェクト指向の限界 アスペクト指向の利点 ある種の処理は複数クラスに散らばる ロギング、同期、永続性などの処理 そのような処理をアスペクトとしてモジュール化 クラスとアスペクトは分離して記述 オブジェクト指向を補完 SPA 2003, Hakone
AOPの利用例:[ロギング] 従来は アプリケーション内にロギングコードを記述 class Car extends Vehicle { void start() { Log.print(“start Car”); ... } void back() { Log.print(“back Car”); } } 従来は アプリケーション内にロギングコードを記述 ログ出力のタイミングや方式が変わるとアプリケーションのコードの変更も必要 class Bike extends Vehicle{ void start() { Log.print(“start Bike”); ... } } class Log { static void print(String msg) { System.out.println(msg); } } SPA 2003, Hakone
AOPの利用例:[ロギング] AOPでは アスペクト : メソッド実行前には Log クラス の print()を呼べ! class Car extends Vehicle { void start() { Log.print(“start Car”); ... } void back() { Log.print(“back Car”); } } AOPでは アプリケーションと分離して記述 アスペクト : メソッド実行前には Log クラス の print()を呼べ! 必要なし class Bike extends Vehicle{ void start() { Log.print(“start Bike”); ... } } class Log { static void print(String msg) { System.out.println(msg); } } SPA 2003, Hakone
合成処理 weave アスペクトを各クラスに埋め込む処理 アスペクトは以下の2つを指定 1. どこに埋め込むか (pointcut) 2. 何のコードを埋め込むか(アドバイス) クラス アスペクト 本研究は前者の pointcut に注目したものである SPA 2003, Hakone
pointcut のメカニズム 条件に応じた join-point の抽出 メソッド呼び出し、フィールド参照、インスタンス生成など 例 : call(void Point.setX(int)) [AspectJ*の文法] call は pointcut指定子の一つ メソッド呼び出し join-point の抽出 カッコ内は条件 void型、Pointクラス、setXという名前、 int型の引数を一つ持つ * Kiczales等 ECOOP1997 SPA 2003, Hakone
pointcut の記述力が高い AOP言語 Josh Java で新しい pointcut指定子を定義可能 強力な pointcut が可能 既存言語では組み込み指定子に限定 記述できない 複雑な pointcut の存在 汎用的な指定子は組み込みで提供 複雑な pointcut指定子のみ定義すればよい SPA 2003, Hakone
この命令の前に値が変えられてるかもしれない 複雑なpointcut例 : 排他制御 マルチスレッドにおいて、フィールド‘balance’の一貫性を保持したい 解決方法: 「balanceにアクセス している全メソッド」 をsynchronizedにする しかしながら, 「balanceにアクセスしている 全メソッド」という条件の pointcutを記述できない class BankAccount { int balance; public void withdraw(int bal){ if (balance < bal) throw new BankException(); balance -= bal; } } ここでフィールドの 値を調べても この命令の前に値が変えられてるかもしれない SPA 2003, Hakone
Josh weaver クラス内の各コードを全てチェック 1 4 3 2 1. join-point の発見 3. pointcut に該当するかの決定 4. アドバイス埋め込み アスペクト埋め込みの ターゲットクラス 1 4 weaver 3 メソッド呼び出し MethodCall フィールド参照 FieldAccess インスタンス生成 NewExpr キャスト式 Cast instanceof 式 Instanceof pointcut アドバイス 2 アスペクト SPA 2003, Hakone
pointcut 指定子の定義(1/2) boolean 型のメソッドで定義 第一引数 : 対象とする join-point オブジェクト weaver から受け取る /* pointcut メソッドの定義例*/ static boolean simpleCall (MethodCall m,String name){ String name2 = m.getMethodName(); if (name.equals(name2)) return true; else return false; } メソッド呼び出し MethodCall フィールド参照 FieldAccess インスタンス生成 NewExpr キャスト式 Cast instanceof 式 Instanceof SPA 2003, Hakone
pointcut 指定子の定義(2/2) join-point の情報を入手可能 例 : MethodCall クラス 名前、属するクラス、型など 例 : MethodCall クラス getMethodName(), getClassName() メタオブジェクトの操作 getMethod()でメソッドの メタオブジェクト 深い情報を得られる /* pointcut メソッドの定義例*/ static boolean simpleCall (MethodCall m,String name){ String name2 = m.getMethodName(); if (name.equals(name2)) return true; else return false; } SPA 2003, Hakone
join-pointオブジェクトの実引数は必要ない Josh アスペクト 全体のコード aspect LogAspect { static int count = 0; static void log() { System.out.println (“callhello” + (count++)); } static boolean simpleCall (MethodCall m, String name) { /* 省略 */ } before : LogAspect.simpleCall(“hello”) { LogAspect.log(); } } アスペクトの宣言 通常のJava要素 pointcut 指定子の定義 pointcut の使用 & アドバイス join-pointオブジェクトの実引数は必要ない SPA 2003, Hakone
Josh実行までの概観 weave コード変換 JVM .josh 独自言語で書いた .class アスペクト埋め込みの ターゲット アスペクトとクラス の両方の機能 weave コード変換 .class pointcut 指定子の定義 pointcut の使用 & アドバイス JVM .class Java の要素 SPA 2003, Hakone
コード変換 独自文法のアスペクトを Javaコードに変換 simpleCall の対象 join-point は MethodCall before : simpleCall(“hello”) { System.out.println(“-hello is called-”); } コード変換 引数 ‘m’ はWeaver から渡される join-pointオブジェクト public void edit(MethodCall m) { if (simpleCall(m, “hello”)) { m.replace (“Sysetem.out.println(\”-hello is called-\”); $_ = $proceed($$);”); } } replace はjoin-pointの コードを変える(アドバイス) SPA 2003, Hakone
weaver のコード CtClass, CtMethod : ExprEditor : instrument(editor) : クラス、メソッドを表す メタオブジェクト ExprEditor : pointcut & アドバイスを 持つ Java コード instrument(editor) : メソッドの中身を editorで走査、改変 public void weave(CtClass target, ExprEditor editor){ CtMethod[] methods = target.getDeclaredMethods(); for (int i=0; i < methods.length; i++) methods[i].instrument(editor); target.writeFile(); } SPA 2003, Hakone
「join-pointの実行時情報」引き渡し 例えばメソッド呼び出しターゲットの、インスタンスの情報 AspectJ では pointcut 命令内に記述 target (p) Josh では 明記する必要なし ドル記号‘$’で始まる予約語 $0 : join-point の動作の対象 となっているオブジェクト $1, $2, ... $r /* AspectJ での引き渡し*/ before(Point p) : call(void Point.*()) && target(p) { String targetObj = p.toString(); System.out.println(targetObj); } /* Josh での引き渡し*/ before : LogAspect.simpleCall(“hello”) { String targetObj = $0.toString(); System.out.println(targetObj); } SPA 2003, Hakone
関連研究 アスペクト指向言語 pointcut の拡張 AspectJ Hyper/J Composition Filters Soul/AOP [Brichau等 GPCE2002] pointcutを論理型言語で記述 埋め込むコードはSmalltalkで記述 SPA 2003, Hakone
まとめ アスペクト指向言語 Josh を提案 pointcut に関して高い記述力を持つ pointcut 指定子を新たにJavaで定義できる 複雑な pointcut が可能 汎用的なものは組み込みで与える 複雑なものだけを自分で定義すればよい SPA 2003, Hakone
SPA 2003, Hakone
SPA 2003, Hakone
(旧)pointcut 指定子の定義方法 boolean set(FieldAccess f, String type, String dec, String name) { CtField cf = f.getField(); String cf_name = cf.getName(); String cf_type = cf.getType().getName(); String cf_dec = cf.getDeclaringClass.getName(); if (f.isWriter() && cf_name.equals(name) && cf_type.equals(type) && cf_dec.equals(dec)) return true; else return false; } SPA 2003, Hakone
従来のAOP言語のpointcutの問題点 組み込み(built-in)のpointcut指定子しか使用できない 意図した場所にpointcutできない、つまりアスペクトを埋め込めない場合がある 複雑な条件のpointcutをしたい場合に不十分 メソッドのシグネチャだけでなく、内部動作に対しても条件を課したいときなど SPA 2003, Hakone
Josh実行までの概観 コード変換 weave JVM .josh 独自言語で書いた アスペクト .class アスペクト埋め込みの ターゲット .class アスペクトとクラス の両方の機能 コード変換 weave .class pointcut 指定子の定義 pointcut の使用 & アドバイス JVM .class Java の要素 SPA 2003, Hakone