Como criar um aplicativo JSF 2.0 modular?

Eu tenho um aplicativo com uma interface bem definida. Ele usa o CDI para resolução dos módulos (especificamente, usa instâncias pontos de injeção em interfaces de API para resolver módulos) e passa vários dados de volta e quarto através das interfaces sem problemas. Eu intencionalmente mantive a API e a implementação separadas, e os módulos apenas herdam da API para evitar um acoplamento rígido, e o aplicativo só conhece os módulos por meio de dependências de tempo de execução e passagem de dados realizada por meio das APIs. O aplicativo é executado sem os módulos, o que pode ser adicionado simplesmente soltando o jar na pasta WEB-INF / lib e reiniciando o servidor de aplicativos.

Onde estou tendo problemas é que eu quero que os módulos criem uma parte da visão, e eu, portanto, quero invocar, de um modo portátil, um componente JSF ou fazer uma inclusão do módulo para tê-lo render a sua visão. Eu já resolvi qual módulo eu quero invocar, e tenho referências à interface do módulo pronta. A maneira que eu inicialmente pensava em fazer isso era fazer um ui: include que pede ao módulo para fornecer onde é o template de view, mas não tenho idéia de como responder essa query de maneira significativa, já que a resolução da view é feita a partir do aplicativo raiz, não a raiz da biblioteca.

O resumo executivo é que não tenho idéia de como saltar a lacuna de Aplicativo para Biblioteca usando o JSF para arquivos .xhtml (modelo / componente).

Usar um CC seria legal, mas como eu especifico que eu quero uma instância de CC em particular em tempo de execução, em vez de ter essa codificação na página?

É claro que posso invocar o código do aplicativo diretamente e pedir marcação, mas isso parece ser realmente uma força bruta e, uma vez que eu tenha a marcação, não sei exatamente como dizer ao JSF para avaliá-lo. Dito isso, posso imaginar um componente que pegaria o caminho do recurso, pegaria a marcação e a avaliaria, retornando a marcação completa, eu simplesmente não sei como implementar isso.

Eu prefiro evitar forçar os desenvolvedores de módulos a usar a abordagem UIComponent para serviços pesados, se possível, o que significa uma maneira dinâmica de fazer ui: include (ou algum equivalente) ou uma maneira dinâmica de invocar CCs. (Eu não me importo de codificar a abordagem UIComponent ONCE no aplicativo, se isso é o que é necessário para facilitar a vida dos desenvolvedores de módulos)

Alguma sugestão sobre onde eu deveria olhar para descobrir isso? (Vou postar a resposta aqui se eu encontrar primeiro)

Eu entendo que sua pergunta basicamente se resume a Como posso include vistas Facelets em um JAR?

Você pode fazer isso colocando um ResourceResolver personalizado no 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 isso no web.xml do webapp da seguinte maneira:

  javax.faces.FACELETS_RESOURCE_RESOLVER com.example.FaceletsResourceResolver  

Imagine que você tenha um /META-INF/resources/foo/bar.xhtml em random.jar , então você pode simplesmente incluí-lo da maneira usual

  

ou mesmo dinamicamente

  

Nota: desde o Servlet 3.0 e versões mais recentes do JBoss / JSF 2.0, toda a abordagem do ResourceResolver não é necessária se você mantiver os arquivos na pasta /META-INF/resources . O ResourceResolver acima é obrigatório apenas no Servlet 2.5 ou em versões mais antigas do JBoss / JSF porque eles possuem erros na resolução de resources do META-INF .

Veja também:

  • Arquivos de Facelets de empacotamento (modelos, includes, compostos) em um JAR
  • Embalagem de modelos JSF facelets

Eu estava procurando informações sobre o mesmo assunto e encontrei este link: How-to: Modular Java EE Applications com CDI e PrettyFaces, que funcionou muito bem para mim.

A propósito … você pode evitar implementar seu próprio resolvedor de resources quando estiver usando solda de junit (atualmente sendo integrado ao deltapike do apache) que é uma biblioteca realmente útil que complementa o CDI (seu modelo de componente típico do Java EE 6)

Eu também experimentei modularidade em aplicações jsf. Basicamente eu construí uma interface de template com uma barra de ferramentas que é preenchida com botões fornecidos por cada módulo. Normalmente, você fará isso fornecendo uma lista de seqüências de caracteres como um object nomeado:

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

Observe como cada um dos botões pode vir de um módulo diferente do aplicativo jsf. A interface do modelo contém um painel onde

você pode usá-lo na sua marcação da seguinte maneira (por sua conta e risco;)):

 .... xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:ui="http://java.sun.com/jsf/facelets" ....           

Esta foi a barra de ferramentas e o painel de conteúdo.

um simples botão ou definição de visualização pode ter esta aparência:

    

permite nomear este artefato view1.xhtml

Quando este botão é pressionado (o que não aciona um postback usando o actionListener, queremos recarregar o conteúdo usando ajax) o switchContentMethod no seu controlador pode alterar a string retornada por getContentPath:

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

agora você pode alterar a visualização exibida no painel usando o botão na barra de menu que oferece navegação sem recarregar a página.

Alguns conselhos (ou ‘o que aprendi’):

  1. Você pode querer escolher um escopo grande para o método getTopMenuItems
  2. Não aninhe a tag ui: include. Infelizmente isso não é possível (por exemplo, seu view1.xhtml não pode include outra composição). Eu realmente gostaria que algo assim fosse possível, já que você pode construir visualizações realmente modulares do jsf com isso, como portlets apenas sem os portlets .. = D
  3. fazendo ui: include em componentes de contêiner como tabviews também se mostra problemático.
  4. geralmente não é aconselhável misturar JSTL (c: forEach) e JSF. Ainda assim, acho que esta é a única maneira de trabalhar como ui: a repetição é avaliada muito tarde, por exemplo, seu conteúdo incluído não aparece.