1

バッキングBean変数にリンクされたプロパティを持つコンポーネントを含むICEfacesWebアプリがあります。理論的には、変数値はプログラムで変更され、コンポーネントは変更を確認し、それに応じて外観/プロパティを更新します。

ただし、変数の変更は、JSFサイクルが終了するまでコンポーネントによって「通知」されないようです(これは、私の基本的な理解では、レンダリング応答フェーズです)。

問題は、実行するファイルコピー操作が長く、inputTextコンポーネントに定期的なステータス更新を表示させたいことです。ただし、コンポーネントはレンダリング応答フェーズでのみ更新されるため、Javaメソッドの実行が終了するまで出力は表示されずすべての変更が一度に累積されて表示されます。

FacesContext.getCurrentInstance().renderResponse()XmlHttpRequestを強制的に早期に初期化するなど、他の関数を使用してみPushRenderer.render(String ID)ましたが、どのような場合でも、Javaコードの実行が完了するまでコンポーネントの外観は変わりません。

考えられる解決策の1つは、長い操作のステップ1が完了したときにBeanによって自動的に「押される」非表示のボタンをどこかに配置し、それをクリックすることでステップ2を呼び出すことです。うまくいくように見えますが、JSF / ICEfacesに組み込まれたよりエレガントなソリューションがあることを期待するときに、このようなエレガントでないソリューションを一緒にハッキングすることに時間を費やしたくありません。

私は何かが足りないのですか、それとも醜いハックに頼って目的の動作を実現する唯一の方法ですか?

4

2 に答える 2

4

マルチスレッドは、PushRendererおよびPortableRendererと組み合わせて欠落していたリンクでした(http://wiki.icesoft.org/display/ICE/Ajax+Push+-+APIsを参照)。

これで、バッキングBeanに3つのスレッドがあります。1つは長い操作を実行するためのもので、もう1つはステータスをポーリングするためのもので、もう1つは新しいスレッドを生成してクライアントブラウザにUIコントロールを返すための「メイン」スレッドです。

メインスレッドが実行スレッドとポーリングスレッドの両方を開始すると、メインスレッドは終了し、元のHTTPリクエストを完了します。私のPortableRendererは次のように宣言されてPortableRender portableRenderer;おり、私のinit()メソッド(クラスコンストラクターによって呼び出されます)には次のものが含まれています。

PushRenderer.addCurrentSession("fullFormGroup");    
portableRenderer = PushRenderer.getPortableRenderer();

スレッド部分についてはimplements Runnable、クラスで使用し、単一のクラスで複数のスレッドを処理するために、次のStackOverflowの投稿に従いました:1つのクラスで複数のスレッドを処理する方法は?

ここにいくつかのソースコードがあります。使用した明示的なソースコードを公開することはできませんが、これは機密情報を公開しない要約版です。私はそれをテストしていません、そして私はそれをgeditで書いたので、構文エラーがあるかもしれません、しかしそれは少なくともあなたが正しい方向に始めるのを手に入れるはずです。

public void init()
{
    // This method is called by the constructor.
    // It doesn't matter where you define the PortableRenderer, as long as it's before it's used.
    PushRenderer.addCurrentSession("fullFormGroup");
    portableRenderer = PushRenderer.getPortableRenderer();
}   


public void someBeanMethod(ActionEvent evt)
{
    // This is a backing bean method called by some UI event (e.g. clicking a button)
    // Since it is part of a JSF/HTTP request, you cannot call portableRenderer.render

    copyExecuting = true;

    // Create a status thread and start it

    Thread statusThread = new Thread(new Runnable() {
        public void run() {
        try {
                        // message and progress are both linked to components, which change on a portableRenderer.render("fullFormGroup") call
            message = "Copying...";
            // initiates render. Note that this cannot be called from a thread which is already part of an HTTP request
            portableRenderer.render("fullFormGroup"); 
            do {
                progress = getProgress();
                portableRenderer.render("fullFormGroup"); // render the updated progress
                Thread.sleep(5000); // sleep for a while until it's time to poll again
            } while (copyExecuting);
            progress = getProgress();
            message = "Finished!";
            portableRenderer.render("fullFormGroup"); // push a render one last time
        } catch (InterruptedException e) {
            System.out.println("Child interrupted.");
        }
    });
    statusThread.start();

    // create a thread which initiates script and triggers the termination of statusThread
    Thread copyThread = new Thread(new Runnable() {           
        public void run() {
        File someBigFile = new File("/tmp/foobar/large_file.tar.gz");
            scriptResult = copyFile(someBigFile); // this will take a long time, which is why we spawn a new thread
            copyExecuting = false; // this will caue the statusThread's do..while loop to terminate


        } 
    });
    copyThread.start();
}
于 2012-06-05T19:54:30.033 に答える
0

ショーケースのデモをご覧になることをお勧めします。

http://icefaces-showcase.icesoft.org/showcase.jsf?grp=aceMenu&exp=progressBarBean

プログレスバーの例のリストの下には、プッシュと呼ばれるものがあります。Ajax Push(ICEfacesで提供される機能)を使用して、私が望むことを実行します。

このページには、AjaxPushの簡単な使用例を紹介するEasyAjaxPushというチュートリアルもあります。

http://www.icesoft.org/community/tutorials-samples.jsf

于 2012-06-05T15:29:00.560 に答える