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: package com.icesoft.faces.context;
034:
035: import com.icesoft.faces.application.D2DViewHandler;
036: import com.icesoft.faces.el.ELContextImpl;
037: import com.icesoft.faces.webapp.command.CommandQueue;
038: import com.icesoft.faces.webapp.http.common.Configuration;
039: import com.icesoft.faces.webapp.xmlhttp.PersistentFacesCommonlet;
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042: import org.w3c.dom.Document;
043: import org.w3c.dom.Element;
044: import org.w3c.dom.NodeList;
045:
046: import javax.el.ELContext;
047: import javax.faces.FactoryFinder;
048: import javax.faces.application.Application;
049: import javax.faces.application.ApplicationFactory;
050: import javax.faces.application.FacesMessage;
051: import javax.faces.component.UIViewRoot;
052: import javax.faces.context.ExternalContext;
053: import javax.faces.context.FacesContext;
054: import javax.faces.context.ResponseStream;
055: import javax.faces.context.ResponseWriter;
056: import javax.faces.render.RenderKit;
057: import javax.faces.render.RenderKitFactory;
058: import java.io.IOException;
059: import java.util.ArrayList;
060: import java.util.Arrays;
061: import java.util.Collections;
062: import java.util.HashMap;
063: import java.util.Iterator;
064: import java.util.List;
065: import java.util.Map;
066: import java.util.Vector;
067:
068: //for now extend BridgeFacesContext since there are so many 'instanceof' tests
069: public class BridgeFacesContext extends FacesContext {
070: private static final Log log = LogFactory
071: .getLog(BridgeFacesContext.class);
072: private Application application;
073: private BridgeExternalContext externalContext;
074: private HashMap faceMessages = new HashMap();
075: private boolean renderResponse;
076: private boolean responseComplete;
077: private ResponseStream responseStream;
078: private ResponseWriter responseWriter;
079: private DOMSerializer domSerializer;
080: private UIViewRoot viewRoot;
081: private String iceFacesId;
082: private String viewNumber;
083: private CommandQueue commandQueue;
084: private Configuration configuration;
085:
086: public BridgeFacesContext(BridgeExternalContext externalContext,
087: String view, String icefacesID, CommandQueue commandQueue,
088: Configuration configuration) {
089: setCurrentInstance(this );
090: this .externalContext = externalContext;
091: this .viewNumber = view;
092: this .iceFacesId = icefacesID;
093: this .commandQueue = commandQueue;
094: this .configuration = configuration;
095: this .application = ((ApplicationFactory) FactoryFinder
096: .getFactory(FactoryFinder.APPLICATION_FACTORY))
097: .getApplication();
098: this .externalContext = externalContext;
099: this .switchToNormalMode();
100: }
101:
102: public void setCurrentInstance() {
103: setCurrentInstance(this );
104: }
105:
106: public Application getApplication() {
107: return application;
108: }
109:
110: public void setApplication(Application application) {
111: this .application = application;
112: }
113:
114: public Iterator getClientIdsWithMessages() {
115: return faceMessages.keySet().iterator();
116: }
117:
118: public ExternalContext getExternalContext() {
119: return this .externalContext;
120: }
121:
122: public void setExternalContext(ExternalContext externalContext) {
123: //do nothing
124: }
125:
126: public ELContext getELContext() {
127: ELContext elContext = new ELContextImpl(application);
128: elContext.putContext(FacesContext.class, this );
129: UIViewRoot root = getViewRoot();
130: if (null != root) {
131: elContext.setLocale(root.getLocale());
132: }
133:
134: return elContext;
135: }
136:
137: public FacesMessage.Severity getMaximumSeverity() {
138: throw new UnsupportedOperationException();
139: }
140:
141: /**
142: * gets all FacesMessages whether or not associatted with clientId.
143: *
144: * @return list of FacesMessages
145: */
146: public Iterator getMessages() {
147:
148: // Jira #1358 The hashmap contains vectors of FacesMessages, not FacesMessages
149: // See following method.
150: ArrayList buffer = new ArrayList();
151: Iterator i = faceMessages.values().iterator();
152: while (i.hasNext()) {
153: buffer.addAll((Vector) i.next());
154: }
155:
156: return buffer.iterator();
157: }
158:
159: /**
160: * returns list of FacesMessages associated with a clientId. If client id is
161: * null, then return all FacesMessages which are not assocaited wih any
162: * clientId
163: *
164: * @param clientId
165: * @return list of FacesMessages
166: */
167: public Iterator getMessages(String clientId) {
168: try {
169: return ((Vector) faceMessages.get(clientId)).iterator();
170: } catch (NullPointerException e) {
171: if (log.isDebugEnabled()) {
172: log.debug("Cannot find clientId " + clientId
173: + "from facesMessages");
174: }
175: return Collections.EMPTY_LIST.iterator();
176: }
177: }
178:
179: public RenderKit getRenderKit() {
180: UIViewRoot viewRoot = getViewRoot();
181: if (null == viewRoot) {
182: return (null);
183: }
184: String renderKitId = viewRoot.getRenderKitId();
185: if (null == renderKitId) {
186: return (null);
187: }
188:
189: RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
190: .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
191: RenderKit renderKit = renderKitFactory.getRenderKit(this ,
192: renderKitId);
193: return (renderKit);
194: }
195:
196: public boolean getRenderResponse() {
197: return this .renderResponse;
198: }
199:
200: public boolean getResponseComplete() {
201: return this .responseComplete;
202: }
203:
204: public ResponseStream getResponseStream() {
205: return this .responseStream;
206: }
207:
208: public void setResponseStream(ResponseStream responseStream) {
209: this .responseStream = responseStream;
210: }
211:
212: public ResponseWriter getResponseWriter() {
213: return responseWriter;
214: }
215:
216: public void setResponseWriter(ResponseWriter responseWriter) {
217: this .responseWriter = responseWriter;
218: }
219:
220: public ResponseWriter createAndSetResponseWriter()
221: throws IOException {
222: return responseWriter = new DOMResponseWriter(this ,
223: domSerializer, configuration);
224: }
225:
226: public void switchToNormalMode() {
227: try {
228: domSerializer = new NormalModeSerializer(this ,
229: externalContext.getWriter("UTF-8"));
230: } catch (IOException e) {
231: throw new RuntimeException(e);
232: }
233: }
234:
235: public void switchToPushMode() {
236: //todo: pull document in this class
237:
238: // Jira #1330.
239: // Normally, just masking a null object just leads to
240: // a bunch of further null testing later. Except, at the time of writing,
241: // a) there is no (well, not much of a) later, and
242: // b) For the problem at hand, there's no easy way to create a Noop responseWriter
243: //
244: // The problem arises when Seam uses a Get request to logout. A Seam link tag
245: // is written with the actionMethod hack to get the Identity object to logout.
246: // As a result of the Get, a new ViewRoot is created, and in our code, the
247: // createAndSetResponseWriter method is not called until the renderResponse phase,
248: // but when the result of a Seam actionMethod hack is a redirect, renderResponse
249: // is not called, and the responseWriter will not have a value.
250: //
251: // Trying to create a Noop DomResponseWriter is problematic since the constructor
252: // of DRW does lots of initialization which needs something more than can
253: // be faked. Look in the initialize method in the DOMResponseWriter class
254: //
255: if (responseWriter != null) {
256: Document document = ((DOMResponseWriter) responseWriter)
257: .getDocument();
258: domSerializer = new PushModeSerializer(document,
259: commandQueue);
260: }
261: }
262:
263: public UIViewRoot getViewRoot() {
264: if (null != externalContext.getRequestParameterMap().get(
265: PersistentFacesCommonlet.SEAM_LIFECYCLE_SHORTCUT)) {
266: //ViewRoot and attributes being cached interferes with PAGE scope
267: return null;
268: }
269: if (null == viewRoot) {
270: Map contextServletTable = D2DViewHandler
271: .getContextServletTable(this );
272: if (null != contextServletTable) {
273: viewRoot = (UIViewRoot) contextServletTable
274: .get(DOMResponseWriter.RESPONSE_VIEWROOT);
275: }
276: }
277:
278: return this .viewRoot;
279: }
280:
281: public void setViewRoot(UIViewRoot viewRoot) {
282: //pointing this FacesContext to the new view
283: Map contextServletTable = D2DViewHandler
284: .getContextServletTable(this );
285: if (null != contextServletTable) {
286: if (viewRoot != null) {
287: contextServletTable.put(
288: DOMResponseWriter.RESPONSE_VIEWROOT, viewRoot);
289: } else {
290: contextServletTable
291: .remove(DOMResponseWriter.RESPONSE_VIEWROOT);
292: }
293: }
294: responseWriter = null;
295: this .viewRoot = viewRoot;
296: }
297:
298: public String getIceFacesId() {
299: return iceFacesId;
300: }
301:
302: /**
303: * Return the unique identifier associated with each browser window
304: * associated with a single user.
305: */
306: public String getViewNumber() {
307: return viewNumber;
308: }
309:
310: /**
311: * Return the id of the Element that currently has focus in the browser.
312: *
313: * @return String
314: */
315: public String getFocusId() {
316: Map map = externalContext.getRequestParameterMap();
317: return (String) (map.containsKey("ice.focus") ? map
318: .get("ice.focus") : "");
319: }
320:
321: /**
322: * Sets the id of the Element that should get focus in the browser.
323: */
324: public void setFocusId(String focusId) {
325: externalContext.getRequestParameterMap().put("ice.focus",
326: focusId);
327: }
328:
329: /**
330: * add a FacesMessage to the set of message associated with the clientId, if
331: * clientId is not null.
332: *
333: * @param clientId
334: * @param message
335: */
336: public void addMessage(String clientId, FacesMessage message) {
337: if (message == null) {
338: throw new IllegalArgumentException("Message is null");
339: }
340: if (faceMessages.containsKey(clientId)) {
341: ((Vector) faceMessages.get(clientId)).addElement(message);
342: } else {
343: Vector vector = new Vector();
344: vector.add(message);
345: faceMessages.put(clientId, vector);
346: }
347: }
348:
349: public void renderResponse() {
350: this .renderResponse = true;
351: }
352:
353: public void responseComplete() {
354: this .responseComplete = true;
355: }
356:
357: public void resetRenderResponse() {
358: this .renderResponse = false;
359: }
360:
361: /**
362: * The release() found in FacesContextImpl is more comprehensive: since they
363: * blow away the context instance after a response, they null/false out much
364: * more than we do. We chose to keep the context instance around across
365: * requests so we need to keep some of our state intact.
366: */
367: public void release() {
368: faceMessages.clear();
369: renderResponse = false;
370: responseComplete = false;
371: setCurrentInstance(null);
372: }
373:
374: public void dispose() {
375: String key = viewNumber + "/"
376: + D2DViewHandler.DOM_CONTEXT_TABLE;
377: externalContext.getSessionMap().remove(key);
378: }
379:
380: public void applyBrowserDOMChanges() {
381: if (responseWriter == null)
382: return;
383: Document document = ((DOMResponseWriter) responseWriter)
384: .getDocument();
385: if (document == null)
386: return;
387: Map parameters = externalContext.getRequestParameterValuesMap();
388:
389: NodeList inputElements = document.getElementsByTagName("input");
390: int inputElementsLength = inputElements.getLength();
391: for (int i = 0; i < inputElementsLength; i++) {
392: Element inputElement = (Element) inputElements.item(i);
393: String id = inputElement.getAttribute("id");
394: if (!"".equals(id) && parameters.containsKey(id)) {
395: String value = ((String[]) parameters.get(id))[0];
396: inputElement.setAttribute("value", value);
397: }
398: }
399:
400: NodeList textareaElements = document
401: .getElementsByTagName("textarea");
402: int textareaElementsLength = textareaElements.getLength();
403: for (int i = 0; i < textareaElementsLength; i++) {
404: Element textareaElement = (Element) textareaElements
405: .item(i);
406: String id = textareaElement.getAttribute("id");
407: if (!"".equals(id) && parameters.containsKey(id)) {
408: String value = ((String[]) parameters.get(id))[0];
409: textareaElement.getFirstChild().setNodeValue(value);//set value on the Text node
410: }
411: }
412:
413: NodeList selectElements = document
414: .getElementsByTagName("select");
415: int selectElementsLength = selectElements.getLength();
416: for (int i = 0; i < selectElementsLength; i++) {
417: Element selectElement = (Element) selectElements.item(i);
418: String id = selectElement.getAttribute("id");
419: if (!"".equals(id) && parameters.containsKey(id)) {
420: List values = Arrays.asList((String[]) parameters
421: .get(id));
422:
423: NodeList optionElements = selectElement
424: .getElementsByTagName("option");
425: int optionElementsLength = optionElements.getLength();
426: for (int j = 0; j < optionElementsLength; j++) {
427: Element optionElement = (Element) optionElements
428: .item(j);
429: if (values.contains(optionElement
430: .getAttribute("value"))) {
431: optionElement.setAttribute("selected",
432: "selected");
433: } else {
434: optionElement.removeAttribute("selected");
435: }
436: }
437: }
438: }
439: }
440: }
|