3

I have the following interface:

public interface ResultEvaluationInterface {
    public void evaluateResults(Event e);
}

and I want to inject in my class depending on my Event.type different classes with the same implementation. Something like that:

@Stateless
@LocalBean    
public class ResultEvaluation implements ResultEvaluationInterface {

    @Override
    public void evaluateResults(Event e) {
        switch (e.getType()) {
            case Type.Running:
               // inject and call ResultEvaluationRunningEJB.evaluateResults(e)
            case Type.Swimming:
               // inject and call ResultEvaluationSwimmingEJB.evaluateResults(e)
            default:
               throw new UnsupportedOperationException("Not supported yet.");
        }
    }

}

ResultEvaluationRunningEJB and ResultEvaluationSwimmingEJB both implement the interface. Anybody has got a good idea how to do that in a good way?

Hash
  • 4,647
  • 5
  • 21
  • 39
perotom
  • 851
  • 13
  • 33
  • Just to get this straight, you want to use a development mock implementation for a dev environment? – dngfng Jul 17 '15 at 11:36
  • Does "Production" and "Development" refer to your deployed instance, i.e. do you have a production instance which will only get "Production" events, or can one installed instance ever get both "Deployment" and "Production" events? – user140547 Jul 17 '15 at 11:36
  • The type was just an example. I will change them for not confusing you. – perotom Jul 17 '15 at 11:38
  • 1
    Do you have to use EJB? or is CDI also an option? CDI has an event system which may be useful for your use case. see http://docs.oracle.com/javaee/7/tutorial/cdi-adv005.htm#GKHIC – user140547 Jul 17 '15 at 11:49

2 Answers2

2

If you really want to use a hard coded if statement to switch between prod and dev events you could use CDI Qualifiers simply inject the two implementations into a Facade:

@Stateless
@LocalBean    
public class ResultEvaluationFacade {

    @Inject
    @Development
    private ResultEvalutationInterface dev;

    @Inject
    @Production
    private ResultEvalutionInterface prod;

    @Override
    public void evaluateResults(Event e) {
        switch (e.getType()) {
            case Type.Production:
               prod.evaluteResult(e);
               break;
            case Type.Development:
               dev.evaluteResult(e);
               break;
            default:
               throw new UnsupportedOperationException("Not supported yet.");
        }
    }

}

And define your two implementations:

@Development
public class ResultEvaluationDevelopment implements ResultEvaluationInterface {
   ...
}

@Production
public class ResultEvaluationDevelopment implements ResultEvaluationInterface {
   ...
}

However I would consider using a mock maven project to house the two separate implementations instead.

Alternatively you could use different CDI Event types, something like this.

public void observeDevEvent(@Observe DevEvent event) {
   //do stuff.
}

public void observeProdEvent(@Observe ProdEvent event) {
   //do stuff
}

Firing the event would look something like this:

@Inject
private Event<ProdEvent> prodEvent;

public void someMethod() {
   ProdEvent pe = new ProdEvent()
   // set some data on ProdEvent
   prodEvent.fire(pe);
}

Note events can also work with Qualifiers, so you could also add a Qualifier annotation to the Event instead of implementing two different types of event.

@Inject
@Production
private Event<MyEvent> event;

And listen for @Prodcution events;

public void handleProdEvent(@Observer @Production MyEvent myEvent) {
    // do Stuff.
}

For lazy instantiation of beans you can use CDI Instance injection.

@Inject
private Instance<BeanA> beanA;

....

public void doStuff(Event e) {
   ...
   case Type.Production:
            //lazily evaluates and instantiatiates bean.
            beanA.get().evaluateResult(e);
}
dngfng
  • 1,923
  • 17
  • 34
  • I thing your first example fits my requirements perfectly just one more question on that: If i add a lot more injection beans with that interface (20-30) and add it in ResultEvaluationFacade wouldn´t that be bad for the performance? specially if i use the PostConstruct event with database interaction in eg ResultEvaluationDevelopment? – perotom Jul 17 '15 at 12:27
  • 1
    In such a secenario I wouldn't employ this technique. To deal with the performance issues you could use Instance, this efficativly allows for lazy loading and initalization of beans. See my extended answer. – dngfng Jul 17 '15 at 14:41
  • Which technique would you use? Very helpful answere! – perotom Jul 18 '15 at 09:04
  • There are several solution options I will outline another solution in a separate answer. – dngfng Jul 18 '15 at 09:22
0

Note: I have not confirmed that this works, but you should be able to work something out with this.

You could use dynamic CDI event dispatching:

public class EventDispatcher {

    @Inject
    BeanManager beanManager;

    public void handle(MyEvents mytype) {
        beanManager.fireEvent(mytype, mytype.getQualifiyer());
    }
}

You can reference your qualifiers in your event enum something like this:

public enum MyEvents {

    EVENTA(new EventA() {
        @Override
        public Class<? extends Annotation> annotationType() {
            return this.getClass();
        }
    }),
    EVENTB (new EventB() {
        @Override
        public Class<? extends Annotation> annotationType() {
            return this.getClass();
        }
    });

    private final Annotation annotation;

    MyEvents(Annotation annotation) {
        this.annotation = annotation;
    }
    public Annotation getQualifiyer() {
        return annotation;
    }

};

The qualifiers look something like this:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,ElementType.FIELD})
public @interface EventA {

}

That way you could simply add observer methods to the event processing beans:

public class EventProcessorA {
   ...
   public void handleEvent(@Observer @BeanA MyEvents myevent) {
       ...
   }
}

Instead of injecting 20-30 in one dispatcher with a giant switch statement.

dngfng
  • 1,923
  • 17
  • 34