<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title><![CDATA[Mentawai Recipes - Latest forum topics]]></title>
		<link>http://recipes.mentaframework.org/recentTopics/list.page</link>
		<description><![CDATA[The newest discussed topics in the entire board]]></description>
		<generator>JForum - http://www.jforum.net</generator>
			<item>
				<title>Projeto MentaBlank - Ponto de partida para qualquer aplicação utilizando o Mentawai</title>
				<description><![CDATA[ Para agilizar as coisas para quem está começando com o Mentawai, preparamos um projeto completo com as principais funcionalidades do framework. Trata-se de uma aplicação web onde você pode realizar um cadastro, se logar, editar esse cadastro e dar logout. <br /> <br /> Essa aplicação pode e deve ser utilizada como ponto de partida para outras aplicações web.<br /> <br /> Os seguintes conceitos são utilizados:<br /> <br /> :arrow: Validação<br /> :arrow: Autenticação<br /> :arrow: Redirect after Login<br /> :arrow: IoC<br /> :arrow: Auto-Wiring<br /> :arrow: Pool de Conexões<br /> :arrow: Tratamento de Exceções<br /> :arrow: ORM (Mapeamento de Beans no BD)<br /> :arrow: Diversas tags do Mentawai (mtw:requiresAuthentication, mtw:bean, etc.)<br /> <br /> <br /> Baixe o projeto aqui: http://www.mentaframework.org/files/MentaBlank.zip<br /> <br /> Abaixa descreveremos um passo a passo de como colocar esse projeto para rodar dentro do Eclipse, assumindo que você possui o [url=http://tomcat.apache.org]Tomcat[/url] e o [url=http://www.eclipsetotale.com/tomcatPlugin.html]Sysdeo[/url] instalado no seu ambiente de desenvolvimento.<br /> <br /> Selecione a opção do menu File -&gt; Import. Escolha a opção &quot;Existing Projects into Workspace&quot;. Clique em &quot;Next&quot;.<br /> <br /> [img]http://www.mentaframework.org/images/MentaBlank/1.JPG[/img]<br /> <br /> <br /> <br /> Selecione a opção "Select archive file", clique em "Browse" e selecione o arquivo MentaBlank.zip que você baixou. Você deverá visualizar o projeto MentaBlank selecionado na caixa de texto logo abaixo.<br /> <br /> [img]http://www.mentaframework.org/images/MentaBlank/2.JPG[/img]<br /> <br /> <br /> <br /> Clique em "Finish" e um novo projeto "MentaBlank" será criado no seu eclipse. Antes de colocarmos ele para rodar no Tomcat precisamos criar um database para ele. O MentaBlank utiliza o MySQL, mas é bastante fácil alterá-lo para qualquer BD de sua preferência.<br /> <br /> Vá no diretório WEB-INF/db e lá você encontrará dois arquivos:<br /> <br /> :arrow: MentaBlank.sql com o script SQL para gerar a base de dados da aplicação<br /> :arrow: grant.txt com o sql para criar o usuário "MentaBlank" no MySQL<br /> <br /> Crie um database "MentaBlank", rode os arquivos acima e o seu banco-de-dados estará pronto para receber a nossa aplicação.<br /> <br /> Repare que no [i]AppManager.java[/i], a configuração do Pool de Conexões é feita nas seguintes linhas:<br /> [code]<br /> String driver = "com.mysql.jdbc.Driver";<br /> String url = "jdbc:mysql://localhost/MentaBlank?autoReconnect=true";<br /> String user = "MentaBlank";<br /> String pass = "MentaBlank";<br /> <br /> this.connHandler = new C3P0ConnectionHandler(driver, url, user, pass);<br /> [/code]<br /> <br /> Agora para testar sua aplicação clique em Project -&gt; Properties. Selecione a opção &quot;Tomcat&quot; e faça as seguintes alterações abaixo:<br /> <br /> [img]http://www.mentaframework.org/images/MentaBlank/3.JPG[/img]<br /> <br /> <br /> <br /> Clique em "Ok", inicie o seu Tomcat e acesse a URL http://localhost:8080/MentaBlank/ para testar a aplicação.<br /> <br /> Obs: Versão para Eclipse WTP pode ser baixada em: http://www.mentaframework.org/files/MentaBlankWTP.zip (por Hélio Frota)<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/73/79.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/73/79.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:48:37]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Especificação da Aplicação de Referência</title>
				<description><![CDATA[ [size=18][color=blue][b]Especificação:[/b][/color][/size]<br /> <br /> A aplicação de referência é bastante simples:<br /> <br /> :arrow: Uma tela de login, uma tela de cadastro, uma página principal de boas-vindas e uma tela para alterar o seu cadastro.<br /> <br /> :arrow: No ato do cadastro, o usuário escolherá um grupo (Guest, Admin ou Master). Esse grupo poderá ser alterado na tela de alteração de cadastro.<br /> <br /> :arrow: Um usuário do grupo Guest não poderá alterar o seu cadastro.<br /> <br /> :arrow: No ato do cadastro, o usuário escolherá um idioma (Inglês ou Português). Esse idioma poderá ser alterado na tela de alteração de cadastro.<br /> <br /> :arrow: A aplicação será apresentada no idioma escolhido pelo usuário.<br /> <br /> :arrow: Ao se cadastrar, o usuário receberá um email com os dados da sua conta. Esse email deve estar no idioma escolhido pelo usuário.<br /> <br /> :arrow: O username deve ser único por usuário, ou seja, dois usuários diferentes não podem possuir o mesmo username.<br /> <br /> [size=18][color=blue][b]Aplicação rodando:[/b][/color][/size]<br /> <br /> <a class="snap_shots" href="http://menta.seducaotecnologica.com.br/" target="_blank" rel="nofollow">http://menta.seducaotecnologica.com.br/</a><br /> <br /> [size=18][color=blue][b]Telas:[/b][/color][/size]<br /> <br /> [color=blue]- Tela inicial para o login:[/color]<br /> <br /> [img]http://saoj-la.dyndns.org/downloads/menta/images/login.png[/img]<br /> <br /> [color=blue]- Tela de cadastro:[/color]<br /> <br /> [img]http://saoj-la.dyndns.org/downloads/menta/images/registration.png[/img]<br /> <br /> [color=blue]- Tela de boas-vindas:[/color]<br /> <br /> [img]http://saoj-la.dyndns.org/downloads/menta/images/welcome.png[/img]<br /> <br /> [color=blue]- Tela de boas-vindas para o Guest:[/color] (sem possibilidade de ir para alteração de cadastro)<br /> <br /> [img]http://saoj-la.dyndns.org/downloads/menta/images/welcome-guest.png[/img]<br /> <br /> [color=blue]- Tela para alteração de cadastro:[/color]<br /> <br /> [img]http://saoj-la.dyndns.org/downloads/menta/images/edit.png[/img]<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/72/78.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/72/78.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:47:48]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Show don't tell</title>
				<description><![CDATA[ Ao invés de começar documentando todas as funcionalidades do Mentawai, que são muitas, optamos por disponibilizar uma aplicação completa como referência. Dessa maneira você pode olhar o código, ver exemplos de várias funcionalidades e decidir por si só a respeito da praticidade e simplicidade do Mentawai em relação aos outros frameworks.<br /> <br /> As características particulares do Mentawai, que o diferenciam de outros frameworks, são:<br /> <br /> :arrow: Full-stack (completo e auto-suficiente, não necessitando de outros frameworks)<br /> :arrow: [url=http://en.wikipedia.org/wiki/Kiss_principle]KISS principle[/url] (se você não sabe ou não consegue fazer algo a culpa é do framework, não sua)<br /> :arrow: Configuração Programática (sem XML ou annotations)<br /> <br /> A aplicação de referência pode ser baixada do SVN:<br /> <br /> [color=blue][b]svn co <a class="snap_shots"  target="_blank" rel="nofollow">svn://saoj-la.dyndns.org/menta/trunk</a> Menta[/b][/color]<br /> <br /> Você também pode vê-la rodando aqui: <a class="snap_shots" href="http://menta.seducaotecnologica.com.br/" target="_blank" rel="nofollow">http://menta.seducaotecnologica.com.br/</a><br /> <br /> Clique [url=http://forum.mentaframework.org/posts/list/2405.page]aqui[/url] para as instruções de como importar esse projeto para dentro do seu Eclipse.<br /> <br /> Poderíamos utilizar o bom marketing para convence-lo de que o Mentawai é bom, mas ao invés disso estaremos incentivando a política do [color=red][b]SHOW DON'T TELL[/b][/color] ([i]mostre não fale[/i]) com um comparativo de frameworks através da aplicação de referência. Essa política funciona assim:<br /> <br /> :arrow: Estarei disponibilizando vários repositórios de SVN, um para cada framework como VRaptor, Struts, Spring MVC, etc.<br /> <br /> :arrow: Uma pessoa com experiência no framework X pode solicitar uma senha de committer para o repositório do framework X.<br /> <br /> :arrow: Feito isso ela pode implementar a aplicação de referência com o framework X de forma que possamos compará-la às outras implementação com diferentes frameworks.<br /> <br /> :arrow: Essaa implementações serão disponibilizadas lado-a-lado com a implementação de referência do Mentawai, ou seja, você poderá decidir por conta própria o framework de sua preferência.<br /> <br /> A especificação completa da aplicação de referência pode ser consultada aqui: <a class="snap_shots" href="http://forum.mentaframework.org/posts/list/0/2406.page" target="_blank" rel="nofollow">http://forum.mentaframework.org/posts/list/0/2406.page</a><br /> <br /> Abaixo listamos as funcionalidades do Mentawai exemplificadas na aplicação de referência:<br /> <br /> [color=blue][b]1) Autenticação[/b][/color]<br /> <br /> :arrow: Filtro de autenticação para bloquear/permitir o acesso às actions<br /> :arrow: Tags de autenticação para bloquear/permitir os acesso às páginas (JSP, Velocity, etc.)<br /> :arrow: [i]Redirect after login[/i], ou seja, quando um usuário acessa uma página sem estar logado, ele é redirecionado para a página de login. Após um login bem sucedido ele é novamente redirecionado para a página que ele inicialmente tentou acessar.<br /> <br /> [color=blue][b]2) Autorização[/b][/color]<br /> <br /> :arrow: Filtro de autorização para bloquear/permitir o acesso às actions<br /> :arrow: Tags de autorização para bloquear/permitir o acesso às páginas (JSP, Velocity, etc.)<br /> :arrow: Tags de autorização para exibir/remover partes de uma página<br /> :arrow: Setar os grupos que um usuário logado pertence (a autorização ou não é concedida de acordo com os grupos do usuário logado)<br /> <br /> [color=blue][b]3) Internacionalização[/b][/color] (i18n)<br /> <br /> :arrow: Arquivos de i18n ficam dentro do diretório i18n. Os nomes são master_pt_BR.i18n, master_en_US.i18n, etc. Um arquivo (com possibilidade de prefixos para as chaves) para tudo, ao invés de vários arquivos espalhados pela aplicação, como um por action por exemplo.<br /> :arrow: Para mensagens que vieram de dentro das actions (mensagens dinâmicas de successo ou erro por exemplo, validação, etc.)<br /> :arrow: Para textos dentro do JSP, com tags aceitando prefixos e valores dinâmicos como por exemplo Hello $1.<br /> :arrow: Reload automático quando os arquivos de propriedades (i18n) são alterados. Você não quer ter que re-iniciar a sua aplicação porque mudou "Olá" para "Oi".<br /> :arrow: Tradução padrão quando uma chave não é encontrada (para Produção).<br /> :arrow: Exibição de texto com erro (! en_US.hello !) quando uma chave não é encontrada (para QA).<br /> :arrow: Localização para imagens através de uma tag para imprimir o sub-diretório do locale.<br /> <br /> [color=blue][b]4) IoC[/b][/color]<br /> <br /> :arrow: IoC completo, integrado com o framework, sem a necessidade de Spring. Mas quem quiser usar Spring também pode.<br /> :arrow: Configuração programática para IoC ao invés de usar um milhão de XMLs. Perguntem para o Google porque eles resolveram lançar o Guice.<br /> <br /> [color=blue][b]5) Mensagens dinâmicas vindo das actions[/b][/color]<br /> <br /> :arrow: "Sua conta foi atualizada com sucess"<br /> :arrow: Integração limpa e fácil com o sistema de i18n, ou seja, essas mensagens virão do arquivo master i18n.<br /> <br /> [color=blue][b]6) Lista de dados estáticos[/b][/color]<br /> <br /> :arrow: É bastante recorrente a necessidade de ter combos com listas estáticas, como grupos, idiomas, países, etc.<br /> :arrow: Eles precisam ser igualmente internacionalizados<br /> :arrow: Tags para facilmente exibir esses combos em um formulário HTML<br /> :arrow: Tags para facilmente exibir um valor (localizado) para um determinado id.<br /> <br /> [color=blue][b]7) Filtros[/b][/color]<br /> <br /> :arrow: Não estamos falando aqui de filtros de Servlet, mas de filtros do framework, como os interceptors do Struts.<br /> :arrow: Filtros precisam ser simples para que você possa fazer os seus e fáceis de usar, para que você possa utilizar os que o framework oferece.<br /> <br /> [color=blue][b]8 ) Validação[/b][/color]<br /> <br /> :arrow: Integrada com o i18n<br /> :arrow: Tags fáceis para mostrar os erros nas páginas<br /> :arrow: Jeito fácil de validar uma action (implementando uma interface ou filtro por exemplo)<br /> <br /> [color=blue][b]9) Jeito fácil de testar as actions[/b][/color]<br /> <br /> :arrow: JUnit para as actions sem complexidades, mocks, etc.<br /> <br /> [color=blue][b]10) Tags pra a view[/b][/color]<br /> <br /> :arrow: Diversas tags para facilitar a sua vida na view, muito melhores do que as genéricas da JSTL.<br /> :arrow: Facilidade para criar suas próprias tags, sem qualquer complexidade ou enrolação (abstraindo a bagunça inicial da api de JSP)<br /> :arrow: Tags para paginação e muitas outras. Ou você faz a paginação na mão com código no JSP?<br /> <br /> [color=blue][b]11) Enviando email[/b][/color]<br /> <br /> :arrow: Tem que ser integrado com o i18n, ou seja, cada usuário recebe um email no seu idioma. Os emails ficam separados dentro do diretório /letters, com um sub-diretório para cada locale.<br /> :arrow: Tem que suportar algum tipo de template, porque você precisa carregar um email e fazer algumas substituições no corpo da mensagem, como username, password, etc.<br /> :arrow: Tem que corretamente suportar charsets, caso contrário o usuário receberá lixo para os caracteres acentuados.<br /> :arrow: Tem que suportar emails em plain/text e também em HTML.<br /> :arrow: Precisa suportar defaults para hostname, from, authentication, etc. para que você só precise configurar isso uma vez de acordo com o ambiente (produção, QA, dev, etc.)<br /> :arrow: Precisa suportar o desativamento dos envios de email para quando você está rodando os unit tests. De maneira fácil e na configuração! (Não vai sair colocando IF em tudo)<br /> :arrow: Tem que suportar envio assíncrono, ou seja, na maioria das vezes você não quer bloquear a action enquanto o email está sendo enviado.<br /> :arrow: Tem que suportar SSL se você quiser utilizar o SMTP do GMAIL.<br /> :arrow: E não se esqueça do título do email, que precisa também ser internacionalizado e suportar templates.<br /> <br /> [color=blue][b]12) Configurações por ambiente[/b][/color]<br /> <br /> :arrow: As configurações estáticas e textuais, como dados de conexão com o banco, smtp, hibernate, logging, etc. precisam ser carregadas de um arquivo properties. A aplicação deve suportar um arquivo properties por ambiente, além de um default que pode ser sobrescrito pelo mais específico do ambiente.<br /> <br /> [color=blue][b]13) Suporte a dois tipos de persistência[/b][/color] (opcional)<br /> <br /> :arrow: a aplicação pode suportar JDBC ou Hibernate, ou seja, ela implementa uma versão dos DAOs com JDBC e outra com HIBERNATE. De acordo com uma variável de ambiente ("persistency") ela decide quais implementações do DAO ela vai utilizar. A flexibilidade de IoC demonstrada na prática.<br /> <br /> <br /> <br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/71/77.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/71/77.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:47:21]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Instruções para instalar a aplicação de referência</title>
				<description><![CDATA[ [color=blue][b]1) Importando para o Eclipse:[/b][/color]<br /> <br /> A aplicação de referência utiliza o Maven2. Com o maven é bastante fácil importar um projeto Java qualquer para dentro do Eclipse. Siga os passos abaixo:<br /> <br /> :arrow: Caso ainda não tenha, instale o SVN na sua máquina: <a class="snap_shots" href="http://subversion.tigris.org/" target="_blank" rel="nofollow">http://subversion.tigris.org/</a><br /> <br /> :arrow: Caso ainda não tenha, instale o Maven 2.x.x na sua máquina: <a class="snap_shots" href="http://maven.apache.org" target="_blank" rel="nofollow">http://maven.apache.org</a><br /> <br /> :arrow: Utilize o comando abaixo para fazer o checkout da aplicação de referência. O diretório 'Menta' será criado com a aplicação.<br /> <br /> [color=darkblue][b]svn co <a class="snap_shots"  target="_blank" rel="nofollow">svn://saoj-la.dyndns.org/menta/trunk</a> Menta[/b][/color]<br /> <br /> :arrow: Vá para dentro do diretório Menta e execute 'mvn clean install'. Os testes deverão ser executados e o WAR da aplicação gerado.<br /> <br /> :arrow: Ainda dentro do diretório Menta, execute 'mvn eclipse:eclipse -Dwtpversion=2.0'. Feito isso o seu projeto está pronto para ser importado para dentro do Eclipse.<br /> <br /> :arrow: Utilize a função [i]Import...[/i] do Eclipse para importar o diretório Menta. Um novo projeto será criado no Eclipse.<br /> <br /> OBS: Para os testes unitários o banco H2 é utilizado, logo não é necessário instalar ou configurar nenhum banco de dados.<br /> <br /> [b][color=blue]2) Configurando o banco de dados:[/color][/b] (para rodar a aplicação no TOMCAT)<br /> <br /> :arrow: Caso ainda não tenha, instale o MYSQL na sua máquina: <a class="snap_shots" href="http://www.mysql.org" target="_blank" rel="nofollow">http://www.mysql.org</a><br /> <br /> :arrow: Crie um database com o nome 'Menta'<br /> <br /> :arrow: Conceda permissões para o usuário 'menta' acessá-lo do localhost:<br /> <br /> [b][color=darkblue]grant all privileges on Menta.* to 'menta'@'localhost' identified by 'menta';[/color][/b]<br /> <br /> [b][color=blue]3) Inicializando o banco de dados:[/color][/b]<br /> <br /> Execute o script 'WEB-INF/db/menta.sql' para a inicialização do banco de dados, tomando cuidado com o charset que deve ser UTF-8:<br /> <br /> :arrow: Vá para o diretório 'WEB-INF/db' onde está o script menta.sql<br /> <br /> :arrow: Acesse o seu banco de dados utilizando o mysql client:<br /> <br /> [b][color=darkblue]mysql -u menta -p Menta[/color][/b]<br /> <br /> :arrow: Ative o charset UTF-8:<br /> <br /> [b][color=darkblue]SET NAMES utf8;[/color][/b]<br /> <br /> :arrow: Execute o script menta.sql:<br /> <br /> [b][color=darkblue]source menta.sql;[/color][/b]<br /> <br /> [color=blue][b]4) Rodando no Tomcat:[/b][/color]<br /> <br /> Para executar a aplicação você pode utilizar o SYSDEO (plugin do Tomcat para Eclipse) ou o WTP (integração do Eclipse com o Tomcat). Caso utilize o SYSDEO você precisará configurá-lo para reconhecer um projeto Maven. Siga os passos abaixo:<br /> <br /> :arrow: Vá em propriedades do seu projeto e selecione Tomcat<br /> <br /> :arrow: Coloque 'src/main/webapp' como "Subdirectory to set as web application root (optional)"<br /> <br /> :arrow: Ative o DevLoader e selecione os jars que deverão ser utilizados pelo Tomcat. Veja imagem no final desse post.<br /> <br /> [color=blue][b]5) Deployando o WAR em um Tomcat standalone:[/b][/color]<br /> <br /> :arrow: Copie o menta.war para dentro do webapps do seu Tomcat.<br /> <br /> :arrow: Restarte o seu tomcat<br /> <br /> :arrow: Um diretório menta deverá ser criado no webapps com sua aplicação.<br /> <br /> [color=blue][b]6) Problemas de permissão com o Tomcat:[/b][/color]<br /> <br /> A aplicação utiliza o método System.getenv() para acessar uma variável de ambiente. É possível que o Tomcat não permita essa operação devido ao seu SecurityManager. Isso ocorreu comigo no tomcat6 rodando em um Ubuntu Server, mas não no meu tomcat6 rodando no Mac. Para resolver isso você pode desativar o SecurityManager assim:<br /> <br /> :arrow: Abra o arquivo /etc/default/tomcat6<br /> <br /> :arrow: Adicione a seguinte linha:<br /> <br /> [color=darkblue][b]TOMCAT6_SECURITY=no[/b][/color]<br /> <br /> :arrow: Reinicie o seu Tomcat<br /> <br /> OBS: Você também pode tentar fazer um ajuste fino no SecurityManager do Tomcat dentro do diretório 'policy-d'.<br /> <br /> [i] Ativando o DevLoader para o Sysdeo: [/i]<br /> [img]http://saoj-la.dyndns.org/downloads/menta/images/devloader.png[/img]<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/70/76.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/70/76.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:46:51]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Comparativo entre diversos frameworks</title>
				<description><![CDATA[ Simon Brown postou no seu blog uma aplicação simples com o objetivo de comparar vários frameworks web, ou seja, de avaliar como cada um se comportaria na hora de implementar essa aplicação simples.<br /> <br /> Link do blog:<br /> <br /> <a class="snap_shots" href="http://weblogs.java.net/blog/simongbrown/archive/2005/11/comparing_webap.html" target="_blank" rel="nofollow">http://weblogs.java.net/blog/simongbrown/archive/2005/11/comparing_webap.html</a><br /> <br /> Implementação com o [b]Mentawai[/b]:<br /> <br /> <a class="snap_shots" href="http://www.mentaframework.org/wp/index.php" target="_blank" rel="nofollow">http://www.mentaframework.org/wp/index.php</a><br /> <br /> Implementação com o [b]Rife[/b]:<br /> <br /> <a class="snap_shots" href="http://rifers.org/blogs/gbevin/2006/3/16/comparing_web_frameworks_rife" target="_blank" rel="nofollow">http://rifers.org/blogs/gbevin/2006/3/16/comparing_web_frameworks_rife</a><br /> <br /> Implementação com o [b]Struts1[/b]:<br /> <br /> <a class="snap_shots" href="http://weblogs.java.net/blog/simongbrown/archive/2006/01/comparing_webap_7.html" target="_blank" rel="nofollow">http://weblogs.java.net/blog/simongbrown/archive/2006/01/comparing_webap_7.html</a><br /> <br /> Implementação com o [b]Wicket[/b]:<br /> <br /> <a class="snap_shots" href="http://weblogs.java.net/blog/simongbrown/archive/2006/03/comparing_webap_8.html" target="_blank" rel="nofollow">http://weblogs.java.net/blog/simongbrown/archive/2006/03/comparing_webap_8.html</a><br /> <br /> Implementação com o [b]Stripes[/b]:<br /> <br /> <a class="snap_shots" href="http://weblogs.java.net/blog/simongbrown/archive/2006/03/comparing_webap_9.html" target="_blank" rel="nofollow">http://weblogs.java.net/blog/simongbrown/archive/2006/03/comparing_webap_9.html</a><br /> <br /> Implementação com o [b]WebWork[/b]:<br /> <br /> <a class="snap_shots" href="http://weblogs.java.net/blog/simongbrown/archive/2006/03/comparing_webap_10.html" target="_blank" rel="nofollow">http://weblogs.java.net/blog/simongbrown/archive/2006/03/comparing_webap_10.html</a><br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/69/75.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/69/75.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:45:25]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Mentawai x Seam</title>
				<description><![CDATA[ Esse artigo tem como intuito analisar a mesma aplicação web implementada por dois frameworks bastante diferentes: Mentawai e Seam.<br /> <br /> A implementação com o Seam pode ser analisada e baixada aqui:<br /> http://www.infoq.com/articles/jboss-seam<br /> <br /> A implementação com o Mentawai pode ser baixada aqui: (Utilizamos o [url="http://www.h2database.com/html/frame.html"]banco de dados embarcado H2[/url] de forma que vc não precisa se preocupar em criar/configurar o seu próprio banco de dados para esse exemplo)<br /> http://www.mentaframework.org/files/Menta_versus_Seam.zip<br /> <br /> Alguns pontos que vc deve observar em relação a implementação com o Mentawai:<br /> <br />  :arrow: Foi difícil configurar um pool de conexões? Duas linhas de código e temos um pool de conexões configurado sem qualquer enrolação.<br /> <br />  :arrow: Repare como a arquitetura da aplicação com o Mentawai fica bem dividida e organizada. Temos nossas actions, entities, repositórios (ou DAOs), implementações para os nossos repositórios (ou DAOs) e nossos serviços onde as regras do negócio serão utilizadas.<br /> <br />  :arrow: Repare que vc utilizou Inversão de Controle de uma maneira bem simples e fácil, sem precisar de Spring ou outro framework. No ApplicationManager estamos dizendo que o nosso UserRepository será do tipo H2UserRepository. Se amanhã quizermos utilizar um OracleUserRepository, tudo que temos que fazer é mudar a configuração de IoC (1 linha).<br /> <br />  :arrow: Repare que vc utilizou Auto-Wiring de uma maneira bem simples e fácil, sem precisar de Spring ou outro framework. No ApplicationManager estamos dizendo que tudo que precisar de uma Connection irá receber automaticamente uma Connection. No nosso exemplo o H2UserRepository vai receber essa connection via auto-wiring.<br /> <br />  :arrow: Repare que as configurações da sua aplicação ficam centralizadas em um único lugar e que a linguagem utilizada na configuração é o Java ([url="http://www.mentaframework.org/configuration.jsp"]poderia ser outras linguagens também[/url]).<br /> <br />  :arrow: Repare que para algumas configurações bem burras e estáticas podemos utilizar também o arquivo properties default chamado AppManager.properties que deve estar no diretório WEB-INF. ([url="http://forum.mentaframework.org/posts/list/1497.page"]mais info sobre isso aqui[/url])<br /> <br />  :arrow: Repare como foi fácil persistir o objeto User no banco de dados utilizando o MentaBean. Repare que a sua entidade e o seu modelo de negócios não receberam qualquer tipo de anotação, em outras palavras, estão totalmente desacopladas do framework web.<br /> <br />  :arrow: Repare que vc não precisou escrever uma linha de SQL para persistir o seu objeto User no banco de dados e que se amanhã vc quiser mudar o seu mecanismo de persistencia para Hibernate, IBatis, JPA, Arquivos Texto, Lista em Memória, etc. tudo que vc tem que fazer é implementar uma nova versão do UserRepository e reconfigurar o seu IoC.<br /> <br />  :arrow: Repare como a sua action [i]UserAction[/i] é bem simples e como vc pode validar campos, obter objetos (Pojos) populados com os dados do seu formulário, retornar facilmente vários resultados, criar várias inner actions, etc.<br /> <br />  :arrow: Repare que na camada de apresentação o Mentawai te oferece diversas tags simples e poderosas como mtw:outError, mtw:list, mtw:loop, mtw:isEmpty, etc. Nada te impede de usar JSTL ou EL, mas as tags do Mentawai são bem mais simples, poderosas e com menos verbosidade pois se encaixam perfeitamente ao framework, enquanto as JSTL são genéricas para todos os frameworks. (Migre o hello.jsp para JSTL e analise por si mesmo!)<br /> <br />  :arrow: Se amanhã eu quiser colocar a minha aplicação num ambiente distribuído (pouco provável), tudo que eu tenho que fazer é transformar os meus [i]services[/i] em web services. ([url="http://xfire.codehaus.org/"]recomendamos xFire para isso[/url]) Partir do pressuposto que toda aplicação web vai ser integrada com EJB como o Seam faz não é legal. Dá para entender porque ele faz isso: JBoss<br /> <br /> Estrutura da Aplicação e Classes:<br /> <br /> [img]http://www.mentaframework.org/images/helloworld.PNG[/img]<br /> <br /> User.java<br /> [code]<br /> package org.helloworld.entity;<br /> <br /> import java.io.Serializable;<br /> <br /> public class User implements Serializable {<br />    <br />    private int id;<br />    <br />    private String name;<br />    <br />    public User() { }<br />    <br />    public User(int id, String name) {<br />       this.id = id;<br />       this.name = name;<br />    }<br />    <br />    public User(int id) {<br />       this.id = id;<br />    }<br />    <br />    public int getId() { return id; }<br />    <br />    public String getName() { return name; }<br />    <br />    public void setId(int id) { this.id = id; }<br />    <br />    public void setName(String name) { this.name = name; }<br /> }<br /> [/code]<br /> <br /> UserRepository.java<br /> [code]<br /> package org.helloworld.repository;<br /> <br /> import java.util.Collection;<br /> <br /> import org.helloworld.entity.User;<br /> <br /> public interface UserRepository {<br />    <br />    public User getById(int id);<br />    <br />    public Collection&lt;User&gt; getUsers();<br />    <br />    public void add(User user);<br />    <br /> }<br /> [/code]<br /> <br /> H2UserRepository.java<br /> [code]<br /> package org.helloworld.repository.h2;<br /> <br /> import java.sql.Connection;<br /> import java.util.Collection;<br /> <br /> import org.helloworld.entity.User;<br /> import org.helloworld.repository.UserRepository;<br /> import org.mentawai.bean.BeanSession;<br /> import org.mentawai.bean.jdbc.H2BeanSession;<br /> <br /> public class H2UserRepository implements UserRepository {<br />    <br />    private BeanSession session; // mentabean...<br />    <br />    // Injeção vai acontecer aqui... (Auto-Wiring)<br />    public void setConn(Connection conn) {<br />       <br />       this.session = new H2BeanSession(conn);<br />    }<br />    <br />    public User getById(int id) {<br />       <br />       User u = new User(id);<br />       <br />       try {<br />       <br />          if (session.load(u)) {<br />             <br />             return u;<br />          }<br />          <br />          return null;<br />          <br />       } catch(Exception e) {<br />          <br />          throw new RuntimeException(e);<br />       }<br />    }<br />    <br />    public void add(User user) {<br />       <br />       try {<br />          <br />          session.insert(user);<br />          <br />       } catch(Exception e) {<br />          <br />          throw new RuntimeException(e);<br />       }<br />    }<br />    <br />    public Collection&lt;User&gt; getUsers() {<br />       <br />       User u = new User(); // no arguments for WHERE clause... (empty user)<br />       <br />       try {<br />       <br />          return session.loadList(u);<br />          <br />       } catch(Exception e) {<br />          <br />          throw new RuntimeException(e);<br />       }<br />    }<br /> }<br /> [/code]<br /> <br /> UserService.java<br /> [code]<br /> package org.helloworld.service;<br /> <br /> import java.util.Collection;<br /> <br /> import org.helloworld.entity.User;<br /> import org.helloworld.repository.UserRepository;<br /> <br /> public class UserService {<br />    <br />    // Injeção vai acontecer aqui (IoC)<br />    private UserRepository userRepo;<br />    <br />    public UserService() { }<br />    <br />    public void add(User user) {<br />       <br />       userRepo.add(user);<br />    }<br />    <br />    public Collection&lt;User&gt; getUsers() {<br />       <br />       return userRepo.getUsers();<br />    }<br /> }<br /> [/code]<br /> <br /> UserAction.java<br /> [code]<br /> package org.helloworld.action;<br /> <br /> import java.util.Collection;<br /> <br /> import org.helloworld.entity.User;<br /> import org.helloworld.service.UserService;<br /> import org.mentawai.core.BaseAction;<br /> import org.mentawai.filter.ModelDriven;<br /> <br /> public class UserAction extends BaseAction implements ModelDriven {<br />    <br />    private UserService userService = new UserService();<br />    <br />    public Object getModel() {<br />       <br />       return userService;<br />    }<br />    <br />    public String add() {<br />       <br />       if (isPost()) { // POST<br />          <br />          String name = input.getStringValue("name");<br />          <br />          if (name == null || name.trim().equals("")) {<br />             <br />             addError("Por favor digite um nome!");<br />             <br />             return ERROR;<br />          }<br />          <br />          User u = input.getObject(User.class);<br />          <br />          userService.add(u);<br />          <br />          return SUCCESS;<br />          <br />       } else { // GET<br />          <br />          return JSP;<br />       }<br />    }<br />    <br />    public String list() {<br />       <br />       Collection&lt;User&gt; users = userService.getUsers();<br />       <br />       output.setValue("users", users);<br />       <br />       return SUCCESS;<br />    }<br /> }<br /> [/code]<br /> <br /> ApplicationManager.java<br /> [code]<br /> package org.helloworld;<br /> <br /> import java.sql.Connection;<br /> import java.sql.PreparedStatement;<br /> import java.util.Properties;<br /> <br /> import org.helloworld.action.UserAction;<br /> import org.helloworld.entity.User;<br /> import org.helloworld.repository.h2.H2UserRepository;<br /> import org.mentawai.bean.DBTypes;<br /> import org.mentawai.core.ActionConfig;<br /> import org.mentawai.core.Context;<br /> import org.mentawai.db.C3P0ConnectionHandler;<br /> import org.mentawai.db.ConnectionHandler;<br /> import org.mentawai.filter.ConnectionFilter;<br /> import org.mentawai.filter.DIFilter;<br /> import org.mentawai.filter.InjectionFilter;<br /> import org.mentawai.filter.IoCFilter;<br /> <br /> public class ApplicationManager extends org.mentawai.core.ApplicationManager {<br />    <br />    private ConnectionHandler connHandler;<br />    <br />    @Override<br />    public void init(Context application) {<br />       <br />       Properties prop = getProperties();<br />       <br />       String driver = prop.getProperty("driver");<br />       String url = prop.getProperty("url");<br />       String user = prop.getProperty("user");<br />       String pass = prop.getProperty("pass");<br />       <br />       // Configuração do pool de conexões (C3P0)<br />       connHandler = new C3P0ConnectionHandler(driver, url, user, pass);<br />       <br />       // Cria a tabela, se ela não existe...<br />       createTable(connHandler);<br />       <br />       // Satck de filtros<br />       filter(new ConnectionFilter(connHandler)); // pool de conexões...<br />       filter(new IoCFilter()); // ioc container...<br />       filter(new DIFilter());  // auto-wiring...<br />       filter(new InjectionFilter()); // action/model injection...<br />       <br />       // IoC<br />       ioc("userRepo", H2UserRepository.class);<br />       <br />       // Auto-wiring<br />       di("conn", Connection.class);<br />       <br />    }<br />    <br />    @Override<br />    public void loadBeans() {<br />       <br />       // ORM mapping...<br />       bean(User.class, "Users")<br />          .pk("id",      DBTypes.AUTOINCREMENT)<br />          .field("name", DBTypes.STRING);<br />    }<br />    <br />    @Override<br />    public void loadActions() {<br />       <br />       // configure list inner action...<br />       ActionConfig listAction = action(UserAction.class, "list")<br />          .on(SUCCESS,   fwd("/hello.jsp"));<br />       <br />       // configure add inner action...<br />       // (depois de adicionar queremos ir para listar)<br />       action(UserAction.class, "add")<br />          .on(JSP,       chain(listAction))<br />          .on(SUCCESS,   chain(listAction))<br />          .on(ERROR,     chain(listAction));<br />       <br />    }<br />    <br />    protected void createTable(ConnectionHandler connHandler) {<br />       <br />       Connection conn = null;<br />       <br />       PreparedStatement stmt = null;<br />       <br />       try {<br />          <br />          conn = connHandler.getConnection();<br />          <br />          stmt = conn.prepareStatement("create table if not exists Users(id " +<br /> "INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))");<br />          <br />          stmt.executeUpdate();<br />          <br />       } catch(Exception e) {<br />          <br />          System.err.println("Cannot create table: " + e.getMessage());<br />          <br />          throw new RuntimeException(e);<br />          <br />       } finally {<br />          <br />          if (stmt != null) try { stmt.close(); } catch(Exception e) { }<br />          <br />          connHandler.release(conn);<br />       }<br />    }<br />    <br /> }<br /> [/code]<br /> <br /> AppManager.properties<br /> [code]<br /> <br /> driver = org.h2.Driver<br /> url = jdbc:h2:~/helloworld<br /> user = helloworld<br /> pass = helloworld<br /> <br /> [/code]<br /> <br /> hello.jsp<br /> [code]<br /> &lt;%@page contentType="text/html;charset=UTF-8" %&gt;<br /> &lt;%@taglib uri="/WEB-INF/lib/mentawai.jar" prefix="mtw" %&gt;<br /> <br /> &lt;html&gt;&lt;body&gt;<br /> <br /> &lt;h1&gt;Mentawai Hello World&lt;/h1&gt;<br /> <br /> &lt;h3&gt;Please enter you name:&lt;/h3&gt;<br /> <br /> &lt;mtw:outError&gt;<font color="red">&lt;mtw:out /&gt;</font><br /><br />&lt;/mtw:outError&gt;<br /> <br /> &lt;form action="&lt;mtw:contextPath /&gt;/UserAction.add.mtw" method="post"&gt;<br /> &lt;mtw:input name="name" type="text" size="20" /&gt; <br /><br /><br /> &lt;input type="submit" value="Say Hello" /&gt;<br /> &lt;/form&gt;<br /> <br /> &lt;h2&gt;The following persons have said "hello" to Mentawai:&lt;/h2&gt;<br /> <br /> &lt;mtw:list value="users"&gt;<br />    &lt;mtw:isEmpty&gt;<br />       &lt;h4&gt;Nobody has said so yet!&lt;/h4&gt;<br />    &lt;/mtw:isEmpty&gt;<br /> <br />    &lt;mtw:loop var="user"&gt;<br />       &lt;mtw:out value="user.name" /&gt;<br /><br />    &lt;/mtw:loop&gt;<br /> &lt;/mtw:list&gt;<br /> <br /> &lt;/body&gt;&lt;/html&gt;<br /> [/code]<br /> <br /> web.xml<br /> [code]<br /> &lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;<br /> <br /> &lt;!DOCTYPE web-app&gt;<br />     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />     &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt;<br /> <br /> &lt;web-app&gt;<br /> 	&lt;display-name&gt;HelloWorld&lt;/display-name&gt;<br /> 	&lt;description&gt;&lt;/description&gt;<br /> <br /> 	&lt;servlet&gt;<br />         &lt;servlet-name&gt;Controller&lt;/servlet-name&gt;<br />         &lt;servlet-class&gt;org.mentawai.core.Controller&lt;/servlet-class&gt;<br />         &lt;init-param&gt;<br />     	    &lt;param-name&gt;applicationManager&lt;/param-name&gt;<br />         	&lt;param-value&gt;org.helloworld.ApplicationManager&lt;/param-value&gt;<br /> 	    &lt;/init-param&gt;    <br /> 		&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;		<br />     &lt;/servlet&gt;<br /> <br />     &lt;!-- You must choose an extension to indicate a mentawai action --&gt;<br />     &lt;servlet-mapping&gt;<br />         &lt;servlet-name&gt;Controller&lt;/servlet-name&gt;<br />         &lt;url-pattern&gt;*.mtw&lt;/url-pattern&gt;<br />     &lt;/servlet-mapping&gt;<br />     <br />     &lt;filter&gt;<br />         &lt;filter-name&gt;DebugFilter&lt;/filter-name&gt;<br />         &lt;filter-class&gt;<br />             org.mentawai.util.DebugServletFilter<br />         &lt;/filter-class&gt;<br />     &lt;/filter&gt;<br />     <br />     &lt;filter-mapping&gt;<br />         &lt;filter-name&gt;DebugFilter&lt;/filter-name&gt;<br />         &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br />         &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt; <br />         &lt;dispatcher&gt;FORWARD&lt;/dispatcher&gt;    <br />         &lt;dispatcher&gt;INCLUDE&lt;/dispatcher&gt;    <br />         &lt;dispatcher&gt;ERROR&lt;/dispatcher&gt;    <br />     &lt;/filter-mapping&gt;<br /> <br /> &lt;/web-app&gt;<br /> [/code]<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/68/74.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/68/74.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:44:04]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Mentawai x Struts2</title>
				<description><![CDATA[ - [color="blue"][b]Validação:[/color][/b]<br /> <br /> O Struts2 oferece validação via XML ou Annotations.<br /> <br /> A documentação do Struts2 continua sendo, na minha opinião, pouco objetiva e pouco clara. Clique aqui para acessar a [url="http://struts.apache.org/2.x/docs/validation.html"]documentação oficial sobre validação[/url], e tire suas próprias conclusões. Repare que não há nenhum código Java, apenas XML.<br /> <br /> Validação via XML: (repare que existe código Java dentro do XML !!!!  :roll: )<br /> <br /> [code]<br /> &lt;!DOCTYPE validators PUBLIC &gt;<br />         "-//OpenSymphony Group//XWork Validator 1.0.2//EN" <br />         &quot;http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd&quot;&gt;<br /> &lt;validators&gt;<br />   &lt;!-- Field Validators for email field --&gt;<br />   &lt;field name="email"&gt;<br />       &lt;field-validator type="required" short-circuit="true"&gt;<br />           &lt;message&gt;You must enter a value for email.&lt;/message&gt;<br />       &lt;/field-validator&gt;<br />       &lt;field-validator type="email" short-circuit="true"&gt;<br />           &lt;message&gt;Not a valid e-mail.&lt;/message&gt;<br />       &lt;/field-validator&gt;<br />   &lt;/field&gt;<br />   &lt;!-- Field Validators for email2 field --&gt;<br />   &lt;field name="email2"&gt;<br />      &lt;field-validator type="required"&gt;<br />           &lt;message&gt;You must enter a value for email2.&lt;/message&gt;<br />       &lt;/field-validator&gt;<br />      &lt;field-validator type="email"&gt;<br />           &lt;message&gt;Not a valid e-mail2.&lt;/message&gt;<br />       &lt;/field-validator&gt;<br />   &lt;/field&gt;<br />   &lt;!-- Plain Validator 1 --&gt;<br />   &lt;validator type="expression"&gt;<br />       &lt;param name="expression"&gt;email.equals(email2)&lt;/param&gt;<br />       &lt;message&gt;Email not the same as email2&lt;/message&gt;<br />   &lt;/validator&gt;<br />   &lt;!-- Plain Validator 2 --&gt;<br />   &lt;validator type="expression" short-circuit="true"&gt;<br />       &lt;param name="expression"&gt;email.startsWith('mark')&lt;/param&gt;<br />       &lt;message&gt;Email does not start with mark&lt;/message&gt;<br />   &lt;/validator&gt;<br /> &lt;/validators&gt;<br /> [/code]<br /> <br /> Validação via Annotations: (como deturpar o uso de annotations assim como foi feito com o uso de XML)<br /> <br /> [url="http://struts.apache.org/2.x/docs/validation-annotation.html"]Clique aqui para ver que isso está na documentação oficial do Struts2[/url]<br /> <br /> [code]<br /> <br /> @Validation()<br /> public class SimpleAnnotationAction extends ActionSupport {<br /> <br />     @RequiredFieldValidator(type = ValidatorType.FIELD, message = "You must enter a value for bar.")<br />     @IntRangeFieldValidator(type = ValidatorType.FIELD, min = "6", <br />      max = "10", message = "bar must be between ${min} and ${max}, current value is ${bar}.")<br />     public void setBar(int bar) {<br />         this.bar = bar;<br />     }<br /> <br />     public int getBar() {<br />         return bar;<br />     }<br /> <br />     @Validations(<br />             requiredFields =<br />                     {@RequiredFieldValidator(type = ValidatorType.SIMPLE, <br /> fieldName = "customfield", message = "You must enter a value for field.")},<br />             requiredStrings =<br />                     {@RequiredStringValidator(type = ValidatorType.SIMPLE,<br />  fieldName = "stringisrequired", message = "You must enter a value for string.")},<br />             emails =<br />                     { @EmailValidator(type = ValidatorType.SIMPLE, <br /> fieldName = "emailaddress", message = "You must enter a value for email.")},<br />             urls =<br />                     { @UrlValidator(type = ValidatorType.SIMPLE, <br /> fieldName = "hreflocation", message = "You must enter a value for email.")},<br />             stringLengthFields =<br />                     {@StringLengthFieldValidator(type = ValidatorType.SIMPLE, trim = true, minLength="10" , <br /> maxLength = "12", fieldName = "needstringlength", message = "You must enter a stringlength.")},<br />             intRangeFields =<br />                     { @IntRangeFieldValidator(type = ValidatorType.SIMPLE, <br /> fieldName = "intfield", min = "6", max = "10", message = "bar must be between ${min} and ${max}, current value is ${bar}.")},<br />             dateRangeFields =<br />                     {@DateRangeFieldValidator(type = ValidatorType.SIMPLE, <br /> fieldName = "datefield", min = "-1", max = "99", message = "bar must be between ${min} and ${max}, current value is ${bar}.")},<br />             expressions = {<br />                 @ExpressionValidator(expression = &quot;foo &gt; 1&quot;, <br /> message = "Foo must be greater than Bar 1. Foo = ${foo}, Bar = ${bar}."),<br />                 @ExpressionValidator(expression = &quot;foo &gt; 2&quot;, <br /> message = "Foo must be greater than Bar 2. Foo = ${foo}, Bar = ${bar}."),<br />                 @ExpressionValidator(expression = &quot;foo &gt; 3&quot;, <br /> message = "Foo must be greater than Bar 3. Foo = ${foo}, Bar = ${bar}."),<br />                 @ExpressionValidator(expression = &quot;foo &gt; 4&quot;,<br />  message = "Foo must be greater than Bar 4. Foo = ${foo}, Bar = ${bar}."),<br />                 @ExpressionValidator(expression = &quot;foo &gt; 5&quot;,<br />  message = "Foo must be greater than Bar 5. Foo = ${foo}, Bar = ${bar}.")<br />     }<br />     )<br />     public String execute() throws Exception {<br />         return SUCCESS;<br />     }<br /> }<br /> [/code]<br /> <br /> Mais uma vez a [b]configuração programática do Mentawai[/b] mostra todo o seu poder facilitando a implementação dessa funcionalidade tão essencial e importante:<br /> <br /> Filtro de Validação do Mentawai: (pode ser aplicado em mais de uma action)<br /> <br /> Ou vc pode também fazer a validação diretamente na action através da interface Validatable: http://recipes.mentaframework.org/posts/list/4.page<br /> <br /> [code]<br /> <br /> public class HelloWorldValidator extends ValidationFilter {<br /> <br />     private static final String FIELD_REQUIRED_ERROR = "Field required!";<br />     private static final String INVALID_USERNAME_LENGTH = "Username length invalid!";<br />     private static final String INVALID_AGE = "Invalid age!";<br />     private static final String INVALID_PASSWORD_LENGTH = "Invalide password length!";<br />     private static final String PASSWORD_DOES_NOT_MATCH = "Passwords do not match!";<br /> <br />     public void initValidator() {<br />         <br />         add("username", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />         add("username", new StringRule(6, 30), INVALID_USERNAME_LENGTH);<br />         <br />         add("age", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />         add("age", new IntegerRule(18, 50), INVALID_AGE);<br />         <br />         add("password", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />         add("password", new StringRule(4, 20), INVALID_PASSWORD_LENGTH);<br />         add("password", new EqualRule("password", "passconf"), PASSWORD_DOES_NOT_MATCH);<br />         <br />         add("passconf", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />     }<br /> <br /> }<br /> [/code]<br /> <br /> E para internacionalizar essas mensagens, tudo que vc precisa fazer é criar um arquivo HelloWorldValidator_en_US.i18n dentro do diretório /validation:<br /> <br /> [code]<br /> <br /> ###############################################<br /> # Messages for the filter HelloWorldValidator #<br /> ###############################################<br />  <br /> required = Required field cannot be left blank<br /> 2 = Your username must be between %min% and %max% characters long.<br /> 3 = You must be %min% years old or older.<br /> 4 = Your password must be between %min% and %max% characters long.<br /> 5 = Passwords do not match.<br /> <br /> [/code]<br /> <br /> E o filtro de validação ficaria assim:<br /> <br /> [code]<br /> public class HelloWorldValidator extends ValidationFilter {<br /> <br />     private static final String FIELD_REQUIRED_ERROR = "required"; // to illustrate that this can be a string too<br />     private static final int INVALID_USERNAME_LENGTH = 2;<br />     private static final int INVALID_AGE = 3;<br />     private static final int INVALID_PASSWORD_LENGTH = 4;<br />     private static final int PASSWORD_DOES_NOT_MATCH = 5;<br /> <br />     public void initValidator() {<br />         <br />         add("username", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />         add("username", new StringRule(6, 30), INVALID_USERNAME_LENGTH);<br />         <br />         add("age", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />         add("age", new IntegerRule(18, 50), INVALID_AGE);<br />         <br />         add("password", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />         add("password", new StringRule(4, 20), INVALID_PASSWORD_LENGTH);<br />         add("password", new EqualRule("password", "passconf"), PASSWORD_DOES_NOT_MATCH);<br />         <br />         add("passconf", new RequiredFieldRule(), FIELD_REQUIRED_ERROR);<br />     }<br /> <br /> }<br /> [/code]<br /> <br /> - [color="blue"][b]Internacionalização:[/color][/b]<br /> <br /> A documentação oficial do Struts para internacionalização está aqui: http://struts.apache.org/2.x/docs/localization.html<br /> <br /> Mais uma vez a documentação deixa em aberto as seguintes questões:<br /> <br /> - Struts2 utiliza ResourceBundle, o que provavelmente vai forçar um restart da aplicação a cada mudança nos arquivos properties do resourcebundle.<br /> <br /> - Se o locale do meu usuário está salvo no banco, como forço para que o locale da aplicação seja esse locale para esse usuário?<br /> <br /> - Tenho a opção de criar apenas um único arquivo onde todo o meu conteúdo internacionalizado estará presente (arquivo master) ?<br /> <br /> - O Struts2 permite internacionalizar actions colocando arquivos properites dentro do pacote da action. É boa prática colocar os arquivos de internacionalização separados do seu código e num lugar que possa ser acessível pelo designer e/ou tradutor. (Ou vc programador vai fazer essa tarefa?)<br /> <br /> Compare o approach do Struts2 com o approach do Mentawai e tire suas próprias conclusões: http://www.mentaframework.org/i18n.jsp?loc=pt<br /> <br /> <br /> - [color="blue"][b]Conversão:[/color][/b]<br /> <br /> Assim como [url="http://struts.apache.org/2.x/docs/type-conversion.html"]sua documentação[/url], os conversores do Struts não são nem simples, nem claros, nem pragmáticos:<br /> <br /> [code]<br /> /**<br />  * Observação bem grande na documentação, para te ajudar: <br />  *  <br />  *  To allow Struts to recognize that a conversion error has occurred,<br />  *   the converter class need to throw XWorkException or preferably <br />  * TypeConversionException.<br /> */<br /> public class MyConverter extends StrutsTypeConverter {<br /> <br />     public Object convertFromString(Map context, String[] values, Class toClass) {<br />        .....<br />     }<br /> <br />     public String convertToString(Map context, Object o) {<br />        .....<br />     }<br />  }<br /> [/code]<br /> <br /> É difícil entender e/ou justficar algo tão bizarro acima para algo tão simples como uma conversão, principalmente quando olhamos a versão do Mentawai abaixo:<br /> <br /> [code]<br /> <br /> public class MyConverter extends BasicConverter {<br /> 	<br /> 	public Object convert(Object value) throws ConversionException {<br />         <br />                // ...       <br />         }<br /> }<br /> <br /> // ou ainda para converter baseado no locale<br /> <br /> public class MyConverter extends LocaleConverter {<br /> 	<br /> 	public Object convert(Object value, Locale loc) throws ConversionException {<br />         <br />                // ...       <br />         }<br /> }<br /> [/code]<br /> <br /> - [color="blue"][b]Filtros:[/color][/b]<br /> <br /> A configuração dos filtros é feita via XML, como sempre. Se tivermos que por exemplo aplicar o mesmo filtro em 100 actions diferentes, teremos que usar copy/paste e transformar a nossa configuração num arquivo XML gigantesco. Em contrapartida, se utilizarmos configuração programática, podemos fazer um for/loop, métodos, if, etc.<br /> <br /> Veja o exemplo de um interceptor do Struts:<br /> <br /> [code]<br /> import com.opensymphony.xwork2.ActionInvocation;<br /> import com.opensymphony.xwork2.interceptor.AbstractInterceptor;<br /> <br /> public class SimpleInterceptor extends AbstractInterceptor {<br /> <br />     public String intercept(ActionInvocation invocation) throws Exception {<br />        MyAction action = (MyAction)invocation.getAction();<br />        action.setDate(new Date());<br />        return invocation.invoke();<br />     }<br /> }<br /> [/code]<br /> <br /> Reparem que, talvez pela falta de um INPUT/OUTPUT para as actions, o interceptor acima está fortemente acoplado a action MyAction, ou seja, só pode ser aplicado a ela.<br /> <br /> Na versão do Mentawai ficaria assim:<br /> <br /> (reparem que o filtro abaixo poderá ser aplicado em qualquer action, e não apenas MyAction)<br /> <br /> [code]<br /> public class SimpleFilter implements Filter {<br /> <br />     public String filter(InvocationChain chain) throws Exception {<br />        Action action = chain.getAction();<br />        Input input = action.getInput();<br /> <br />        input.setValue("someDate", new Date());<br /> <br />        return chain.invoke();<br />     }<br /> <br />     public void destroy() { }<br /> }<br /> [/code]<br /> <br /> [i]Aguardem mais comparativos !!![/i]]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/67/73.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/67/73.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:43:42]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Martin Fowler sobre configurações</title>
				<description><![CDATA[ Fonte: <a class="snap_shots" href="http://www.javafree.org/content/view.jf?idContent=1" target="_blank" rel="nofollow">http://www.javafree.org/content/view.jf?idContent=1</a><br /> <br /> [quote]<br /> Código ou arquivos de configuração<br /> <br /> Um assunto separado, mas freqüentemente adicionado, é quando usar arquivos de configuração ou código sobre uma API para amarrar os serviços. Para a maioria das aplicações que tem de ser instaladas em vários lugares, um arquivo de configuração separado normalmente faz mais sentido. Quase sempre será um arquivo XML, e isto faz sentido. Entretanto, há casos onde é mais fácil usar código de programação para fazer a montagem. Um caso é onde se tem uma aplicação simples, que não tem muitas variações de instalação. Neste caso, um pouco de código pode ser mais claro que um arquivo XML separado.<br /> <br /> Um caso constrastante é onde a montagem é muito complexa, envolvendo passos condicionais. Uma vez que se chega mais próximo de uma linguagem de programação, o XML começa a entrar em colapso, e é melhor usar uma linguagem real que tem toda a sintaxe para se escrever um programa claro. É feita então uma classe construtora que faz a montagem. Se há diferentes cenários de montagem, pode-se prover várias classes construtoras e usar um arquivo de configuração simples que faz a seleção entre eles.<br /> <br /> Muitas vezes penso que as pessoas estão ansiosas demais por definir arquivos de configuração. Muitas vezes, uma linguagem de programação serve como um mecanismo de configuração direto e poderoso. Linguagens modernas podem facilmente compilar pequenos montadores que podem ser usados para juntar plugins em sistemas maiores. Se a compilação é trabalhosa demais, existem também linguagens script que podem funcionar muito bem.<br /> <br /> É freqüentemente falado que arquivos de configuração não deveriam usar uma linguagem de programação, porque eles precisam ser editados por não-programadores. Mas quão freqüente este é o caso? As pessoas realmente esperam que não-programadores alterem os níveis de isolamento de transações de aplicações servidoras complexas? Arquivos de configuração que não usam uma linguagem de programação funcionam bem apenas enquanto simples. Se eles se tornaram complexos, então é hora de pensar sobre usar uma linguagem de programação apropriada.<br /> <br /> Uma coisa que vemos no mundo Java no momento é uma dissonância de arquivos de configuração, onde cada componente tem seus próprios arquivos de configuração, que são diferentes de quaisquer outros. Se uma dúzia destes componentes forem usados, pode-se facilmente acabar com uma dúzia de arquivos de configuração que devem ser atualizados.<br /> <br /> Meu conselho aqui é sempre prover uma maneira de fazer toda a configuração facilmente com uma interface programática, e então tratar o arquivo de configuração separado como uma característica opcional. Pode-se facilmente construir a manipulação de um arquivo de configuração usando uma interface programática. Quando se cria um componente, deve-se deixar a cargo do usuário quando utilizar a interface programática, o formato padrão do arquivo de configuração, ou criar seu próprio formato de arquivo, amarrando-o à interface programática.<br /> Separando Configuração do Uso<br /> <br /> A coisa mais importante nisto tudo é assegurar-se de que a configuração dos serviços seja separada de seu uso. Isto é um princípio fundamental do design próximo à separação entre interfaces e implementação. É algo que vemos dentro de um programa orientado-a-objetos quando lógica condicional decide que classe instanciar, e então, futuras avaliações desta condição é feita por polimorfismo ao invés de ter código condicional duplicado.<br /> <br /> Se esta separação é útil dentro de uma única base de código, é especialmente vital quando se usa elementos externos, como componentes e serviços. A primeira questão é se é desejável deferir a escolha da classe de implementação para instalações particulares. Se sim, é necessário o uso de alguma implementação de plugin. Uma vez que plugins estejam sendo utilizados, é essencial que a montagem dos plugins seja feita separadamente do resto da aplicação, para que seja possível substituir diferentes configurações facilmente para diferentes instalações. Como se consegue isto é secundário. Este mecanismo de configuração pode tanto configurar um service locator quanto usar injeção para configurar os objetos diretamente. <br /> [/quote]<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/66/72.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/66/72.page</link>
				<pubDate><![CDATA[Fri, 17 Dec 2010 17:42:48]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Choosing consequences for handling different outputs (JSP, Ajax, Binary, etc.)</title>
				<description><![CDATA[ Mentawai has the concept of Consequence, also known as Resolver in other frameworks like Spring MVC.<br /> <br /> Basically, depending on the RESULT of an Action you can trigger the appropriate CONSEQUENCE.<br /> <br /> The most common consequences are FORWARD to a JSP or REDIRECT to an URL:<br /> [code]<br /> <br /> action("/Users", UserAction.class, "add")<br />    .on(ERROR, fwd("/jsp/users/add.jsp"))<br />    .on(SUCCESS, redir("/Users.list.mtw"));<br /> <br /> // if you have an action configured, you can also redir to an action<br /> // the code below is identical to the code above<br /> <br /> ActionConfig listAC = action("/Users", UserAction.class, "list")<br />     .on(SUCCESS, fwd("/jsp/users/list.jsp"));<br /> <br /> action("/Users", UserAction.class, "add")<br />    .on(ERROR, fwd("/jsp/users/add.jsp"))<br />    .on(SUCCESS, redir(listAC));<br /> [/code]<br /> Now we talk about consequences for other types of output:<br /> <br /> [b]1) AJAX consequence generating JSON:[/b]<br /> <br /> Action:<br /> [code]<br /> public String list() {<br /> <br />    List&lt;User&gt; users = getUsersSomehow();<br /> <br />    output.setValue("users", users);<br /> <br />    return AJAX; // or any result you want...<br /> }<br /> [/code]<br /> Configuration:<br /> [code]<br /> <br /> action("/User", UserAction.class, "list")<br />     .on(AJAX, ajax(new JsonRenderer());<br /> [/code]<br /> [b]2) Streaming binary (images, pdf or anything):[/b]<br /> <br /> Action:<br /> [code]<br /> public String get() {<br /> <br />     // you can add a byte array or an InputStream to the action output:<br /> <br />     byte[] image = getImageDataSomehow();<br /> <br />     output.add(image); // you can also do output.setValue(StreamConsequence.STREAM, image);<br /> <br />     // or<br /> <br />     InputStream is = getInputStreamSomehow();<br /> <br />     output.add(is); // you can also do output.setValue(StreamConsequence.STREAM, is);<br /> <br />     return STREAM; // or any result you want<br /> }<br /> [/code]<br /> Configuration:<br /> [code]<br /> action("/Images", ImageAction.class, "get")<br />     .on(STREAM, stream("image/jpeg"));<br /> <br /> action("/Docs", PdfAction.class, "get")<br />     .on(STREAM, stream("application/pdf"));<br /> [/code]<br /> <br />    <br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/65/71.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/65/71.page</link>
				<pubDate><![CDATA[Tue, 24 Aug 2010 15:06:25]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Easy internationalization (i18n)</title>
				<description><![CDATA[ [b]OBS:[/b] Mentawai i18n files are auto-reloadable, in other words, from time to time the file is checked for modifications. If it was modified it is reloaded. That means you do NOT have to restart your web container each time you change some text inside your i18n file.<br /> <br /> When the user is authenticated, you set his locale:<br /> [code]<br />          setSessionObj(user);<br />          <br />          setSessionLocale("es_ES");<br /> [/code]<br /> Then all you have to do is create a directory i18n and place one file per language in there. Example:<br /> <br /> /i18n/master_en_US.i18n<br /> [code]<br /> # a comment<br /> hello = Hi there. You can even jump \<br /> 		a line here. Enjoy!<br /> [/code]<br /> /i18n/master_es_ES.i18n<br /> [code]<br /> # comentário<br /> hello = Hola. Incluso puede saltar una línea \<br /> 		aquí. Disfrute!<br /> [/code]<br /> Then in the JSP you can do:<br /> [code]<br /> &lt;!-- top of the page --&gt;<br /> &lt;mtw:useI18N /&gt;<br /> <br /> &lt;h1&gt;Your message: &lt;mtw:i18n key="hello" /&gt;&lt;/h1&gt;<br /> [/code]<br /> To better organize your text file you can use prefixes. Example:<br /> <br /> /i18n/master_en_US.i18n<br /> [code]<br /> # a comment<br /> index.hello = Hi there. You can even jump \<br /> 		a line here. Enjoy!<br /> [/code]<br /> /i18n/master_es_ES.i18n<br /> [code]<br /> # comentário<br /> index.hello = Hola. Incluso puede saltar una línea \<br /> 		aquí. Disfrute!<br /> [/code]<br /> Then in the JSP you do:<br /> [code]<br /> &lt;!-- top of the page --&gt;<br /> &lt;mtw:useI18N prefix="index" /&gt;<br /> <br /> &lt;h1&gt;Your message: &lt;mtw:i18n key="hello" /&gt;&lt;/h1&gt;<br /> [/code]<br /> If you have a text that is global, for example, the title of all pages, you can skip the prefix by doing:<br /> <br /> /i18n/master_en_US.i18n<br /> [code]<br /> # a comment<br /> <br /> title = Your title here<br /> <br /> index.hello = Hi there. You can even jump \<br /> 		a line here. Enjoy!<br /> [/code]<br /> /i18n/master_es_ES.i18n<br /> [code]<br /> # comentário<br /> <br /> title = Su titulo aqui<br /> <br /> index.hello = Hola. Incluso puede saltar una línea \<br /> 		aquí. Disfrute!<br /> [/code]<br /> An in the JSP:<br /> [code]<br /> &lt;!-- top of the page --&gt;<br /> &lt;mtw:useI18N prefix="index" /&gt;<br /> <br /> &lt;html&gt;<br /> &lt;head&gt;<br /> <br /> &lt;title&gt;&lt;mtw:i18n key="title" noPrefix="true" /&gt;&lt;/title&gt;<br /> <br /> &lt;/head&gt;<br /> <br /> &lt;body&gt;<br /> &lt;h1&gt;Your message: &lt;mtw:i18n key="hello" /&gt;&lt;/h1&gt;<br /> &lt;/body&gt;<br /> &lt;/html&gt;<br /> [/code]<br /> And there is much more:<br /> <br /> :arrow: You can have localized texts inside your actions.<br /> <br /> :arrow: If the user is not logged, you can pick a locale based on browser request, cookie, etc.<br /> <br /> :arrow: You can use placeholders to help the designer:<br /> [code]<br /> &lt;mtw:i18n key="hello"&gt;This is a simple message just for the designer to see something!&lt;/mtw:i18n&gt;<br /> [/code]<br /> :arrow: You can configure what to do if the key is not found: show the default locale translation or show the key with exclamation marks around it so someone can spot the problem and fix it. (good for QA)<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/64/70.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/64/70.page</link>
				<pubDate><![CDATA[Sun, 15 Aug 2010 20:12:34]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Easy Authorization with groups</title>
				<description><![CDATA[ An authenticated user can belong to one or more groups. All you have to do is:<br /> [code]<br /> setSessionObj(user); // user is authenticated<br /> <br /> setSessionGroup("admin"); // and belongs to the admin groups<br /> <br /> // or<br /> <br /> setSessionGroups("admin", "moderator"); // user can belong to more than one group<br /> [/code]<br /> Now to protect access to an action you can do:<br /> [code]<br /> on(ACCESSDENIED, redir("/denied.jsp")); // a global consequence for ACCESSDENIED<br /> <br />        action("/DeleteRecord", DeleteRecordAction.class)<br />             .on(SUCCESS, redir("/deleted.jsp"))<br />             .filter(new AuthorizationFilter("admin"));<br /> [/code]<br /> The AuthorizationFilter returns the result [i]ACCESSDENIED[/i] if the current authenticated user does not belong to the [i]admin[/i] group. Then a global consequence can redirect to a page or throw an exception.<br /> <br /> And how to protect access to an JSP page<br /> <br /> 1) Blocking access to a page:<br /> [code]<br /> &lt;mtw:requiresAuthorization group="admin" /&gt;<br /> <br /> &lt;!-- OR --&gt;<br /> <br /> &lt;mtw:requiresAuthorization groups="admin, moderator" /&gt;<br /> [/code]<br /> 2) Block access to a portion of the page:<br /> [code]<br /> &lt;mtw:hasAuthorization group="admin"&gt;<br />    &lt;h1&gt;Admins can see this!&lt;/h1&gt;<br /> &lt;/mtw:hasAuthorization&gt;<br /> <br /> &lt;!-- OR --&gt;<br /> <br /> &lt;mtw:hasAuthorization groups="admin, moderator"&gt;<br />    &lt;h1&gt;Admins and moderators can see this!&lt;/h1&gt;<br /> &lt;/mtw:hasAuthorization&gt;<br /> <br /> <br /> [/code]<br /> Mentawai also supports authorization by permissions. For more info see here: http://www.mentaframework.org/authorization.jsp]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/63/69.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/63/69.page</link>
				<pubDate><![CDATA[Sun, 15 Aug 2010 19:36:25]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Easy Authentication</title>
				<description><![CDATA[ After checking username and password, in any way you want, you decide that your user is authenticated. So you do:<br /> [code]<br /> <br /> setSessionObj(user);<br /> <br /> [/code]<br /> Now if you use the [i]AuthenticationFilter[/i] as a global filter, all access to your actions will only be allowed if the user is authenticated, in other words, if you called the method above for the current session. If not the [i]LOGIN[/i] result is returned and you can redirect for the login page.<br /> [code]<br /> filter(new AuthenticationFilter());<br /> on(LOGIN, redir("/login.jsp"));<br /> [/code]<br /> Now, some actions need to bypass authentication. Example: the action for registration. All you have to do is implement te [i]AuthenticationFree[/i] interface.<br /> [code]<br /> public class UserAction extends BaseAction implements AuthenticationFree {<br /> <br /> 	// You don't need to log to register...<br /> 	public boolean bypassAuthentication(String method) {<br /> 		<br /> 		if (method != null && method.equals("register")) return true;<br /> 		<br /> 		return false;<br /> 	}<br /> }<br /> [/code]<br /> The [i]LoginAction[/i] is another one that should not be authenticated. The org.mentawai.action.LoginAction implements [i]AuthenticationFree[/i] as you might expect.<br /> <br /> You blocked access to actions. Now it is time to block access to JSPs. You can use the simple tag:<br /> [code]<br /> &lt;mtw:requiresAuthentication /&gt;<br /> [/code]<br /> That's it. Mentawai also supports redirect after login in a very simple way. See here: http://www.mentaframework.org/authentication.jsp<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/62/68.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/62/68.page</link>
				<pubDate><![CDATA[Sun, 15 Aug 2010 19:19:47]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>How to use internationalization in DisplayTags</title>
				<description><![CDATA[ If you don't have any i18n file, follow this link:<br /> http://www.mentaframework.org/i18n.jsp<br /> <br /> if you want create your own DisplayTags, follow this link:<br /> http://recipes.mentaframework.org/posts/list/34.page<br /> <br /> To use internationalization in DisplayTags, do the following:<br /> <br /> 1) Create your taglib. For example:<br /> <br /> [code]public class NumberOfFriendsTag extends PrintTag {<br />     <br />     public String getStringToPrint() throws JspException {<br />         <br />         Output output = action.getOutput();<br />         <br />         User user = (User) output.getValue("user");<br />         <br />         int nFriends = user.getNumberOfFriends();<br />         <br />         if (nFriends == 1) {<br />             <br />             return "You have 1 friend!";<br />             <br />         } else if (nFriends == 0) {<br />             <br />             return "You do not have any friend!";<br />             <br />         } else {<br />             <br />             return "You have " + nFriends + " friends!";<br />             <br />         }<br />     }<br /> }<br /> [/code]<br /> <br /> 2) Flaunt your taglib where are the i18n files. To do that, use<br /> <br /> [code]I18N i18n = I18NMap.getI18N("/WEB-INF/i18n/master", loc);[/code]<br /> <br /> inside your [i]getStringToPrint()[/i] method. After that, use<br /> <br /> [code]i18n.get( "chave_no_arquivo_i18n" );[/code]<br /> <br /> to get the internationalized text.<br /> <br /> The first string is the path to your master file, from the application root. [i]loc[/i] is the user localeé o locale do usuário, available [i]automagically[/i] inside the class.<br /> <br /> See the code:<br /> <br /> [code]public class NumberOfFriendsTag extends PrintTag {<br />     <br />     public String getStringToPrint() throws JspException {<br /> <br />         // Método para pegar os arquivos i18n.<br />         I18N i18n = I18NMap.getI18N("/i18n/master", loc);<br />         <br />         Output output = action.getOutput();<br />         <br />         User user = (User) output.getValue("user");<br />         <br />         int nFriends = user.getNumberOfFriends();<br />         <br />         if (nFriends == 1) {<br />             <br />             return i18n.get( "apenas_um_amigo" );<br />             <br />         } else if (nFriends == 0) {<br />             <br />             return i18n.get( "nenhum_amigo" );<br />             <br />         } else {<br />             <br />             //return "Você tem " + nFriends + " amigos!";<br />             return i18n.get( "voce_tem" ) + " " + nFriends + " " + i18n.get( "amigo_plural" );<br />             <br />         }<br />     }<br /> }<br /> [/code]<br /> <br /> Master file:<br /> <br /> /i18n/master_pt_BR.i18n<br /> [code]apenas_um_amigo = Você tem 1 amigo!<br /> nenhum_amigo = Você não tem amigos!<br /> voce_tem = Você tem<br /> amigo_plural = amigos[/code]<br /> <br /> /i18n/master_en_US.i18n<br /> [code]apenas_um_amigo = You have 1 friend.<br /> nenhum_amigo = You don't have any friend.<br /> voce_tem = You have<br /> amigo_plural = friends[/code]]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/61/67.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/61/67.page</link>
				<pubDate><![CDATA[Thu, 29 Jul 2010 12:21:16]]> GMT</pubDate>
				<author><![CDATA[ rodrigo.avila]]></author>
			</item>
			<item>
				<title>Logging: how to enable and use in 3 easy steps</title>
				<description><![CDATA[ The Mentawai logging system is very simple and non-intrusive. To use it, follow these steps:<br /> <br /> 1) Activate the logging system in ApplicationManager:<br /> [code]public void init(Context application){<br /> <br />   Debug.enable(true);<br /> <br />   [...]<br /> <br /> } [/code]<br /> <br /> 2) Use:<br /> [code]Debug.log("logged text: bla bla bla...");[/code]<br /> <br /> 3) See the logged text in<br /> [code]&lt;nome_do_contexto&gt;/WEB-INF/logs[/code]]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/60/63.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/60/63.page</link>
				<pubDate><![CDATA[Thu, 4 Dec 2008 06:42:28]]> GMT</pubDate>
				<author><![CDATA[ rodrigo.avila]]></author>
			</item>
			<item>
				<title>Dynamic/Ajax Combos with mtw:select tag</title>
				<description><![CDATA[ One recurrent problem is when you want to display a dynamic list, in other words, a list that depends on other field. One standard example is State and City where each State has its own list of Cities.<br /> <br /> One possible approach to this problem is to add all 50 lists to [i]ListManager[/i], but that would not be a good solution because you would have to have a bunch of IFs in your JSP, like below:<br /> [code]<br /> &lt;mtw:if test="state" value="NY"&gt;<br /> &lt;tr&gt;<br /> &lt;td&gt;Cities&lt;/td&gt;&lt;td&gt;&lt;mtw:select name="city" list="cities_ny" emptyField="true" /&gt;&lt;/td&gt;<br /> &lt;/tr&gt;<br /> &lt;/mtw:if&gt;<br /> &lt;mtw:if test="state" value="CA"&gt;<br /> &lt;tr&gt;<br /> &lt;td&gt;Cities&lt;/td&gt;&lt;td&gt;&lt;mtw:select name="city" list="cities_ca" emptyField="true" /&gt;&lt;/td&gt;<br /> &lt;/tr&gt;<br /> &lt;/mtw:if&gt;<br /> &lt;mtw:if test="state" value="FL"&gt;<br /> &lt;tr&gt;<br /> &lt;td&gt;Cities&lt;/td&gt;&lt;td&gt;&lt;mtw:select name="city" list="cities_fl" emptyField="true" /&gt;&lt;/td&gt;<br /> &lt;/tr&gt;<br /> &lt;/mtw:if&gt;<br /> [/code]<br /> This is awkward and will introduce other problems. For example when we first show the page and no state is selected, we must show an empty list.<br /> <br /> Luckily there is a much better solution by using a Mentawai filter to create a dynamic list [i]on the fly[/i] and place it in the action output. Remember that the [i]mtw:select tag[/i] is smart enough to pick up lists straight from the action output, if it finds one.<br /> <br /> Let's define the problem before we dive into the code. Below are the situations where we need to take action:<br /> <br />     1) Empty form is being displayed to insert a new bean =&gt; List should be empty<br /> <br />     2) Form is being redisplayed probably because of a validation error =&gt; List should be the same one when the used submitted the form, in other words, it should not lose its state when a validation error occurs.<br /> <br />     3) Form is being used to EDIT a bean, in other words, a bean object was placed in the action output and a forward was performed to the JSP with the form =&gt; List should display the appropriate list corresponding to the bean State.<br /> <br />     4) The user selected another State =&gt; List should be changed through Ajax (out of the scope of this recipe)<br /> <br /> Here are the conditions for 1), 2) and 3):<br /> <br />     1) Nothing is in the action input and nothing is in the action output =&gt; Form is being used to insert a bean and an empty list should be displayed.<br /> <br />     2) The current State id is in the action input =&gt; A validation error occurred and you should use the State id to show the appropriate City list.<br /> <br />     3) There is an object in the action output with a State id property =&gt; The object (bean) is being edited, so show the appropriate City list corresponding to this bean State id.<br /> <br /> Below is a simple filter that I coded to address all these scenarios:<br /> [code]<br /> public class CityListFilter implements Filter {<br /> 	<br /> 	private Map&lt;Integer, String&gt; getMap(int state_id) {<br /> 		<br /> 		Map&lt;Integer, String&gt; list = new LinkedHashMap&lt;Integer, String&gt;();<br /> 		<br /> 		List&lt;City&gt; cities = State.getCities(state_id);<br /> 		<br /> 		if (cities != null) {<br /> 			<br /> 			list.put(0, "-- Select a City --");<br /> 			<br /> 			for(City c : cities) {<br /> 				<br /> 				list.put(c.getId(), c.getName());<br /> 			}<br /> 			<br /> 		} else {<br /> 			<br /> 			list.put(0, "-- Select a State --");<br /> 		}<br /> 		<br /> 		return list;<br /> 	}<br /> 	<br /> 	public String filter(InvocationChain chain) throws Exception {<br /> 		<br /> 		Action action = chain.getAction();<br /> 		<br /> 		Input input = action.getInput();<br /> 		<br /> 		Output output = action.getOutput();<br /> 		<br /> 		int state_id = input.getIntValue("state");<br /> 		<br /> 		if (state_id &gt; 0) {<br />             <br />             // 2) VALIDATION ERROR<br /> 			<br /> 			output.setValue("cities", getMap(state_id));<br /> 			<br /> 			return chain.invoke();<br /> 			<br /> 		} else {<br /> 			<br /> 			// 3) EDITING A BEAN<br /> 			<br />              // execute action first, so bean is placed in<br />              // action output for editing<br /> 			String res = chain.invoke();<br /> 			<br /> 			Object obj = output.getValue("user");<br /> 			<br /> 			if (obj instanceof User) {<br /> 				<br /> 				User user = (User) obj;<br /> 				<br /> 				state_id = user.getState();<br /> 				<br /> 				output.setValue("cities", getMap(state_id));<br /> 				<br /> 			} else {<br /> 				<br />                 // 1) EMPTY FORM FOR INSERTING BEAN<br />                 <br /> 				// just show an empty list...<br /> 				output.setValue("cities", getMap(-1));<br /> 			}<br /> 			<br /> 			return res;<br /> 		}<br /> 	}<br />     <br />     public void destroy() { }<br /> }<br /> [/code]<br /> So now you can use a single [i]mtw:select[/i] tag and your list will be filled appropriately according to the situation and the State id.<br /> [code]<br /> &lt;mtw:select name="city" list="cities" /&gt;<br /> [/code]<br /> <br /> One last catch when setting the filter in the application manager: This filter should  be executed *before* the [i]ValidatorFilter[/i] which is a [i]global filter[/i] that performs validation. That's because the [i]ValidatorFilter[/i] aborts the execution chain if it finds an error and as we know global filters are executed before any [i]action specific[/i] filter.<br /> <br /> Luckily there is an easy way to place an action specific filter before all global filters. Just use the [i]addFilterFirst()[/i] or [i]filterFirst()[/i] method from [i]ActionConfig[/i].<br /> [code]<br /> <br /> filter(new ValidatorFilter()); // global filter for validation<br /> <br /> action("/User", UserAction.class)<br />     .filterFirst(new CityListFilter())<br />     .on(SUCCESS, fwd("/show.jsp"))<br />     .on(ERROR, fwd("/error.jsp"));<br /> [/code]<br /> In a web application project, you will probably have to code a filter like that for every dynamic list. To make this job easier, Mentawai 1.14 includes the [i]org.mentawai.filter.DynamicListFilter[/i] that you can use to fast code these filters. See how we could have coded the filter above with this new abstract class:<br /> [code]<br /> public class CityListFilter extends DynamicListFilter {<br /> 	<br /> 	protected Map&lt;Integer, String&gt; getMap(int state_id) {<br /> 		<br /> 		Map&lt;Integer, String&gt; list = new LinkedHashMap&lt;Integer, String&gt;();<br /> 		<br /> 		List&lt;City&gt; cities = State.getCities(state_id);<br /> 		<br /> 		if (cities != null) {<br /> 			<br /> 			list.put(0, "-- Select a City --");<br /> 			<br /> 			for(City c : cities) {<br /> 				<br /> 				list.put(c.getId(), c.getName());<br /> 			}<br /> 			<br /> 		} else {<br /> 			<br /> 			list.put(0, "-- Select a State --");<br /> 		}<br /> 		<br /> 		return list;<br /> 	}<br />     <br />     protected String getParamName() {<br />         return "state";<br />     }<br />     <br />     protected String getListName() {<br />         return "cities";<br />     }<br />     <br />     protected String getBeanName() {<br />         return "user";<br />     }<br />     <br />     // not needed if == getParamName()<br />     protected String getBeanProperty() {<br />         return "state";<br />     }<br /> }<br /> [/code]<br /> ]]></description>
				<guid isPermaLink="true">http://recipes.mentaframework.org/posts/preList/59/62.page</guid>
				<link>http://recipes.mentaframework.org/posts/preList/59/62.page</link>
				<pubDate><![CDATA[Fri, 22 Aug 2008 11:41:41]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
	</channel>
</rss>
