課題A1 (アーキテクチャ理解)

課題A1では, ArgoUMLの図形の削除機能について見ていきます.
ArgoUMLはオープンソースのUMLモデリングツールで, Javaで書かれております.
また, ArgoUML内部では, グラフ編集用フレームワークであるGEFが使用されています.
ワークスペース内のargouml-*が、ArgoUMLを構成するプロジェクトであり, GEF-0.13.7がGEFのプロジェクトです.


実行手順

  1. デスクトップのEclipseを起動し, 指定されたワークスペースを開いてください.
  2. ワークスペース中にあるGEF-0.13.7プロジェクトを選択し, メニューバーの Search → Java で Fig というタイプの宣言を検索してください.
  3. Figクラスのソースファイルを開いて743行目 (Fig#removeFromDiagram()) にブレークポイントを入れてください.
  4. メニューバーの Window → Perspective → Open Perspective → Other... → トレースデバッガ(順方向) でトレースデバッガのパースペクティブを開いてください.
  5. 開いたトレースデバッガのパースペクティブ右上のブレークポイントビュー上にあるフォルダアイコン(左から1番目)を
    クリックしてトレースファイル (ArgoUMLBenchMarkWithMoreStandardClasses.trace) を開いてください.
  6. トレースファイルの読み込みが終わるまで待ってから, ブレークポイントビュー上にある「ブレークポイントをEclipseから取り入れる」アイコン(左から2番目)を
    クリックしてトレースデバッガ用のブレークポイントを作成してください.
  7. ブレークポイントビュー上にあるデバッグアイコン(左から3番目)をクリックしてください.
    トレースデバッガによるデバッグ実行が起動し, ブレークポイントを入れた位置の行が選択された状態で一時停止します.


アーキテクチャ理解

Fig クラスはグラフィックエディタ上の図形を表すGEFの内部のクラスです.
また, FigClass クラスはクラス図上に配置された「クラス」を表す ArgoUML のクラスで, Fig クラスの子孫クラスにあたります.
ブレークポイントを置いた行は、図形を削除するたびに実行されます.

先ほどの実行手順にしたがって進めていくと, 下図のように Fig クラスの removeFromDiagram() メソッド内の743行目で一時停止している状態になっているはずです.
この状態になっていれば, ここから時間計測を開始してください.
ここで, 変数ビューを確認すると, このメソッド実行は FigClass クラスのインスタンス (id = 1675174935) に対する呼び出しだとわかります.
この FigClass クラスのインスタンス (id = 1675174935) がどこから来たのかを確認していきます.
まずは, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である FigNode クラスの removeFromDiagram() メソッドを見ています.
ここで, 変数ビューを見ると, このメソッドも同一の FigClass クラスのインスタンス (id = 1675174935) に対して呼び出されていることがわかります.
これを確認したら, 呼び出しスタック上でさらに1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である FigNodeModelElement クラスの removeFromDiagramImpl() メソッドを見ています.
ここで, 変数ビューを見ると, このメソッドも先ほどと同様に FigClass クラスのインスタンス (id = 1675174935) によって呼び出されていることがわかります.
これを確認したら, 呼び出しスタック上でさらに1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である FigNodeModelElement クラスの removeFromDiagram() メソッドを見ています.
ここで, ソースコードを見ると, ローカル変数 delegate が参照しているインスタンスに対して removeFromDiagramImpl() メソッドが呼び出されていることがわかります.
ここでは, ローカル変数 delegate の値がどこから来たのかを見ていきます.
FigNodeModelElement クラスの removeFromDiagram() メソッドの1965行目にブレークポイントを入れ,
ブレークポイントビュー上の「ブレークポイントをEclipseから取り入れる」アイコンを押してください.

ここで, いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
すると, FigNodeModelElement クラスの removeFromDiagram() メソッドの1965行目で実行が止まります.
ここで, 最初にブレークポイントを入れた地点である Fig クラスの removeFromDiagram() メソッドの743行目に実行が進むかどうかを確認します.
再開ボタンを1回押すと, 実際に Fig クラスの removeFromDiagram() メソッドの743行目に実行時点が進むことが確認できます.

先ほどの確認が終わったら, いったんデバッグ実行を終了して, 再びデバッグ実行してください.
FigClassModelElement クラスの removeFromDiagram() メソッドの1965行目に止まります.
ここでは, ステップインを2回押して getRemoveDelegate() メソッドの中に入ってください.

FigNodeModelElement クラスの getRemoveDelegate() メソッドに入りました.
ここで, ソースコードを見ると, このメソッドでは return this で自分自身が戻り値として返されていることがわかります.
これを確認したら, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である FigNodeModelElement クラスの removeFromDiagram() メソッドを見ています.
ここで, 呼び出しスタック上でさらに1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である ActionRemoveFromDiagram() クラスの actionPerformed(ActionEvent) メソッドの89行目を見ています.
ここで, 変数ビュー上で 「呼び出し前」を開いて, レシーバのIDを確認してください.

ソースコードを見ると, ローカル変数 f の値は, 86行目の拡張for文で ローカル変数 figs から取得した要素を代入していることが確認できます.
ここからは, ローカル変数 figs の値がどこから来たのかを見ていきます.
すぐ上にある85行目にブレークポイントを入れてから, ブレークポイントビュー上の「ブレークポイントをEclipseから取り入れる」アイコンを押してください.

いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
すると, まずは ActionRemoveFromDiagram() クラスの actionPerformed(ActionEvent) メソッドの85行目に止まります.
ここで, 先ほどブレークポイントを入れていた箇所に実行が進むかどうかを見ていきます.
再開ボタンを1回押すと, FigNodeModelElement クラスの removeFromDiagram() メソッドの1965行目に現在の実行時点が移ることが確認できます.
もう一度再開ボタンを押すと, 今度は Fig クラスの removeFromDiagram() メソッドの743行目に現在の実行時点が移ることが確認できます.

いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
ActionRemoveFromDiagram() クラスの actionPerformed(ActionEvent) メソッドの85行目に止まります.
ソースコードを見ると, ここでは ローカル変数 ce で参照されているインスタンスに対して getSelectionManager() メソッドが呼び出され,
その戻り値に対して getFigs() メソッドが呼び出され, getFigs() メソッドの戻り値として返されたリストが, ローカル変数 figs に代入されていることが確認できます.
ここで, まずはステップインを1回押して Editor クラスの getSelectionManager() メソッドの中に入ってください.

Editor クラスの getSelectionManager() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, Editor クラスのインスタンス (id = 371019845) が
フィールド _selectionManager として SelectionManager クラスのインスタンス (id = 4310438) を参照していることがわかります.
これを確認したら, ステップリターンを1回押して呼び出し元に戻ってください.

呼び出し元である ActionRemoveFromDiagram クラスの actionPerformed(ActionEvent) メソッドに戻ってきました.
ここでは, ステップイン1回押して, getSelectionManager クラスの getFigs() メソッドの中に入ってください.

SelectionManager クラスの getFigs() メソッドに入りました.
ソースコードを見ると, 360行目ではローカル変数 figs を生成し, それが366行目では return figs で戻り値として返されていることが確認できます.
ここで, ステップオーバーを2回押して363行目に進んでください.

現在は SelectionManager クラスの getFigs() メソッドの363行目にいます.
ソースコードを見ると, フィールド selections から get() メソッドで取り出した要素に対して,
さらに getContent() メソッドを呼び出し, その戻り値をローカル変数 figs に追加していることが確認できます.

ここで, まずはステップインを3回押してください.
すると, selections に対する get() メソッドの実行が終了し, その戻り値に対して getContent() メソッドを呼び出す直前の時点にまで現在の実行時点が進みます.
ここで, ステップインを1回押して, SelectionClass クラスの getContent() メソッドの中に入ってください.

SelectionClass クラスの getContent() メソッドの中に入りました.
ここで, 変数ビュー上の this を開くと SelectionClass クラスのインスタンス (id = 1672744985) が
フィールド content として FigClass クラスのインスタンス (id = 1675174935) を参照していることがわかります.
これを確認したら, ステップリターンを1回押して呼び出し元に戻ってください.

SelectionManager クラスの getFigs() メソッドに戻ってきました.
ここで, 変数ビュー上の「呼び出し前」を開いて引数のIDを確認してください.
すると, 先ほど取得してきた FigClass クラスのインスタンス (id = 1675174935) をローカル変数 figs に追加することがわかります.

ここで, ステップオーバーを1回押して, ローカル変数 figs にそれ以上何も追加されずに
そのまま366行目の return figs まで進むことを確認してください.
これを確認したら, ステップオーバーを1回押して呼び出し元に戻ってください.

呼び出し元である ActionRemoveFromDiagram クラスの actionPerformed(ActionEvent) メソッドに戻ってきました.
ここで, ステップオーバーを1回押して, 87行目に進んでください.
そのあと, 変数ビュー上の「呼び出し後」を開いて戻り値のIDを確認してください.
すると, 先ほどの FigClass クラスのインスタンス (id = 1675174935) を取得していることがわかります.
これを確認したら, ステップオーバーを2回押して89行目に進んでください.

現在は ActionRemoveFromDiagram クラスの actionPerformed(ActionEvent) メソッドの89行目にいます.
ここで, ステップインを1回押すと, 変数ビュー上に「呼び出し前」が新たに表示されます.
この「呼び出し前」を開いてレシーバのIDを確認してください.
すると, ここでは, 先ほどの FigClass クラスのインスタンス (id = 1675174935) に対して removeFromDiagram() メソッドを呼び出していることがわかります.
これを確認したら, ステップインをもう1回押して FigClass クラスの removeFromDiagram() メソッドの中に入ってください.

FigClass クラスの removeFromDiagram() メソッドに入りました.
ここでは, 変数ビューを見て this の ID を確認してください.
これを確認したら, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

今までの結果から, FigClass クラスのインスタンス (id = 1675174935) に関連するオブジェクトについて, 以下のことがわかりました.

  1. FigClass クラスのインスタンス (id = 1675174935) は SelectionClass クラスのインスタンス (id = 1672744985) が参照している.
  2. SelectionClass クラスのインスタンス (id = 1672744985) は SelectionManager クラスのインスタンス (id = 4310438) が参照している.
  3. SelectionManager クラスのインスタンス (id = 4310438) は Editor クラスのインスタンス (id = 371019845) が参照している.
ここからは, Editor クラスのインスタンス (id = 371019845) について見ていきます.
Editor クラスのインスタンスは, 85行目でローカル変数 ce の値として参照されていることがわかっています.
したがって, ここでは, ローカル変数 ce の値がどこから来たのかを探していきます.
すぐ上の83行目にブレークポイントを入れてから, ブレークポイントビュー上の「ブレークポイントをEclipseから取り入れる」アイコンを押してください.

いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
すると, まずは ActionRemoveFromDiagram クラスの actionPerformed() メソッドの83行目に止まることが確認できます.
この状態で再開ボタンを押していくと, 現在の実行時点が 85行目 → 1965行目 → 743行目と移り変わることを確認してください.

先ほどの流れが確認できたら, いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
ActionRemoveFromDiagram クラスの actionPerformed() メソッドの83行目に止まっています.
この83行目では, Globals クラスの static メソッドである curEditor() メソッドが呼び出され,
その戻り値がローカル変数 ce に代入されていることが確認できます.
ここで, ステップインを2回押してこのメソッドの中に入ってください.

Globals クラスの static メソッドである curEditor() メソッドに入りました.
ここで, ソースコードを見ると, Globals クラスが static フィールド _curEditor として Editor クラスのインスタンスを参照していることがわかります.
これを確認したら, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は 呼び出し元である ActionRemoveFromDiagram クラスの actionPerformed() メソッドを見ています.
ここで, 課題A1は終了です. 時間計測を終了してください.