課題A2 (機能理解)

課題A2では, ArgoUMLの図形の選択機能について見ていきます.
具体的には,

「配置された図形がArgoUMLのシステム内部でどのように管理され,選択機能の実行によってどのように取り出されて,どのように選択図形として登録されるか?」
ArgoUMLはオープンソースのUMLモデリングツールで, Javaで書かれております.
また, ArgoUML内部では, グラフ編集用フレームワークであるGEFが使用されています.
ワークスペース内のargouml-*が、ArgoUMLを構成するプロジェクトであり, GEF-0.13.7がGEFのプロジェクトです.


前準備

課題A1 (機能理解) のときと同様に「トレースデバッガ(順方向)」のパースペクティブを開いてください.

ここでは, フィールド selections に SelectionClass クラスのインスタンス (id = 1672744985) を実際に追加しているのはどこなのかを見ていきます.
ソースコード中の selections にカーソルを入れ, そのフィールドに対してオブジェクトを追加している全ての行にブレークポイントを入れてください.
今回は, SelectionManager クラスの125行目と130行目の二か所が該当します.

SelectinoManager クラスの125行目と130行目にブレークポイントを入れた状態で,
ブレークポイントビュー上の「ブレークポイントをEclipseから取り入れる」アイコンを押してください.
すると, 実際にトレース上に実行された記録が残っている130行目にだけブレークポイントが新規追加されます.
そのあと, ブレークポイントビュー上で下記のブレークポイントのチェックを外してください.

  1. 83行目 ActionRemoveFromDiagram.actionPerformed(ActionEvent)

デバッグ実行を押すと, SelectionManager クラスの addFig(Fig) メソッドの130行目で止まります.
ここで, 再開ボタンを押して, このあと実行がどのように移り変わるかを確認していきます.
まずは再開ボタンを1回押すと, 再び130行目に止まることが確認できます.
もう一度再開ボタンを押すと 今度は ActionRemoveFromDiagram クラスの actionPerformed(ActionEvent) メソッドの85行目に止まることが確認できます.
そこからさらに再開ボタンを押していくと, 現在の実行時点は FigNodeModelElement クラスの 1965行目 → Fig クラスの743行目に移り変わっていくことが確認できます.
これを確認したら, デバッグ実行をいったん終了してから再び実行して, 再開ボタンを1回押して2回目の130行目に進めてください.
下図の状態になれば, ここで課題A2の前準備は終了です.


機能理解

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

先ほどの実行手順にしたがって進めていくと, 下図のように SelectionManager クラスの addFig(Fig) メソッド内の130行目で一時停止している状態になっているはずです.
この状態になっていれば, ここから時間計測を開始してください. 時間計測はできる限り,1分以内の単位での計測をお願いします.
ここで, ソースコードと変数ビューを見ると, SelectionManager クラスのインスタンス (id = 4310438) が参照するフィールド selections へは
makeSelectionFor(Fig) メソッドの戻り値 (SelectionClass クラスのインスタンス) が追加されていることがわかります.
課題A2では, このオブジェクトの追加に関わっている SelectionManager クラスのインスタンスと SelectionClass クラスのインスタンスについて見ていきます.
まずは, ステップインを3回押して, この makeSelectionFor(Fig) メソッドの中に入ってください.

SelectionManager クラスの makeSelectionFor(Fig) メソッドに入りました.
ここで, 変数ビューを見ると, 仮引数として FigClass クラスのインスタンス (id = 1675174935) が渡されてきていることがわかります.
また, ソースコードを見ると, 1129行目では 仮引数 f で渡されてきたこのインスタンスに対して makeSelection() メソッドが呼び出され,
その戻り値がローカル変数 customSelection に代入されていることが確認できます.
ここでは, ステップインを2回押してこのメソッドの中に入ってください.

FigClass クラスの makeSelection() メソッドに入りました.
ソースコードを見ると, ここで SelectionClass クラスのインスタンスを新たに生成し, その引数として自分自身が渡されていることが確認できます.
よって, ここで新たに生成された SelectionClass クラスのインスタンスが FigClass クラスのインスタンス (id = 1675174935) を参照していることがわかります.
また, このメソッドでは, この SelectionClass クラスのインスタンスを戻り値として返していることが確認できます.
これを確認したら, ステップオーバーを1回押して, 呼び出し元に戻ってください.

SelectionManager クラスの makeSelectionFor(Fig) メソッドに戻ってきました.
ここで, ソースコードを見ると, 先ほど呼び出された FigClass クラスの makeSelection() メソッドの戻り値が,
ローカル変数 customSelection に代入されて, それがここでは戻り値として返されていることがわかります.
これを確認したら, ステップオーバーで呼び出し元に戻ってください.

