UMLモデリングツールastah*(Community版)でプラグイン開発環境を試してみた（2）

#はじめに
前回[UMLモデリングツールastah*(Community版)でプラグイン開発環境を試してみた（1）](https://qiita.com/azuki8/items/348cf76f8ffec1357c5c)で、チュートリアルに従って、クラス数を表示するところまで進めました。
今回は、チュートリアルから外れて、クラスの種々の情報を取得してみたいと思います。

#やってみること
クラスの名前や属性、操作の詳細をコンソールに出力します。
個人的には、独自のコード出力をしてみたいので、それを念頭に進めます。

#準備
- 前回作成したプログラムファイル(**CountClassAction.java**)をコピーし、**PrintClassAction.java**を作成。
　　 ![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/36797b02-e085-6f0d-bf50-070bcab6d0b2.png)
- astahのメニューから呼び出す部分を**CountClassAction**から**PrintClassAction**に変更
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/44a7d5a3-42e0-ddcc-b7cf-b342f478e6ab.png)


前回同様に、プラグインプロジェクトのルートフォルダでビルドを実行。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/37902440-f517-c327-75e8-64f01c2be6e8.png)

そして、同様に起動。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/a60414fa-f882-fe73-0680-7e96fe80d414.png)

前回のjavaファイルをコピーして、クラス名を変更して、ビルドし直しただけなので、
もちろん、実行しても同じ動きをしました。

#class名を取得して表示する
元のコードを、次のように書き換えました。選択されている行が変更後の箇所です。
変更前は、前回のコードと比較してください。すみません。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/9ece9551-a4ab-ebcf-817b-9a72e4679380.png)
図1 元のサンプルコード

変更前のサンプルは、「全クラスリストのCount」をメッセージボックスに出していたのですが、
変更後は、全クラスリストをfor文で回してクラス名を出力、最後に「Finished」とメッセージボックスを出すようにしました。

再び、ビルドと、launchします。

いざ実行！
すんなり動きました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/5bf4bc0c-98dd-e841-7564-1554b5c5a74d.png)

でも、よく見ると、期待と違う動きをしています。
全クラスリストから、クラス名を表示しているのですが、途中途中に 「**T**」 という名前のクラスがあります。
左側の構造ツリーの「`Comparable<T>`」の 「**T**」 が一つのクラスとして出てしまっているみたいです。

コードを読んでみたところ、getAllClasses()関数内のgetNestedClasses()が怪しそうです。
APIドキュメントで調べたところ、インナークラスなるものを取得するとのこと。
なので、NestedClassesの取得を下記のようにコメントアウトして、実行すると、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/ceed32d8-632a-cec7-0ac9-cb5f6b047b2b.png)

見事に、クラス名のリストを取得できました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/154607e1-8ccb-fd34-8dcb-c85182f12b56.png)

#クラス名以外の基本的な情報もすべて取得してみる
では、クラス名以外も表示してみます。
先ほどのコードを以下のように改造しました。以下は、ファイル全文です。

