Hi everyone! I'm currently migrating an application from Glassfish 3.1.1 to TomEE. Now the problem is that this application contains a custom component which was unfortunately coded with hard dependencies on com.sun.faces classes (maven dependency jsf-impl).
Now my question is how can i port this component in such a way that it is independent from any concrete JSF implementation (or at least in such a way that it works with MyFaces). Here's the component: import java.io.IOException; import java.util.Iterator; import java.util.Map; import javax.faces.component.UIComponent; import javax.faces.component.UINamingContainer; import javax.faces.component.ValueHolder; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.convert.Converter; import javax.faces.model.SelectItem; import javax.faces.model.SelectItemGroup; import com.sun.faces.renderkit.Attribute; import com.sun.faces.renderkit.AttributeManager; import com.sun.faces.renderkit.RenderKitUtils; import com.sun.faces.renderkit.html_basic.MenuRenderer; import com.sun.faces.util.RequestStateManager; import com.sun.faces.util.Util; /** * {@inheritDoc}. */ public class CustomSelectManyCheckboxListRenderer extends MenuRenderer { /** {@inheritDoc}. */ private static final Attribute[] ATTRIBUTES = AttributeManager.getAttributes(AttributeManager.Key.SELECTMANYCHECKBOX); /** Representing the border string. */ private static final String BORDER = "border"; /** Representing the tr string. */ private static final String TR = "tr"; /** Representing the td string. */ private static final String TD = "td"; /** Representing the label string. */ private static final String LABEL = "label"; /** Representing the newline string. */ private static final String NEWLINE = "\n"; /** Representing the tab string. */ private static final String TAB = "\t"; /** Representing the class string. */ private static final String CLASS = "class"; /** Representing the style string. */ private static final String STYLE = "style"; /** Representing the valign string. */ private static final String VALIGN = "valign"; // ---------------------------------------------------------- Public Methods @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { rendererParamsNotNull(context, component); if (!shouldEncode(component)) { return; } ResponseWriter writer = context.getResponseWriter(); assert (writer != null); String alignStr; Object borderObj; boolean alignVertical = false; int border = 0; if (null != component.getAttributes().get("layout")) { alignStr = (String) component.getAttributes().get("layout"); alignVertical = alignStr.equalsIgnoreCase("pageDirection"); } if (null != component.getAttributes().get(BORDER)) { borderObj = component.getAttributes().get(BORDER); border = (Integer) borderObj; } Converter converter = null; if (component instanceof ValueHolder) { converter = ((ValueHolder)component).getConverter(); } renderBeginText(component, border, alignVertical, context, true); Iterator<SelectItem> items = RenderKitUtils.getSelectItems(context, component); Object currentSelections = getCurrentSelectedValues(component); Object[] submittedValues = getSubmittedSelectedValues(component); Map<String, Object> attributes = component.getAttributes(); OptionComponentInfo optionInfo = new OptionComponentInfo((String) attributes.get("disabledClass"), (String) attributes.get("enabledClass"), (String) attributes.get("unselectedClass"), (String) attributes.get("selectedClass"), Util.componentIsDisabled(component), isHideNoSelection(component)); int idx = -1; while (items.hasNext()) { SelectItem curItem = items.next(); idx++; // If we come across a group of options, render them as a nested // table. if (curItem instanceof SelectItemGroup) { // write out the label for the group. if (curItem.getLabel() != null) { if (alignVertical) { writer.startElement(TR, component); } writer.startElement(TD, component); writer.writeText(curItem.getLabel(), component, LABEL); writer.endElement(TD); if (alignVertical) { writer.endElement(TR); } } if (alignVertical) { writer.startElement(TR, component); } writer.startElement(TD, component); writer.writeText(NEWLINE, component, null); renderBeginText(component, 0, alignVertical, context, false); // render options of this group. SelectItem[] itemsArray = ((SelectItemGroup) curItem).getSelectItems(); for (int i = 0; i < itemsArray.length; ++i) { renderOption(context, component, converter, itemsArray[i], currentSelections, submittedValues, alignVertical, i, optionInfo); } renderEndText(component, alignVertical, context); writer.endElement(TD); if (alignVertical) { writer.endElement(TR); writer.writeText(NEWLINE, component, null); } } else { renderOption(context, component, converter, curItem, currentSelections, submittedValues, alignVertical, idx, optionInfo); } } renderEndText(component, alignVertical, context); } // ------------------------------------------------------- Protected Methods /** * {@inheritDoc} */ @Override protected boolean isBehaviorSource(FacesContext ctx, String behaviorSourceId, String componentClientId) { if (behaviorSourceId == null) { return false; } char sepChar = UINamingContainer.getSeparatorChar(ctx); String actualBehaviorId = behaviorSourceId.substring(0, behaviorSourceId.lastIndexOf(sepChar)); return (actualBehaviorId.equals(componentClientId)); } /** * {@inheritDoc} */ protected void renderBeginText(UIComponent component, int border, boolean alignVertical, FacesContext context, boolean outerTable) throws IOException { ResponseWriter writer = context.getResponseWriter(); assert (writer != null); writer.startElement("table", component); if (border != Integer.MIN_VALUE) { writer.writeAttribute(BORDER, border, BORDER); } // render style and styleclass attribute on the outer table instead of // rendering it as pass through attribute on every option in the list. if (outerTable) { // render "id" only for outerTable. if (shouldWriteIdAttribute(component)) { writeIdAttributeIfNecessary(context, writer, component); } String styleClass = (String) component.getAttributes().get( "styleClass"); String style = (String) component.getAttributes().get(STYLE); if (styleClass != null) { writer.writeAttribute(CLASS, styleClass, CLASS); } if (style != null) { writer.writeAttribute(STYLE, style, STYLE); } } writer.writeText(NEWLINE, component, null); if (!alignVertical) { writer.writeText(TAB, component, null); writer.startElement(TR, component); writer.writeText(NEWLINE, component, null); } } /** * {@inheritDoc} */ protected void renderEndText(UIComponent component, boolean alignVertical, FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); assert (writer != null); if (!alignVertical) { writer.writeText(TAB, component, null); writer.endElement(TR); writer.writeText(NEWLINE, component, null); } writer.endElement("table"); } /** * {@inheritDoc} */ protected void renderOption(FacesContext context, UIComponent component, Converter converter, SelectItem curItem, Object currentSelections, Object[] submittedValues, boolean alignVertical, int itemNumber, OptionComponentInfo optionInfo) throws IOException { String valueString = getFormattedValue(context, component, curItem.getValue(), converter); Object valuesArray; Object itemValue; if (submittedValues != null) { valuesArray = submittedValues; itemValue = valueString; } else { valuesArray = currentSelections; itemValue = curItem.getValue(); } RequestStateManager.set(context, RequestStateManager.TARGET_COMPONENT_ATTRIBUTE_NAME, component); boolean isSelected = isSelected(context, component, itemValue, valuesArray, converter); if (optionInfo.isHideNoSelection() && curItem.isNoSelectionOption() && currentSelections != null && !isSelected) { return; } ResponseWriter writer = context.getResponseWriter(); assert (writer != null); if (alignVertical) { writer.writeText(TAB, component, null); writer.startElement(TR, component); writer.writeText(NEWLINE, component, null); } writer.startElement(TD, component); writer.writeAttribute(VALIGN, "top", VALIGN); writer.writeText(NEWLINE, component, null); writer.startElement("input", component); writer.writeAttribute("name", component.getClientId(context), "clientId"); String idString = component.getClientId(context) + UINamingContainer.getSeparatorChar(context) + Integer.toString(itemNumber); writer.writeAttribute("id", idString, "id"); writer.writeAttribute("value", valueString, "value"); writer.writeAttribute("type", "checkbox", null); if (isSelected) { writer.writeAttribute(getSelectedTextString(), Boolean.TRUE, null); } // Don't render the disabled attribute twice if the 'parent' // component is already marked disabled. if (!optionInfo.isDisabled()) { if (curItem.isDisabled()) { writer.writeAttribute("disabled", true, "disabled"); } } // Apply HTML 4.x attributes specified on UISelectMany component to all // items in the list except styleClass and style which are rendered as // attributes of outer most table. RenderKitUtils.renderPassThruAttributes(context, writer, component, ATTRIBUTES, getNonOnClickSelectBehaviors(component)); RenderKitUtils.renderXHTMLStyleBooleanAttributes(writer, component); RenderKitUtils.renderSelectOnclick(context, component, true); writer.endElement("input"); //-------------------------------------------------------- // New stuff for event selecting //-------------------------------------------------------- writer.endElement(TD); // starting the label td writer.startElement(TD, component); writer.writeAttribute(VALIGN, "top", VALIGN); writer.writeAttribute("width", "80px", "width"); writer.writeAttribute(STYLE, "padding-top:4px", STYLE); String itemLabel = curItem.getLabel(); if (itemLabel == null) { itemLabel = valueString; } writer.writeText(" ", component, null); writer.startElement(LABEL, component); writer.writeAttribute("for", component.getClientId() + ":" + itemNumber, "for"); if (!curItem.isEscape()) { // It seems the ResponseWriter API should // have a writeText() with a boolean property // to determine if it content written should // be escaped or not. writer.write(itemLabel); } else { writer.writeText(itemLabel, component, null); } writer.endElement(LABEL); isSelected(context, component, itemValue, valuesArray, converter); // if (isSelected(context, component, itemValue, valuesArray, converter)) // { // // selected // } // else // { // // not selected // } writer.endElement(TD); // starting the description td writer.startElement(TD, component); writer.writeAttribute(VALIGN, "top", VALIGN); writer.writeAttribute(STYLE, "padding-top:4px", STYLE); String itemLabelDesc = curItem.getDescription(); if (itemLabelDesc == null) { itemLabelDesc = ""; } writer.writeText(" ", component, null); if (!curItem.isEscape()) { // It seems the ResponseWriter API should // have a writeText() with a boolean property // to determine if it content written should // be escaped or not. writer.write(itemLabelDesc); } else { writer.writeText(itemLabelDesc, component, null); } writer.endElement(TD); //-------------------------------------------------------- // New stuff for event selecting end //-------------------------------------------------------- writer.writeText(NEWLINE, component, null); if (alignVertical) { writer.writeText(TAB, component, null); writer.endElement(TR); writer.writeText(NEWLINE, component, null); } } // ------------------------------------------------- Package Private Methods /** * {@inheritDoc} */ String getSelectedTextString() { return "checked"; } } Any help is appreciated! Thanks! René