SelectionManager クラスの addFig(Fig) メソッドに戻ってきました.
ここで, 変数ビュー上の「呼び出し前」を開くと, 先ほどの SelectionClass クラスのインスタンス (id = 1672744985) が引数として渡されており,
これがフィールド selections に追加されることがわかります.
また, この引数をさらに開くと, SelectionClass クラスのインスタンス (id = 1672744985) が
フィールド content として 実際に FigClass クラスのインスタンス(id = 1675174935) を参照していることを確認できます.
ここからは, FigClass クラスのインスタンス(id = 1675174935) について見ていきます.
ソースコードと変数ビューを見ると, このインスタンスは 仮引数 f として渡されていることが確認できます.
この仮引数 f の値がどこから来たのかを見るために, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は SelectionManager クラスの select(Fig) メソッドの180行目を見ています.
ここで, ソースコードを見ると, この FigClass クラスのインスタンス (id = 1675174935) は, ここでも仮引数として渡されてきていることが確認できます.
これを確認したら, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は ModeSelect クラスの mousePressed(MouseEvent) メソッドの187行目を見ています.
ここで, ソースコードを見ると, ローカル変数 underMouse で参照されているインスタンスが実引数として渡されていることがわかります.

ここからは, このローカル変数 underMouse の値がどこから来たのかを見ていきます.
ローカル変数 underMouse にカーソルを入れて この underMouse に代入された箇所を探していきます.
ローカル変数 underMouse の初期化が160行目にあるので, ここにブレークポイントを入れてください.
ブレークポイントを入れたら, ブレークポイントビュー上の「ブレークポイントをEclipseから取り入れる」アイコンを押してください.
そのあと, ブレークポイントビュー上で130行目と160行目以外のブレークポイントのチェックを外してください.

いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
すると, まずは SelectionManager クラスの addFig(Fig) メソッドの130行目で止まります.
ここで, 再開ボタンを1回押すと, 次は ModeSelect クラスの mousePressed(MouseEvent) メソッドの160行目で止まります.
そのあと, 再開ボタンをもう1回押すと, 再び160行目で止まることが確認できます.
さらに再開ボタンを押すと, SelectionManager クラスの addFig(Fig) メソッドの130行目に止まることが確認できます.
これによって, 2回目の160行目の時点がローカル変数 underMouse に値が代入された直前の実行時点だとわかります.

これを確認したら, いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
そのあと, 再開ボタンを2回押して, 2回目の160行目にまで進んでください.
ここで, ステップオーバーを1回押すと, 163行目に止まることが確認できます.
163行目では, ローカル変数 underMouse で参照されているインスタンスに対して deepSelect(Rectangle) メソッドが呼び出され
その戻り値がローカル変数 underMouse に再び代入されていることが確認できます.

ここでは, ステップオーバーを8回押して, このローカル変数がこれ以上更新されずに187行目まで進むことを確認してください.
これにより, 187行目で実引数として渡しているローカル変数 underMouse の値は, 163行目で呼び出されたメソッドの戻り値から来ていることがわかります.

いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
まずは, 再開ボタンを2回押して, 2回目の160行目にまで進んでください.
そのあと, ステップオーバーを1回押して163行目に進んでください.
ここで, ステップインを2回押して FigGroup クラスの deepSelect(Rectangle) メソッドの中に入ってください.

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

現在は, ModeSelect クラスの mousePressed(MouseEvent) メソッドを見ています.
163行目では元々参照されていた値と同じ FigClass クラスのインスタンス (id = 1675174935) が, 再び代入されているだけだということがわかりました.
ここで, ソースコードを見ると, 元々の値は160行目で代入されていることが確認できます.

いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
そのあと, 再開ボタンを2回押して, 2回目の160行目にまで進んでください.
ソースコードを見ると, 160行目では Editor クラスの hit(Point) メソッドが呼び出され,
その戻り値がローカル変数 underMouse に代入されていることが確認できます.
ここで, ステップインを3回押して, このメソッドの中に入ってください.

Editor クラスの hit(Point) メソッドに入りました.
ここでは, ステップオーバーを1回押して446行目に進んだあと, ステップインを2回押して hit(Rectangle) メソッドの中に入ってください.

Editor クラスの hit(Rectangle) メソッドに入りました.
ここで, ソースコードを見ると, getLayerManager() メソッドの戻り値に対して hit() メソッドが呼び出され,
その戻り値がローカル変数 f に代入されたあと, 次の行で return f によって戻り値として返されていることが確認できます.
まずは, ステップインを2回押して getLayerManager() メソッドの中に入ってください.

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

Editor クラスの hit(Rectangle) メソッドに戻ってきました.
ここでは, ステップインを1回押して, LayerManager クラスの hit(Rectangle) メソッドの中に入ってください.

