1

I have Stateless bean that calls asynchronous operation. I would like to inject to this bean my another bean, which stores (or rather should store) running process status. Here is my code:

Processor:

@Stateless
public class Processor {

    @Asynchronous
    public void runLongOperation() {
        System.out.println("Operation started");
        try {
            for (int i = 1; i <= 10; i++) {
                //Status update goes here...
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
        }
        System.out.println("Operation finished");
    }

}

ProcessorHandler:

@ManagedBean(eager = true, name="ph")
@ApplicationScoped
public class ProcessorHandler implements RemoteInterface {

    public String status;

    @EJB
    private Processor processor;

    @PostConstruct
    public void init(){
        status = "Initialized";
    }

    @Override
    public void process() {
        processor.runLongOperation();
    }

    public String getStatus() {
        return status;
    }


}

Process method of ProcessHandler is bound to a button. I would like to modify status of ProcessHandler bean from inside of Processor, so I can display updated status to user.

I tried to use @Inject, @ManagedProperty and @EJB annotations, but without success.

I'm testing my soulution on Websphere v8.5 developed using Eclipse EE.


When added inject to Processor class...

@Inject
public ProcessorHandler ph;

I got error:

The @Inject java.lang.reflect.Field.ph reference of type ProcessorHandler for the <null> component in the Processor.war module of the ProcessorEAR application cannot be resolved.
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
The Raven
  • 527
  • 1
  • 6
  • 31

1 Answers1

3

You should never have any client-specific artifacts (JSF, JAX-RS, JSP/Servlet, etc) in your service layer (EJB). It makes the service layer unreusable across different clients/front-ends.

Simply move private String status field into the EJB as it's actually the one responsible for managing it.

@ManagedBean(eager = true, name="ph")
@ApplicationScoped
public class ProcessorHandler implements RemoteInterface {

    @EJB
    private Processor processor;

    @Override
    public void process() {
        processor.runLongOperation();
    }

    public String getStatus() {
        return processor.getStatus();
    }

}

Note that this won't work on a @Stateless, but on @Singleton or Stateful only for the obvious reasons.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Cool! I will try it right now. Thanks for your suggestions :) – The Raven Nov 20 '15 at 14:32
  • 1
    @Tiny: Because they are supposed to be stateless (i.e. don't have any instance variables). Namely, the container won't guarantee that across method invocations exactly the same stateless EJB instance is reused. See also a.o. http://stackoverflow.com/a/31639830 – BalusC Nov 21 '15 at 20:13
  • Uh! I now see, "*Simply move `private String status` field into the EJB*" which I completely missed before. Thanks. – Tiny Nov 22 '15 at 00:03
  • I modified my solution as you suggested. Status is now stored in Processor @Sigleton ejb, and async methods are called from yet another bean (@Stateless, methods are @Asynchronous) from Processor object. Thanks again for your suggestions! – The Raven Nov 23 '15 at 15:25