java jsf-2 cdi jboss-weld modular

java - ¿Cómo crear una aplicación modular JSF 2.0?



jsf-2 cdi (3)

Tengo una aplicación con una interfaz bien definida. Utiliza CDI para la resolución de los módulos, (Específicamente usa Instance <> puntos de inyección en interfaces API para resolver módulos) y pasa varios datos atrás y cuarto a través de las interfaces sin problema. He mantenido intencionalmente la API y la implementación por separado, y los módulos solo heredan de la API para evitar un acoplamiento estricto, y la aplicación solo conoce los módulos a través de las dependencias de tiempo de ejecución y el paso de datos logrado a través de las API. La aplicación funciona bien sin los módulos, que se pueden agregar simplemente soltando el contenedor en la carpeta WEB-INF / lib y reiniciando el servidor de la aplicación.

Cuando me encuentro con problemas es que quiero que los módulos creen una parte de la vista, y por eso quiero invocar, de manera portátil, un componente JSF o hacer una inclusión desde el módulo para tenerlo renderizar su vista. Ya he resuelto qué módulo quiero invocar y tengo listas las referencias a la interfaz del módulo. La forma en que inicialmente pensé hacer esto fue hacer un ui: incluir que le pida al módulo que proporcione dónde está la plantilla de vista, pero no tengo idea de cómo responder esa consulta de manera significativa, ya que la resolución de la vista se realiza desde la aplicación raíz, no la raíz de la biblioteca.

El resumen ejecutivo es que no tengo idea de cómo pasar de la aplicación a la biblioteca usando JSF para los archivos .xhtml (plantilla / componente).

Usar un CC sería agradable, pero ¿cómo especifico que quiero una instancia de CC particular en tiempo de ejecución, en lugar de tener ese código rígido en la página?

Por supuesto, puedo invocar el código de la aplicación directamente y pedirle que marque, pero esto parece realmente fuerza bruta, y una vez que tenga el marcado, no estoy seguro de cómo decirle a JSF que lo evalúe. Dicho esto, puedo imaginarme un componente que tomaría la ruta del recurso, tomaría el marcado y lo evaluaría, devolviendo el marcado completo, simplemente no sé cómo implementarlo.

Prefiero evitar forzar a los desarrolladores de módulos para que adopten el enfoque UIComponent de trabajo pesado si es posible, lo que significa una forma dinámica de hacer ui: include (o algún equivalente) o una forma dinámica de invocación de CC. (No me importa codificar el enfoque de UIComponent UNA VEZ en la aplicación si eso es lo que se necesita para facilitar la vida de los desarrolladores de módulos)

¿Alguna sugerencia sobre dónde debería buscar para resolver esto? (Voy a publicar la respuesta aquí si la encuentro primero)


Entiendo que su pregunta básicamente se reduce a ¿Cómo puedo incluir vistas de Facelets en un JAR?

Puede hacer esto colocando un ResourceResolver personalizado en el JAR.

public class FaceletsResourceResolver extends ResourceResolver { private ResourceResolver parent; private String basePath; public FaceletsResourceResolver(ResourceResolver parent) { this.parent = parent; this.basePath = "/META-INF/resources"; // TODO: Make configureable? } @Override public URL resolveUrl(String path) { URL url = parent.resolveUrl(path); // Resolves from WAR. if (url == null) { url = getClass().getResource(basePath + path); // Resolves from JAR. } return url; } }

Configure esto en web.xml de web.xml siguiente manera:

<context-param> <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name> <param-value>com.example.FaceletsResourceResolver</param-value> </context-param>

Imagine que tiene un /META-INF/resources/foo/bar.xhtml en random.jar , luego puede simplemente incluirlo de la manera habitual

<ui:include src="/foo/bar.xhtml" />

o incluso dinámicamente

<ui:include src="#{bean.path}" />

Nota: desde Servlet 3.0 y las versiones más recientes de JBoss / JSF 2.0, todo el enfoque de ResourceResolver no es necesario si mantiene los archivos en la carpeta /META-INF/resources . El ResourceResolver anterior solo es obligatorio en Servlet 2.5 o versiones anteriores de JBoss / JSF porque tienen errores en la resolución de recursos META-INF .

Ver también:



Por cierto ... puedes evitar implementar tu propio solucionador de recursos cuando utilizas Seam Solder (que se está integrando actualmente en apache deltaspike) que es una biblioteca realmente útil que complementa a CDI (tu modelo típico de componentes de Java EE 6)

Yo también experimenté con modularidad en aplicaciones jsf. Básicamente construí una interfaz de plantilla con una barra de herramientas que se llena con los botones proporcionados por cada módulo. Normalmente, hará esto proporcionando una Lista de cadenas como objeto con nombre:

@Produces @SomethingScoped @Named("topMenuItems") public List<String> getTopMenuItems(){ return Arrays.asList("/button1.xhtml", "/button2.xhtml", "/button3.xhtml"); }

Observe cómo cada uno de los botones puede provenir de un módulo diferente de la aplicación jsf. La interfaz de la plantilla contiene un panel donde

puede usarlo en su marcado de la siguiente manera (bajo su propio riesgo;)):

.... xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:ui="http://java.sun.com/jsf/facelets" .... <xy:toolbar> <xy:toolbarGroup> <c:forEach items="#{topMenuItems}" var="link"> <ui:include src="#{link}" /> </c:forEach> </xy:toolbarGroup> </xy:toolbar> <xy:panel> <ui:include src="#{contentPath}"/> </xy:panel>

Esta era la barra de herramientas y el panel de contenido.

una simple definición de botón o vista puede verse así:

<ui:composition ...> <xy:commandButton actionListener="#{topMenuController.switchContent()}" value="Test" id="testbutton" /> </ui:composition>

vamos a nombrar este artefacto view1.xhtml

Cuando se pulsa este botón (que no desencadena una devolución de datos utilizando actionListener, queremos volver a cargar el contenido utilizando ajax) el método switchContentMethod en su controlador puede cambiar la cadena devuelta por getContentPath:

public void switchContent(){ contentPath = "/view1.xhtml"; } @Produces @SomethingScoped @Named("contentPath") public String getContentPath(){ return contentPath; }

ahora puede cambiar la vista que se muestra en el panel con el botón en la barra de menú, que le da una navegación sin recargas de página.

Algunos consejos (o "lo que he aprendido"):

  1. Puede elegir un amplio alcance para el método getTopMenuItems
  2. No anide la etiqueta ui: include. Lamentablemente, esto no es posible (por ejemplo, su view1.xhtml no puede incluir otra composición). Realmente me gustaría que algo como esto sea posible, ya que puedes construir vistas jsf realmente modulares con esto, como portlets solo sin los portlets .. = D
  3. Hacer ui: incluir en los componentes del contenedor como tabviews también resulta problemático.
  4. en general, no es aconsejable mezclar JSTL (c: forEach) y JSF. Aún así, me pareció que esta era la única manera de trabajar como ui: la repetición se evalúa demasiado tarde, por ejemplo, el contenido incluido no aparece.