Sink JSF 2.0 Composite Component Event in Parent Page Backing Bean

流过昼夜 提交于 2019-12-06 16:57:07

问题


I have a conceptual mind-block around the use of a JSF 2.0 composite component within a parent page. I understand how to implement an ActionListener (and others) for a composite component's action but how is this wired-up for the parental page to consume? For example, I want my login composite component to perform authentication and when complete, inform the parent page's backing bean through the an event (ActionListener?) to do some UI initialization work. The key here is the login component would say, "Hey, I'm done and the user is good. Your turn."

Thanks in advance for the assistance.

Peace.

Chris


回答1:


One way I found you can acomplish this is using composite component + custom component type + ActionSource2 + system events.

In the interface of your composite set a component-type (when not definied, the implementation (Mojarra or MyFaces) uses a default component type.

<cc:interface componentType="example.Login">
  <cc:attribute name="text" type="java.lang.String"/>
  <cc:attribute name="actionExpression" method-signature="void method()"/>
</cc:interface>

<cc:implementation>
    <p>
      <h:outputLabel value="User"/>
      <h:inputText id="user"/>
    </p>
    <p>
      <h:outputLabel value="Password"/>
      <h:inputSecret id="password"/>
    </p>
</cc:implementation>

This component type is a java class that implements NamingContainer (UINamingContainer is a subclass of component implementing this interface). Next you have to implement ActionSource2 so you could generate an action event when the user is verified.

The verifyng must be after the user and password components have been validated (not your verification but JSF PROCESS VALIDATIONS). In order to know when the validation has occurs, we use System Events.

This is an example of the code for the custom component. The class implements the methods of the ActionSource2 interface and overrides broadcast to handle ActionEvent's. I use some specific classes in Mojarra (because the legacy between ActionSource and ActionSource2).

 @FacesComponent("example.Login") //Component type in the composite
@ListenerFor(systemEventClass=PostValidateEvent.class) //Event to listen for user and password verification
public class LoginComponent extends UINamingContainer implements  ActionSource2{

    @Override
    public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
        if(event instanceof PostValidateEvent){
            System.out.println("post validate");
        }
        super.processEvent(event);
        String user=(String) ((HtmlInputText)findComponent("user")).getValue();
        String password=(String) ((HtmlInputSecret)findComponent("password")).getValue();
        System.out.println("user: "+user);
        System.out.println("password: "+password);
        //a simple logic for verification
        if(user != null && user.equals("victor") && password != null && password.equals(user)){
            System.out.println("user ok");
            queueEvent(new ActionEvent(this));
        }
    }


    private MethodExpression exp;

    @Override
    public MethodExpression getActionExpression() {
        return exp;
    }

    @Override
    public void setActionExpression(MethodExpression action) {
        exp=action;
    }

    @Override
    public MethodBinding getAction() {
        return exp != null ? new MethodBindingMethodExpressionAdapter(exp): null;
    }

    @Override
    public void setAction(MethodBinding action) {
        setActionExpression(new MethodExpressionMethodBindingAdapter(action));
    }

    private MethodBinding actionListener;

    @Override
    public MethodBinding getActionListener() {
        return actionListener;
    }

    @Override
    public void setActionListener(MethodBinding actionListener) {
        this.actionListener=actionListener;
    }

    private boolean i;

    @Override
    public boolean isImmediate() {
        return i;
    }

    @Override
    public void setImmediate(boolean immediate) {
        this.i=immediate;
    }

    List<ActionListener> listeners=new LinkedList<ActionListener>();

    @Override
    public void addActionListener(ActionListener listener) {
        listeners.add(listener);
    }

    @Override
    public ActionListener[] getActionListeners() {
        return listeners.toArray(new ActionListener[0]);
    }

    @Override
    public void removeActionListener(ActionListener listener) {
        listeners.remove(listener);
    }

    @Override
     public void broadcast(FacesEvent event) throws AbortProcessingException {
        super.broadcast(event);

        if (event instanceof ActionEvent) {
            FacesContext context = getFacesContext();
            MethodBinding binding = getActionListener();
            if (binding != null) {
                binding.invoke(context, new Object[] { event });
            }

            ActionListener listener = context.getApplication().getActionListener();
            if (listener != null) {
                listener.processAction((ActionEvent) event);
            }
        }
    }

}

And this is the code in the using page:

<ez:login actionExpression="#{bean.logged}"/>


来源:https://stackoverflow.com/questions/4034917/sink-jsf-2-0-composite-component-event-in-parent-page-backing-bean

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!