Injeção de Dependência em Taglib + VRaptor

Como faço para injetar um repositório dentro de uma taglib?

A taglib deve ter um construtor default para funcionar, como eu faço para injetar uma dependência nela?

Estou usando VRaptor…

acho que não dá pra fazer a injeção automática, pq é a api do jstl que controla a criação das suas tags…

mas como o spring coloca as suas classes instanciadas como atributos do request acho que vc pode fazer o seguinte:

public class SuaTag extends TagSupport {

     @Override
     public void doStartTag() { //ou algo do tipo
          BlahRepository repository = (BlahRepository) getValue("blahRepository");

          //e continue daqui
     }

}

isso deve funcionar se o BlahRepository foi instanciado na requisição atual…

de qqer forma, fazer esse tipo de coisa que vc quer pula uma camada… as jsps deveriam mostrar dados só: é a camada View, não deveria mexer com repositorios e coisas do tipo

http://www.java2s.com/Tutorial/Java/0360__JSP/CustomTagToGetParameterFromPageContext.htm
algo assim

[quote=Lucas Cavalcanti]http://www.java2s.com/Tutorial/Java/0360__JSP/CustomTagToGetParameterFromPageContext.htm
algo assim[/quote]

Lucas obrigado pela resposta.

Vou explicar o que estou querendo fazer e talvez você me de uma sugestão melhor.

Esta custom tag que eu estou tentando injetar um repositório é responsável por criar um menu da aplicação de acordo com as permissões do usuário. Você vê uma forma melhor de fazer isto sem ser acessando o repositório diretamente?

Abraço

se o usuário estiver na sessão (ou no request), vc pode pegar o próprio usuário (supondo que o usuário tem as permissões dentro dele)…

daí vc pegaria o usuário por aquele pageContext e só perguntaria… se tiver getter pra role, vc nem precisa que seja uma classe de tag, pode ser um tagfile que é bem mais fácil pra gerar html:

<c:if test="${usuario.role eq 'ADMIN'}">
    parte do menu só do admin
</c:if>
<c:if test="${usuario.role eq 'TODO_PODEROSO'}">
    parte do menu só o todo poderoso acessa
</c:if>
parte do menu que todo mundo acessa

[quote=Lucas Cavalcanti]se o usuário estiver na sessão (ou no request), vc pode pegar o próprio usuário (supondo que o usuário tem as permissões dentro dele)…

daí vc pegaria o usuário por aquele pageContext e só perguntaria… se tiver getter pra role, vc nem precisa que seja uma classe de tag, pode ser um tagfile que é bem mais fácil pra gerar html:

<c:if test="${usuario.role eq 'ADMIN'}">
    parte do menu só do admin
</c:if>
<c:if test="${usuario.role eq 'TODO_PODEROSO'}">
    parte do menu só o todo poderoso acessa
</c:if>
parte do menu que todo mundo acessa

[/quote]

Acho que não me expliquei direito Lucas.

A estrutura que está é assim, tenho uma custom tag que diz qual o menu principal que esta página pertence.
ex:

<html>
<head>
</head>
<body>
<body>
		<menu:parent parentMenu="expenseType"/>
</body>
</html>

Estou dizendo que esta jsp pertence ao menu “expenseType”. Nesta custom tag eu procuro um menu pelo nome “expenseType” se encontro seto ele no page context se não lanço uma exception falando que não existe este menu. É nesta custom tag que eu preciso do repositório, para buscar pelo nome.

Tenho outra custom tag que lista os menus e submenus da página, mas nesta eu não preciso de uma referência para o repositório porque eu tenho um usuário setado na sessão para listar os menus e o menu principal setado no page context para listar os submenus, e neles consigo pegar os menus e submenus dele através de relacionamentos lazy do hibernate.

Nesta situação acho que tagfile não ajudaria.

Valeu

vc guarda os menus possíveis no banco?

Isso, tudo configurável no banco

bom, a solução que eu faria é o seguinte:

-crie um MenuInterceptor que, baseado no usuário atual, pega os menus que ele tem acesso e joga num atributo:

result.include("menus", menusAcessiveis);

-na sua tag, vc pergunta se o menu atual está nessa lista de menus

Desculpe a sinceridade, mas isso que você quer fazer é uma gambiarra! Taglib não deve acessar repositórios, ainda mais para ficar pesquisando no repositório a cada requisição.

Lembre-se que a taglib é um view-helper, e views não devem acessar infraestrutura e repositórios. Elas, assim como a view, são responsável apenas por mostrar os dados que já vem do controller.

Outra coisa que você precisa ter em mente é que um usuário faz muitas requisições, e usando dessa forma de acessar o repositório a toda hora você terá um overhead grande, afinal a cada requisição você precisa remontar o menu. Quantas vezes seu menu muda? Será que não é melhor fazer um cache disso?

