Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple CDI configuration profiles (devel, beta, qa, production) in one war?

Having experience with the Spring DI applicationContext.xml way of declaring Dependency Injection I now try to figure out how to do the same with Java EE6 CDI.

With Spring, I could ship my .jar with several configuration profiles like unittest.xml, devel.xml, qa.xml, production.xml and activate them using command line parameters or environment variables.

With CDI, I could use @Alternative in beans.xml and properties in of web.xml but there seems no way of shipping multiple beans.xml for different environments.

I don't want to use Maven profiles/filters to produce 4-6 versions of my app although I understand that for some scenarios that would be the better solution (i.e. shipping ready build wars to customers - but I only use my wars internally so let's save compile time!)

Preferably, I would also be able to load those configuration files from the file system so that they could be edited by the sysadmins without having to re-build the app.

What is the Java EE6 way of having multiple configuration sets of dependencies and properties?

If there is none, what are the recommended alternatives as of 2013? Using Spring? Seam? Guice? I saw mentionings of Apache DeltaSpike but they still seem alpha juding from the web page.

like image 994
lathspell Avatar asked Jun 03 '13 22:06

lathspell


1 Answers

I'd use a dynamic producer, using a Qualifier to identify the desired environment

// The qualifier for the production/qa/unit test 
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD,
 ElementType.FIELD, ElementType.PARAMETER})
public @interface Stage {
   String value() default "production";
}

// The interface for the stage-dependant service
public interface Greeting{
    public String sayHello();
}

// The production service
@Stage("production")
public class ProductionGreeting implements Greeting{
    public String sayHello(){return "Hello customer"; }
}

// The QA service
@Stage("qa")
public class QAGreeting implements Greeting{
    public String sayHello(){return "Hello tester"; }
}

// The common code wich uses the service
@Stateless
public class Salutation{
   @Inject Greeting greeting; 
   public String sayHello(){ return greeting.sayHello(); };
}

// The dynamic producer
public class GreetingFactory{
    @Inject
    @Any
    Instance<Greeting> greetings;        

    public String getEnvironment(){
         return System.getProperty("deployenv");
    }

    @Produces
    public Greeting getGreeting(){
        Instance<Greeting> found=greetings.select(
           new StageQualifier(getEnvironment()));
        if (!found.isUnsatisfied() && !found.isAmbiguous()){
           return found.get();
        }
        throw new RuntimeException("Error ...");
    }

    public static class StageQualifier 
      extends AnnotationLiteral<Stage> 
      implements Stage {
       private String value;

       public StageQualifier(String value){
           this.value=value;
       }
       public String value() { return value; }
     }

}

So here the container injects all available Greeting implementations into GreetingFactory, which in turn serves as @Producer for the intended one, basing the decision on the system property 'deployenv'.

like image 116
Carlo Pellegrini Avatar answered Sep 28 '22 09:09

Carlo Pellegrini