1 33 34 package com.icesoft.faces.context; 35 36 import com.icesoft.faces.application.D2DViewHandler; 37 import com.icesoft.faces.application.StartupTime; 38 import com.icesoft.faces.context.effects.JavascriptContext; 39 import com.icesoft.faces.util.CoreUtils; 40 import com.icesoft.faces.webapp.http.common.Configuration; 41 import com.icesoft.jasper.Constants; 42 import org.apache.commons.logging.Log; 43 import org.apache.commons.logging.LogFactory; 44 import org.w3c.dom.Document ; 45 import org.w3c.dom.Element ; 46 import org.w3c.dom.Node ; 47 import org.w3c.dom.NodeList ; 48 49 import javax.faces.FacesException; 50 import javax.faces.application.ViewHandler; 51 import javax.faces.component.UIComponent; 52 import javax.faces.context.FacesContext; 53 import javax.faces.context.ResponseWriter; 54 import javax.servlet.http.HttpServletRequest ; 55 import javax.xml.parsers.DocumentBuilder ; 56 import javax.xml.parsers.DocumentBuilderFactory ; 57 import javax.xml.parsers.ParserConfigurationException ; 58 import java.beans.Beans ; 59 import java.io.IOException ; 60 import java.io.Writer ; 61 import java.util.ArrayList ; 62 import java.util.Collection ; 63 import java.util.HashMap ; 64 import java.util.Iterator ; 65 import java.util.Locale ; 66 import java.util.Map ; 67 68 72 public class DOMResponseWriter extends ResponseWriter { 73 private static final Log log = LogFactory.getLog(DOMResponseWriter.class); 74 public static final String STREAM_WRITING = "com.icesoft.faces.streamWriting"; 75 public static final String DOCTYPE_PUBLIC = "com.icesoft.doctype.public"; 77 public static final String DOCTYPE_SYSTEM = "com.icesoft.doctype.system"; 78 public static final String DOCTYPE_ROOT = "com.icesoft.doctype.root"; 79 public static final String DOCTYPE_OUTPUT = "com.icesoft.doctype.output"; 80 public static final String DOCTYPE_PRETTY_PRINTING = 81 "com.icesoft.doctype.prettyprinting"; 82 83 public static final String RESPONSE_DOM = "com.icesoft.domResponseDocument"; 84 public static final String RESPONSE_DOM_ID = 85 "com.icesoft.domResponseDocumentID"; 86 public static final String OLD_DOM = "com.icesoft.oldDocument"; 87 public static final String RESPONSE_VIEWROOT = 88 "com.icesoft.domResponseViewRoot"; 89 public static final String RESPONSE_CONTEXTS_TABLE = 91 "com.icesoft.domResponseContexts"; 92 private static DocumentBuilder DOCUMENT_BUILDER; 93 94 static { 95 try { 96 DOCUMENT_BUILDER = 97 DocumentBuilderFactory.newInstance().newDocumentBuilder(); 98 } catch (ParserConfigurationException e) { 99 log.error("Cannot acquire a DocumentBuilder", e); 100 } 101 } 102 103 private static boolean isStreamWritingFlag = false; 104 private Document document; 105 private Node cursor; 106 private Map domResponseContexts; 107 private Map contextServletTable; 108 private BridgeFacesContext context; 109 private DOMSerializer serializer; 110 private Configuration configuration; 111 112 public DOMResponseWriter(FacesContext context, DOMSerializer serializer, Configuration configuration) { 113 this.serializer = serializer; 114 this.configuration = configuration; 115 try { 116 this.context = (BridgeFacesContext) context; 117 } catch (ClassCastException e) { 118 throw new IllegalStateException ( 119 "ICEfaces requires the PersistentFacesServlet. " + 120 "Please check your web.xml servlet mappings"); 121 } 122 this.initialize(); 123 } 124 125 Map getDomResponseContexts() { 126 return domResponseContexts; 127 } 128 129 public Node getCursorParent() { 130 return cursor; 131 } 132 133 public Document getDocument() { 134 return document; 135 } 136 137 public String getContentType() { 138 return "text/html; charset=UTF-8"; 139 } 140 141 public String getCharacterEncoding() { 142 return "UTF-8"; 143 } 144 145 public void startDocument() throws IOException { 146 } 147 148 private void initialize() { 149 contextServletTable = D2DViewHandler.getContextServletTable(context); 150 if (contextServletTable 152 .containsKey(DOMResponseWriter.RESPONSE_CONTEXTS_TABLE)) { 153 domResponseContexts = (Map ) contextServletTable 154 .get(DOMResponseWriter.RESPONSE_CONTEXTS_TABLE); 155 } 156 if (null == domResponseContexts) { 157 domResponseContexts = new HashMap (); 158 contextServletTable.put(DOMResponseWriter.RESPONSE_CONTEXTS_TABLE, 159 domResponseContexts); 160 } 161 contextServletTable.put(DOMResponseWriter.RESPONSE_VIEWROOT, 163 context.getViewRoot()); 164 cursor = document = DOCUMENT_BUILDER.newDocument(); 165 contextServletTable.put(DOMResponseWriter.RESPONSE_DOM, document); 166 boolean streamWritingParam = "true".equalsIgnoreCase( 167 context.getExternalContext().getInitParameter( 168 DOMResponseWriter.STREAM_WRITING)); 169 DOMResponseWriter.isStreamWritingFlag = 170 Beans.isDesignTime() || streamWritingParam; 171 } 172 173 public void endDocument() throws IOException { 174 if (!isStreamWriting()) { 175 enhanceAndFixDocument(); 176 serializer.serialize(document); 177 } 178 } 179 180 public void flush() throws IOException { 181 } 182 183 public void startElement(String name, UIComponent componentForElement) 184 throws IOException { 185 Node oldCursor = cursor; 186 Element elem = document.createElement(name); 187 cursor = cursor.appendChild(elem); 188 if (log.isTraceEnabled()) { 189 log.trace("startElement() name: " + name + " elem: " + elem + 190 " oldCursor: " + oldCursor + " newCursor: " + cursor); 191 } 192 } 193 194 public void endElement(String name) throws IOException { 195 Node oldCursor = cursor; 196 cursor = cursor.getParentNode(); 197 if (log.isTraceEnabled()) { 198 log.trace("endElement() name: " + name + " oldCursor: " + 199 oldCursor + " newCursor: " + cursor); 200 } 201 } 202 203 public void writeAttribute(String name, Object value, 204 String componentPropertyName) 205 throws IOException { 206 ((Element ) cursor).setAttribute(name.trim(), String.valueOf(value)); 209 } 210 211 public void writeURIAttribute(String name, Object value, 212 String componentPropertyName) 213 throws IOException { 214 String stringValue = String.valueOf(value); 215 if (stringValue.startsWith("javascript:")) { 216 ((Element ) cursor).setAttribute(name, stringValue); 217 } else { 218 ((Element ) cursor) 219 .setAttribute(name, stringValue.replace(' ', '+')); 220 } 221 } 222 223 public void writeComment(Object comment) throws IOException { 224 if (log.isTraceEnabled()) { 225 log.trace("writeComment() comment: " + comment); 226 } 227 cursor.appendChild(document.createComment(String.valueOf(comment))); 228 } 229 230 public void writeText(Object text, String componentPropertyName) 231 throws IOException { 232 if (log.isTraceEnabled()) { 233 log.trace("writeText(O,S) text: " + text); 234 } 235 cursor.appendChild(document.createTextNode(String.valueOf(text))); 236 } 237 238 public void writeText(char text[], int off, int len) throws IOException { 239 if (log.isTraceEnabled()) { 240 log.trace("writeText(c[],i,i) text: " + 241 (new String (text, off, len))); 242 } 243 cursor.appendChild(document.createTextNode(new String (text, off, len))); 244 } 245 246 public ResponseWriter cloneWithWriter(Writer writer) { 247 if (null != document) { 250 try { 251 endDocument(); 252 } catch (IOException e) { 253 throw new IllegalStateException (e.toString()); 254 } 255 } 256 try { 257 return new DOMResponseWriter(context, serializer, configuration); 258 } catch (FacesException e) { 259 throw new IllegalStateException (); 260 } 261 } 262 263 public void close() throws IOException { 264 } 265 266 public void write(char[] cbuf, int off, int len) throws IOException { 267 if (log.isTraceEnabled()) { 268 log.trace("writeText(c[],i,i) str: " + 269 (new String (cbuf, off, len))); 270 } 271 cursor.appendChild(document.createTextNode(new String (cbuf, off, len))); 272 } 273 274 public void write(int c) throws IOException { 275 if (log.isTraceEnabled()) { 276 log.trace("write(i) hex: " + Integer.toHexString(c) + 277 " decimal: " + c); 278 } 279 cursor.appendChild(document.createTextNode(String.valueOf((char) c))); 280 } 281 282 public void write(String str) throws IOException { 283 if (log.isTraceEnabled()) { 284 log.trace("write(S) str: " + str); 285 } 286 cursor.appendChild(document.createTextNode(str)); 287 } 288 289 public void write(String str, int off, int len) throws IOException { 290 if (log.isTraceEnabled()) { 291 log.trace("write(S,i,i) str_sub: " + str.substring(off, len)); 292 } 293 cursor.appendChild(document.createTextNode(str.substring(off, len))); 294 } 295 296 private void enhanceAndFixDocument() { 297 Element html = (Element ) document.getDocumentElement(); 298 enhanceHtml(html = "html".equals(html.getTagName()) ? html : fixHtml()); 299 300 Element head = (Element ) document.getElementsByTagName("head").item(0); 301 enhanceHead(head == null ? fixHead() : head); 302 303 Element body = (Element ) document.getElementsByTagName("body").item(0); 304 enhanceBody(body == null ? fixBody() : body); 305 } 306 307 private void enhanceHtml(Element html) { 308 Locale locale = context.getApplication().getViewHandler().calculateLocale(context); 310 html.setAttribute("lang", locale.getLanguage()); 311 } 312 313 private void enhanceBody(Element body) { 314 body.setAttribute("id", "body"); 316 Element iframe = document.createElement("iframe"); 317 body.insertBefore(iframe, body.getFirstChild()); 318 iframe.setAttribute("id", "history-frame"); 319 Object request = context.getExternalContext().getRequest(); 320 321 final String frameURI; 322 if (request instanceof HttpServletRequest ) { 324 HttpServletRequest httpRequest = (HttpServletRequest ) request; 325 if (httpRequest.getRequestURI() == null) { 326 frameURI = "about:blank"; 327 } else { 328 frameURI = CoreUtils.resolveResourceURL(FacesContext.getCurrentInstance(), 329 "/xmlhttp/blank.iface"); 330 } 331 } else { 332 frameURI = "about:blank"; 333 } 334 iframe.setAttribute("title", "Icefaces Redirect"); 335 iframe.setAttribute("src", frameURI); 336 iframe.setAttribute("frameborder", "0"); 337 iframe.setAttribute("style", 338 "z-index: 10000; visibility: hidden; width: 0; height: 0; position: absolute; opacity: 0.22; filter: alpha(opacity=22);"); 339 340 String focusId = context.getFocusId(); 342 if (focusId != null && !focusId.equals("null")) { 343 JavascriptContext.focus(context, focusId); 344 } 345 346 Element script = 347 (Element ) body.appendChild(document.createElement("script")); 348 script.setAttribute("id", JavascriptContext.DYNAMIC_CODE_ID); 349 script.setAttribute("language", "javascript"); 350 String calls = JavascriptContext.getJavascriptCalls(context); 351 script.appendChild(document.createTextNode(calls)); 352 353 Map session = context.getExternalContext().getSessionMap(); 354 ElementController.from(session).addInto(body); 355 356 String sessionIDScript = "window.session='" + context.getIceFacesId() + "'; "; 357 String configurationScript = 358 "window.configuration = {" + 359 "synchronous: " + configuration.getAttribute("synchronousUpdate", "false") + "," + 360 "redirectURI: " + configuration.getAttribute("connectionLostRedirectURI", "null") + "," + 361 "connection: {" + 362 "context: '" + context.getApplication().getViewHandler().getResourceURL(context, "/") + "'," + 363 "timeout: " + configuration.getAttributeAsLong("connectionTimeout", 30000) + "," + 364 "heartbeat: {" + 365 "interval: " + configuration.getAttributeAsLong("heartbeatInterval", 20000) + "," + 366 "timeout: " + configuration.getAttributeAsLong("heartbeatTimeout", 3000) + "," + 367 "retries: " + configuration.getAttributeAsLong("heartbeatRetries", 3) + 368 "}" + 369 "}" + 370 "};"; 371 372 Element configurationElement = (Element ) body.appendChild(document.createElement("script")); 373 configurationElement.setAttribute("language", "javascript"); 374 configurationElement.appendChild(document.createTextNode(sessionIDScript + configurationScript)); 375 body.appendChild(configurationElement); 376 } 377 378 private void enhanceHead(Element head) { 379 ViewHandler handler = context.getApplication().getViewHandler(); 380 head.setAttribute("id", "head"); 382 Element meta = 383 (Element ) head.appendChild(document.createElement("meta")); 384 meta.setAttribute("name", "icefaces"); 385 meta.setAttribute("content", "Rendered by ICEFaces D2D"); 386 387 Element noscript = 388 (Element ) head.appendChild(document.createElement("noscript")); 389 Element noscriptMeta = 390 (Element ) noscript.appendChild(document.createElement("meta")); 391 noscriptMeta.setAttribute("http-equiv", "refresh"); 392 noscriptMeta 393 .setAttribute("content", "0;url=" + handler.getResourceURL(context, "/xmlhttp/javascript-blocked")); 394 395 Collection libs = new ArrayList (); 397 if (context.getExternalContext().getInitParameter(D2DViewHandler.INCLUDE_OPEN_AJAX_HUB) != null) { 398 libs.add("/xmlhttp/openajax.js"); 399 } 400 libs.add("/xmlhttp" + StartupTime.getStartupInc() + "icefaces-d2d.js"); 401 libs.add("/xmlhttp" + StartupTime.getStartupInc() + "ice-extras.js"); 403 if (context.getExternalContext().getRequestMap().get(Constants.INC_SERVLET_PATH) == null) { 404 String [] componentLibs = JavascriptContext.getIncludedLibs(context); 405 for (int i = 0; i < componentLibs.length; i++) { 406 String componentLib = componentLibs[i]; 407 if (!libs.contains(componentLib)) { 408 libs.add(componentLib); 409 } 410 } 411 } 412 413 Iterator iterator = libs.iterator(); 414 while (iterator.hasNext()) { 415 String lib = (String ) iterator.next(); 416 Element script = (Element ) head 417 .appendChild(document.createElement("script")); 418 script.setAttribute("language", "javascript"); 419 script.setAttribute("src", handler.getResourceURL(context, lib)); 420 } 421 422 String sessionIdentifier = context.getIceFacesId(); 423 Element viewAndSessionScript = (Element ) head.appendChild(document.createElement("script")); 424 viewAndSessionScript.setAttribute("language", "javascript"); 425 viewAndSessionScript.appendChild(document.createTextNode( 426 "window.session = '" + sessionIdentifier + "';" 427 )); 428 } 429 430 private Element fixHtml() { 431 Element root = document.getDocumentElement(); 432 Element html = document.createElement("html"); 433 document.replaceChild(html, root); 434 html.appendChild(root); 435 436 return html; 437 } 438 439 private Element fixBody() { 440 Element html = document.getDocumentElement(); 441 Element body = document.createElement("body"); 442 NodeList children = html.getChildNodes(); 443 int length = children.getLength(); 444 Node [] nodes = new Node [length]; 445 for (int i = 0; i < nodes.length; i++) nodes[i] = children.item(i); 447 for (int i = 0; i < nodes.length; i++) { 448 Node node = nodes[i]; 449 if (!(node instanceof Element && 450 "head".equals(((Element ) node).getTagName()))) 451 body.appendChild(node); 452 } 453 html.appendChild(body); 454 455 return body; 456 } 457 458 private Element fixHead() { 459 Element html = document.getDocumentElement(); 460 Element head = document.createElement("head"); 461 html.insertBefore(head, html.getFirstChild()); 462 463 return head; 464 } 465 466 472 protected void setCursorParent(Node cursorParent) { 473 this.cursor = cursorParent; 474 } 475 476 public static boolean isStreamWriting() { 477 return isStreamWritingFlag; 478 } 479 480 481 } 482 | Popular Tags |