Eu normalmente carrego todos os dados que preciso do menu no momento da autenticação do usuário e guardo na http-session. E a taglib responsável pelo menu sempre busca do escopo session os dados do menu.

Acho ser a forma mais elegante a fazer.

Não dá mesmo. O ciclo de vida de uma taglib, mesmo sendo gerenciado pelo container, não suporta injeção de dependencias.

[quote=garcia-jj]Desculpe a sinceridade, mas isso que você quer fazer é uma gambiarra! Taglib não deve acessar repositórios, ainda mais para ficar pesquisando no repositório a cada requisição.

Lembre-se que a taglib é um view-helper, e views não devem acessar infraestrutura e repositórios. Elas, assim como a view, são responsável apenas por mostrar os dados que já vem do controller.

Outra coisa que você precisa ter em mente é que um usuário faz muitas requisições, e usando dessa forma de acessar o repositório a toda hora você terá um overhead grande, afinal a cada requisição você precisa remontar o menu. Quantas vezes seu menu muda? Será que não é melhor fazer um cache disso?

Eu normalmente carrego todos os dados que preciso do menu no momento da autenticação do usuário e guardo na http-session. E a taglib responsável pelo menu sempre busca do escopo session os dados do menu.

Acho ser a forma mais elegante a fazer.

Não dá mesmo. O ciclo de vida de uma taglib, mesmo sendo gerenciado pelo container, não suporta injeção de dependencias.[/quote]

Eu só gostaria de acessar o repositório diretamente para verificar se o main menu que está sendo setado para a página realmente existe. Para listar o menu eu utilizo o objeto usuário que está na sessão e o main manu que foi setado no contexto de página.
Eu posso fazer um cache do hibernate e é uma busca em uma tabela com poucos dados e com indice, então não é uma consulta custosa.

Já trabalhei em sistemas que funcionavam assim, eu creio que é uma boa solução porque quando há alterações nas permissões do usuário (e elas ocorrem porque eu já vi mudar em sistemas em produção) isso é refletido na mesma hora no sistema.

Posso estar errado, mas pelo que eu li repositório é parte do dominio, nós acessamos o domínio na nossa camada de visualização. Eu não estou buscando de um banco de dados, pelo menos não diretamente. Estou buscando de um repositório, que pertence ao domínio, da onde vai vim os dados dele pouco me interessa. Eu não preciso carregar todo o menu de uma só vez para fazer cache.

[quote=Lucas Cavalcanti]bom, a solução que eu faria é o seguinte:

-crie um MenuInterceptor que, baseado no usuário atual, pega os menus que ele tem acesso e joga num atributo:

result.include("menus", menusAcessiveis);

-na sua tag, vc pergunta se o menu atual está nessa lista de menus[/quote]

Oi Lucas, achei legal esta solução. Vou tentar aplicar ela aqui e ver como fica, mas acho que vai ficar legal, assim não precisarei de uma referência do repositório dentro da custom tag.

Valeu pela ajuda Lucas e Garcia

Pessoal to pegando o bonde andando, mais tenho exatamente o mesmo problema!

Testei e funcionou a solução do Lucas, mas gostaria de deixar mais enxuto meu JSP e taglibs próprias (is), o que eu já tenha funcionando:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib uri="http://www.internetsistemas.com.br/tags-html"
	prefix="is"%>

<is:html>
<is:header></is:header>
<is:body titulo="Login">
	<form action="<c:url value="/home/login"/>" method="post">
		<fieldset>
			<label for="login">Login:</label>
			<input type="text" name="login" />
	
			<label for="senha" class="sep">Senha:</label>
			<input type="password" name="senha" />
	
			<button type="submit" " id="submit">Logar</button>
		</fieldset>
	</form>
</is:body>
</is:html>

Porem dentro da minha taglib (is) gostaria de deixar a criação de menu dinâmica apenas para usuários logados, ou seja, não passando como um parâmetro: <is:body titulo=“Login” menu="${menu}">, por exemplo.

Pergunta final, tem alguma maneira de eu pegar o result.include() do interceptor do vraptor e utilizar na TAGLIB (pageContext)?

O legal que eu poderia extrapolar e incluir (result.include()) o objeto de usuário logado (usuarioSession), onde contem todo o menu criado no momento do login. Ficaria show! Imagino

É a melhor maneira de fazer? Visto que concordo com o Garcia de que view não deve acessar camada nenhuma (foi isso que entendi :)).

Abraços a todos!

se vc consegue usar ${menu} na sua jsp, vc tb consegue usar ${menu} nas tags…

se vc deu um result.include(“bolinha”, bolinha) vc consegue acessar por ${bolinha} tanto na jsp qto na tag