目次
・本日の成果・考え
・最後に
本日の成果
本日よりJavaScript→Javaを中継するブリッジクラスとウインドウ表示機能を制御するロジッククラスのPGに入りたいと思います。
では、考えてみました。
ブリッジクラス
package app.windowView.window;
import window_interface.BridgeCallback;
public class JavaBridge {
//ロジッククラスのメソッドを呼び出すための抽象化オブジェクト
private final BridgeCallback bridgecall;
/**
* コンストラクタ。
* @param bc Java側でユーザー入力を処理するロジッククラスの抽象オブジェクト
*/
public JavaBridge(BridgeCallback bc) {
this.bridgecall = bc;
}
/**
* JavaScriptからのメッセージをJava側に送信するためのメソッド。
* @param input ユーザー入力の文字列(nullと空白はフロント側でチェック)
*/
public void sendToJava(String input) {
bridgecall.onUserInput(input);
}
}
ロジッククラス
package app.windowView.window;
import java.util.Properties;
import app.util.CommonFunction;
import app.windowView.api.DifyApiClient;
import app.windowView.config.AppSettingDto;
import app.windowView.config.SettingLoader;
import javafx.application.Application;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;
import window_interface.BridgeCallback;
public class WindowLogic {
//
private final static String PROPS_PATH = "/resources/app.properties";
//
private Properties props = null;
//
private AppSettingDto configDto = null;
//
private WindowView windowview = null;
//
private WebView webview = null;
//
private WindowController windowController = null;
//
private DifyApiClient apiClient;
// WebViewエンジンのラッパー(onWindowSet内で初期化)
private WebEngineWrapper wrapper;
//
private UiIniWrapper uiRunnable = new UiIniWrapper();
/**
* ウィンドウ表示を制御する実行メソッド
*/
public void execute() {
//プロパティオブジェクトとその初期化
try {
props = CommonFunction.load(PROPS_PATH);
//設定ファイルDtoの初期化
configDto = SettingLoader.startSettings(props);
//API通信オブジェクトの初期化
apiClient = new DifyApiClient(configDto.getApiUrl(), configDto.getApiKey());
//コールバックオブジェクトをセット。匿名クラスでコールバック後のブリッジセットメソッド実装。
WindowView.setStaticCallback(new BridgeCallback() {
/**
* JSオブジェクトにブリッジを登録する
* @param view 登録対象のWebViewオブジェクト(JSオブジェクトを内包している)
*/
@Override
public void onWindowSet(WindowView view) {
windowview = view;
webview = windowview.getView();
// JS Bridge登録
JavaBridge bridge = new JavaBridge(this);
JSObject js = (JSObject) webview.getEngine().executeScript("window");
js.setMember("JavaBridge", bridge);
//初期化したUIオブジェクトからラッパーオブジェクトの初期化
wrapper = new WebEngineWrapper(webview.getEngine());
//コントローラークラスの初期化
windowController = new WindowController(wrapper, apiClient, uiRunnable);
}
/**
* コントローラークラスのAPI通信処理起動(ブリッジクラスからの中継)
* @param input ブリッジから受け取ったユーザー入力文字列
*/
@Override
public void onUserInput(String input) {
//API通信処理呼び出し
windowController.onSendMessage(input);
};
});
//WindowViewに設定値Dtoを渡すための変数を用意
String setTitle = configDto.getTitle();
String setWidth = String.valueOf(configDto.getWindWidth());
String setHeight = String.valueOf(configDto.getWindHeight());
//ウィンドウ初期化処理呼び出し 引数;1、WindowView(Application実装クラス)2〜、ウィンドウ設定値
Application.launch(WindowView.class,setTitle, setWidth, setHeight);
} catch (Exception e) {
// TODO: handle exception
}
//ウィンドウの初期化処理の呼び出し:WindowView 引数:設定ファイルDto
}
}
現段階では、ウィンドウ表示をexecuteメソッドを始点として制御するようにしています。
また、ロジッククラスは各クラスのインスタンスを保持するが、逆は許可しないようにしています。
※循環参照をさけることで、ロジック以外のクラスは単一機能以外の責任を持たないようになると考えています。あと、テストしやすいです。
またこの設計にしたことで、API通信呼び出しの流れは以下となり、
ブリッジクラス→ロジッククラス→コントローラークラス
ブリッジクラスで、ロジッククラスのメソッドを呼び出すのにインスタンスを保持する必要がありました。
しかし、クラス間の結合やクラス同士での依存が発生することを避けたいので、インターフェースを中継してロジッククラスのメソッドを呼び出すことにしました。
話は変わりますが、
ロジッククラスのテストに移る前、ロジック制御の構成をする際に色々と修正を行いました。
ですので、修正したクラスのテストを再度行いたいと思います。
対象
- AppSettingFactory.java
- SettingLoader.java
修正内容は、DifyのAPI叩く用のURLとAPIキーの要素の追加になります。
元々は、DfiyのWebページをそのまま表示するだけだったので、ページURLだけで良かったのですが、APIを叩く構成に変更となったため修正が必要となりました。
かなり前に構成変更した段階で修正してしまえば良かったのですが、完成までの工数がかなり増えたことにより、完全に無視を決め込んでいました。
まぁ、テストソースは既存Junitのものに、修正で追加した項目をテスト項目に追加するだけです。
AppSettingFactoryのテスト結果
SettingLoadaerのテスト結果
前回実施したテストソースからAPI_URL、API_KEYの追加。
あと、正常系では例外発生した場合はfailで落ちるようにし、異常系では例外キャッチした時のメッセージを「正しくエラー発生」に変更し、テストパターンごとで正しいことがわかるように微修正しました。
結果も変わりありませんので、これで完了です。
最後に
お付き合いありがとうございます。
ロジックの制御を考えるのは難航しており、今回コードをお見せしましたが、現在も修正中です。
できれば、正しく動く形までお見せしたかったのですが、JSObjectの初期化設定の処理がうまく動かない状況でして、おそらく解決に時間を要しそうだったので記事をこことで中断して投稿することにしました。
振り返りとしては、Junitでテストソースを作成したのことと、各クラスの責任を可能な限り単一にしたので、単体テストの再実施がかなり楽でした。
まぁ、今回ではDBとの連携処理がないのでDBにテストデータをセットしたりすることが一切ないこともテストが簡単な理由だと思います。