astah* API用ユーティリティ

astah* のモデルを操作する際に便利なメソッド群
/*
 * パッケージ名は、生成したプラグインのパッケージ名よりも
 * 下に移してください。
 * プラグインのパッケージ名=> com.example
 *   com.change_vision.astah.extension.plugin => X
 *   com.example                              => O
 *   com.example.internal                     => O
 *   learning                                 => X
 */
package com.example.internal;

import java.util.ArrayList;
import java.util.List;

import com.change_vision.jude.api.inf.exception.InvalidEditingException;
import com.change_vision.jude.api.inf.model.IAttribute;
import com.change_vision.jude.api.inf.model.IClass;
import com.change_vision.jude.api.inf.model.IClassifierTemplateParameter;
import com.change_vision.jude.api.inf.model.IElement;
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.IOperation;
import com.change_vision.jude.api.inf.model.IPackage;
import com.change_vision.jude.api.inf.model.IParameter;
import com.change_vision.jude.api.inf.model.IRealization;

public class AstahUtils {

  /**
   * 対象が所有しているクラスを取得します。
   *
   * @param owner クラス または パッケージ
   * @return クラスの場合はネストしているクラス群
   *         パッケージの場合はパッケージにあるクラス群
   */
  public static IClass[] getOwnedClasses(Object owner) {
    if (owner instanceof IClass) {
      return ((IClass) owner).getNestedClasses();
    } else if (owner instanceof IPackage) {
      List<IClass> classes = new ArrayList<IClass>();
      for (INamedElement element : ((IPackage) owner)
			.getOwnedElements()) {
        if (element instanceof IClass) {
          classes.add((IClass) element);
        }
      }
      return classes.toArray(new IClass[classes.size()]);
    } else {
      return new IClass[0];
    }
  }

  /**
   * 対象が所有しているクラスのうち、名前を指定して取得します。
   *
   * @param owner クラス または パッケージ
   * @param name  名前
   * @return クラスの場合はネストしているクラスのうち、同名のもの
   *   パッケージの場合はパッケージにあるクラスのうち、同名のもの
   */
  public static IClass getOwnedClass(Object owner, String name) {
    if (owner instanceof IClass) {
      return getNestedClass((IClass) owner, name);
    } else if (owner instanceof IPackage) {
      return getOwnedElement((IPackage) owner, name, IClass.class);
    } else {
      return null;
    }
  }


  /**
   * 対象のパッケージが所有しているINamedElementから、
	 * 名前を指定して取得します。
   *
   * @param owner パッケージ
   * @param name  名前
   * @return 該当するINamedElement
   */
  public static INamedElement
	getOwnedElement(IPackage owner, String name) {
    return getOwnedElement(owner, name, INamedElement.class);
  }

  /**
   * 対象のパッケージが所有しているオブジェクトから、
	 * 名前と型を指定して取得します。
   *
   * @param owner       パッケージ
   * @param name        名前
   * @param elementType INamedElementの子クラス型
   * @return 該当するINamedElementの子クラス型
   */
  public static <T extends INamedElement>
	T getOwnedElement(IPackage owner,
      String name, Class<T> elementType) {
    for (INamedElement element : owner.getOwnedElements()) {
      if (name.equals(element.getName())) {
        if (elementType.isInstance(element)) {
          return elementType.cast(element);
        }
      }
    }
    return null;
  }

  /**
   * 対象のクラスが所有しているネストクラスから、
	 * 名前を指定して取得します。
   *
   * @param owner クラス
   * @param name  名前
   * @return 該当するネストクラス
   */
  public static IClass getNestedClass(IClass owner, String name) {
    for (IClass element : owner.getNestedClasses()) {
      if (name.equals(element.getName())) {
        return element;
      }
    }
    return null;
  }

  /**
   * 対象のクラスと指定した親クラスの汎化を取得します。
   *
   * @param owner     クラス
   * @param superType 親クラス
   * @return 汎化オブジェクト
   *  ただし、指定した親クラスが対象のクラスの親でない場合は、
	 *  nullを返す
   */
  public static IGeneralization getGeneralization(IClass owner,
      IClass superType) {
    for (IGeneralization generalization : owner.getGeneralizations()) {
      if (superType.equals(generalization.getSuperType())) {
        return generalization;
      }
    }
    return null;
  }

