JSFチュートリアル(7)-ライフサイクルのRestore View Phase

7411 ワード

JSFマクロのライフサイクルではExecuteとRenderに分けられ、Execute部分では具体的なステップ(前のブログのフローチャートを参照)に分けて6つのステップがあります.後の文章では、筆者がゆっくりとJSFに入ります(JavaEEはコードがどのように実現されるかについては、具体的なコードが異なります).このブログでは、第1段階のRestore View Phaseについて詳しく説明します.
道徳経には「道生一、一生二、二生三、三生万物」とある.いかなる複雑な過程も簡単から始まり、JSFに対しても例外ではなく、JSFが行ったすべての動作は要求によって引き起こされる.通常、この要求のトリガは、ユーザがリンクをクリックしたり、コミットボタンをクリックしたりしたためであり、要求がサーバJSFに到着すると、このステップ(Restore View Phase)が開始される.JSF宣言サイクルに触れたばかりの人は、なぜ最初の段階がRestoreなのか理解できないかもしれません.これは前のJSFに連絡して要求を2種類に分けて話します.JSFにとってリクエストはinitialではなくpostbackなので、1つのリクエストが到着したときにJSFはこのリクエストに対応するviewがデフォルトで格納されているので、すべきことはRestoreというviewです.このviewが保存されていない場合(新しいview)、簡単に直接作成して保存すればいいです.この過程は楽観的なロックに似ていて、すべてが素晴らしいと信じています.素晴らしいことを楽しむ過程で問題に遭遇したとしたら、私たちはそれを解決してから再び美しさに戻ります.
RestoreView Phaseコアexecuteメソッド(jsf-impl-2.1.3,RestoreView Phase.java)
public void execute(FacesContext facesContext) throws FacesException {

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Entering RestoreViewPhase");
        }
        if (null == facesContext) {
            throw new FacesException(MessageUtils.getExceptionMessageString(
                  MessageUtils.NULL_CONTEXT_ERROR_MESSAGE_ID));
        }

        // If an app had explicitely set the tree in the context, use that;
        //
        UIViewRoot viewRoot = facesContext.getViewRoot();
        if (viewRoot != null) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Found a pre created view in FacesContext");
            }
            facesContext.getViewRoot().setLocale(
                 facesContext.getExternalContext().getRequestLocale());

            // do per-component actions
            deliverPostRestoreStateEvent(facesContext);

            if (!facesContext.isPostback()) {
                facesContext.renderResponse();
            }
            return;
        }
        FacesException thrownException = null;

        try {

            // Reconstitute or create the request tree
            Map requestMap = facesContext.getExternalContext().getRequestMap();
            String viewId = (String)
              requestMap.get("javax.servlet.include.path_info");
            if (viewId == null) {
                viewId = facesContext.getExternalContext().getRequestPathInfo();
            }

            // It could be that this request was mapped using
            // a prefix mapping in which case there would be no
            // path_info.  Query the servlet path.
            if (viewId == null) {
                viewId = (String)
                  requestMap.get("javax.servlet.include.servlet_path");
            }

            if (viewId == null) {
                viewId = facesContext.getExternalContext().getRequestServletPath();
            }

            if (viewId == null) {
                throw new FacesException(MessageUtils.getExceptionMessageString(
                  MessageUtils.NULL_REQUEST_VIEW_ERROR_MESSAGE_ID));
            }

            ViewHandler viewHandler = Util.getViewHandler(facesContext);

            boolean isPostBack = (facesContext.isPostback() && !isErrorPage(facesContext));
            if (isPostBack) {
                facesContext.setProcessingEvents(false);
            // try to restore the view
                viewRoot = viewHandler.restoreView(facesContext, viewId);
                if (viewRoot == null) {
                    if (is11CompatEnabled(facesContext)) {
                        // 1.1 -> create a new view and flag that the response should
                        //        be immediately rendered
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.fine("Postback: recreating a view for " + viewId);
                        }
                        viewRoot = viewHandler.createView(facesContext, viewId);
                        facesContext.renderResponse();

                    } else {
                        Object[] params = {viewId};
                        throw new ViewExpiredException(
                                MessageUtils.getExceptionMessageString(
                                MessageUtils.RESTORE_VIEW_ERROR_MESSAGE_ID,
                                params),
                                viewId);
                    }
                }

                facesContext.setViewRoot(viewRoot);
                facesContext.setProcessingEvents(true);
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine("Postback: restored view for " + viewId);
                }
            } else {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine("New request: creating a view for " + viewId);
                }

                String derivedViewId = viewHandler.deriveLogicalViewId(facesContext, viewId);
                ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext, derivedViewId);

                if (vdl != null) {
                    // If we have one, get the ViewMetadata...
                    ViewMetadata metadata = vdl.getViewMetadata(facesContext, viewId);

                    if (metadata != null) { // perhaps it's not supported
                        // and use it to create the ViewRoot.  This will have, at most
                        // the UIViewRoot and its metadata facet.
                        viewRoot = metadata.createMetadataView(facesContext);

                        // Only skip to render response if there are no view parameters
                        Collection<UIViewParameter> params =
                                ViewMetadata.getViewParameters(viewRoot);
                        if (params.isEmpty()) {
                            facesContext.renderResponse();
                        }
                    }
                } else {
                    facesContext.renderResponse();
                }

                if (null == viewRoot) {
                    viewRoot = (Util.getViewHandler(facesContext)).
                        createView(facesContext, viewId);
                }
                facesContext.setViewRoot(viewRoot);
                assert (null != viewRoot);
            }
        } catch (FacesException fe) {
            thrownException = fe;
        } finally {
            if (null == thrownException) {
                deliverPostRestoreStateEvent(facesContext);
            } else {
                throw thrownException;
            }
        }

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Exiting RestoreViewPhase");
        }

    }

FacesContextには、1つのリクエストを処理するすべての情報が含まれています.すべてのプログラムのコンポーネント、イベントプロセッサ、変換器、検証器はFacesContextのインスタンスに配置されます.したがって、このステップでは、対応するviewが確立され保存されるほか、イベントプロセッサおよび検証期間がviewのコンポーネントに提供され、ユーザーの後続の操作の準備ができます.
JSFではinitialタイプのリクエストがリクエストされた場合(初めて)、JSFは空のviewを作成し、ライフサイクルはRender Responseに直接進み(コード98行から)、このプロセスの中空のviewは表示するページでコンポーネントを参照するtagと一緒に置かれます(実はこの言葉は分かりません!).
リクエストがpostbacks方式のリクエストであれば、対応するこのviewはすでにFacesContextインスタンスにあり、このステップでJSF実装者はクライアントまたはサーバの状態情報に基づいてこのview(コード85行)を復元するが、ここで筆者は公式ドキュメントに答えが見つからず、コード65行はこのViewがnullであるかどうかを判断し、postbackタイプのリクエストであればなぜViewがnullであるのかという問題がある.さらに次のコードで新しいviewを再作成したが,筆者はメソッド名(is 11 CompatEnabled)に基づいて互換性に関係する可能性があると推測した.
Restore Viewフェーズ全体で、コアの目的は異なるリクエストの区別です.initial-->作成+保存;postback-->リカバリ.