I didn't expect anyone to rewrite that code, i just wanted to present the whole problem :-) As i said, i'd accept a MyFaces port too, it's just that my shots at a solution were unsuccessful. For example I tried to extend from Tobago's MenuRenderer instead of Mojarra's, but it said that MenuRenderer in Tobago is final, although I'm not sure that that's the correct approach in the first place.
Gesendet: Donnerstag, 13. Februar 2014 um 13:23 Uhr Von: "Thomas Andraschko" <andraschko.tho...@gmail.com> An: "MyFaces Discussion" <users@myfaces.apache.org> Betreff: Re: Problems with a custom component when migrating from Glassfish(mojarra) to TomEE I don't think that anyone will port your complete code and give you a complete solution ;) The biggest problem is AFAIR that the renderer implementations are not in the API packages. So you have to rebuild all this functionality without dependencies to the Impl. e.g. Attribute,AttributeManager -> String[] with attribute namens Move all the utils functions to your own code (Util.componentIsDisabled, RenderKitUtils.getSelectItems. etc.) The most code doesn't really depent on the IMPL code. 2014-02-13 12:44 GMT+01:00 Rene Perschon <chummer_r...@gmx.net>: > 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é >