  /**
   * 対象のクラスと指定した子クラスの汎化を取得します。
   *
   * @param owner   クラス
   * @param subType 子クラス
   * @return 汎化オブジェクト
   *  ただし、指定した子クラスが対象のクラスの子でない場合は、
	 *  nullを返す
   */
  public static IGeneralization
	getSpecialization(IClass owner, IClass subType) {
    for (IGeneralization generalization : owner.getSpecializations()) {
      if (subType.equals(generalization.getSubType())) {
        return generalization;
      }
    }
    return null;
  }

  /**
   * 対象のクラスと指定した実現先クラスの実現を取得します。
   *
   * @param owner    対象のクラス
   * @param supplier 実現先
   *
   * @return 実現
   *  ただし、指定した実現先クラスが対象のクラスの実現先でない場合は、
	 *  nullを返す
   */
  public static IRealization getClientRealization(IClass owner,
      IClass supplier) {
    for (IRealization realization : owner.getClientRealizations()) {
      if (supplier.equals(realization.getSupplier())) {
        return realization;
      }
    }
    return null;
  }

  /**
   * 対象のクラスと指定した実現元クラスの実現を取得します。
   *
   * @param owner    対象のクラス
   * @param client   実現元
   *
   * @return 実現
   *  ただし、指定した実現元クラスが対象のクラスの
	 *  実現元でない場合は、nullを返す
   */
  public static IRealization getSupplierRealization(IClass owner,
      IClass client) {
    for (IRealization realization : owner.getSupplierRealizations()) {
      if (client.equals(realization.getClient())) {
        return realization;
      }
    }
    return null;
  }


  /**
   * 対象クラスから指定した名前のテンプレートパラメータを取得します。
   *
   * @param owner  対象のクラス
   * @param name   パラメータ名
   * @return テンプレートパラメータ
   *  該当の名前のテンプレートパラメータが存在しない場合は
	 *  nullが返ります。
   */
  public static IClassifierTemplateParameter getTemplateParameter(
      IClass owner, String name) {
    for (IClassifierTemplateParameter templateParameter : owner
        .getTemplateParameters()) {
      if (name.equals(templateParameter.getName())) {
        return templateParameter;
      }
    }
    return null;
  }

  /**
   * 対象のクラスから指定した名前の属性を取得します。
   *
   * @param owner 対象のクラス
   * @param name  属性名
   * @return 属性
   *  該当の名前の属性が存在しない場合はnullが返ります。
   */
  public static IAttribute getAttribute(IClass owner, String name) {
    for (IAttribute attribute : owner.getAttributes()) {
      if (name.equals(attribute.getName())) {
        return attribute;
      }
    }
    return null;
  }

  /**
   * 対象のクラスから指定した名前の操作を取得します。
   *
   * @param owner 対象のクラス
   * @param name  操作名
   * @return 操作
   *         該当の名前の操作が存在しない場合はnullが返ります。
   */
  public static IOperation getOperation(IClass owner, String name,
      Object[] parameterTypes) {
    for (IOperation operation : owner.getOperations()) {
      if (name.equals(operation.getName())) {
        IParameter[] parameters = operation.getParameters();
        if (matches(parameters, parameterTypes)) {
          return operation;
        }
      }
    }
    return null;
  }

  /**
   * 対象のクラスにインタフェースであるかどうかを設定します。
   *
   * @param type 対象のクラス
   * @param isInterfase インタフェースであるかどうか
   */
  public static void setInterface(IClass type, boolean isInterface)
      throws InvalidEditingException {
    if (isInterface) {
      addStereotype(type, "interface");
    } else {
      type.removeStereotype("interface");
    }
  }

