001: /*
002: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003: *
004: * "The contents of this file are subject to the Mozilla Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
011: * License for the specific language governing rights and limitations under
012: * the License.
013: *
014: * The Original Code is ICEfaces 1.5 open source software code, released
015: * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
016: * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
017: * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
018: *
019: * Contributor(s): _____________________.
020: *
021: * Alternatively, the contents of this file may be used under the terms of
022: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
023: * License), in which case the provisions of the LGPL License are
024: * applicable instead of those above. If you wish to allow use of your
025: * version of this file only under the terms of the LGPL License and not to
026: * allow others to use your version of this file under the MPL, indicate
027: * your decision by deleting the provisions above and replace them with
028: * the notice and other provisions required by the LGPL License. If you do
029: * not delete the provisions above, a recipient may use your version of
030: * this file under either the MPL or the LGPL License."
031: *
032: */
033:
034: /*
035: * BridgeExternalContext.java
036: */
037:
038: package com.icesoft.faces.context;
039:
040: import com.icesoft.faces.webapp.command.CommandQueue;
041: import com.icesoft.faces.webapp.command.Redirect;
042: import com.icesoft.faces.webapp.command.SetCookie;
043: import com.icesoft.faces.webapp.http.common.Configuration;
044: import com.icesoft.faces.webapp.xmlhttp.PersistentFacesCommonlet;
045: import com.icesoft.util.SeamUtilities;
046:
047: import javax.faces.context.ExternalContext;
048: import javax.faces.context.FacesContext;
049: import javax.faces.render.ResponseStateManager;
050: import javax.servlet.http.Cookie;
051: import javax.servlet.http.HttpServletRequest;
052: import javax.servlet.http.HttpServletResponse;
053: import java.io.IOException;
054: import java.io.Writer;
055: import java.lang.reflect.Field;
056: import java.net.URI;
057: import java.util.HashMap;
058: import java.util.Iterator;
059: import java.util.Map;
060:
061: /**
062: * This class is supposed to provide a generic interface to the
063: * environment that we're running in (e.g. servlets, portlets).
064: */
065: public abstract class BridgeExternalContext extends ExternalContext {
066: private static String PostBackKey;
067:
068: static {
069: //We will place VIEW_STATE_PARAM in the requestMap so that
070: //JSF 1.2 doesn't think the request is a postback and skip
071: //execution
072: try {
073: Field field = ResponseStateManager.class
074: .getField("VIEW_STATE_PARAM");
075: if (null != field) {
076: PostBackKey = (String) field
077: .get(ResponseStateManager.class);
078: }
079: } catch (Exception e) {
080: }
081: }
082:
083: protected String viewIdentifier;
084: protected CommandQueue commandQueue;
085: protected boolean standardScope;
086: protected Map applicationMap;
087: protected Map sessionMap;
088: protected Map requestMap;
089: protected Map initParameterMap;
090: protected Redirector redirector;
091: protected CookieTransporter cookieTransporter;
092: protected String requestServletPath;
093: protected String requestPathInfo;
094: protected Map requestParameterMap;
095: protected Map requestParameterValuesMap;
096: protected Map requestCookieMap;
097: protected Map responseCookieMap;
098:
099: protected BridgeExternalContext(String viewIdentifier,
100: CommandQueue commandQueue, Configuration configuration) {
101: this .viewIdentifier = viewIdentifier;
102: this .commandQueue = commandQueue;
103: this .standardScope = configuration.getAttributeAsBoolean(
104: "standardRequestScope", false);
105: }
106:
107: public abstract String getRequestURI();
108:
109: public abstract Writer getWriter(String encoding)
110: throws IOException;
111:
112: public abstract void switchToNormalMode();
113:
114: public abstract void switchToPushMode();
115:
116: public abstract void update(HttpServletRequest request,
117: HttpServletResponse response);
118:
119: public abstract void updateOnReload(Object request, Object response);
120:
121: public void addCookie(Cookie cookie) {
122: responseCookieMap.put(cookie.getName(), cookie);
123: cookieTransporter.send(cookie);
124: }
125:
126: public void setRequestPathInfo(String viewId) {
127: requestPathInfo = viewId;
128: }
129:
130: public void setRequestServletPath(String viewId) {
131: requestServletPath = viewId;
132: }
133:
134: public Map getApplicationSessionMap() {
135: return sessionMap;
136: }
137:
138: /**
139: * This method is not necessary. The application developer can keep track
140: * of the added cookies.
141: *
142: * @deprecated
143: */
144: public Map getResponseCookieMap() {
145: return responseCookieMap;
146: }
147:
148: //todo: see if we can execute full JSP cycle all the time (not only when page is parsed)
149: //todo: this way the bundles are put into the request map every time, so we don't have to carry
150: //todo: them between requests
151: public Map collectBundles() {
152: Map result = new HashMap();
153: Iterator entries = requestMap.entrySet().iterator();
154: while (entries.hasNext()) {
155: Map.Entry entry = (Map.Entry) entries.next();
156: Object value = entry.getValue();
157: if (value != null) {
158: String className = value.getClass().getName();
159: if ((className.indexOf("LoadBundleTag") > 0) || //Sun RI
160: (className.indexOf("BundleMap") > 0)) { //MyFaces
161: result.put(entry.getKey(), value);
162: }
163: }
164: }
165:
166: return result;
167: }
168:
169: public void injectBundles(Map bundles) {
170: requestMap.putAll(bundles);
171: }
172:
173: protected void insertPostbackKey() {
174: if (null != PostBackKey) {
175: requestParameterMap.put(PostBackKey, "not reload");
176: requestParameterValuesMap.put(PostBackKey,
177: new String[] { "not reload" });
178: }
179: }
180:
181: /**
182: * Any GET request performed by the browser is a non-faces request to the framework.
183: * (JSF-spec chapter 2, introduction). Given this, the framework must create a new
184: * viewRoot for the request, even if the viewId has already been visited. (Spec
185: * section 2.1.1) <p>
186: * <p/>
187: * Only during GET's remember, not during partial submits, where the JSF framework must
188: * be allowed to attempt to restore the view. There is a great deal of Seam related code
189: * that depends on this happening. So put in a token that allows the D2DViewHandler
190: * to differentiate between the non-faces request, and the postbacks, for this
191: * request, which will allow the ViewHandler to make the right choice, since we keep
192: * the view around for all types of requests
193: */
194: protected void insertNewViewrootToken() {
195: if (SeamUtilities.isSeamEnvironment()) {
196: requestParameterMap.put(
197: PersistentFacesCommonlet.SEAM_LIFECYCLE_SHORTCUT,
198: Boolean.TRUE);
199: }
200: }
201:
202: /**
203: * If in Standard request scope mode, remove all parameters from
204: * the Request Map.
205: */
206: public void resetRequestMap() {
207: if (standardScope) {
208: requestMap.clear();
209: }
210: }
211:
212: public void dispose() {
213: requestMap.clear();
214: commandQueue.take();
215: }
216:
217: protected void applySeamLifecycleShortcut(boolean persistSeamKey) {
218: if (persistSeamKey) {
219: requestParameterMap.put(
220: PersistentFacesCommonlet.SEAM_LIFECYCLE_SHORTCUT,
221: Boolean.TRUE);
222: }
223: }
224:
225: protected boolean isSeamLifecycleShortcut() {
226: boolean persistSeamKey = false;
227: if (requestParameterMap != null) {
228: persistSeamKey = requestParameterMap
229: .containsKey(PersistentFacesCommonlet.SEAM_LIFECYCLE_SHORTCUT);
230: }
231:
232: return persistSeamKey;
233: }
234:
235: public Map getApplicationMap() {
236: return applicationMap;
237: }
238:
239: public Map getSessionMap() {
240: return sessionMap;
241: }
242:
243: public Map getRequestMap() {
244: return requestMap;
245: }
246:
247: public String getInitParameter(String name) {
248: return (String) initParameterMap.get(name);
249: }
250:
251: public Map getInitParameterMap() {
252: return initParameterMap;
253: }
254:
255: public void redirect(String requestURI) throws IOException {
256: final URI uri = URI.create(SeamUtilities
257: .encodeSeamConversationId(requestURI, viewIdentifier));
258: final String redirectURI;
259: if (uri.isAbsolute()) {
260: redirectURI = uri.toString();
261: } else {
262: String query = uri.getQuery();
263: if (query == null) {
264: redirectURI = uri + "?rvn=" + viewIdentifier;
265: } else {
266: if (query.matches(".*rvn=.*")) {
267: redirectURI = uri.toString();
268: } else {
269: redirectURI = uri + "&rvn=" + viewIdentifier;
270: }
271: }
272: }
273: redirector.redirect(redirectURI);
274: FacesContext.getCurrentInstance().responseComplete();
275: }
276:
277: public Map getRequestParameterMap() {
278: return requestParameterMap;
279: }
280:
281: public Map getRequestParameterValuesMap() {
282: return requestParameterValuesMap;
283: }
284:
285: public Iterator getRequestParameterNames() {
286: return requestParameterMap.keySet().iterator();
287: }
288:
289: public Map getRequestCookieMap() {
290: return requestCookieMap;
291: }
292:
293: public interface Redirector {
294: void redirect(String uri);
295: }
296:
297: public interface CookieTransporter {
298: void send(Cookie cookie);
299: }
300:
301: public class CommandQueueRedirector implements Redirector {
302: public void redirect(String uri) {
303: commandQueue.put(new Redirect(uri));
304: }
305: }
306:
307: public class CommandQueueCookieTransporter implements
308: CookieTransporter {
309: public void send(Cookie cookie) {
310: commandQueue.put(new SetCookie(cookie));
311: }
312: }
313:
314: }
|