View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.lifecycle;
20  
21  import java.io.IOException;
22  import java.util.Map;
23  
24  import javax.faces.FacesException;
25  import javax.faces.application.Application;
26  import javax.faces.application.ViewHandler;
27  import javax.faces.component.UIViewRoot;
28  import javax.faces.context.ExternalContext;
29  import javax.faces.context.FacesContext;
30  import javax.faces.event.PhaseId;
31  import javax.portlet.PortletRequest;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.myfaces.portlet.MyFacesGenericPortlet;
36  import org.apache.myfaces.portlet.PortletUtil;
37  import org.apache.myfaces.shared_impl.util.RestoreStateUtils;
38  import org.apache.myfaces.util.DebugUtils;
39  import org.apache.myfaces.renderkit.html.HtmlResponseStateManager;
40  
41  /**
42   * Implements the lifecycle as described in Spec. 1.0 PFD Chapter 2
43   * @author Nikolay Petrov
44   *
45   * Restore view phase (JSF Spec 2.2.1)
46   */
47  class RestoreViewExecutor implements PhaseExecutor {
48  
49      private static final Log log = LogFactory.getLog(LifecycleImpl.class);
50  
51      public boolean execute(FacesContext facesContext) {
52          if(facesContext.getViewRoot() != null) {
53              facesContext.getViewRoot().setLocale(facesContext.getExternalContext().getRequestLocale());
54              RestoreStateUtils.recursivelyHandleComponentReferencesAndSetValid(facesContext, facesContext.getViewRoot());
55              return false;
56          }
57  
58          // Derive view identifier
59          String viewId = deriveViewId(facesContext);
60  
61          if (viewId == null) {
62              ExternalContext externalContext = facesContext.getExternalContext();
63  
64              if(externalContext.getRequestServletPath() == null) {
65                  return true;
66              }
67              
68              if (!externalContext.getRequestServletPath().endsWith("/")) {
69                  try {
70                      externalContext.redirect(externalContext.getRequestServletPath() + "/");
71                      facesContext.responseComplete();
72                      return true;
73                  } catch (IOException e) {
74                      throw new FacesException("redirect failed", e);
75                  }
76              }
77          }
78  
79          Application application = facesContext.getApplication();
80          ViewHandler viewHandler = application.getViewHandler();
81  
82          // boolean viewCreated = false;
83          UIViewRoot viewRoot = viewHandler.restoreView(facesContext, viewId);
84          if (viewRoot == null) {
85              viewRoot = viewHandler.createView(facesContext, viewId);
86              viewRoot.setViewId(viewId);
87              facesContext.renderResponse();
88              // viewCreated = true;
89          }
90  
91          facesContext.setViewRoot(viewRoot);
92  
93      if (!isPostback(facesContext)) {
94              // no POST or query parameters --> set render response flag
95              facesContext.renderResponse();
96          }
97  
98          RestoreStateUtils.recursivelyHandleComponentReferencesAndSetValid(facesContext, viewRoot);
99          return false;
100     }
101   
102     
103   /**
104    * Return <code>true</code> if the current request is a post back and
105    * <code>false</code> otherwise.
106    * 
107    * @param  facesContext  the current faces context
108    * @return <code>true</code> if the current request is a post back and
109    *         <code>false</code> otherwise
110    */
111   private boolean isPostback(FacesContext facesContext) {
112       Map requestParameterMap = facesContext.getExternalContext().getRequestParameterMap(); 
113       return (requestParameterMap.containsKey(HtmlResponseStateManager.STANDARD_STATE_SAVING_PARAM) ||
114           requestParameterMap.containsKey("org.apache.myfaces.trinidad.faces.STATE"));
115   } 
116 
117     public PhaseId getPhase() {
118         return PhaseId.RESTORE_VIEW;
119     }
120 
121     private static String deriveViewId(FacesContext facesContext) {
122         ExternalContext externalContext = facesContext.getExternalContext();
123 
124         if (PortletUtil.isPortletRequest(facesContext)) {
125             PortletRequest request = (PortletRequest) externalContext.getRequest();
126             return request.getParameter(MyFacesGenericPortlet.VIEW_ID);
127         }
128 
129         String viewId = externalContext.getRequestPathInfo(); // getPathInfo
130         if (viewId == null) {
131             // No extra path info found, so it is probably extension mapping
132             viewId = externalContext.getRequestServletPath(); // getServletPath
133             DebugUtils.assertError(viewId != null, log,
134                     "RequestServletPath is null, cannot determine viewId of current page.");
135             if (viewId == null)
136                 return null;
137 
138             // TODO: JSF Spec 2.2.1 - what do they mean by "if the default
139             // ViewHandler implementation is used..." ?
140             String defaultSuffix = externalContext.getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
141             String suffix = defaultSuffix != null ? defaultSuffix : ViewHandler.DEFAULT_SUFFIX;
142             DebugUtils.assertError(suffix.charAt(0) == '.', log, "Default suffix must start with a dot!");
143 
144             int slashPos = viewId.lastIndexOf('/');
145             int extensionPos = viewId.lastIndexOf('.');
146             if (extensionPos == -1 || extensionPos <= slashPos) {
147                 log.error("Assumed extension mapping, but there is no extension in " + viewId);
148                 viewId = null;
149             } else {
150                 viewId = viewId.substring(0, extensionPos) + suffix;
151             }
152         }
153 
154         return viewId;
155     }
156 }