  /**
   * 対象の要素にステレオタイプを追加します。
   * @param element 対象の要素
   * @param stereotype 追加するステレオタイプ
   * @return 追加できた場合はtrue
   *         既に該当するステレオタイプがある場合はfalse
   */
  public static boolean addStereotype(IElement element, String stereotype)
      throws InvalidEditingException {
    for (String exists : element.getStereotypes()) {
      if (stereotype.equals(exists)) {
        return false;
      }
    }
    element.addStereotype(stereotype);
    return true;
  }

  static boolean matches(IParameter[] parameters, Object[] parameterTypes) {
    if (parameterTypes.length != parameters.length) {
      return false;
    }
    for (int i = 0; i < parameterTypes.length; i++) {
      Object type = parameterTypes[i];
      if (type instanceof IClass) {
        if (!type.equals(parameters[i].getType())) {
          return false;
        }
      } else {
        if (!type.equals(parameters[i].getTypeExpression())) {
          return false;
        }
      }
    }
    return true;
  }

} 

astah* のAPIのハンドリングをまとめたメソッド群
/*
 * パッケージ名は、生成したプラグインのパッケージ名よりも
 * 下に移してください。
 * プラグインのパッケージ名=> com.example
 *   com.change_vision.astah.extension.plugin => X
 *   com.example                              => O
 *   com.example.internal                     => O
 *   learning                                 => X
 */
package com.example.internal;

import javax.swing.JFrame;

import com.change_vision.astah.extension.plugin.util.exception.APIException;
import com.change_vision.jude.api.inf.AstahAPI;
import com.change_vision.jude.api.inf.editor.BasicModelEditor;
import com.change_vision.jude.api.inf.editor.ClassDiagramEditor;
import com.change_vision.jude.api.inf.editor.IDiagramEditorFactory;
import com.change_vision.jude.api.inf.editor.IModelEditorFactory;
import com.change_vision.jude.api.inf.exception.InvalidEditingException;
import com.change_vision.jude.api.inf.exception.InvalidUsingException;
import com.change_vision.jude.api.inf.model.IClassDiagram;
import com.change_vision.jude.api.inf.project.ProjectAccessor;
import com.change_vision.jude.api.inf.view.IDiagramViewManager;
import com.change_vision.jude.api.inf.view.IViewManager;

/**
 * astah* APIを扱いやすいように包んだユーティリティクラスです。
 * 利用時にインスタンスを作成してください。
 */
public class AstahAPIUtils {

  /**
   * 図の表示領域を管理するマネージャを返却します。
   */
  public IDiagramViewManager getDiagramViewManager() {
    IViewManager viewManager = getViewManager();
    IDiagramViewManager diagramViewManager =
		viewManager.getDiagramViewManager();
    return diagramViewManager;
  }


  /**
   * クラス図上にあるモデルを編集するためのエディタを取得します。
   */
  public ClassDiagramEditor getClassDiagramEditor() {
    try {
      return getDiagramEditorFactory().getClassDiagramEditor();
    } catch (InvalidUsingException e) {
      throw new APIException(e);
    }
  }

  /**
   * 各図に共通する基本的なモデルを編集するためのエディタを取得します。
   *
   * @return BasicModelEditor
   */
  public BasicModelEditor getBasicModelEditor() {
    try {
      return getModelEditorFactory().getBasicModelEditor();
    } catch (InvalidEditingException e) {
      throw new APIException(e);
    }
  }

  /**
   * astah*のプロジェクトを扱うためのProjectAccessorを取得します。
   */
  public ProjectAccessor getProjectAccessor() {
    ProjectAccessor projectAccessor = null;
    try {
      AstahAPI api = AstahAPI.getAstahAPI();
      projectAccessor = api.getProjectAccessor();
    } catch (ClassNotFoundException e) {
          throw new IllegalStateException(e);
    }
    if(projectAccessor == null)
		throw new IllegalStateException("projectAccessor is null.");
    return projectAccessor;
  }

  /**
   * astah*本体のメインウィンドウに対応するJFrameを取得します。
   *
   * @return JFrame
   */
  public JFrame getMainFrame() {
    return getProjectAccessor().getViewManager().getMainFrame();
  }

  /**
   * 現在実行しているastah*のエディションを取得します。
   */
  public String getEdition() {
    return getProjectAccessor().getAstahEdition();
  }

