001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.pageflow.faces.internal;
020:
021: import org.apache.beehive.netui.pageflow.PageFlowUtils;
022: import org.apache.beehive.netui.pageflow.PageFlowController;
023: import org.apache.beehive.netui.pageflow.PreviousPageInfo;
024: import org.apache.beehive.netui.pageflow.FacesBackingBean;
025: import org.apache.beehive.netui.pageflow.FacesBackingBeanFactory;
026: import org.apache.beehive.netui.pageflow.RequestContext;
027: import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper;
028: import org.apache.beehive.netui.pageflow.internal.InternalUtils;
029: import org.apache.beehive.netui.util.internal.FileUtils;
030: import org.apache.beehive.netui.script.common.ImplicitObjectUtil;
031:
032: import javax.faces.application.ViewHandler;
033: import javax.faces.context.FacesContext;
034: import javax.faces.context.ExternalContext;
035: import javax.faces.component.UIViewRoot;
036: import javax.faces.FacesException;
037: import javax.servlet.http.HttpServletRequest;
038: import javax.servlet.http.HttpServletResponse;
039: import javax.servlet.ServletContext;
040: import javax.servlet.ServletRequest;
041: import javax.servlet.ServletResponse;
042: import java.util.Locale;
043: import java.io.IOException;
044: import java.io.Serializable;
045:
046: /**
047: * Internal class used in JSF/Page Flow integration. Delegates in all cases except:
048: * <ul>
049: * <li>
050: * {@link #restoreView}, which prevents view restoration if we're in a request forwarded by
051: * {@link PageFlowNavigationHandler}.
052: * </li>
053: * <li>
054: * {@link #createView}, which integrates with the "navigateTo" feature in Page Flow to save/restore the
055: * component tree.
056: * </li>
057: * </ul>
058: *
059: * @see org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory
060: */
061: class PageFlowViewHandler extends ViewHandler {
062: private ViewHandler _delegate;
063:
064: public PageFlowViewHandler(ViewHandler delegate) {
065: _delegate = delegate;
066: }
067:
068: public Locale calculateLocale(FacesContext context) {
069: return _delegate.calculateLocale(context);
070: }
071:
072: public String calculateRenderKitId(FacesContext context) {
073: return _delegate.calculateRenderKitId(context);
074: }
075:
076: private static class PageClientState implements Serializable {
077: private UIViewRoot _viewRoot;
078: private FacesBackingBean _backingBean;
079:
080: public PageClientState(UIViewRoot viewRoot,
081: FacesBackingBean backingBean) {
082: _viewRoot = viewRoot;
083: _backingBean = backingBean;
084: }
085:
086: public UIViewRoot getViewRoot() {
087: return _viewRoot;
088: }
089:
090: public FacesBackingBean getBackingBean() {
091: return _backingBean;
092: }
093: }
094:
095: private static void setBackingBean(ServletRequest request,
096: ServletResponse response, ServletContext servletContext) {
097: if (request instanceof HttpServletRequest) {
098: FacesBackingBeanFactory factory = FacesBackingBeanFactory
099: .get(servletContext);
100: FacesBackingBean fbb = factory
101: .getFacesBackingBeanForRequest(new RequestContext(
102: request, response));
103:
104: if (fbb != null) {
105: ImplicitObjectUtil.loadFacesBackingBean(request, fbb);
106: } else {
107: ImplicitObjectUtil.unloadFacesBackingBean(request);
108: }
109: }
110: }
111:
112: public UIViewRoot createView(FacesContext context, String viewId) {
113: ExternalContext externalContext = context.getExternalContext();
114: Object request = externalContext.getRequest();
115: HttpServletRequest httpRequest = null;
116:
117: if (request instanceof HttpServletRequest) {
118: //
119: // If this is a navigateTo=Jpf.NavigateTo.currentPage or a navigateTo=Jpf.NavigateTo.previousPage,
120: // see if we've saved view state from the original page. If so, just restore that.
121: //
122: httpRequest = (HttpServletRequest) request;
123: PageFlowRequestWrapper rw = PageFlowRequestWrapper
124: .unwrap(httpRequest);
125:
126: if (rw != null) {
127: PreviousPageInfo prevPageInfo = rw
128: .getPreviousPageInfo(true);
129:
130: if (prevPageInfo != null) {
131: Object clientState = prevPageInfo.getClientState();
132:
133: if (clientState != null
134: && clientState instanceof PageClientState) {
135: PageClientState pcs = (PageClientState) clientState;
136: FacesBackingBean fbb = pcs.getBackingBean();
137: ServletContext servletContext = (ServletContext) externalContext
138: .getContext();
139:
140: if (fbb != null) {
141: HttpServletResponse httpResponse = (HttpServletResponse) externalContext
142: .getResponse();
143: fbb.restore(httpRequest, httpResponse,
144: servletContext);
145: } else {
146: InternalUtils
147: .removeCurrentFacesBackingBean(
148: httpRequest, servletContext);
149: }
150:
151: return pcs.getViewRoot();
152: }
153: }
154: }
155:
156: //
157: // Create/restore the backing bean that corresponds to this request.
158: //
159: HttpServletResponse response = (HttpServletResponse) externalContext
160: .getResponse();
161: ServletContext servletContext = (ServletContext) externalContext
162: .getContext();
163: setBackingBean(httpRequest, response, servletContext);
164: }
165:
166: UIViewRoot viewRoot = _delegate.createView(context, viewId);
167: savePreviousPageInfo(httpRequest, externalContext, viewId,
168: viewRoot);
169: return viewRoot;
170: }
171:
172: public String getActionURL(FacesContext context, String viewId) {
173: return _delegate.getActionURL(context, viewId);
174: }
175:
176: public String getResourceURL(FacesContext context, String path) {
177: return _delegate.getResourceURL(context, path);
178: }
179:
180: public void renderView(FacesContext context, UIViewRoot viewToRender)
181: throws IOException, FacesException {
182: // Create/restore the backing bean that corresponds to this request.
183: ExternalContext externalContext = context.getExternalContext();
184: Object request = externalContext.getRequest();
185:
186: if (request instanceof HttpServletRequest) {
187: HttpServletRequest httpRequest = (HttpServletRequest) request;
188: HttpServletResponse response = (HttpServletResponse) externalContext
189: .getResponse();
190: ServletContext servletContext = (ServletContext) externalContext
191: .getContext();
192: setBackingBean(httpRequest, response, servletContext);
193: }
194:
195: _delegate.renderView(context, viewToRender);
196: }
197:
198: /**
199: * If we are in a request forwarded by {@link PageFlowNavigationHandler}, returns <code>null</code>; otherwise,
200: * delegates to the base ViewHandler.
201: */
202: public UIViewRoot restoreView(FacesContext context, String viewId) {
203: ExternalContext externalContext = context.getExternalContext();
204: Object request = externalContext.getRequest();
205: HttpServletRequest httpRequest = null;
206:
207: if (request instanceof HttpServletRequest) {
208: httpRequest = (HttpServletRequest) request;
209:
210: //
211: // If we did a forward in PageFlowNavigationHandler, don't try to restore the view.
212: //
213: if (httpRequest
214: .getAttribute(PageFlowNavigationHandler.ALREADY_FORWARDED_ATTR) != null) {
215: return null;
216: }
217:
218: //
219: // Create/restore the backing bean that corresponds to this request.
220: //
221: HttpServletResponse response = (HttpServletResponse) externalContext
222: .getResponse();
223: ServletContext servletContext = (ServletContext) externalContext
224: .getContext();
225: setBackingBean(httpRequest, response, servletContext);
226:
227: }
228:
229: UIViewRoot viewRoot = _delegate.restoreView(context, viewId);
230: savePreviousPageInfo(httpRequest, externalContext, viewId,
231: viewRoot);
232: return viewRoot;
233: }
234:
235: private static void savePreviousPageInfo(
236: HttpServletRequest request,
237: ExternalContext externalContext, String viewID,
238: UIViewRoot viewRoot) {
239: //
240: // Save the current view state in the PreviousPageInfo structure of the current page flow.
241: //
242: if (request != null) {
243: ServletContext servletContext = (ServletContext) externalContext
244: .getContext();
245: PageFlowController curPageFlow = PageFlowUtils
246: .getCurrentPageFlow(request, servletContext);
247:
248: if (curPageFlow != null
249: && !curPageFlow.isPreviousPageInfoDisabled()) {
250: //
251: // Only save the previous page info if the JSF view-ID is the same as the current forward path.
252: // Note that we strip the file extension from the view-ID -- different JSF implementations give
253: // us different things (foo.jsp vs. foo.faces).
254: //
255: viewID = FileUtils.stripFileExtension(viewID);
256: String currentForwardPath = FileUtils
257: .stripFileExtension(curPageFlow
258: .getCurrentForwardPath());
259: if (viewID.equals(currentForwardPath)) {
260: PreviousPageInfo prevPageInfo = curPageFlow
261: .theCurrentPageInfo();
262: FacesBackingBean backingBean = InternalUtils
263: .getFacesBackingBean(request,
264: servletContext);
265: prevPageInfo.setClientState(new PageClientState(
266: viewRoot, backingBean));
267: }
268: }
269: }
270: }
271:
272: public void writeState(FacesContext context) throws IOException {
273: _delegate.writeState(context);
274: }
275: }
|