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 javax.faces.FacesException;
22  import javax.faces.application.Application;
23  import javax.faces.application.ViewExpiredException;
24  import javax.faces.application.ViewHandler;
25  import javax.faces.component.UIViewRoot;
26  import javax.faces.context.ExternalContext;
27  import javax.faces.context.FacesContext;
28  import javax.faces.event.PhaseId;
29  import javax.portlet.PortletRequest;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.myfaces.portlet.MyFacesGenericPortlet;
34  import org.apache.myfaces.portlet.PortletUtil;
35  import org.apache.myfaces.util.DebugUtils;
36  
37  /**
38   * Implements the Restore View Phase (JSF Spec 2.2.1)
39   * 
40   * @author Nikolay Petrov
41   * @author Bruno Aranda (JSF 1.2)
42   * @version $Revision: 673926 $ $Date: 2008-07-04 02:03:53 -0500 (Fri, 04 Jul 2008) $
43   * 
44   */
45  class RestoreViewExecutor implements PhaseExecutor
46  {
47  
48      private static final Log log = LogFactory.getLog(RestoreViewExecutor.class);
49      private RestoreViewSupport _restoreViewSupport;
50  
51      public boolean execute(FacesContext facesContext)
52      {
53          if (facesContext == null)
54          {
55              throw new FacesException("FacesContext is null");
56          }
57  
58          // init the View
59          Application application = facesContext.getApplication();
60          ViewHandler viewHandler = application.getViewHandler();
61          viewHandler.initView(facesContext);
62  
63          UIViewRoot viewRoot = facesContext.getViewRoot();
64  
65          RestoreViewSupport restoreViewSupport = getRestoreViewSupport();
66          
67          if (viewRoot != null)
68          {
69              if (log.isTraceEnabled())
70                  log.trace("View already exists in the FacesContext");
71  
72              viewRoot.setLocale(facesContext.getExternalContext().getRequestLocale());
73              restoreViewSupport.processComponentBinding(facesContext, viewRoot);
74              return false;
75          }
76  
77          String viewId = restoreViewSupport.calculateViewId(facesContext);
78  
79          // Determine if this request is a postback or initial request
80          if (restoreViewSupport.isPostback(facesContext))
81          {
82              if (log.isTraceEnabled())
83                  log.trace("Request is a postback");
84  
85              viewRoot = viewHandler.restoreView(facesContext, viewId);
86              if (viewRoot == null)
87              {
88                  throw new ViewExpiredException(
89                      "No saved view state could be found for the view identifier: "
90                          + viewId, viewId);
91              }
92              restoreViewSupport.processComponentBinding(facesContext, viewRoot);
93          }
94          else
95          {
96              if (log.isTraceEnabled())
97                  log.trace("Request is not a postback. New UIViewRoot will be created");
98  
99              viewRoot = viewHandler.createView(facesContext, viewId);
100             facesContext.renderResponse();
101         }
102 
103         facesContext.setViewRoot(viewRoot);
104 
105         return false;
106     }
107 
108     protected RestoreViewSupport getRestoreViewSupport()
109     {
110         if (_restoreViewSupport == null)
111         {
112             _restoreViewSupport = new DefaultRestoreViewSupport();
113         }
114         return _restoreViewSupport;
115     }
116 
117     /**
118      * @param restoreViewSupport
119      *            the restoreViewSupport to set
120      */
121     public void setRestoreViewSupport(RestoreViewSupport restoreViewSupport)
122     {
123         _restoreViewSupport = restoreViewSupport;
124     }
125 
126     public PhaseId getPhase()
127     {
128         return PhaseId.RESTORE_VIEW;
129     }
130 
131     /**
132      * TODO place that stuff into the default view handler implementation.
133      */
134     private static String deriveViewId(FacesContext facesContext)
135     {
136         ExternalContext externalContext = facesContext.getExternalContext();
137 
138         if (PortletUtil.isPortletRequest(facesContext))
139         {
140             PortletRequest request = (PortletRequest) externalContext.getRequest();
141             return request.getParameter(MyFacesGenericPortlet.VIEW_ID);
142         }
143 
144         String viewId = externalContext.getRequestPathInfo(); // getPathInfo
145         if (viewId == null)
146         {
147             // No extra path info found, so it is probably extension mapping
148             viewId = externalContext.getRequestServletPath(); // getServletPath
149             DebugUtils.assertError(viewId != null, log,
150                     "RequestServletPath is null, cannot determine viewId of current page.");
151             if (viewId == null)
152                 return null;
153 
154             // TODO: JSF Spec 2.2.1 - what do they mean by "if the default
155             // ViewHandler implementation is used..." ?
156             // - probably that this should use DefaultViewHandlerSupport.calculateServletFacesMapping
157             // rather than duplicating the logic here.
158             String defaultSuffix = externalContext.getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
159             String suffix = defaultSuffix != null ? defaultSuffix : ViewHandler.DEFAULT_SUFFIX;
160             DebugUtils.assertError(suffix.charAt(0) == '.', log, "Default suffix must start with a dot!");
161 
162             int slashPos = viewId.lastIndexOf('/');
163             int extensionPos = viewId.lastIndexOf('.');
164             if (extensionPos == -1 || extensionPos <= slashPos)
165             {
166                 log.error("Assumed extension mapping, but there is no extension in " + viewId);
167                 viewId = null;
168             }
169             else
170             {
171                 viewId = viewId.substring(0, extensionPos) + suffix;
172             }
173         }
174 
175         return viewId;
176     }
177 }