  private IViewManager getViewManager() {
    ProjectAccessor projectAccessor = getProjectAccessor();
    IViewManager viewManager = projectAccessor.getViewManager();
    if(viewManager == null)
		throw new IllegalStateException("ViewManager is null.");
    return viewManager;
  }

  private IModelEditorFactory getModelEditorFactory() {
    ProjectAccessor projectAccessor = getProjectAccessor();
    IModelEditorFactory modelEditorFactory =
		projectAccessor.getModelEditorFactory();
    if(modelEditorFactory == null)
		throw new IllegalStateException("modelEditorFactory is null.");
    return modelEditorFactory;
  }

  private IDiagramEditorFactory getDiagramEditorFactory() {
    ProjectAccessor projectAccessor = getProjectAccessor();
    IDiagramEditorFactory diagramEditorFactory =
		projectAccessor.getDiagramEditorFactory();
    if(diagramEditorFactory == null)
		throw new IllegalStateException("diagramEditorFactory is null.");
    return diagramEditorFactory;
  }

}

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<extension point="com.change_vision.astah.ui.actionSets">
	<actionSet
			label="%action_set_label"
			visible="true"
			id="com.example.helloworld.actionSet">
		<menu
			id="helloworld"
			label="%menu_group"
			path="tool/helloworld">
		</menu>
		<action
			label="%menu_label"
			icon="icons/sample.gif"
			class="com.example.TemplateAction"
			tooltip="%menu_tooltip"
			menubarPath="tool/helloworld/"
			id="com.example.actions.HelloWorldAction">
		</action>
	</actionSet>
</extension>
</plugin>

/*
 * パッケージ名は、生成したプラグインのパッケージ名よりも
 * 下に移してください。
 * プラグインのパッケージ名=> com.example
 *   com.change_vision.astah.extension.plugin => X
 *   com.example                              => O
 *   com.example.internal                     => O
 *   learning                                 => X
 */
package com.example.actions;

import javax.swing.JOptionPane;
import com.change_vision.jude.api.inf.ui.IPluginActionDelegate;
import com.change_vision.jude.api.inf.ui.IWindow;

public class HelloWorldAction implements IPluginActionDelegate {
  public Object run(IWindow window) throws UnExpectedException {
    try {
      JOptionPane.showMessageDialog
			(window.getParent(), "Hello World");
    } catch (Exception e) {
      JOptionPane.showMessageDialog(window.getParent(),
          "Exception occured", "Alert",
			JOptionPane.ERROR_MESSAGE);
      throw new UnExpectedException();
    }
    return null;
  }
}

拡張ビューの拡張

plugin.xmlの例
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
  <extension point="com.change_vision.astah.ui.view">
    <view
	      id="com.example.internal.HelloWorldView"
	      type="extraTab"
	      class="com.example.internal.HelloWorldView" />
  </extension>
</plugin>

ビューの例
/*
 * パッケージ名は、生成したプラグインのパッケージ名よりも
 * 下に移してください。
 * プラグインのパッケージ名=> com.example
 *   com.change_vision.astah.extension.plugin => X
 *   com.example                              => O
 *   com.example.internal                     => O
 *   learning                                 => X
 */
package com.example.internal;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import com.change_vision.jude.api.inf.AstahAPI;
import com.change_vision.jude.api.inf.project.ProjectAccessor;
import com.change_vision.jude.api.inf.project.ProjectEvent;
import com.change_vision.jude.api.inf.project.ProjectEventListener;
import com.change_vision.jude.api.inf.ui.IPluginExtraTabView;
import com.change_vision.jude.api.inf.ui.ISelectionListener;

