Index: compat/components/src/main/java/com/icesoft/faces/component/panelseries/UISeries.java =================================================================== --- compat/components/src/main/java/com/icesoft/faces/component/panelseries/UISeries.java (revision 26047) +++ compat/components/src/main/java/com/icesoft/faces/component/panelseries/UISeries.java (revision ) @@ -28,7 +28,6 @@ import com.icesoft.faces.component.util.CustomComponentUtils; import com.icesoft.faces.model.SetDataModel; import com.icesoft.faces.utils.SeriesStateHolder; -import org.icefaces.util.EnvUtils; import javax.faces.FacesException; import javax.faces.application.FacesMessage; @@ -48,6 +47,8 @@ import javax.faces.model.ResultDataModel; import javax.faces.model.ResultSetDataModel; import javax.faces.model.ScalarDataModel; +import javax.faces.render.Renderer; +import javax.faces.view.Location; import javax.swing.tree.TreeModel; import java.io.IOException; import java.io.Serializable; @@ -72,7 +73,10 @@ public class UISeries extends HtmlDataTable implements SeriesStateHolder { public static final String COMPONENT_TYPE = "com.icesoft.faces.series"; public static final String RENDERER_TYPE = "com.icesoft.faces.seriesRenderer"; - + + private static final String SHARED_STRING_BUILDER_KEY + = "javax.faces.component.UIComponentBase.SHARED_STRING_BUILDER"; + private static Class javax_servlet_jsp_jstl_sql_Result_class = null; static { try { @@ -89,6 +93,7 @@ private String var = null; private String varStatus; + private String clientId = null; public UISeries() { super(); @@ -234,29 +239,226 @@ * @see javax.faces.component.UIData#getClientId(FacesContext) */ public String getClientId(FacesContext context) { - if (context == null) { - throw new NullPointerException(); + System.out.println("UISeries.getClientId: transplanted MyFaces version"); + if (context == null) + throw new NullPointerException("context"); + + if (clientId != null) + return clientId; + + //boolean idWasNull = false; + String id = getId(); + if (id == null) + { + // Although this is an error prone side effect, we automatically create a new id + // just to be compatible to the RI + + // The documentation of UniqueIdVendor says that this interface should be implemented by + // components that also implements NamingContainer. The only component that does not implement + // NamingContainer but UniqueIdVendor is UIViewRoot. Anyway we just can't be 100% sure about this + // fact, so it is better to scan for the closest UniqueIdVendor. If it is not found use + // viewRoot.createUniqueId, otherwise use UniqueIdVendor.createUniqueId(context,seed). + UniqueIdVendor parentUniqueIdVendor = findParentUniqueIdVendor(this); + if (parentUniqueIdVendor == null) + { + UIViewRoot viewRoot = context.getViewRoot(); + if (viewRoot != null) + { + id = viewRoot.createUniqueId(); - } + } + else + { + // The RI throws a NPE + String location = getComponentLocation(this); + throw new FacesException("Cannot create clientId. No id is assigned for component" + + " to create an id and UIViewRoot is not defined: " + + getPathToComponent(this) + + (location != null ? " created from: " + location : "")); + } + } + else + { + id = parentUniqueIdVendor.createUniqueId(context, null); + } + setId(id); + // We remember that the id was null and log a warning down below + // idWasNull = true; + } - String baseClientId = super.getClientId(context); + UIComponent namingContainer = findParentNamingContainer(this, false); + if (namingContainer != null) + { + String containerClientId = namingContainer.getContainerClientId(context); + if (containerClientId != null) + { + StringBuilder bld = getSharedStringBuilder(context); + clientId = bld.append(containerClientId).append(UINamingContainer.getSeparatorChar(context)).append(id).toString(); + } + else + { + clientId = id; + } + } + else + { + clientId = id; + } - if (getRowIndex() >= 0) { - //this extra if is to produce the same ids among myfaces and sunri - //myfaces uses the getRowIndex() and SunRI directly using the rowIndex - //variable inside its getClientId() - if (!baseClientId.endsWith( - "" + NamingContainer.SEPARATOR_CHAR + getRowIndex())) { - return (baseClientId + NamingContainer.SEPARATOR_CHAR + - getRowIndex()); + Renderer renderer = getRenderer(context); + if (renderer != null) + { + clientId = renderer.convertClientId(context, clientId); - } + } - return (baseClientId); - } else { - return (baseClientId); + + return clientId; - } + } + + /** + * Logic for this method is borrowed from MyFaces + * + * @param facesContext + * @return + */ + @Override + public String getContainerClientId(FacesContext facesContext) { + System.out.println("UISeries.getContainerClientId: transplanted MyFaces version"); + String clientId = getClientId(facesContext); + + int rowIndex = getRowIndex(); + if (rowIndex == -1) + { + return clientId; - } + } + StringBuilder bld = getSharedStringBuilder(facesContext); + return bld.append(clientId).append(UINamingContainer.getSeparatorChar(facesContext)).append(rowIndex).toString(); + } /** + * Logic for this method is borrowed from MyFaces + * + * @param facesContext + * @return + */ + private static StringBuilder getSharedStringBuilder(FacesContext facesContext) + { + Map attributes = facesContext.getAttributes(); + StringBuilder sb = (StringBuilder) attributes.get(SHARED_STRING_BUILDER_KEY); + if (sb == null) + { + sb = new StringBuilder(); + attributes.put(SHARED_STRING_BUILDER_KEY, sb); + } + sb.setLength(0); + return sb; + } + + /** + * Logic for this method is borrowed from MyFaces + * + * @param component + * @return + */ + private String getComponentLocation(UIComponent component) + { + Location location = (Location) component.getAttributes().get(UIComponent.VIEW_LOCATION_KEY); + if (location != null) + { + return location.toString(); + } + return null; + } + + private String getPathToComponent(UIComponent component) + { + StringBuffer buf = new StringBuffer(); + + if (component == null) + { + buf.append("{Component-Path : "); + buf.append("[null]}"); + return buf.toString(); + } + + getPathToComponent(component, buf); + + buf.insert(0, "{Component-Path : "); + buf.append("}"); + + return buf.toString(); + } + + private void getPathToComponent(UIComponent component, StringBuffer buf) + { + if (component == null) + return; + + StringBuffer intBuf = new StringBuffer(); + + intBuf.append("[Class: "); + intBuf.append(component.getClass().getName()); + if (component instanceof UIViewRoot) + { + intBuf.append(",ViewId: "); + intBuf.append(((UIViewRoot) component).getViewId()); + } + else + { + intBuf.append(",Id: "); + intBuf.append(component.getId()); + } + intBuf.append("]"); + + buf.insert(0, intBuf.toString()); + + getPathToComponent(component.getParent(), buf); + } + + static UniqueIdVendor findParentUniqueIdVendor(UIComponent component) + { + UIComponent parent = component.getParent(); + + while (parent != null) + { + if (parent instanceof UniqueIdVendor) + { + return (UniqueIdVendor) parent; + } + parent = parent.getParent(); + } + return null; + } + + static UIComponent findParentNamingContainer(UIComponent component, boolean returnRootIfNotFound) + { + UIComponent parent = component.getParent(); + if (returnRootIfNotFound && parent == null) + { + return component; + } + while (parent != null) + { + if (parent instanceof NamingContainer) + return parent; + if (returnRootIfNotFound) + { + UIComponent nextParent = parent.getParent(); + if (nextParent == null) + { + return parent; // Root + } + parent = nextParent; + } + else + { + parent = parent.getParent(); + } + } + return null; + } + + + /** * @see javax.faces.component.UIData#queueEvent(FacesEvent) */ public void queueEvent(FacesEvent event) {