LayerManager クラスの hit(Rectangle) メソッドに入りました.
ここで, 変数ビュー上の this を開くと LayerManager クラスのインスタンス (id = 1975264229) が
フィールド _activeLayer として LayerPerspectiveMutable クラスのインスタンス (id = 1248750852) を参照していることがわかります.
これを確認したら, ステップインを4回押して LayerPerspectiveMutable クラスの hit(Rectangle) メソッドの中に入ってください.

LayerPerspectiveMutable クラスの hit(Rectangle) メソッドに入りました.
ここで, 変数ビュー上の this を開くと, LayerPerspectiveMutable クラスのインスタンス (id = 1248750852) が
フィールド contents として ArrayList を参照していることがわかります.
また, ソースコードを見ると, 231行目でこの ArrayList から取り出してきた要素を, 233行目の return f で戻り値として返されていることが確認できます.
ここでは, ステップオーバーを2回押して232行目にまで進んでください.

現在は LayerPerspectiveMutable クラスの hit(Rectangle) メソッドの232行目にいます.
ここで, 変数ビュー上の「呼び出し後」を開くと, フィールド contents から戻り値として
FigClass クラスのインスタンス (id = 1675174935) を取得していることがわかります.
ステップオーバーを1回押して, 実際に233行目の return f で戻り値として返されていることを確認してください.
これを確認したら, 呼び出しスタック上で4つ呼び出し元である ModeSelect クラスの mousePressed(MouseEvent) メソッドをクリックしてください.

現在は ModeSelect クラスの mousePressed(MouseEvent) メソッドの160行目を見ています.
ここで, 変数ビュー上の this を開くと, ModeSelect クラスのインスタンス (id = 1807431709) が
フィールド editor として Editor クラスのインスタンス (id = 371019845) を参照していることがわかります.

ここまでの結果から, SelectionClass クラスのインスタンスに関わる各オブジェクトの関係について, 以下のことがわかりました.

  1. SelectionClass クラスのインスタンス (id = 1672744985) は Fig クラスのインスタンス (id = 1675174935) を引数に渡して生成している.
  2. FigClass クラスのインスタンス (id = 1675174935) は LayerPerspectiveMutable クラスのインスタンス (id = 1248750852) が参照している.
  3. LayerPerspectiveMutable クラスのインスタンス (id = 1248750852) は LayerManager クラスのインスタンス (id = 1975264229) が参照している.
  4. LayerManager クラスのインスタンス (id = 1975264229) は Editor クラスのインスタンス (id = 371019845) が参照している.
  5. Editor クラスのインスタンス (id = 371019845) は ModeSelect クラスのインスタンス (id = 1807431709) が参照している.
課題A2では, オブジェクトの追加に関わっている SelectionManager クラスのインスタンスと SelectionClass クラスのインスタンスについて見ていくのでした.
ここからは, SelectionManager クラスのインスタンスの方がどこから来たかを見ていきます.

ソースコードをスクロールして187行目を見ると, SelectionManager クラスのインスタンスはローカル変数 sm で参照されていることが確認できます.
ここでは, このローカル変数 sm の値がどこから来たかを見るために, ローカル変数 sm にカーソルを入れて, 代入された箇所を探していきます.
ローカル変数 sm の初期化が156行目にあるので, ここにブレークポイントを入れてください.
ブレークポイントを入れたら, ブレークポイントビュー上の「ブレークポイントをEclipseから取り入れる」アイコンを押してください.
そのあと, ブレークポイントビュー上で130行目と156行目以外のブレークポイントのチェックを外してください.

いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
すると, まずは SelectionManager クラスの addFig(Fig) メソッドの130行目で止まります.
ここで, 再開ボタンを1回押すと, 次は ModeSelect クラスの mousePressed(MouseEvent) メソッドの156行目で止まります.
そのあと, 再開ボタンをもう1回押すと, 再び156行目で止まることが確認できます.
さらに再開ボタンを押すと, SelectionManager クラスの addFig(Fig) メソッドの130行目に止まることが確認できます.
これによって, 2回目の156行目の時点がローカル変数 sm に値が代入された直前の実行時点だとわかります.

これを確認したら, いったんデバッグ実行を終了してから, 再びデバッグ実行してください.
そのあと, 再開ボタンを2回押して, 2回目の156行目にまで進んでください.
156行目では, Editor クラスの getSelectionManager() メソッドが呼び出され, その戻り値がローカル変数 sm に代入されていることが確認できます.
ここで, ステップインを2回押して, このメソッドの中に入ってください.

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

現在は ModeSelect クラスの mousePressed(MouseEvent) メソッドを見ています.
ここで, 課題A2は終了です. 時間計測を終了してください.
また, 終了アイコンを押して, デバッグ実行を終了しておいてください.


課題A2の機能理解が終了しましたら, 以下のアンケートにお答えください.

アンケート回答

次へ