public class HelloWorldView extends JPanel
      implements IPluginExtraTabView, ProjectEventListener {
  public HelloWorldView() {
    initComponents();
  }

  private void initComponents() {
    setLayout(new BorderLayout());
    add(createLabelPane(), BorderLayout.CENTER);
    addProjectEventListener();
  }

  private void addProjectEventListener() {
  try {
    AstahAPI api = AstahAPI.getAstahAPI();
    ProjectAccessor projectAccessor = api.getProjectAccessor();
    projectAccessor.addProjectEventListener(this);
  } catch (ClassNotFoundException e) {
    e.getMessage();
  }
  }

  private Container createLabelPane() {
    JLabel label = new JLabel("hello world");
    JScrollPane pane = new JScrollPane(label);
    return pane;
  }

  @Override
  public void projectChanged(ProjectEvent e) {
  }

  @Override
  public void projectClosed(ProjectEvent e) {
  }

   @Override
  public void projectOpened(ProjectEvent e) {
  }

  @Override
  public void addSelectionListener(ISelectionListener listener) {
  }

  @Override
  public Component getComponent() {
    return this;
  }

  @Override
  public String getDescription() {
    return "Show Hello World here";
  }

  @Override
  public String getTitle() {
    return "Hello World View";
  }

  public void activated() {
  }

  public void deactivated() {
  }
}

Drag and Drop拡張

Activator#start (BundleContext context)の実装例

プラグインの初期化時にDropTargetListenerを追加するため、Activator#start(BundleContext context)を実装する

package com.example;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import com.example.internal.ClassDiagramDropExtension;
import com.example.internal.util.AstahAPIUtils;
import com.change_vision.jude.api.inf.view.IDiagramViewManager;

public class Activator implements BundleActivator {

  private AstahAPIUtils utils = new AstahAPIUtils();

  public void start(BundleContext context) {
    ClassDiagramDropExtension diagramDropTargetListener =
		new ClassDiagramDropExtension();
    IDiagramViewManager diagramViewManager =
		utils.getDiagramViewManager();
    diagramViewManager.addDropTargetListener
		(diagramDropTargetListener);
  }

  public void stop(BundleContext context) {
  }
}

DropTargetListenerの実装例
/*
 * パッケージ名は、生成したプラグインのパッケージ名よりも
 * 下に移してください。
 * プラグインのパッケージ名=> com.example
 *   com.change_vision.astah.extension.plugin => X
 *   com.example                              => O
 *   com.example.internal                     => O
 *   learning                                 => X
 */
package com.example.internal;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.change_vision.jude.api.inf.model.IClassDiagram;
import com.change_vision.jude.api.inf.view.DiagramDropTargetListener;

public final class ClassDiagramDropExtension
extends DiagramDropTargetListener {

  public ClassDiagramDropExtension() {
    super(IClassDiagram.class);
  }

  @Override
  public void dropExternalData(DropTargetDropEvent dtde) {
    if(dtde.isLocalTransfer()) return;

    if(dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) {
      System.out.println("ClassDiagramDropExtension.stringFlavor"
			+ getURLStringFromDropContent(dtde));
      dtde.dropComplete(true);
    } else if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
      List<File> files = getFilesFromDropContent(dtde);
      System.out.println("javaFileListFravor" + files);
      dtde.dropComplete(true);
    }
  }

  private String getURLStringFromDropContent(DropTargetDropEvent dtde) {
    dtde.acceptDrop(DnDConstants.ACTION_LINK);
    Transferable target = dtde.getTransferable();

    String urlString;
    try {
      urlString = (String)target.getTransferData(DataFlavor.stringFlavor);
    } catch (Exception e) {
      urlString = "";
    }
    return urlString;
  }

  @SuppressWarnings("unchecked")
  private List<File> getFilesFromDropContent(DropTargetDropEvent dtde) {
    dtde.acceptDrop(DnDConstants.ACTION_COPY);
    List<File> list;
    try {
      list = (List<File>)
	dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
    } catch (Exception e) {
      list = new ArrayList<File>();
    }
    return list;
  }

  @Override
  public void dropModels(DropTargetDropEvent dtde, Set<?> models) {
  }

  @Override
  public void dragEnter(DropTargetDragEvent dtde) {
  }

  @Override
  public void dragExit(DropTargetEvent dte) {
  }

  @Override
  public void dragOver(DropTargetDragEvent dtde) {
  }

  @Override
  public void dropActionChanged(DropTargetDragEvent dtde) {
  }
}