Antes de mais nada gostaria de falar que o VRaptor é um excelente framework e que se eu não usasse o Mentawai usaria o VRaptor.
Um diferencial do VRaptor em relaçao aos outros frameworks é que ele é bastante “desacoplado” do framework em si, ou seja, uma Action, ou lógica do VRaptor não extende nada do framework e trabalha com poucas classes do framework. Não tem como fugir das anotações, mas pelo menos vc não extende nenhuma classe e não trabalha como nenhum input e output.
A filosofia do Mentawai é que a action pode e deve ser apenas uma ponte para o seu modelo de negócios, ou seja, uma action vai ser algo burro que vai apenas passar dados de um lado para o outro e decidir sobre a consequencia web que cada requisiçao terá.
É difícil pensar numa situaçao onde uma Action precisará estender outra coisa que não seja o BaseAction do framework ou uma outra BaseAction qualquer criada pela aplicaçao. Dessa maneira “salvar” a action de gastar sua herança me parece que não trará nenhum ganho na maioria dos casos.
Mesma coisa se aplica para o input e output. Numa situaçao ideal, sua action não deve precisar do input nem do output, ou seja, os dados de entrada devem ser automaticamente injetados na action (ou diretamente no modelo do qual essa action depende para executar suas funções) e os dados de saída devem ser automaticamente obtidos da action (ou novamente do modelo).
Para esses casos, basta fazer uso do InjectionFilter e do OutputFilter para que a action do Mentawai tenha exatamente o comportamente acima, ou seja, possa ignorar o input e o output por completo.
Entretanto existirão muitos outros casos não ideais, em que sua action/filtro, por comodidade ou necessidade, precisará trabalhar com o input e o output. Exemplo:
// permite apenas que certos IPs acessem essa action...
if (!input.getProperty("remoteAddr").starts("200.100.22.")) {
return ACCESS_DENIED;
}
// permite apenas autenticacao via POST...
if (input.getProperty("method").equalsIgnoreCase("get")) {
addError("Não é permitido se autenticar via get!");
return GLOBAL_ERROR;
}
// computa o tempo de execucao dessa action e coloca no output... (provavelmente um filtro)
long now = System.currentTimeMillis();
String result = chain.invoke();
long time = System.currentTimeMillis() - now;
output.setValue("execTime", String.valueOf(time));
Outra argumento para favorecer o total desacoplamento seria TESTES. Minha opinião sobre isso é primeiro que a action deverá ser tão burra e simples que testes serão desnecessários. Entretanto se vc é daqueles que gosta de testar todo e qualquer IF da sua aplicacao, então vc pode usar uma MockAction fornecida pelo próprio framework para realizar os testes de maneira bem simples. Ex:
Action action = new MyActionDoMentawai();
MockAction mockAction = new MockAction(action);
mockAction.getInput().setValue("name", "Whatever");
String result = mockAction.execute();
assertEqual(result, Action.SUCCESS);
assertEqual(mockAction.getOutput().getValue("name"), "WHATEVER");
Outra questão é a CoC, que acredito ser bastante subjetiva e dependente do projeto em questão. Mais sobre isso aqui: http://www.guj.com.br/posts/list/60/49817.java