+package jp.ac.aiit.xdf.application;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.application.interceptors.UIDesignInterceptingManager;
+import jp.ac.aiit.xdf.application.interceptors.UIDesignResource;
+import jp.ac.aiit.xdf.component.common.CommonTagReferences;
+import jp.ac.aiit.xdf.core.action.factory.ActionFactory;
+import jp.ac.aiit.xdf.core.action.factory.DefaultActionFactory;
+import jp.ac.aiit.xdf.core.exceptions.UnexpectedBehaviorException;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.selector.Selector;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 本フレームワークで作成されたアプリケーションを管理するクラス
+ * プラグイン提供されたコンポーネント群やアクションインスタンスの生成方法などを設定することができる
+ * なお、本クラスはSigletonになっているため、インスタンスの取得にはgetInstanceメソッドを用いること
+ *
+ * @author Shunichi Takagi
+ */
+public class Application {
+ private static final Logger log = LoggerFactory.getLogger(Application.class);
+
+ /**
+ * アプリケーションのインスタンス
+ */
+ public static final Application instance = new Application();
+
+ private Application(){
+ this.toolkit = "swing";
+ this.definedTags = new HashMap<String, Tag>();
+ this.factory = new DefaultActionFactory();
+ this.windows = new HashMap<String, InputStream>();
+
+ this.refs = new ArrayList<TagReferences>();
+ useTags(new CommonTagReferences());
+
+ this.openedWindows = new HashMap<String, ObjectModel>();
+ }
+
+ private LifeCycle lifeCycle = new DefaultLifeCycle();
+
+ private String toolkit;
+ private Map<String, Tag> definedTags;
+ private Map<String, InputStream> windows;
+
+ private ActionFactory factory;
+ private List<TagReferences> refs;
+
+ private Map<String, ObjectModel> openedWindows;
+
+ /**
+ * アプリケーションのインスタンス取得メソッド
+ * @return シングルトン化されたApplicationのインスタンス
+ */
+ public static Application getInstance() {
+ return instance;
+ }
+
+ /**
+ * アプリケーションのインスタンス取得メソッド
+ * 引数で与えられたタグ参照の読み込みをインスタンス取得と同時に行う
+ *
+ * @param refs このアプリケーションで利用するタグ参照の固まり。プラグインによって提供される
+ * @return アプリケーションのインスタンス
+ */
+ public static Application getInstance(TagReferences ...refs) {
+ for(TagReferences ref : refs) {
+ instance.useTags(ref);
+ }
+ return instance;
+ }
+
+ /**
+ * このアプリケーションに対するライフサイクルを設定
+ *
+ * @param lifeCycle このアプリケーションに設定されるライフサイクル
+ */
+ public void setLifeCycle(LifeCycle lifeCycle) {
+ this.lifeCycle = lifeCycle;
+ }
+ /**
+ * このアプリケーションを実行するツールキット環境を設定する
+ * @param toolkit
+ */
+ public void setToolkit(String toolkit) {
+ this.toolkit = toolkit;
+ }
+
+ /**
+ * このアプリケーションを実行するツールキット環境名を取得する
+ * @return ツールキット環境名
+ */
+ public String getToolkit() {
+ return toolkit;
+ }
+
+ /**
+ * アプリケーション内で使用するタグを追加する
+ * @param refs
+ */
+ public void useTags(TagReferences refs) {
+ this.refs.add(refs);
+ this.definedTags = mergeTags(definedTags, refs.getDefinedTags());
+ }
+
+ /**
+ * アプリケーション内で利用されるActionをインスタンス化するための方法を設定する
+ * @param factory アクションのインスタンス生成ファクトリ
+ */
+ public void setActionFactory(ActionFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * アプリケーション内でアクションのインスタンス化に使用されるファクトリを取得
+ * @return アクションファクトリのインスタンス
+ */
+ public ActionFactory getActionFactory() {
+ return factory;
+ }
+
+ /**
+ * アプリケーションにウィンドウを追加する
+ *
+ * @param name ウィンドウ名
+ * @param uidesign ウィンドウ定義ファイルへのClasspath上のパス
+ * @throws FileNotFoundException 指定されたファイルが見つからなかった場合にthrowされる
+ */
+ public void registWindow(String name, String uidesign) throws FileNotFoundException {
+ URL url = ClassLoader.getSystemResource(uidesign);
+
+ if( url == null ) {
+ log.warn("指定された画面定義XMLファイルが見つかりません file:"+uidesign);
+ throw new FileNotFoundException("指定された画面定義XMLファイルが見つかりません file:"+uidesign);
+ } else {
+ try {
+ windows.put(name, new FileInputStream( new File( url.toURI() ) ));
+ } catch (URISyntaxException e) {
+ log.warn("フレームワーク内部で予期しない例外が発生しました。", e);
+ throw new UnexpectedBehaviorException("フレームワーク内部で予期しない例外が発生しました。", e);
+ }
+ }
+ }
+
+ /**
+ * アプリケーションにウィンドウを追加する
+ *
+ * @param name ウィンドウ名
+ * @param uidesign ウィンドウ定義ファイルを読み込むためのストリーム
+ */
+ public void registWindow(String name, InputStream uidesign) {
+ windows.put(name, uidesign);
+ }
+
+ /**
+ * 指定した名前のウィンドウを起動する
+ *
+ * @param name 起動するウィンドウの名前
+ */
+ public void open(String name) {
+ if( windows.containsKey(name) ) {
+ if( openedWindows.size() == 0 ) {
+ lifeCycle.launch();
+ }
+ lifeCycle.beforeOpened(name);
+
+ InputStream inputStream = windows.get(name);
+
+ UIDesignResource resource = new UIDesignResource(inputStream, definedTags);
+ UIDesignInterceptingManager manager = UIDesignInterceptingManager.getDefaultManager();
+ manager.invoke(resource);
+
+ ObjectModel model = resource.getModel();
+ model.attr("windowName", name);
+
+ for (ObjectModel menuModel: new Selector("menugroup").find(model)){
+ menuModel.realize();
+ }
+
+ ObjectModel frameModel = new Selector("frame").find(model).get(0);
+ frameModel.realize();
+
+ frameModel.open();
+
+ openedWindows.put(name, model);
+
+ lifeCycle.afterOpened(name);
+ } else {
+ log.warn("指定された名前のウィンドウは登録されていません name:"+name);
+ }
+ }
+
+ /**
+ * 指定した名前のウィンドウを閉じる
+ *
+ * @param name 閉じるウィンドウの名前
+ */
+ public void close(String name) {
+ if( openedWindows.containsKey(name) ) {
+ lifeCycle.beforeClosed(name);
+
+ ObjectModel model = openedWindows.get(name);
+ openedWindows.remove(name);
+
+ ObjectModel frameModel = new Selector("frame").find(model).get(0);
+ frameModel.close();
+
+ lifeCycle.afterClosed(name);
+ if( openedWindows.size() == 0 ) {
+ lifeCycle.shutdown();
+ }
+ } else {
+ log.info("指定されたウィンドウは登録されていないか既に閉じられています。 name:"+name);
+ }
+ }
+
+ private Map<String,Tag> mergeTags(Map<String,Tag> arg0, Map<String,Tag> arg1) {
+ for(String tagname1 : arg1.keySet()) {
+ if( arg0.containsKey(tagname1) ) {
+ Tag tag0 = arg0.get(tagname1);
+ Tag tag1 = arg1.get(tagname1);
+
+ tag0.merge(tag1);
+ } else {
+ arg0.put(tagname1, arg1.get(tagname1));
+ log.info(tagname1+":"+arg1.get(tagname1));
+ }
+ }
+
+ return arg0;
+ }
+
+ /**
+ * アプリケーションインスタンスからウィンドウ登録名にてウィンドウオブジェクトモデルを取得する
+ * @param name
+ * @return オブジェクトモデル
+ */
+ public ObjectModel getWindow(String name){
+ return this.openedWindows.get(name);
+ }
+
+ /**
+ * 指定されたウィンドウにあるIDのコンポーネントを検索する
+ *
+ * @param window ウィンドウ登録名
+ * @param id コンポーネントID
+ * @return コンポーネントオブジェクト
+ */
+ public static ObjectModel findById(String window, String id){
+ return Selector.find("#" + id, Application.getInstance().getWindow(window)).get(0);
+ }
+
+ /**
+ * 指定されたウィンドウのコンポーネントをセレクタ構文を用いて検索する
+ *
+ * @param window ウィンドウ登録名
+ * @param selector コンポーネント検索用セレクタ
+ * @return コンポーネントオブジェクト
+ */
+ public static List<ObjectModel> findBySelector(String window, String selector) {
+ return Selector.find(selector, Application.getInstance().getWindow(window));
+ }
+}