Java tutorial
/** * License Agreement. * * Rich Faces - Natural Ajax for Java Server Faces (JSF) * * Copyright (C) 2007 Exadel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * AbstractProgressBarRenderer.java Date created: 20.12.2007 * Last modified by: $Author$ * $Revision$ $Date$ */ package org.richfaces.renderkit; import java.io.IOException; import java.io.PrintWriter; import java.math.BigDecimal; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.faces.FactoryFinder; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.event.ActionEvent; import javax.faces.render.RenderKit; import javax.faces.render.RenderKitFactory; import javax.servlet.http.HttpServletResponse; import org.ajax4jsf.context.AjaxContext; import org.ajax4jsf.event.AjaxEvent; import org.ajax4jsf.javascript.JSFunction; import org.ajax4jsf.javascript.JSFunctionDefinition; import org.ajax4jsf.javascript.JSLiteral; import org.ajax4jsf.javascript.JSReference; import org.ajax4jsf.javascript.ScriptUtils; import org.ajax4jsf.renderkit.AjaxRendererUtils; import org.ajax4jsf.renderkit.ComponentVariables; import org.ajax4jsf.renderkit.ComponentsVariableResolver; import org.ajax4jsf.renderkit.RendererUtils.HTML; import org.ajax4jsf.resource.CountingOutputWriter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.richfaces.component.UIProgressBar; /** * Abstract progress bar renderer * * @author "Andrey Markavtsov" * */ public class AbstractProgressBarRenderer extends TemplateEncoderRendererBase { private static final Log log = LogFactory.getLog(AbstractProgressBarRenderer.class); /** Ajax function performing polling */ private static final String AJAX_POLL_FUNCTION = "A4J.AJAX.Poll"; /* * (non-Javadoc) * * @see org.ajax4jsf.renderkit.AjaxCommandRendererBase#doDecode(javax.faces.context.FacesContext, * javax.faces.component.UIComponent) */ @Override protected void doDecode(FacesContext facesContext, UIComponent uiComponent) { new AjaxEvent(uiComponent).queue(); //uiComponent.queueEvent(new ActionEvent(uiComponent)); } /** * Render progress state forced from javascript * * @param state * @param context * @param component * @throws IOException */ public void renderForcedState(String state, FacesContext context, UIComponent component) throws IOException { if ("initialState".equals(state)) { encodeInitialState(context, component, true); } else if ("progressState".equals(state)) { encodeProgressState(context, component, true); } else if ("completeState".equals(state)) { encodeCompletedState(context, component, true); } component.getAttributes().remove(UIProgressBar.FORCE_PERCENT_PARAM); } /** * Gets state forced from javascript * * @param component * @return */ public String getForcedState(FacesContext context, UIComponent component) { String forcedState = null; Map<String, String> params = context.getExternalContext().getRequestParameterMap(); if (params.containsKey(UIProgressBar.FORCE_PERCENT_PARAM)) { forcedState = params.get(UIProgressBar.FORCE_PERCENT_PARAM); } return forcedState; } /** * Renderes label markup * * @param context * @param component * @return */ public StringBuffer getMarkup(FacesContext context, UIComponent component) { StringBuffer result = new StringBuffer(); CountingOutputWriter customWriter = new CountingOutputWriter(); try { if (hasChildren(component)) { ResponseWriter writer = context.getResponseWriter(); String defaultRenderKitId = context.getApplication().getDefaultRenderKitId(); if (null == defaultRenderKitId) { defaultRenderKitId = RenderKitFactory.HTML_BASIC_RENDER_KIT; } RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder .getFactory(FactoryFinder.RENDER_KIT_FACTORY); RenderKit renderKit = renderKitFactory.getRenderKit(context, defaultRenderKitId); ResponseWriter responseWriter = renderKit.createResponseWriter(customWriter, null, "UTF-8"); context.setResponseWriter(responseWriter); writeScriptBody(context, component, true); result = customWriter.getContent(); if (writer != null) { context.setResponseWriter(writer); } else { HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse(); PrintWriter wr = response.getWriter(); if (wr != null) { context.setResponseWriter(renderKit.createResponseWriter(wr, null, "UTF-8")); } } } else { writeScriptBody(customWriter, (String) component.getAttributes().get("label")); result = customWriter.getContent(); } } catch (Exception e) { log.error("Error occurred during rendering of progress bar label. It switched to empty string", e); } return result; } /** * Methods encodes AJAX script for polling * * @param context - * faces context * @param component - * component instance * @throws IOException - * IOException */ public void encodePollScript(FacesContext context, UIComponent component) throws IOException { ResponseWriter writer = context.getResponseWriter(); UIProgressBar progressBar = (UIProgressBar) component; String clientId = component.getClientId(context); StringBuffer pollScript = new StringBuffer("\n"); StringBuffer script = new StringBuffer("\n"); if (isAjaxMode(component) && progressBar.isEnabled()) { JSFunction function = AjaxRendererUtils.buildAjaxFunction(component, context, AJAX_POLL_FUNCTION); function.addParameter(new JSReference("$('" + clientId + "').component.options")); function.appendScript(script); pollScript.append(script); } else { pollScript.append(getStopPollScript(clientId)); } pollScript.append(";\n"); writer.writeText(pollScript.toString(), null); } /** * Encodes script for state rendering in client mode * * @param context * @param component * @param state * @throws IOException */ public void encodeRenderStateScript(FacesContext context, UIComponent component, String state) throws IOException { ResponseWriter writer = context.getResponseWriter(); StringBuffer script = new StringBuffer("\n"); script.append("$('" + component.getClientId(context) + "').component.renderState('").append(state) .append("');"); writer.write(script.toString()); } /** * Encodes script for label rendering in client * * @param context * @param component * @throws IOException */ public void encodeLabelScript(FacesContext context, UIComponent component) throws IOException { ResponseWriter writer = context.getResponseWriter(); StringBuffer script = new StringBuffer("\n"); script.append("$('" + component.getClientId(context) + "').component.renderLabel(") .append(getMarkup(context, component)).append(",null);\n"); writer.append(script.toString()); } /** * Encode initial javascript * * @param context * @param component * @throws IOException */ public void encodeInitialScript(FacesContext context, UIComponent component, String state) throws IOException { ResponseWriter writer = context.getResponseWriter(); UIProgressBar progressBar = (UIProgressBar) component; ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component); StringBuffer script = new StringBuffer(); String clientId = component.getClientId(context); String containerId = ((UIComponent) AjaxRendererUtils.findAjaxContainer(context, component)) .getClientId(context); String mode = (String) component.getAttributes().get("mode"); UIComponent form = AjaxRendererUtils.getNestingForm(component); String formId = ""; if (form != null) { formId = form.getClientId(context); } else if ("ajax".equals(mode)) { // Ignore form absent. It can be rendered by forcing from any // component // throw new FaceletException("Progress bar component in ajax mode // should be placed inside the form"); } Number minValue = getNumber(component.getAttributes().get("minValue")); Number maxValue = getNumber(component.getAttributes().get("maxValue")); Number value = (Number) variables.getVariable("value"); StringBuffer markup = getMarkup(context, component); script.append("new ProgressBar('").append(clientId).append("','") // id .append(containerId).append("','") // containerId .append(formId).append("','") // formId .append(mode).append("',") // mode .append(minValue).append(",") // min value .append(maxValue).append(","); // max value script.append(getContext(component)); // context script.append(","); script.append(markup != null ? new JSLiteral(markup.toString()) : JSReference.NULL); // markup script.append(","); script.append(ScriptUtils.toScript(buildAjaxOptions(clientId, // options progressBar, context))); String progressVar = (String) component.getAttributes().get("progressVar"); if (progressVar != null) { script.append(",'"); script.append(progressVar); // progress var script.append("','"); } else { script.append(",null,'"); } script.append(state); script.append("',"); script.append(value.toString()); script.append(")\n;"); writer.write(script.toString()); } /** * Creates options map for AJAX requests * * @param clientId * @param progressBar * @param context * @return */ private Map buildAjaxOptions(String clientId, UIProgressBar progressBar, FacesContext context) { Map options = AjaxRendererUtils.buildEventOptions(context, progressBar); Integer interval = new Integer(progressBar.getInterval()); options.put("pollId", clientId); options.put("pollinterval", interval); JSFunctionDefinition onsubmit = getUtils().getAsEventHandler(context, progressBar, "onsubmit", ""); if (onsubmit != null) { options.put("onsubmit", onsubmit); } if (progressBar.getAttributes().containsKey("ignoreDupResponses")) { options.put("ignoreDupResponses", progressBar.getAttributes().get("ignoreDupResponses")); } Map parameters = (Map) options.get("parameters"); parameters.put("percent", "percent"); parameters.put(clientId, clientId); parameters.put("ajaxSingle", clientId); // options.put("onbeforedomupdate", getOnComplete(clientId, progressBar, // context)); return options; } /** * Check if component mode is AJAX * * @param component * @return */ private boolean isAjaxMode(UIComponent component) { String mode = (String) component.getAttributes().get("mode"); return "ajax".equalsIgnoreCase(mode); } /** * Encodes client mode * * @param context * @param component * @param value * @param min * @param max * @throws IOException */ public void encodeClientMode(FacesContext context, UIComponent component, Number value, Number min, Number max) throws IOException { ResponseWriter writer = context.getResponseWriter(); String clientId = component.getClientId(context); String state = (value.doubleValue() <= min.doubleValue()) ? "initialState" : ((value.doubleValue() >= max.doubleValue()) ? "completeState" : "progressState"); writer.startElement(HTML.DIV_ELEM, component); writer.writeAttribute(HTML.id_ATTRIBUTE, clientId, null); encodeInitialState(context, component, false); encodeProgressState(context, component, false); encodeCompletedState(context, component, false); startScript(writer, component); encodeInitialScript(context, component, state); encodeLabelScript(context, component); encodeRenderStateScript(context, component, state); endScript(writer, component); writer.endElement(HTML.DIV_ELEM); } /** * Methods encodes start facet of progress bar component * * @param context - * faces context * @param component - * component instance * @throws IOException - * IOException */ public void encodeInitialState(FacesContext context, UIComponent component, boolean isAjaxMode) throws IOException { String clientId = component.getClientId(context); String initialClass = (String) component.getAttributes().get("initialClass"); String style = (String) component.getAttributes().get("style"); if (null == style) style = ""; ResponseWriter writer = context.getResponseWriter(); writer.startElement(HTML.DIV_ELEM, component); getUtils().writeAttribute(writer, HTML.class_ATTRIBUTE, initialClass); getUtils().writeAttribute(writer, "style", style + (!isAjaxMode ? "display: none" : "")); writer.writeAttribute(HTML.id_ATTRIBUTE, (isAjaxMode) ? clientId : clientId + ":initialState", null); UIComponent initial = component.getFacet("initial"); if (initial != null) { renderChild(context, initial); } if (isAjaxMode) { startScript(writer, component); encodeInitialScript(context, component, "initialState"); encodePollScript(context, component); endScript(writer, component); } writer.endElement(HTML.DIV_ELEM); } /** * Encodes progress state of the component * * @param context * @param component * @throws IOException */ public void encodeProgressState(FacesContext context, UIComponent component, boolean isAjaxMode) throws IOException { ResponseWriter writer = context.getResponseWriter(); ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component); String clientId = component.getClientId(context); String styleClass = (String) variables.getVariable("styleClass"); boolean isSimple = isSimpleMarkup(component); String style = (String) component.getAttributes().get("style"); if (null == style) style = ""; String shellClass = (!isSimple) ? "rich-progress-bar-shell-dig " : "rich-progress-bar-shell "; writer.startElement("div", component); getUtils().writeAttribute(writer, "class", "rich-progress-bar-block rich-progress-bar-width " + shellClass + (styleClass != null ? styleClass : "")); getUtils().writeAttribute(writer, HTML.id_ATTRIBUTE, (isAjaxMode) ? clientId : clientId + ":progressState"); getUtils().writeAttribute(writer, "style", style + (!isAjaxMode ? "display: none" : "")); getUtils().encodePassThruWithExclusions(context, component, "onsubmit"); encodeProgressBar(context, component, isSimple); if (isAjaxMode) { startScript(writer, component); encodeInitialScript(context, component, "progressState"); encodeLabelScript(context, component); encodePollScript(context, component); endScript(writer, component); } writer.endElement("div"); } /** * Encodes html of component * * @param context - * faces context * @param component - * component instance * @throws IOException */ public void encodeProgressBar(FacesContext context, UIComponent component, boolean isSimple) throws IOException { ResponseWriter writer = context.getResponseWriter(); String clientId = component.getClientId(context); ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component); Number value = (Number) variables.getVariable("percent"); String width = String.valueOf(value.intValue()); String style = (String) component.getAttributes().get("style"); if (null == style) style = ""; String completeClass = (String) component.getAttributes().get("completeClass"); String remainClass = (String) component.getAttributes().get("remainClass"); if (!isSimple) { // <div class='remainClass' id='clientId:remain' // style='style'></div> writer.startElement("div", component); getUtils().writeAttribute(writer, "class", "rich-progress-bar-width rich-progress-bar-remained rich-progress-bar-padding " + remainClass); getUtils().writeAttribute(writer, "id", clientId + ":remain"); getUtils().writeAttribute(writer, "style", style); writer.endElement("div"); // <div class='rich-progress-bar-uploaded-dig' id='clientId:upload' // style='style'> writer.startElement("div", component); getUtils().writeAttribute(writer, "class", "rich-progress-bar-uploaded-dig"); getUtils().writeAttribute(writer, "id", clientId + ":upload"); getUtils().writeAttribute(writer, "style", (style != null ? style + ";" : "") + " width: " + width + "%;"); // <div class='completeClass' id='clientId:complete' // style='style'></div> writer.startElement("div", component); getUtils().writeAttribute(writer, "class", "rich-progress-bar-height-dig rich-progress-bar-width rich-progress-bar-completed rich-progress-bar-padding " + completeClass); getUtils().writeAttribute(writer, "id", clientId + ":complete"); getUtils().writeAttribute(writer, "style", style); writer.endElement("div"); // </div> writer.endElement("div"); } else { writer.startElement("div", component); getUtils().writeAttribute(writer, "class", "rich-progress-bar-height rich-progress-bar-uploaded " + completeClass); getUtils().writeAttribute(writer, "id", clientId + ":upload"); getUtils().writeAttribute(writer, "style", (style != null ? style + ";" : "") + " width: " + width + "%;"); writer.write(" "); writer.endElement("div"); } } /** * Returns parameters attr * * @param component * @param renderer * @param percent * @return */ public String getParameters(UIComponent component) { String parameters = (String) component.getAttributes().get("parameters"); return parameters; } /** * Writes start script element * * @param writer * @param component * @throws IOException */ private void startScript(ResponseWriter writer, UIComponent component) throws IOException { writer.startElement(HTML.SPAN_ELEM, component); writer.writeAttribute(HTML.style_ATTRIBUTE, "display: none;", null); writer.startElement(HTML.SCRIPT_ELEM, component); writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null); } /** * Writes end script element * * @param writer * @param component * @throws IOException */ private void endScript(ResponseWriter writer, UIComponent component) throws IOException { writer.endElement(HTML.SCRIPT_ELEM); writer.endElement(HTML.SPAN_ELEM); } /** * Returns context for macrosubstitution * * @param component * @return */ private JSLiteral getContext(UIComponent component) { StringBuffer buffer = new StringBuffer(); String parameters = getParameters(component); JSLiteral literal = null; if (parameters != null) { buffer.append("{").append(parameters).append("}"); literal = new JSLiteral(buffer.toString()); } else { literal = new JSLiteral("null"); } return literal; } /** * Return true if component has children components * * @param component * @return */ private boolean hasChildren(UIComponent component) { return (component.getChildCount() != 0); } /** * Returns true if markup should rendered as simple 2 divs * * @param component * @return */ public boolean isSimpleMarkup(UIComponent component) { if (hasChildren(component)) { return false; } else { if (component.getAttributes().get("label") != null) { return false; } } return true; } /** * Methods encodes finish facet of progress bar component * * @param context - * faces context * @param component - * component instance * @throws IOException - * IOException */ public void encodeCompletedState(FacesContext context, UIComponent component, boolean isAjaxMode) throws IOException { String clientId = component.getClientId(context); String finishClass = (String) component.getAttributes().get("finishClass"); String style = (String) component.getAttributes().get("style"); if (null == style) style = ""; ResponseWriter writer = context.getResponseWriter(); writer.startElement(HTML.DIV_ELEM, component); writer.writeAttribute(HTML.id_ATTRIBUTE, (isAjaxMode) ? clientId : clientId + ":completeState", null); getUtils().writeAttribute(writer, HTML.class_ATTRIBUTE, finishClass); getUtils().writeAttribute(writer, "style", style + (!isAjaxMode ? "display: none" : "")); UIComponent completed = component.getFacet("complete"); if (completed != null) { renderChild(context, completed); } if (isAjaxMode) { startScript(writer, component); encodeInitialScript(context, component, "completeState"); writer.write(getStopPollScript(clientId).toString()); endScript(writer, component); } writer.endElement(HTML.DIV_ELEM); } /** * Converts value attr to number value * * @param v - * value attr * @return result */ public Number getNumber(Object v) { Number result = null; if (v != null) { try { if (v instanceof String) { result = Double.parseDouble((String) v); } else { Number n = (Number) v; if (n instanceof BigDecimal || n instanceof Double || n instanceof Float) { result = n.floatValue(); } else if (n instanceof Integer || n instanceof Long) { result = n.longValue(); } } } catch (Exception e) { // no action } return result; } return new Integer(0); } /** * Calculates percent value according to min & max value * * @param value * @param minValue * @param maxValue * @return */ public Number calculatePercent(Number value, Number minValue, Number maxValue) { if (minValue.doubleValue() < value.doubleValue() && value.doubleValue() < maxValue.doubleValue()) { return (Number) ((value.doubleValue() - minValue.doubleValue()) * 100.0 / (maxValue.doubleValue() - minValue.doubleValue())); } else if (value.doubleValue() <= minValue.doubleValue()) { return 0; } else if (value.doubleValue() >= maxValue.doubleValue()) { return 100; } return 0; } /** * Returns JS script to stop polling * * @param clientId * @return */ private StringBuffer getStopPollScript(String clientId) { StringBuffer buffer = new StringBuffer(); buffer.append("A4J.AJAX.StopPoll('").append(clientId).append("');\n"); return buffer; } /* * (non-Javadoc) * * @see org.ajax4jsf.renderkit.RendererBase#getComponentClass() */ protected Class getComponentClass() { // only poll component is allowed. return UIProgressBar.class; } /* * (non-Javadoc) * * @see org.richfaces.renderkit.TemplateEncoderRendererBase#encodeChildren(javax.faces.context.FacesContext, * javax.faces.component.UIComponent) */ @Override public void encodeChildren(FacesContext context, UIComponent component) throws IOException { ; // We should not render children } /* * (non-Javadoc) * * @see org.ajax4jsf.renderkit.RendererBase#doEncodeChildren(javax.faces.context.ResponseWriter, * javax.faces.context.FacesContext, javax.faces.component.UIComponent) */ @Override public void doEncodeChildren(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { ; // We should not render children } }