```java:PrintClassAction.java
package com.azuki.actions;

import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
import com.change_vision.jude.api.inf.AstahAPI;
import com.change_vision.jude.api.inf.exception.ProjectNotFoundException;
import com.change_vision.jude.api.inf.model.IClass;
import com.change_vision.jude.api.inf.model.IModel;
import com.change_vision.jude.api.inf.model.IAttribute;
import com.change_vision.jude.api.inf.model.IMultiplicityRange;
import com.change_vision.jude.api.inf.model.IOperation;
import com.change_vision.jude.api.inf.model.IGeneralization;
import com.change_vision.jude.api.inf.model.INamedElement;
import com.change_vision.jude.api.inf.model.ITemplateBinding;
import com.change_vision.jude.api.inf.model.IClassifierTemplateParameter;
import com.change_vision.jude.api.inf.model.IRealization;
import com.change_vision.jude.api.inf.model.IParameter;
import com.change_vision.jude.api.inf.model.IPackage;
import com.change_vision.jude.api.inf.project.ProjectAccessor;
import com.change_vision.jude.api.inf.ui.IPluginActionDelegate;
import com.change_vision.jude.api.inf.ui.IWindow;

public class PrintClassAction implements IPluginActionDelegate {
  public Object run(IWindow window) throws UnExpectedException {
    try {
      AstahAPI api = AstahAPI.getAstahAPI();
      ProjectAccessor projectAccessor = api.getProjectAccessor();
      IModel iCurrentProject = projectAccessor.getProject();
      List<IClass> classeList = new ArrayList<IClass>();
      getAllClasses(iCurrentProject, classeList);
      // changed code from here.
			for(IClass c : classeList){
				System.out.println("\n---CLASS---------------------------");
				System.out.println(getClassOption(c) + getClassTypeName(c) + getTemplateParameter(c) + ":" + getBaseClassName(c) + getInterfaceClassName(c));
				System.out.println("/*****************");
				System.out.println( getClassDefinition(c) );
				System.out.println("******************/");

				if( getClassIsActive(c) == true ){ System.out.println("IsActive"); }
				
				System.out.println("------ASSOCIATIONS-----------------");
				IAttribute[] assos = getAssociations(c);
				for( int i = 0; i < assos.length ; i++ ){
      		System.out.println(getAssociation(assos[i]));
	     	}
				
				System.out.println("------ATTRIBUTES-------------------");
      	IAttribute[] atts = getAttributes(c);
      	for( int i = 0; i < atts.length ; i++ ){
      		System.out.println(getAttribute(atts[i]));
	     	}
      	
				System.out.println("------OPERATIONS-------------------");
      	IOperation[] opes = c.getOperations();
      	for( int i = 0; i < opes.length ; i++ ){
      		System.out.println(getOperation(opes[i]));
      	}
      }
      JOptionPane.showMessageDialog(window.getParent(),"Finished");
      // changed code to here.
    } catch (ProjectNotFoundException e) {
      String message = "Please open a project";
      JOptionPane.showMessageDialog(window.getParent(), message,
          "Warning", JOptionPane.WARNING_MESSAGE);
      throw new CalculateUnExpectedException();
    } catch (Exception e) {
      JOptionPane.showMessageDialog(window.getParent(),
          "Exception occured", "Alert", JOptionPane.ERROR_MESSAGE);
      throw new UnExpectedException();
    }
    return null;
  }

  public class CalculateUnExpectedException extends UnExpectedException {
  }

  private void getAllClasses(INamedElement element, List<IClass> classList)
      throws ClassNotFoundException, ProjectNotFoundException {
    if (element instanceof IPackage) {
      for(INamedElement ownedNamedElement : ((IPackage)element).getOwnedElements()) {
        getAllClasses(ownedNamedElement, classList);
      }
    } else if (element instanceof IClass) {
      classList.add((IClass)element);
    }
  }
	
	// My Methods
	
	private String getClassTypeName(IClass _class){
		return _class.getName();
	}
	
	private String getClassOption(IClass _class){
		StringBuilder buff = new StringBuilder();
		if( _class.isAbstract() == true ){ buff.append("abstract "); }
		if( _class.isPublicVisibility() == true ){ buff.append("public "); }
		if( _class.isPackageVisibility() == true ){ buff.append("internal "); }
		if( _class.isProtectedVisibility() == true ){ buff.append("C# class can not to be protected. "); }
		if( _class.isPrivateVisibility() == true ){ buff.append("C# class can not to be private. "); }
		return buff.toString();
	}
	
	private String getTemplateParameter(IClass _class){
		StringBuilder buff = new StringBuilder();
		IClassifierTemplateParameter[] ctemps = _class.getTemplateParameters();
		if( ctemps.length > 0 ){ buff.append("<"); }
		for( int i = 0; i < ctemps.length ; i++ ){
			buff.append(ctemps[i].getName());
			if( i < ctemps.length - 1 ){ buff.append(","); }
		}
		if( ctemps.length > 0 ){ buff.append(">"); }
		return buff.toString();
	}
	
	private boolean getClassIsActive(IClass _class){
		return _class.isActive();
	}
	
	private String getClassDefinition(IClass _class){
		return _class.getDefinition();
	}
	
	private String getBaseClassName(IClass _class){
		StringBuilder buff = new StringBuilder();
		IGeneralization[] gens = _class.getGeneralizations();
		for( int i = 0 ; i < gens.length ; i++ ){
			buff.append(gens[i].getSuperType().getName() + " ");
			if( i < gens.length-1 ){
				buff.append(" , ");
			}
		}
		return buff.toString();
	}
	
		private String getInterfaceClassName(IClass _class){
		StringBuilder buff = new StringBuilder();
		IRealization[] ifs = _class.getClientRealizations();
		for( int i = 0 ; i < ifs.length ; i++ ){
			buff.append(ifs[i].getSupplier().getName() + " ");
			if( i < ifs.length-1 ){
				buff.append(" , ");
			}
		}
		return buff.toString();
	}
	
	private IAttribute[] getAssociations(IClass _class){
		IAttribute[] atts = _class.getAttributes();
		int count = 0;
		for( int i = 0; i < atts.length ; i++ ){
			if( atts[i].getAssociation() != null ){
				count++;
			}
		}
		IAttribute data[] = new IAttribute[count];
		int add = 0;
		for( int i = 0; i < atts.length ; i++ ){
			if( atts[i].getAssociation() != null ){
				data[add++] = atts[i];
			}
		}
		return data;
	}
	
	private IAttribute[] getAttributes(IClass _class){
		IAttribute[] atts = _class.getAttributes();
		int count = 0;
		for( int i = 0; i < atts.length ; i++ ){
			if( atts[i].getAssociation() == null ){
				count++;
			}
		}
		IAttribute data[] = new IAttribute[count];
		int add = 0;
		for( int i = 0; i < atts.length ; i++ ){
			if( atts[i].getAssociation() == null ){
				data[add++] = atts[i];
			}
		}
		return data;
	}
	
	private String getAssociation(IAttribute _att){
		if( _att.getAssociation() != null ){
			StringBuilder buff = new StringBuilder();
			buff.append(getAttributeOption(_att));
			boolean isList = isList(_att);
			if( isList == true ){  buff.append("List<"); }
			buff.append(_att.getType() + " ");
			if( isList == true ){  buff.append("> "); }
			buff.append(_att.getName() + " ");
			buff.append(";");
			return buff.toString();
		}
		return "";
	}
	
	private String getAttribute(IAttribute _att){
		if( _att.getAssociation() == null ){
			StringBuilder buff = new StringBuilder();
			buff.append(getAttributeOption(_att));
			boolean isList = isList(_att);
			if( isList == true ){  buff.append("List<"); }
			buff.append(_att.getType() + " ");
			if( isList == true ){  buff.append("> "); }
			buff.append(_att.getName() + " ");
			buff.append(";");
			return buff.toString();
		}
		return "";
	}
	
	private boolean isList(IAttribute _att){
		boolean _list = false;
		IMultiplicityRange[] multis = _att.getMultiplicity();
		for( int i = 0; i < multis.length ; i++ ){ // fukusuu aru ?
			if( multis[i].getUpper() > 1 ){
				_list = true;
			}
		}
		return _list;
	}
	
	private String getAttributeOption(IAttribute _att){
		StringBuilder buff = new StringBuilder();
		if( _att.isStatic() == true ){ buff.append("static "); }
		if( _att.isPublicVisibility() == true ){ buff.append("public "); }
		if( _att.isPackageVisibility() == true ){ buff.append("internal "); }
		if( _att.isProtectedVisibility() == true ){ buff.append("protected "); }
		if( _att.isPrivateVisibility() == true ){ buff.append("private "); }
		return buff.toString();
	}
	
	public String getOperation(IOperation _ope){
		StringBuilder buff = new StringBuilder();
		buff.append(getOpearationOption(_ope));
		buff.append(_ope.getReturnTypeExpression() + " ");
		buff.append(_ope.getName() + "(" );
		buff.append(getOperationAttributes(_ope));
		buff.append("){\n" + _ope.getDefinition() + "\n}");
		return buff.toString();
	}
	
	private String getOpearationOption(IOperation _ope){
		StringBuilder buff = new StringBuilder();
		if( _ope.isStatic() == true ){ buff.append("static "); }
		if( _ope.isAbstract() == true ){ buff.append("abstract "); }
		if( _ope.isPublicVisibility() == true ){ buff.append("public "); }
		if( _ope.isPackageVisibility() == true ){ buff.append("internal "); }
		if( _ope.isProtectedVisibility() == true ){ buff.append("protected "); }
		if( _ope.isPrivateVisibility() == true ){ buff.append("private "); }
		return buff.toString();
	}
	
	private String getOperationAttributes(IOperation _ope){
		StringBuilder buff = new StringBuilder();
		IParameter[] params = _ope.getParameters();
		for( int i = 0; i < params.length; i++ ){
			if( params[i].getDirection().equals("out") == true ){ buff.append("out "); } else if( params[i].getDirection().equals("inout") == true ){ buff.append("ref "); }
			buff.append(params[i].getType().getName() + " ");
			buff.append(params[i].getName());
			if( i < params.length-1 ){
				buff.append(" , ");
			}
		}
		return buff.toString();
	}

}
```
全クラスのについて、名前や属性、操作、可視性などの情報を取得して表示しています。
実際の実行結果の画面キャプチャがこちら。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/197297/51dd852e-d9f3-6be2-1e92-7dbee2d3845d.png)

