Question

I have a composite component:

<cc:interface componentType="com.example.MyComponent">
    <!-- ... -->
</cc:interface>

<cc:implementation>
    <f:phaseListener binding="#{cc}"/>
    <div id="#{cc.clientId}">
        <!-- ... -->
    </div>
</cc:implementation>

And its class:

@FacesComponent("com.example.MyComponent")
public class MyComponent extends UIOutput implements NamingContainer, PhaseListener
{
    @Override
    public String getFamily()
    {
        return "javax.faces.NamingContainer";
    }

    @Override
    public PhaseId getPhaseId()
    {
        return PhaseId.ANY_PHASE;
    }

    @Override
    public void beforePhase(PhaseEvent event)
    {
        // Do something ...
    }

    @Override
    public void afterPhase(PhaseEvent event)
    {
        // Do something ...
    }
}

Neither the beforePhase(PhaseEvent) nor afterPhase(PhaseEvent) methods are called in any case, be it a full or partial page load.

I note this bug here: http://java.net/jira/browse/JAVASERVERFACES-1200, but it seems to have been fixed quite a while ago.

I'm using GlassFish 3.1.2.2 on Java 6u33 x64.

Was it helpful?

Solution

The #{cc} is re-evaluated everytime when the beforePhase() or afterPhase() method of the <f:phaseListener> actually needs to be executed by the UIViewRoot. The #{cc} is not available in the EL scope at that moment. It's only available within the component's scope.

It works fine if the binding points to at least a request scoped variable like as follows in the composite component's constructor:

public MyComponent() {
    FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("ccc", this);
}

with

<f:phaseListener binding="#{ccc}" />

This construct only fails if you've multiple composite components of this type, of course.

You'd better look for an alternate approach: get rid of the <f:phaseListener> altogether and just use UIViewRoot#addPhaseListener() in the composite component's constructor:

public MyComponent() {
    FacesContext.getCurrentInstance().getViewRoot().addPhaseListener(this);
}

Unrelated to the concrete problem, better use UINamingContainer.COMPONENT_FAMILY constant instead of hardcoding "javax.faces.NamingContainer".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top