0

Extention ライブラリのダイアログ コントロールに問題があります。

いくつかのビューを検索し、いくつかのデータを収集して表示する Java カスタム コントロールを作成しました。これを XPage に配置するとうまくいきます。

しかし、データをダイアログに表示したいので、拡張ライブラリのダイアログ コントロールを使用しました。構成なしで Dialog コントロールを使用しても問題なく動作しますが、ダイアログを開くたびにコントロールがビューを検索してデータを表示するのに時間がかかります。そのため、ユーザーの待ち時間を短縮するために"keepComponents="true"、ダイアログ コントロール。

ダイアログを初めて開くと、すべてが完璧ですが、2回目に開くと、controlRendererからのエラーに加えて、最初のオープニングからのコンテンツが表示され、コントロールからviewNameを取得できなかったことがわかります. このエラーは、ダイアログを開いたり閉じたりするたびに発生します。

このオプションを使用したときにダイアログの複数のコンテンツで同じ問題を抱えていたが、質問に対する回答が得られなかった誰かからの OpenNtf に関する投稿を見つけました。これはコンポーネントのバグですか?このオプションを忘れて、データを Bean にキャッシュする必要がありますか? レンダラーがコンポーネントからビュー名を取得できないのはなぜですか?

4

1 に答える 1

0

次の回答では、質問の「Java カスタム コントロール」という語句が、開発した JSF コンポーネントを指していると想定しています。XPages では、「カスタム コントロール」という用語は通常、「複合コンポーネント」の JSF 概念の IBM の実装であるカスタム コントロール設計要素のインスタンスを指します。

コンポーネントは最初は意図したとおりに動作しますが、後続のリクエストでは失敗すると述べました。これは通常、コンポーネントのrestoreStateおよびsaveStateメソッドが適切に実装されていないことを示します。

アプリケーションでデフォルトのシリアル化オプションが有効になっている場合、すべてのコンポーネントの状態が各リクエストの最後にディスクに書き込まれ、次のリクエストの開始時にメモリに読み込まれます。これら 2 つの操作は、各コンポーネントの メソッドsaveStateとメソッドによってそれぞれ処理されます。restoreState

たとえば、HTML キャンバス タグを XPage に追加するためのコンポーネントを定義し、その要素に関連付けられたジェスチャ イベントとタッチ イベントをサポートすることにしたとします。したがって、コンポーネント クラスには、これらのイベントにバインドされたコードを格納するためのフィールドが含まれます。

private String ongesturechange;
private String ongestureend;
private String ongesturestart;
private String ontouchcancel;
private String ontouchend;
private String ontouchmove;
private String ontouchstart;

通常、これらの各フィールドには、関連付けられた「getter」および「setter」メソッドがあります。

public String getOngesturechange() {
    return getStringProperty("ongesturechange", this.ongesturechange);
}

public void setOngesturechange(String ongesturechange) {
    this.ongesturechange = ongesturechange;
}

そのコンポーネントのインスタンスが初期化されると、そのコンポーネント インスタンスに定義された各属性に関連付けられた「setter」メソッドに、その属性に定義された値が渡されます。最初のページ要求の残りの部分では、定義された各属性のプライベート フィールドに、設定された値が格納されます。要求の最後に、saveStateメソッドはこれらのフィールドの値をディスクに書き込みます。一般的なsaveState方法は次のようになります。

@Override
public Object saveState(FacesContext context) {
    Object[] properties = new Object[8];
    int idx = 0;
    properties[idx++] = super.saveState(context);
    properties[idx++] = this.ongesturechange;
    properties[idx++] = this.ongestureend;
    properties[idx++] = this.ongesturestart;
    properties[idx++] = this.ontouchcancel;
    properties[idx++] = this.ontouchend;
    properties[idx++] = this.ontouchmove;
    properties[idx++] = this.ontouchstart;
    return properties;
}

への呼び出しsuper.saveState()は同じメソッドを実行しますが、親クラスで定義されたメソッドのバージョンを使用します。したがって、各コンポーネントのディスク上の表現は本質的にネストされた配列です。階層内の各レイヤーは、親クラスから継承したすべてのプロパティを配列の最初の要素に格納し、定義するすべてのプロパティを追加の配列要素に格納します。 .

後続の要求でコンポーネント ツリーが復元されると、各コンポーネントはそのrestoreStateメソッドを使用して、そのすべてのフィールドの値を再構成します。一般的なrestoreState方法は次のようになります。

@Override
public void restoreState(FacesContext context, Object state) {
    Object[] properties = (Object[]) state;
    int idx = 0;
    super.restoreState(context, properties[idx++]);
    this.ongesturechange = ((String) properties[idx++]);
    this.ongestureend = ((String) properties[idx++]);
    this.ongesturestart = ((String) properties[idx++]);
    this.ontouchcancel = ((String) properties[idx++]);
    this.ontouchend = ((String) properties[idx++]);
    this.ontouchmove = ((String) properties[idx++]);
    this.ontouchstart = ((String) properties[idx++]);
}

これにより、ディスク上のデータが階層的に読み込まれます。各クラスは一連のプロパティを親クラスに渡し、コンポーネントの状態が保存されたときに関連付けられていたフィールドに残りの配列要素を割り当てます。

このプロセスにより、リクエスト全体でコンポーネントの状態を維持する簡単な方法が提供されます。継承の各レイヤーは、そのレイヤーが定義する新しいプロパティに関係するだけで済みます。しかし、これらの状態維持方法は、実装するのを忘れがちです。いずれかのメソッドがコンポーネントの実装から省略されている場合、ページは後続のリクエストでプロパティ値を「忘れ」ます。これは、プロパティ値がディスクに書き込まれなかったか、メモリに再度読み込まれなかったか、またはその両方であるためです。

falseこれが問題の根本原因であると仮定すると、コンポーネントがデフォルト ( ) 値のダイアログ内にあるときに問題が発生しない理由はkeepComponents、デフォルトのダイアログの動作が、コンポーネント ツリーからその子を完全に削除するためです。ダイアログが閉じます。この動作はパフォーマンス上の理由によるものです。理論的には、ユーザーが現在対話していないダイアログ内にのみ存在するコンポーネントのサーバー側表現を格納しても、メリットはありません。ダイアログを再度開くと、新しい各子コンポーネントのインスタンスは、元のプロパティ値を使用して作成されます。このシナリオでは、コンポーネントが使用されるたびに新しいインスタンスが作成されるため、コンポーネントがその状態を保存していなくても問題ありません。しかし、ダイアログがその子をコンポーネント ツリーに保持するように指示された場合、コンポーネントは独自の状態を適切に維持する必要があります。そうしないと、各リクエストの最後にそのプロパティ値が破棄され、後続のリクエストは以前の値を認識しません。

要約すると、はい、表示しているデータは、すべてのイベント中にデータを再度取得することを正当化するためにリクエスト間でデータが十分に変更される可能性が低い場合、Bean (またはデータ ソース) にキャッシュする必要があります。ただし、説明している特定の動作の理由は、コンポーネントの実装が独自の状態を適切に維持していないためである可能性が最も高いです。

于 2013-04-07T06:48:04.710 に答える