十分に情報が取得できています。

#さいごに

今回はここまでにしますが、
取得したものを表にまとめると、

＜クラスの値＞　IClass型

| 取得したい内容     |      取得メソッド |
|:-----------------|:------------------|
| 名前             |       getName()   |
| 可視性             |  isPublicVisibility(),isProtectedVisibility(),   isPrivateVisibility(),isPackageVisibility()|
| 抽象クラスか  　　 |       isAbstract() |
| テンプレートの指定     |       getTemplateParameters() |
| アクティブクラスか    |  isActive() |
| 定義            |    getDefinition()  |
| ベースクラス     |    getGeneralizations()のgetSuperType().getName()  |
| インタフェース   |    getClientRealizations()のgetSupplier().getName()  |


＜属性／関連の値＞　IAttribute型

| 取得したい内容     |      取得メソッド |
|:-----------------|:------------------|
| 名前             |       getName()   |
| 可視性             |  isPublicVisibility(),isProtectedVisibility(),   isPrivateVisibility(),isPackageVisibility()|
| 型          　　 |       getType() |
| 多重度           |       getMultiplicity() |
| 初期値           |  getInitialValue() |
| 集約かどうか      |  isAggregate()  |
| コンポジション     |  isComposite()  |
| 派生しているか　   |  isDerived()   |
| 限定子　   |  getQualifiers()   |

＜操作の値＞

| 取得したい内容               |      取得メソッド                   |
|:------------------------|:------------------------------------|
| 名前             |       getName()   |
| 可視性             |  isPublicVisibility(),isProtectedVisibility(),   isPrivateVisibility(),isPackageVisibility()|
| 戻り値の型       |   getReturnTypeExpression()   |
| 抽象クラスか  　　 |       isAbstract() |
| 引数の名前  |  getParameters()のgetName()  |
| 引数の型           | getParameters()のgetType().getName()  |
| 操作の定義            |    getDefinition()  |

以上のようで、なかなか、順調です。