VRaptor

Trabalhando com diferentes ambientes

Environment é uma funcionalidade do VRaptor que nos permite definir componentes e configurações diferentes conforme o ambiente que você está: produção, testes, desenvolvimento, etc.

Você pode, por exemplo, desativar o envio de e-mails no ambiente de desenvolvimento, porém habilitar quando estiver em produção.

Configuração

Há várias formas de configurar o environment. A primeira opção é adicionando as linhas abaixo no seu web.xml para, por exemplo, configurar o nome do environment para PRODUCTION:

<context-param>
    <param-name>br.com.caelum.vraptor.environment</param-name>
    <param-value>PRODUCTION</param-value>
</context-param>

A segunda opção é configurar uma propriedade na JVM. Para isso, basta iniciar a instância do seu Servlet Container ou Application Server com o seguinte parâmetro:

-Dbr.com.caelum.vraptor.environment=PRODUCTION

A terceira opção permite configurarmos o nome do environment usando as variáveis de ambiente do sistema operacional, bastando adicionar a variável VRAPTOR_ENV.

Exemplo no windows:

set VRAPTOR_ENV=PRODUCTION

Exemplo no unix:

export VRAPTOR_ENV=PRODUCTION

Nota: A configuração usando variáveis do sistema operacional possui maior prioridade sobre a configuração de propriedades da JVM, que possui maior prioridade sobre a configuração no web.xml.

Definindo as propriedades de um ambiente

Basta criar um arquivo de propriedades no classpath da aplicação com o nome do seu ambiente. Por exemplo, para definir as propriedades de produção, devemos criar um arquivo production.properties:

ambiente_de_teste=false
email=production.mail@mail.com

Se você tem propriedades que são comuns a outros ambientes, você pode criar um arquivo chamado environment.properties com as propriedades comuns. Quando você precisar usar alguma propriedade, o Environment irá procurar primeiro no arquivo do ambiente, e caso não encontrar, irá procurar o environment.properties.

Você também pode sobrescrever propriedades usando System Properties. Propriedades definidas nas System Properties irão sobreescrever quaisquer outras definições. Nota: Você só pode usar System Properties para sobreescrever propriedades existentes nos arquivos de propriedades e não para definir novas propriedades.

Considerando que você tenha um environment.properties abaixo: ~~~ #!properties my.prop hello ~~~

Você pode sobrescrever a propriedade existente my.prop com uma System Property: ~~~ #!java System.setProperty(“my.prop”, “bye”); environment.get(“my.prop”); //bye ~~~

Se a chave não existir no arquivo de propriedades, o método get irá lançar uma NoSuchElementException.

Acessando propriedades de ambiente no seu código

Há dois métodos para acessar as propriedades de ambiente via código: get e getOrDefault. O método get retorna o valor da propriedade ou uma MissingResourceException se a propriedade não for encontrada. Já o método getOrDefault retorna o valor da propriedade, ou um valor padrão caso não encontrada.

@Controller
public class MeuController {

    private final Environment environment;

    private final MailSender sender;

    /**
     * @deprecated CDI eyes only
     */
    protected MeuController(){
        this(null, null);
    }

    @Inject
    public MeuController(Environment environment, MailSender sender) {
        this.environment = environment;
        this.sender = sender;
    }

    public void sendMail(String email) {
        if(environment.isDevelopment()) {
            sender.sendMailTo(environment.get("email"));
            return;
        }
        sender.sendMailTo(email);
    }
}

No código acima, environment.get("email") irá retornar o valor da propriedade email. Porém caso a propriedade não existir em todos os ambientes, você pode usar o método getOrDefault para retornar um valor padrão.

public void sendMail(String email) {
    if(environment.isDevelopment()) {
        sender.sendMailTo(environment.getOrDefault("email"), "noreply@vraptor.org");
    } else {
        sender.sendMailTo(email);
    }
}

Acessando propriedades de ambiente no JSP

<c:if test="${environment.isTest()}">
    <p>Você está no ambiente de teste. Suas ações aqui não afetarão o sistema.</p>
</c:if>

Enviando e-mail para: ${environment.get('email')}

Acessando arquivos de configuração de acordo com o environment

Se você precisa acessar um arquivo de configuração diferente para suas bibliotecas, de acordo com seu ambiente, você também pode utilizar o Environemnt. Basta colocar, por exemplo, seu hibernate.cfg.xml em diretórios com o nome de seus ambientes: development e production (por exemplo). Environment.getResource(...) retornará o resource de acordo com seu ambiente atual:

cfg = new AnnotationConfiguration();
cfg.configure(environment.getResource("/hibernate.cfg.xml"));

Para manter compatibilidade com quem não utilizava o environment, caso o arquivo não seja encontrado no diretório com o nome do ambiente, ele será carregado no diretório root (do classpath).

Injetando o valor de suas configuração programaticamente

Você também consegue injetar suas configurações programaticamente usando o @Property, por exemplo:

@Controller
public class MeuController {

    @Inject
    @Property("email")
    private String email;

    public void sendMail(String email) {
        sender.sendMailTo(email);
    }
}

Neste caso, se o seu environment estiver com valor DEVELOPMENT, vai injetar o valor que corresponde a chave email do arquivo development.properties, se estiver com PRODUCTION do production.properties e assim por diante. Dessa forma você não precisa dos ifs como: if(environment.isDevelopment()) {...} em seu código.

Outra facilidade, é que se o nome da chave for o mesmo nome do field injetado, como em nosso caso com a chave email, você pode deixar apenas o @Property que o nome será inferido. Seu controller ficaria assim:

@Controller
public class MeuController {

    @Inject
    @Property
    private String email;

    public void sendMail(String email) {
        sender.sendMailTo(email);
    }
}

Você também pode definir um valor padrão para essa propriedade:

@Inject
@Property(defaultValue = "config.properties")
private String fileName;