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.
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.
Related
I want to run some process just after the deployment of Glassfish. Process will run every hour and it contains fetching data from DB table via stateless bean CarService with findAll() below:
#PersistenceContext
private EntityManager em;
public List<Cars> findAll() {
javax.persistence.criteria.CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(Cars.class));
return em.createQuery(cq).getResultList();
}
Then i am using ScheduledExecutorService with starts process after deployment.
#ManagedBean(eager=true)
#ApplicationScoped
public class ApplicationStateChange {
private ScheduledExecutorService scheduler;
#PostConstruct
public void init() {
System.out.println("ejb init method called");
scheduler = Executors.newScheduledThreadPool(2);
scheduler.scheduleAtFixedRate(new ScheduleTask();, 15, 30, TimeUnit.SECONDS);
}
#PreDestroy
public void destroy() {
/* Shutdown stuff here */
System.out.println("ejb destroy method called");
scheduler.shutdownNow();
}
above ScheduleTask() contains the process including business logic e.g:
public class ScheduleTask implements Runnable {
#Inject
CarService carService;
private volatile ScheduledExecutorService scheduler = null;
#Override
public void run() {
System.out.println("scheduletask is called");
List<Car> carList = new ArrayList<>();
carList = carService.findAll();
if (carList != null) {
for (Car car : carList) {
System.out.println(car);
}
}
}
i am unable to get the findALL() method by injecting into above runnable class. scheduler works fine but it fails when it reaches to carList = carService.findAll(); infact its failing at javax.persistence.criteria.CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
I suspect persistence context is not loaded properly at the time of its calling.
I have followed following questionsSpawning threads in a JSF managed bean for scheduled tasks using a timer
scheduledExecutorService, timerService and Stateless EJB on scheduled jobs
As clearly exposed in the answer for the first question you have linked, simply use #Schedule into a #Singleton SessionBean annotated with #Startup in order to ensure it runs when the server starts or the application is deployed.
As you correctly mentioned, EntityManager and PersistenceContext cannot be injected into a non container-mananged class (and Singleton SessionBean is a managed class).
Linked Answer:
Spawning threads in a JSF managed bean for scheduled tasks using a timer
Still learning JSF and Java and having trouble understanding how to access a session bean property.
I have a LoggedUser session bean which sets the user that is logged in(using the login method).
#ManagedBean(name="loggedUser")
#Stateless
#LocalBean
#SessionScoped
public class LoggedUser {
#EJB
UserEJB userEJB;
#PersistenceContext
private EntityManager em;
private UserEntity loggedUser;
private String loginUserName;
private String loginPassword;
public LoggedUser() {}
public UserEntity getLoggedUser() {
return loggedUser;
}
public void setLoggedUser(UserEntity loggedUser) {
this.loggedUser = loggedUser;
}
public String authenticate() {
if (loggedUser == null) {
return "login.xhtml";
} else {
return "";
}
}
public String login() {
if (userEJB.validateLogin(loginUserName, loginPassword)) {
setLoggedUser(userEJB.fetchUser(loginUserName));
return "index.xhtml";
}
return "";
}
public String getLoginUserName() {
return loginUserName;
}
public void setLoginUserName(String loginUserName) {
this.loginUserName = loginUserName;
}
public String getLoginPassword() {
return loginPassword;
}
public void setLoginPassword(String loginPassword) {
this.loginPassword = loginPassword;
}
}
I want to be able to view the logged user from other areas in the application. I think I am injecting it incorrectly because loggedUser is always null when I am in a different bean for example something like..
#Stateless
#LocalBean
public class HistoryEJB {
#PersistenceContext
EntityManager em;
#ManagedProperty(value = "#{loggedUser}")
private LoggedUser loggedUser;
public LoggedUser getLoggedUser() {
return loggedUser;
}
public void setLoggedUser(LoggedUser loggedUser) {
this.loggedUser = loggedUser;
}
public void testLoggedUser() {
loggedUser.getLoggedUser();
// Just an example but would be null here - why?
}
}
How can I access this property from other areas in my application? Thanks for any help.
You can't use #ManagedProperty in an EJB and you shouldn't inject a view component into a business-tier component, period. #ManagedProperty is strictly web-tier stuff and is able to inject only and into web-tier, JSF components.
Your EJB ought to have a method that accepts a LoggedUser. This way, you can then pass your logged-in user to the EJB (which is the proper flow of data in a web application). What you have now is just turning best practice on its head.
So
Add a provideLoggedUser(LoggedUser loggedUser) method to your EJB
Call that method on your instance of UserEJB from within your managed bean
Rule of Thumb: Your EJB should not be aware of the web application
It seems you are missing the setter and getter for loggedUser. In principe it is there but it is convention to name it as follows
setProperty
and
setProperty
for a field named property. Note the capital first letter of the field name in the setter and getter!
I'm trying to inject a bean in a stateless EJB. But i would like that bean be different when EJB is called from a ManagedBean or from a EJB Timer.
Here is my EJB in which i inject a User bean:
MyEjb.java
#Stateless
class MyEjb{
#Inject
#CurrentContext
private User user;
public void foo(){
System.out.println(user);
}
}
Here is a EJB Timer that use the EJB:
TimerTest.java
#Singleton
#Startup
class TimerTest {
#EJB
private MyEjb myEjb;
#Timeout
public void doIt(Timer timer) {
myEjb.foo();
}
#Produces
#CurrentContext
public User produceCurrentUserInEjbTimer(){
return new User("system");
}
}
Finally, the ManagedBean using MyEjb :
MyManagedBean.java
#ManagedBean
#SessionScoped
class MyManagedBean {
#EJB
private MyEjb myEjb;
public void bar() {
myEjb.foo();
}
#Produces
#CurrentContext
#RequestScoped
public User produceCurrentUserInManagedBean(){
return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
}
}
When the timeout is reach, i would like that foo method of MyEbj use the system User created by the method produceCurrentUserInEjbTimer.
And when the bar method of the ManagedBean is invoked, i would like that foo method of MyEbj use the remote User of the FaceContext (created by the method produceCurrentUserInManagedBean).
I would rather have only one producer that checks if FacesContext.getCurrentInstance() != null then call the apropriate code:
public User produceCurrentUser(){
if(FacesContext.getCurrentInstance() != null){
return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
}
else{
return new User("system");
}
}
You can also inject you User directly on the timer or the ManagedBean and then use InjectionPoint object to know to which class your User is injected:
public User produceCurrentUser(InjectionPoint injectionPoint){
System.out.println(injectionPoint.getBean());
}
You should also use #Named and #javax.enterprise.context.SessionScoped as you have CDI on your application instead of #ManagedBean.
UPDATE
I'm not sure that there is a direct method to get the context of the injection, it wil be possible throw CDI extension but I've never try it.
What about obtaining a contextual instance by programmatic lookup:
#Stateless
class MyEjb{
#Inject #Any Instance<User> userSource;
public void foo(String context) // you should define contexts your self as jms, jsf ...
{
// Every expected context will have a qualifier
Annotation qualifier = context.equals("jsf") ?
new JSFQualifier() : new JMSQualifier();
User p = userSource.select(qualifier).get();
System.out.println(user);
}
}
This was you can inject your EJB and pass the context param to foo:
#Named
#SessionScoped
class MyManagedBean {
#EJB
private MyEjb myEjb;
public void bar() {
myEjb.foo("jsf");
}
}
I wanted to know, is there any option to call a managed bean inside of EJB bean. Imagine, we have the code:
#ManagedBean
#SessionScoped
public class MyManagedBean implements Serializable {
public String getUrl() {
return "http://www.google.com";
}
}
#Stateless
public class MyEJB {
#ManagedProperty(value = "#{myManagedBean}")
MyManagedBean myManagedBean;
public void setMyManagedBean(MyManagedBean myManagedBean) {
this.myManagedBean = myManagedBean;
}
public void call() {
// NullPointerException here
System.out.println(myManagedBean.getUrl());
}
}
I also tried this:
#Stateless
public class MyEJB {
#EJB
MyManagedBean myManagedBean;
...
}
... but it returns different MyManagedBean instance.
This is not right. With CDI managed beans instead of JSF managed beans it's possible, but it is just not right as in, bad design. The business service should not be aware about the front-end at all. It makes the business service unreusable on other front-ends than JSF.
You should do it the other way round. You should inject the EJB in the managed bean, not the other way round. The EJB should be kept entirely stateless. You should just directly pass the EJB the information it needs as method argument (and never assign it as instance variable of EJB afterwards).
E.g.
#ManagedBean
#SessionScoped // <-- Did you read https://stackoverflow.com/q/7031885?
public class MyManagedBean implements Serializable {
private String url = "http://www.google.com";
#EJB
private MyEJB myEJB;
public void submit() {
myEJB.call(url);
}
public String getUrl() {
return url;
}
}
and
#Stateless
public class MyEJB {
public void call(String url) {
// No NullPointerException here.
System.out.println(url);
}
}
See also:
JSF Service Layer
I want a managed bean to run internally on start up in my JSF web application when the application loads. How can I write this class and configure in Glassfish?
In JSF with CDI, observe the initialization of the application scope.
#Named
#ApplicationScoped
public class App {
public void startup(#Observes #Initialized(ApplicationScoped.class) Object context) {
// ...
}
public void shutdown(#Observes #Destroyed(ApplicationScoped.class) Object context) {
// ...
}
}
When having OmniFaces at hands, this can be simplified with #Eager.
#Named
#Eager
#ApplicationScoped
public class App {
#PostConstruct
public void startup() {
// ...
}
#PreDestroy
public void shutdown() {
// ...
}
}
In JSF 2.2- with the now deprecated javax.faces.bean annotations, use an application scoped managed bean which is eagerly initialized.
#ManagedBean(eager=true)
#ApplicationScoped
public class App {
#PostConstruct
public void startup() {
// ...
}
#PreDestroy
public void shutdown() {
// ...
}
}