My original discovery was that there was a failure in the PartialSubmitPhaseListener to find the component that triggered the partial submit. The purpose of the phase listener was to detect which component triggered the partial submit, and then set the "required" attribute of all of the other components to false during validation. When validation was complete, the "required" attribute was set back to it's previous value.
The inability to find the component that triggered the partial submit meant that all the components in the form (including the one that triggered the partial submit) would have "required" set to false. Therefore no validation was being performed.
I was able to verify that CoreComponentUtils.findComponent() could not locate the component in the view by changing the comparison from an object comparison to a String comparison of the ids. In other words, while iterating through the components of the form, instead of comparing like this:
if (input == componentToAvoid) {
I changed to do it like this:
if (input.getId().equals((componentID)) {
While this wasn't acceptable as a fix, it was able to show that validation would occur properly.
I then tried switching from using CoreComponentUtils.findComponent() method (which is our own algorithm for find components) to the standard JSF method of UIViewRoot.findComponent(). This still didn't work for locating the component we were interested in.
After discussing with other team members, I did a variety of different searches and what ended up working was removing the "namespace" from the front of the id. In portlets, in order to guarantee that components in different portlets are uniquely identified, the portal provides a portlet "namespace". This value is a container-specific value. In the current version of Liferay, our markup of:
<ice:inputText id="requiredField" value="#
{basic.requiredMessage}
" required="#
{true}
" partialSubmit="true"/>
would render out an id like this:
A1364:mFormId:requiredField
By stripping the A1364 from the front of id before performing the search, it was able to find the component.
The value A1364 represents the portlet namespace. In the PortletFaces bridge, the namespacing is handled by the PortletNamingContainerUIViewRoot, which is basically the container or "body" of the portlet. However, that class is not overriding the getId()/setId() methods (which is a what we used to do with the ice:portlet tag back in ICEfaces 1.8). Because this component id is rendered out by not actually set in the PortletNamingContainerUIViewRoot itself, searches in the component tree fail.
So the options are to either:
1) remove the portlet namespace in our code before attempting the search or
2) have the PortletFaces bridge use the namespace as the id as described above
I believe 2 is the right way. So we will work with the bridge developer to make this change.
I did some additional testing using an inputText with required=true and partialSubmit=true nested in a PanelSeries to ensure that the search for the component still worked and was able to verify that it does.
This can also be reproduced with the Example ICEfaces 2.x Portlet at portletfaces.org:
http://www.portletfaces.org/portletfaces-bridge/examples/icefaces-2.x-portlet