1 33 34 package com.icesoft.faces.facelets; 35 36 import com.icesoft.faces.application.D2DViewHandler; 37 import com.icesoft.faces.context.BridgeFacesContext; 38 import com.sun.facelets.Facelet; 39 import com.sun.facelets.FaceletFactory; 40 import com.sun.facelets.compiler.Compiler; 41 import com.sun.facelets.compiler.SAXCompiler; 42 import com.sun.facelets.compiler.TagLibraryConfig; 43 import com.sun.facelets.impl.DefaultFaceletFactory; 44 import com.sun.facelets.impl.DefaultResourceResolver; 45 import com.sun.facelets.impl.ResourceResolver; 46 import com.sun.facelets.tag.TagDecorator; 47 import com.sun.facelets.tag.TagLibrary; 48 import com.sun.facelets.tag.jsf.ComponentSupport; 49 import org.apache.commons.logging.Log; 50 import org.apache.commons.logging.LogFactory; 51 52 import javax.faces.FacesException; 53 import javax.faces.application.ViewHandler; 54 import javax.faces.component.UIComponent; 55 import javax.faces.component.UIViewRoot; 56 import javax.faces.context.ExternalContext; 57 import javax.faces.context.FacesContext; 58 import javax.faces.context.ResponseWriter; 59 import java.io.FileNotFoundException ; 60 import java.io.IOException ; 61 import java.net.URL ; 62 import java.util.HashMap ; 63 import java.util.Iterator ; 64 import java.util.ArrayList ; 65 66 71 public class D2DFaceletViewHandler extends D2DViewHandler { 72 73 public final static long DEFAULT_REFRESH_PERIOD = 2; 75 public final static String PARAM_REFRESH_PERIOD = "facelets.REFRESH_PERIOD"; 76 public final static String PARAM_SKIP_COMMENTS = "facelets.SKIP_COMMENTS"; 77 public final static String PARAM_VIEW_MAPPINGS = "facelets.VIEW_MAPPINGS"; 78 public final static String PARAM_LIBRARIES = "facelets.LIBRARIES"; 79 public final static String PARAM_DECORATORS = "facelets.DECORATORS"; 80 public final static String PARAM_RESOURCE_RESOLVER = 81 "facelets.RESOURCE_RESOLVER"; 82 83 private static Log log = LogFactory.getLog(D2DFaceletViewHandler.class); 85 86 protected FaceletFactory faceletFactory; 87 88 public D2DFaceletViewHandler() { 89 } 90 91 public D2DFaceletViewHandler(ViewHandler delegate) { 92 super(delegate); 93 } 94 95 protected void faceletInitialize() { 96 try { 97 if (faceletFactory == null) { 98 com.sun.facelets.compiler.Compiler c = new SAXCompiler(); 99 initializeCompiler(c); 100 faceletFactory = createFaceletFactory(c); 101 } 102 } 103 catch (Throwable t) { 104 if (log.isErrorEnabled()) { 105 log.error("Failed initializing facelet instance", t); 106 } 107 } 108 } 109 110 111 protected void initializeCompiler(Compiler c) { 112 FacesContext ctx = FacesContext.getCurrentInstance(); 113 ExternalContext ext = ctx.getExternalContext(); 114 115 c.addTagLibrary(new UIXhtmlTagLibrary()); 117 c.addTagDecorator(new UIXhtmlTagDecorator()); 118 119 c.addTagDecorator(new JspTagDetector()); 120 121 String paramLibraries = ext.getInitParameter(PARAM_LIBRARIES); 123 if (paramLibraries != null) { 124 paramLibraries = paramLibraries.trim(); 125 String [] paramLibrariesArray = paramLibraries.split(";"); 126 for (int i = 0; i < paramLibrariesArray.length; i++) { 127 try { 128 URL url = ext.getResource(paramLibrariesArray[i]); 129 if (url == null) { 130 throw new FileNotFoundException (paramLibrariesArray[i]); 131 } 132 TagLibrary tagLibrary = TagLibraryConfig.create(url); 133 c.addTagLibrary(tagLibrary); 134 if (log.isDebugEnabled()) { 135 log.debug("Loaded library: " + paramLibrariesArray[i]); 136 } 137 } 138 catch (IOException e) { 139 if (log.isWarnEnabled()) { 140 log.warn("Problem loading library: " + paramLibrariesArray[i], e); 141 } 142 } 143 } 144 } 145 146 String paramDecorators = ext.getInitParameter(PARAM_DECORATORS); 148 if (paramDecorators != null) { 149 paramDecorators = paramDecorators.trim(); 150 String [] paramDecoratorsArray = paramDecorators.split(";"); 151 for (int i = 0; i < paramDecoratorsArray.length; i++) { 152 try { 153 Class tagDecoratorClass = Class.forName(paramDecoratorsArray[i]); 154 TagDecorator tagDecorator = (TagDecorator) 155 tagDecoratorClass.newInstance(); 156 c.addTagDecorator(tagDecorator); 157 if (log.isDebugEnabled()) { 158 log.debug("Loaded decorator: " + 159 paramDecoratorsArray[i]); 160 } 161 } 162 catch (Exception e) { 163 if (log.isWarnEnabled()) { 164 log.warn("Problem loading decorator: " + 165 paramDecoratorsArray[i], e); 166 } 167 } 168 } 169 } 170 171 String paramSkipComments = 176 ext.getInitParameter(PARAM_SKIP_COMMENTS); 177 if (paramSkipComments != null && paramSkipComments.equals("false")) { 180 c.setTrimmingComments(false); 181 } 182 183 c.setTrimmingWhitespace(true); 187 c.setTrimmingComments(true); 188 c.setTrimmingXmlDeclarations(true); 189 c.setTrimmingDoctypeDeclarations(true); 190 } 191 192 protected FaceletFactory createFaceletFactory(Compiler c) { 193 long refreshPeriod = DEFAULT_REFRESH_PERIOD; 194 FacesContext ctx = FacesContext.getCurrentInstance(); 195 String paramRefreshPeriod = ctx.getExternalContext().getInitParameter( 196 PARAM_REFRESH_PERIOD); 197 if (paramRefreshPeriod != null && paramRefreshPeriod.length() > 0) { 198 try { 199 refreshPeriod = Long.parseLong(paramRefreshPeriod); 200 } 201 catch (NumberFormatException nfe) { 202 if (log.isWarnEnabled()) { 203 log.warn("Problem parsing refresh period: " + 204 paramRefreshPeriod, nfe); 205 } 206 } 207 } 208 209 ResourceResolver resourceResolver = null; 210 String paramResourceResolver = ctx.getExternalContext().getInitParameter( 211 PARAM_RESOURCE_RESOLVER); 212 if (paramResourceResolver != null && paramResourceResolver.length() > 0) { 213 try { 214 Class resourceResolverClass = Class.forName( 215 paramResourceResolver, 216 true, 217 Thread.currentThread().getContextClassLoader()); 218 resourceResolver = (ResourceResolver) 219 resourceResolverClass.newInstance(); 220 } 221 catch (Exception e) { 222 throw new FacesException("Problem initializing ResourceResolver: " + 223 paramResourceResolver, e); 224 } 225 } 226 if (resourceResolver == null) 227 resourceResolver = new DefaultResourceResolver(); 228 229 resourceResolver = preChainResourceResolver(resourceResolver); 230 231 return new DefaultFaceletFactory(c, resourceResolver, refreshPeriod); 232 } 233 234 245 protected ResourceResolver preChainResourceResolver(ResourceResolver after) { 246 return after; 247 } 248 249 250 protected String getRenderedViewId(FacesContext context, String actionId) { 251 ExternalContext extCtx = context.getExternalContext(); 252 String viewId = actionId; 253 if (extCtx.getRequestPathInfo() == null) { 254 String facesSuffix = actionId.substring(actionId.lastIndexOf('.')); 255 String viewSuffix = context.getExternalContext() 256 .getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME); 257 viewId = actionId.replaceFirst(facesSuffix, viewSuffix); 258 } 259 return viewId; 260 } 261 262 263 protected void renderResponse(FacesContext facesContext) throws IOException { 264 if (log.isTraceEnabled()) { 265 log.trace("renderResponse(FC)"); 266 } 267 BridgeFacesContext context = (BridgeFacesContext) facesContext; 268 try { 269 clearSession(context); 270 ResponseWriter responseWriter = context.createAndSetResponseWriter(); 271 272 UIViewRoot viewToRender = context.getViewRoot(); 273 String renderedViewId = 274 getRenderedViewId(context, viewToRender.getViewId()); 275 viewToRender.setViewId(renderedViewId); 276 if (viewToRender.getId() == null) { 277 viewToRender.setId(viewToRender.createUniqueId()); 278 } 279 280 ComponentSupport.removeTransient(viewToRender); 281 282 faceletInitialize(); 284 Facelet f = null; 285 FaceletFactory.setInstance(faceletFactory); 286 try { 287 f = faceletFactory.getFacelet(viewToRender.getViewId()); 288 } finally { 289 FaceletFactory.setInstance(null); 290 } 291 292 f.apply(context, viewToRender); 294 295 verifyUniqueComponentIds(context, viewToRender); 296 297 tracePrintComponentTree(context); 299 300 responseWriter.startDocument(); 301 renderResponse(context, viewToRender); 302 responseWriter.endDocument(); 303 } 304 catch (Exception e) { 305 if (log.isErrorEnabled()) { 306 log.error("Problem in renderResponse: " + e.getMessage(), e); 307 } 308 throw new FacesException("Problem in renderResponse: " + e.getMessage(), e); 309 } 310 } 311 312 protected static void removeTransient(UIComponent c) { 313 UIComponent d, e; 314 if (c.getChildCount() > 0) { 315 for (Iterator itr = c.getChildren().iterator(); itr.hasNext();) { 316 d = (UIComponent) itr.next(); 317 if (d.getFacets().size() > 0) { 318 for (Iterator jtr = d.getFacets().values().iterator(); jtr 319 .hasNext();) { 320 e = (UIComponent) jtr.next(); 321 if (e.isTransient()) { 322 jtr.remove(); 323 } else { 324 D2DFaceletViewHandler.removeTransient(e); 325 } 326 } 327 } 328 if (d.isTransient()) { 329 itr.remove(); 330 } else { 331 D2DFaceletViewHandler.removeTransient(d); 332 } 333 } 334 } 335 if (c.getFacets().size() > 0) { 336 for (Iterator itr = c.getFacets().values().iterator(); itr 337 .hasNext();) { 338 d = (UIComponent) itr.next(); 339 if (d.isTransient()) { 340 itr.remove(); 341 } else { 342 D2DFaceletViewHandler.removeTransient(d); 343 } 344 } 345 } 346 } 347 348 359 protected static void verifyUniqueComponentIds( 360 FacesContext context, UIComponent comp) 361 { 362 if (!log.isDebugEnabled()) 363 return; 364 365 HashMap ids = new HashMap (512); 366 ArrayList duplicateIds = new ArrayList (256); 367 quicklyDetectDuplicateComponentIds(comp, ids, duplicateIds); 368 369 if(!duplicateIds.isEmpty()) { 370 HashMap duplicateIds2comps = new HashMap (512); 371 compileDuplicateComponentIds(comp, duplicateIds2comps, duplicateIds); 372 reportDuplicateComponentIds(context, duplicateIds2comps, duplicateIds); 373 } 374 } 375 376 388 private static void quicklyDetectDuplicateComponentIds( 389 UIComponent comp, HashMap ids, ArrayList duplicateIds) 390 { 391 String id = comp.getId(); 392 if (id == null) { 393 log.debug("UIComponent has null id: " + comp); 394 } else { 395 if (ids.containsKey(id)) { 396 if(!duplicateIds.contains(id)) 397 duplicateIds.add(id); 398 } else { 399 ids.put(id, id); 400 } 401 } 402 Iterator children = comp.getFacetsAndChildren(); 403 while (children.hasNext()) { 404 UIComponent child = (UIComponent) children.next(); 405 quicklyDetectDuplicateComponentIds(child, ids, duplicateIds); 406 } 407 } 408 409 421 private static void compileDuplicateComponentIds( 422 UIComponent comp, HashMap duplicateIds2comps, ArrayList duplicateIds) 423 { 424 String id = comp.getId(); 425 if (id != null && duplicateIds.contains(id)) { 426 ArrayList duplicateComps = (ArrayList ) duplicateIds2comps.get(id); 427 if(duplicateComps == null) { 428 duplicateComps = new ArrayList (); 429 duplicateIds2comps.put(id, duplicateComps); 430 } 431 duplicateComps.add(comp); 432 } 433 Iterator children = comp.getFacetsAndChildren(); 434 while (children.hasNext()) { 435 UIComponent child = (UIComponent) children.next(); 436 compileDuplicateComponentIds(child, duplicateIds2comps, duplicateIds); 437 } 438 } 439 440 451 private static void reportDuplicateComponentIds( 452 FacesContext context, HashMap duplicateIds2comps, ArrayList duplicateIds) 453 { 454 459 int numDuplicateIds = duplicateIds.size(); 460 log.debug("There were " + numDuplicateIds + " ids found which are duplicates, meaning that multiple UIComponents share that same id"); 461 for(int i = 0; i < numDuplicateIds; i++) { 462 String id = (String ) duplicateIds.get(i); 463 ArrayList duplicateComps = (ArrayList ) duplicateIds2comps.get(id); 464 StringBuffer sb = new StringBuffer (512); 465 sb.append("Duplicate id: "); 466 sb.append(id); 467 sb.append(". Number of UIComponents sharing that id: "); 468 sb.append(Integer.toString(duplicateComps.size())); 469 sb.append('.'); 470 for(int c = 0; c < duplicateComps.size(); c++) { 471 UIComponent comp = (UIComponent) duplicateComps.get(c); 472 sb.append("\n clientId: "); 473 sb.append(comp.getClientId(context)); 474 if(comp.isTransient()) 475 sb.append(". TRANSIENT"); 476 sb.append(". component: "); 477 sb.append(comp.toString()); 478 } 479 log.debug(sb.toString()); 480 } 481 } 482 } 483 | Popular Tags |