001// Generated by delombok at Sun Jul 30 17:21:56 UTC 2023
002package de.cuioss.test.jsf.mocks;
003
004import static de.cuioss.tools.string.MoreStrings.isEmpty;
005import java.io.IOException;
006import java.util.Map.Entry;
007import javax.faces.component.EditableValueHolder;
008import javax.faces.component.UIComponent;
009import javax.faces.component.UIInput;
010import javax.faces.component.UIOutcomeTarget;
011import javax.faces.component.UIOutput;
012import javax.faces.component.ValueHolder;
013import javax.faces.component.html.HtmlInputText;
014import javax.faces.component.html.HtmlOutcomeTargetLink;
015import javax.faces.component.html.HtmlOutputLink;
016import javax.faces.context.FacesContext;
017import javax.faces.render.Renderer;
018import de.cuioss.tools.property.PropertyHolder;
019// owolff: Not an issue because the is for tests
020/**
021 * Simple Mock renderer that is capable of rendering any element by using the
022 * simple-name of the given component. In addition it is capable of rendering
023 * the 'id'-attribute as 'id' and 'name' in case the component is of type
024 * {@link UIInput} or the attribute {@link UIComponent#getId()} is set, the
025 * 'styleClass' and 'style' attributes and reacts to the 'rendered'-attribute.
026 * It can be configured to use a certain tagname to be rendered by using
027 * {@link #CuiMockRenderer(String)}. Otherwise the simple-name of the component
028 * will be used.
029 *
030 * @author Oliver Wolff
031 */
032@SuppressWarnings("resource")
033public class CuiMockRenderer extends Renderer {
034    private static final String OUTCOME = "outcome";
035    private static final String TARGET = "target";
036    private static final String VALUE = "value";
037    private static final String STYLE_CLASS = "styleClass";
038    private static final String STYLE_ATTRIBUTE = "style";
039    private static final String TITLE = "title";
040    private static final String DISABLED = "disabled";
041    private final String tagName;
042
043    /**
044     * Default constructor resulting in the actual component to be used as tagname.
045     */
046    public CuiMockRenderer() {
047        this(null);
048    }
049
050    @Override
051    public void encodeBegin(final FacesContext context, final UIComponent component) throws IOException {
052        if (component.isRendered()) {
053            context.getResponseWriter().startElement(getTagName(component), component);
054            writeIdAndName(context, component);
055            handleInputText(context, component);
056            writeBasicAttributes(context, component);
057            if (component instanceof EditableValueHolder) {
058                var valueHolder = (ValueHolder) component;
059                context.getResponseWriter().writeAttribute(VALUE, valueHolder.getValue(), VALUE);
060            } else if (component instanceof UIOutcomeTarget) {
061                handleOutputTarget(context, component);
062            } else if (component instanceof HtmlOutputLink) {
063                handleHtmlOutputLink(context, component);
064            } else if (component instanceof UIOutput) {
065                handleUIOutput(context, component);
066            }
067            handleOutcomeTargetLink(context, component);
068        }
069    }
070
071    private void handleOutcomeTargetLink(final FacesContext context, final UIComponent component) throws IOException {
072        if (component instanceof HtmlOutcomeTargetLink) {
073            var output = (HtmlOutcomeTargetLink) component;
074            if (null != output.getTarget()) {
075                context.getResponseWriter().writeAttribute(TARGET, output.getTarget(), TARGET);
076            }
077        }
078    }
079
080    private void handleUIOutput(final FacesContext context, final UIComponent component) throws IOException {
081        var output = (UIOutput) component;
082        if (null != output.getValue()) {
083            context.getResponseWriter().writeText(output.getValue(), VALUE);
084        }
085    }
086
087    private void handleHtmlOutputLink(final FacesContext context, final UIComponent component) throws IOException {
088        var output = (HtmlOutputLink) component;
089        if (null != output.getTarget()) {
090            context.getResponseWriter().writeAttribute(TARGET, output.getTarget(), TARGET);
091        }
092        if (null != output.getValue()) {
093            context.getResponseWriter().writeAttribute(VALUE, output.getValue(), VALUE);
094        }
095    }
096
097    private void handleOutputTarget(final FacesContext context, final UIComponent component) throws IOException {
098        var output = (UIOutcomeTarget) component;
099        if (null != output.getOutcome()) {
100            context.getResponseWriter().writeAttribute(OUTCOME, output.getOutcome(), OUTCOME);
101        }
102        if (null != output.getValue()) {
103            context.getResponseWriter().writeAttribute(VALUE, output.getValue(), VALUE);
104        }
105    }
106
107    private void writeBasicAttributes(final FacesContext context, final UIComponent component) throws IOException {
108        writeAttributeIfPresent(context, component, STYLE_CLASS, "class");
109        writeAttributeIfPresent(context, component, STYLE_ATTRIBUTE, STYLE_ATTRIBUTE);
110        writeAttributeIfPresent(context, component, TITLE, TITLE);
111        for (Entry<String, Object> entry : component.getPassThroughAttributes(true).entrySet()) {
112            context.getResponseWriter().writeAttribute(entry.getKey(), entry.getValue(), null);
113        }
114    }
115
116    private void handleInputText(final FacesContext context, final UIComponent component) throws IOException {
117        if (component instanceof HtmlInputText) {
118            context.getResponseWriter().writeAttribute("type", "text", null);
119            if (((HtmlInputText) component).isDisabled()) {
120                context.getResponseWriter().writeAttribute(DISABLED, DISABLED, null);
121            }
122        }
123    }
124
125    private void writeIdAndName(final FacesContext context, final UIComponent component) throws IOException {
126        if (!isEmpty(component.getId()) || component instanceof UIInput) {
127            var id = component.getClientId();
128            context.getResponseWriter().writeAttribute("id", id, null);
129            context.getResponseWriter().writeAttribute("name", id, null);
130        }
131    }
132
133    private static void writeAttributeIfPresent(final FacesContext context, final UIComponent component, final String propertyName, final String attributeName) throws IOException {
134        var holder = PropertyHolder.from(component.getClass(), propertyName);
135        if (holder.isPresent() && holder.get().getReadWrite().isReadable()) {
136            var propertyValue = holder.get().readFrom(component);
137            if (null != propertyValue) {
138                context.getResponseWriter().writeAttribute(attributeName, propertyValue, null);
139            }
140        }
141    }
142
143    @Override
144    public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException {
145        if (component.isRendered()) {
146            context.getResponseWriter().endElement(getTagName(component));
147        }
148    }
149
150    private String getTagName(final UIComponent component) {
151        if (!isEmpty(tagName)) {
152            return tagName;
153        }
154        return component.getClass().getSimpleName();
155    }
156
157    @java.lang.SuppressWarnings("all")
158    @lombok.Generated
159    public CuiMockRenderer(final String tagName) {
160        this.tagName = tagName;
161    }
162}