/* * Copyright 2011-2012 Blazebit */ package com.blazebit.blazefaces.util; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.faces.FacesException; import javax.faces.application.Application; import javax.faces.application.FacesMessage; import javax.faces.application.ProjectStage; import javax.faces.application.Resource; import javax.faces.component.UIComponent; import javax.faces.component.html.HtmlMessages; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.context.ResponseStream; import javax.faces.context.ResponseWriter; import javax.faces.render.Renderer; import org.owasp.validator.html.Policy; import com.blazebit.blazefaces.context.BlazeEncoder; import com.blazebit.blazefaces.context.BlazeResponseStream; import com.blazebit.blazefaces.context.BlazeResponseWriter; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Christian Beikov */ public class RendererUtils { private static final Logger log = Logger.getLogger(RendererUtils.class.getName()); private static final Map<String, String> cssMap = new HashMap<String, String>(); public static final String BODY_BOTTOM_SCRIPT_KEY = "com.blazebit.blazefaces.BODY_BOTTOM_SCRIPT_KEY"; static { cssMap.put("rel", "stylesheet"); } public static void encodeCss(FacesContext context, String library, String resource) throws IOException { encodeResource(context, library, resource, "link", "text/css", false, cssMap, null); } public static void encodeCss(FacesContext context, String library, String resource, String condition) throws IOException { encodeResource(context, library, resource, "link", "text/css", false, cssMap, condition); } public static void encodeExternalCss(FacesContext context, String href) throws IOException { encodeExternalResource(context, href, "link", "text/css", false, cssMap, null); } public static void encodeExternalCss(FacesContext context, String href, String condition) throws IOException { encodeExternalResource(context, href, "link", "text/css", false, cssMap, condition); } public static void encodeScript(FacesContext context, String library, String resource) throws IOException { encodeResource(context, library, resource, "script", "text/javascript", true, null, null); } public static void encodeScript(FacesContext context, String library, String resource, String condition) throws IOException { encodeResource(context, library, resource, "script", "text/javascript", true, null, condition); } public static void encodeExternalScript(FacesContext context, String src) throws IOException { encodeExternalResource(context, src, "script", "text/javascript", true, null, null); } public static void encodeExternalScript(FacesContext context, String src, String condition) throws IOException { encodeExternalResource(context, src, "script", "text/javascript", true, null, condition); } public static Policy getPolicy() { try { return Policy.getInstance(RendererUtils.class.getClassLoader().getResource("META-INF/antisamy-tinymce-1.4.4.xml")); } catch (Exception ex) { throw new RuntimeException(ex); } } public static void encodeAttribute(ResponseWriter writer, String attribute, Object value, String defaultValue) throws IOException { encodeAttribute(writer, attribute, value, defaultValue, null); } public static void encodeAttribute(ResponseWriter writer, String attribute, Object value, String defaultValue, String property) throws IOException { if (value == null) { if (defaultValue != null) { writer.writeAttribute(attribute, defaultValue, property); } return; } writer.writeAttribute(attribute, value, property); } public static void encodeBooleanAttribute(ResponseWriter writer, String attribute, Boolean value, boolean defaultValue) throws IOException { encodeBooleanAttribute(writer, attribute, value, defaultValue, null); } public static void encodeBooleanAttribute(ResponseWriter writer, String attribute, Boolean value, boolean defaultValue, String property) throws IOException { if (value == null) { if (defaultValue) { writer.writeAttribute(attribute, attribute, property); } return; } if(value) { writer.writeAttribute(attribute, attribute, property); } } public static String encodeToString(FacesContext facesContext, BlazeEncoder encoder) throws IOException { return encodeToString(facesContext, new HashMap<String, Object>(), encoder); } public static String encodeToString(FacesContext facesContext, Map<String, Object> attributes, BlazeEncoder encoder) throws IOException { if (attributes == null) { throw new NullPointerException(); } BlazeResponseStream responseStream = new BlazeResponseStream(); BlazeResponseWriter responseWriter = new BlazeResponseWriter(); ResponseStream rs = facesContext.getResponseStream(); ResponseWriter rw = facesContext.getResponseWriter(); facesContext.setResponseStream(responseStream); facesContext.setResponseWriter(rw.cloneWithWriter(responseWriter)); try { encoder.encode(facesContext, attributes); } finally { if (rs != null) { facesContext.setResponseStream(rs); } if (rw != null) { facesContext.setResponseWriter(rw); } } String content = responseStream.getContent(); if (content == null || content.isEmpty()) { content = responseWriter.getContent(); } return content.trim(); } public static String encodeComponent(FacesContext facesContext, UIComponent component) throws IOException { BlazeResponseStream responseStream = new BlazeResponseStream(); BlazeResponseWriter responseWriter = new BlazeResponseWriter(); ResponseStream rs = facesContext.getResponseStream(); ResponseWriter rw = facesContext.getResponseWriter(); facesContext.setResponseStream(responseStream); facesContext.setResponseWriter(rw.cloneWithWriter(responseWriter)); try { component.encodeAll(facesContext); } finally { if (rs != null) { facesContext.setResponseStream(rs); } if (rw != null) { facesContext.setResponseWriter(rw); } } String content = responseStream.getContent(); if (content == null || content.isEmpty()) { content = responseWriter.getContent(); } return content.trim(); } private static void encodeResource(FacesContext context, String library, String resource, String element, String type, boolean srcAttribute, Map<String, String> attributes, String condition) throws IOException { Resource res = context.getApplication().getResourceHandler().createResource(resource, library); if (res == null) { throw new FacesException("Cannot find \"" + resource + "\" resource of \"" + library + "\" library"); } else { encodeExternalResource(context, res.getRequestPath(), element, type, srcAttribute, attributes, condition); } } private static void encodeExternalResource(FacesContext context, String srcOrHref, String element, String type, boolean srcAttribute, Map<String, String> attributes, String condition) throws IOException { ResponseWriter writer = context.getResponseWriter(); if (condition != null) { writer.write("<!--[if "); writer.write(condition); writer.write("]>"); } writer.startElement(element, null); writer.writeAttribute("type", type, null); if (attributes != null) { for (Map.Entry<String, String> entry : attributes.entrySet()) { writer.writeAttribute(entry.getKey(), entry.getValue(), null); } } srcOrHref = context.getExternalContext().encodeResourceURL(srcOrHref); if (srcAttribute) { writer.writeURIAttribute("src", srcOrHref, null); } else { writer.writeURIAttribute("href", srcOrHref, null); } writer.endElement(element); if (condition != null) { writer.write("<![endif]-->"); } } @SuppressWarnings("unchecked") public static void addBodyBottomScript(FacesContext ctx, String script) { List<String> scripts = (List<String>) ctx.getAttributes().get(BODY_BOTTOM_SCRIPT_KEY); if (scripts == null) { scripts = new ArrayList<String>(); } scripts.add(script); ctx.getAttributes().put(BODY_BOTTOM_SCRIPT_KEY, scripts); } @SuppressWarnings("unchecked") public static List<String> getBodyBottomScripts(FacesContext ctx) { return (List<String>) ctx.getAttributes().get(BODY_BOTTOM_SCRIPT_KEY); } public static String getEventHandlerScript(FacesContext context, String targetClientId, String event, String code) { StringBuilder scriptBuilder = new StringBuilder(); scriptBuilder.append("BlazeJS.EventHandler.add('"); scriptBuilder.append(ComponentUtils.escapeJQueryId(targetClientId)); scriptBuilder.append("','"); scriptBuilder.append(event); scriptBuilder.append("',function(event){"); scriptBuilder.append(code); scriptBuilder.append("});"); return scriptBuilder.toString(); } public static void encodeSequentialEventHandler(FacesContext context, String targetClientId, String domEvent, String code){ StringBuilder scriptBuilder = new StringBuilder(); scriptBuilder.append("BlazeJS.EventHandler.add('"); scriptBuilder.append(ComponentUtils.escapeJQueryId(targetClientId)); scriptBuilder.append("','"); scriptBuilder.append(domEvent); scriptBuilder.append("',BlazeJS.EventHandler.create('sequential',[function(event){"); scriptBuilder.append(code); scriptBuilder.append("}]));"); RendererUtils.addBodyBottomScript(context, scriptBuilder.toString()); } /** * Originally taken from mojarra implementation */ public static void renderUnhandledMessages(FacesContext ctx) { if (ctx.isProjectStage(ProjectStage.Development)) { Application app = ctx.getApplication(); HtmlMessages messages = (HtmlMessages) app.createComponent(HtmlMessages.COMPONENT_TYPE); messages.setId("javax_faces_developmentstage_messages"); Renderer messagesRenderer = ctx.getRenderKit().getRenderer(HtmlMessages.COMPONENT_FAMILY, "javax.faces.Messages"); messages.setErrorStyle("Color: red"); messages.setWarnStyle("Color: orange"); messages.setInfoStyle("Color: blue"); messages.setFatalStyle("Color: red"); messages.setTooltip(true); messages.setTitle("Project Stage[Development]: Unhandled Messages"); messages.setRedisplay(false); try { messagesRenderer.encodeBegin(ctx, messages); messagesRenderer.encodeEnd(ctx, messages); } catch (IOException ioe) { log.log(Level.SEVERE, ioe.toString(), ioe); } } else { Iterator<String> clientIds = ctx.getClientIdsWithMessages(); int messageCount = 0; if (clientIds.hasNext()) { //Display each message possibly not displayed. StringBuilder builder = new StringBuilder(); while (clientIds.hasNext()) { String clientId = clientIds.next(); Iterator<FacesMessage> messages = ctx.getMessages(clientId); while (messages.hasNext()) { FacesMessage message = messages.next(); if (message.isRendered()) { continue; } messageCount++; builder.append("\n"); builder.append("sourceId=").append(clientId); builder.append("[severity=(").append(message.getSeverity()); builder.append("), summary=(").append(message.getSummary()); builder.append("), detail=(").append(message.getDetail()).append(")]"); } } if (messageCount > 0) { log.log(Level.INFO, "jsf.non_displayed_message", builder.toString()); } } } } public static boolean isPartialOrBehaviorAction(FacesContext context, String clientId) { if ((clientId == null) || (clientId.length() == 0)) { return false; } ExternalContext external = context.getExternalContext(); Map<String, String> params = external.getRequestParameterMap(); String source = params.get(Constants.PARTIAL_SOURCE_PARAM); if (!clientId.equals(source)) { return false; } // First check for a Behavior action event. String behaviorEvent = params.get(Constants.PARTIAL_BEHAVIOR_EVENT_PARAM); if (null != behaviorEvent) { return ("action".equals(behaviorEvent)); } // Not a Behavior-related request. Check for jsf.ajax.request() // request params. String partialEvent = params.get(Constants.PARTIAL_EVENT_PARAM); return ("click".equals(partialEvent)); } }