java ajax jsf-2 listener composite-component

java - JSF 2: ¿Cómo puedo agregar un método de escucha Ajax a la interfaz de componente compuesto?



jsf-2 listener (2)

Aquí hay un ejemplo sobre cómo usar la interfaz para establecer un atributo y hacer referencia a él dentro de la implementación. Debe definir el método-firma del método que se llamará. Esto informa al controlador de componente compuesto que hay un valor de método, en lugar de una expresión de valor, contenida en la expresión # {cc.attrs.ajaxEventListener}.

<cc:interface name="composite-comp" <cc:attribute required="true" name="ajaxEventListener" method-signature="void f1(javax.faces.event.AjaxBehaviorEvent)" /> <cc:attribute required="true" name="ajaxRenderTargets" /> </cc:interface> <cc:implementation> . . . <f:ajax event="valueChange" execute="@this" listener="#{cc.attrs.ajaxEventListener}" render="#{cc.attrs.ajaxRenderTargets}" /> </cc:implementation>

Tengo un componente compuesto JSF 2 que emplea algún comportamiento Ajax. Quiero agregar un método de listener a la etiqueta <f:ajax> dentro de mi componente compuesto, pero el método de listener se debe proporcionar como un <composite:attribute> en el <composite:interface> .

La etiqueta <f:ajax> dentro de mi componente compuesto actualmente está codificada para un oyente como este:

<f:ajax event="valueChange" execute="@this" listener="#{controller.genericAjaxEventLogger}" render="#{cc.attrs.ajaxRenderTargets}" />

El método de escucha en el bean tiene esta firma:

public void genericAjaxEventLogger(AjaxBehaviorEvent event) throws AbortProcessingException { // implementation code... }

Quiero que el componente compuesto sea algo como esto para que la página pueda proporcionar su propio método de evento, pero no puedo averiguar la sintaxis correcta para la interfaz.

<f:ajax event="valueChange" execute="@this" listener="#{cc.attrs.ajaxEventListener}" render="#{cc.attrs.ajaxRenderTargets}" />

¿Cómo puedo hacer esto?

ACTUALIZADO CON SOLUCION:

Tomé el enfoque sugerido por BalusC y funciona muy bien. Los fragmentos relevantes son:

La declaración de interfaz en el componente compuesto

<composite:interface> <composite:attribute name="myattributeUpdatedEventListener" method-signature="void listener()" required="true" /> ... </composite:interface>

La etiqueta Ajax utilizada en mi componente compuesto

<f:ajax event="valueChange" execute="@this" listener="#{cc.attrs.myattributeUpdatedEventListener}" render="#{cc.attrs.ajaxRenderTargets}" />

El lugar en mi página donde uso el componente compuesto.

<h:form> <compcomp:myCompositeComponent myattributeUpdatedEventListener="#{myBackingBean.updatedEventListenerXYZ}" /> </h:form>

Y el método en mi frijol respaldo.

public void updatedEventListenerXYZ() { // do something here... }


Si puede deshacerse del argumento AjaxBehaviorEvent ,

public void genericAjaxEventLogger() { // ... }

entonces puedes usar

<cc:attribute name="ajaxEventListener" method-signature="void listener()" />

Si el argumento es obligatorio (¿para el registro?), Deberá volver a especificar el atributo de la siguiente manera:

<cc:attribute name="ajaxEventListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)" />

Sin embargo, esto no funciona aquí como se esperaba.

<f:ajax listener="#{cc.attrs.ajaxEventListener}" />

en GF 3.1 + Mojarra 2.1.1:

SEVERE: javax.faces.FacesException: wrong number of arguments at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:89) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:409) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1534) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) at com.sun.grizzly.ContextTask.run(ContextTask.java:71) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at com.sun.el.parser.AstValue.invoke(AstValue.java:234) at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297) at com.sun.faces.facelets.el.ContextualCompositeMethodExpression.invoke(ContextualCompositeMethodExpression.java:177) at com.sun.faces.facelets.tag.TagAttributeImpl$AttributeLookupMethodExpression.invoke(TagAttributeImpl.java:450) at com.sun.faces.facelets.tag.jsf.core.AjaxBehaviorListenerImpl.processAjaxBehavior(AjaxHandler.java:447) at javax.faces.event.AjaxBehaviorEvent.processListener(AjaxBehaviorEvent.java:113) at javax.faces.component.behavior.BehaviorBase.broadcast(BehaviorBase.java:102) at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:760) at javax.faces.component.UICommand.broadcast(UICommand.java:300) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) ... 28 more

No estoy seguro de si esto es un error o no. Para eso necesitaría invertir un poco más de tiempo para descubrirlo. Sin embargo, era una solución alternativa al crear un componente de respaldo que obtiene la MethodExpression de los atributos y la invoca con el número correcto de argumentos. Aquí hay un ejemplo completo de kickoff:

<ui:component xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:cc="http://java.sun.com/jsf/composite" xmlns:ui="http://java.sun.com/jsf/facelets" > <cc:interface componentType="testCC"> <cc:attribute name="ajaxEventListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)" /> </cc:interface> <cc:implementation> <h:commandButton value="Submit"> <f:ajax listener="#{cc.ajaxEventListener}" /> </h:commandButton> </cc:implementation> </ui:component>

con

package com.example; import javax.el.MethodExpression; import javax.faces.component.FacesComponent; import javax.faces.component.UINamingContainer; import javax.faces.context.FacesContext; import javax.faces.event.AjaxBehaviorEvent; @FacesComponent(value="testCC") public class TestCC extends UINamingContainer { public void ajaxEventListener(AjaxBehaviorEvent event) { FacesContext context = FacesContext.getCurrentInstance(); MethodExpression ajaxEventListener = (MethodExpression) getAttributes().get("ajaxEventListener"); ajaxEventListener.invoke(context.getELContext(), new Object[] { event }); } }

En cualquier caso, creo que el componente de respaldo abre las puertas para nuevas formas de lograr el requisito funcional que ha tenido en mente de todos modos;)