In my JSF application i have a process that takes to long to complete and i don't want that the user keeps waiting till its finish. I'm trying to implement some kind of 'fire and forget task' to run in background.
I'm doing it using an #Asynchronous method. This is the right approach?
My controller:
#ViewScoped
#Named
public class Controller implements Serializable {
private static final long serialVersionUID = -6252722069169270081L;
#Inject
private Record record;
#Inject
private Service service;
public void save() {
this.record.generateHash();
boolean alreadyExists = this.service.existsBy(this.record.getHash());
if (alreadyExists)
Messages.add(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "This record already exists"));
else {
this.service.save(this.record);
this.clearFields();
}
}
}
My service:
#Stateless
public class Service extends AbstractService<Record> {
private static final long serialVersionUID = -6327726420832825798L;
#Inject
private BeanManager beanManager;
#Override
public void save(Record record) {
super.save(record);
this.preProcess(record);
}
#Asynchronous
private void preProcess(Cd cd) {
// Long task running here ...
this.beanManager.fireEvent(cd);
}
}
But even with this approach the user keeps stuck at the page till the preProcess method finishes.
The problem here is that annotations that modify the behavior of EJBs (and CDI beans) are only applied when called by the "proxy" object that gets injected to appropriate injection points, like fields annotated with #EJB or #Inject.
This is because of how the containers implement the functionality that modifies the behavior. The object that the container injects to clients of EJBs (and normal-scoped CDI beans) is actually a proxy that knows how to call the correct instance of the target bean (e.g. the correct instance of e #RequestScoped bean). The proxy also implements the extra behaviors, like #Transactional or #Asynchronous. Calling the method through this bypasses the proxy functionalities! For this reason placing these annotations on non-public methods is effectively a NO-OP!
A non-exclusive list of solutions:
Move preProcess() to a different EJB, make it public and keep the #Asynchronous annotation
Make preProcess() public and call it from the Controller
If the computation is truly private to the Service and exposing it would break design, and ou don't mind doing a bit more manual work, you can always run async tasks from the container-provided ManagedExecutorService:
#Resource
private ManagedExecutorService managedExecutorService;
Pay attention to the semantics of the thread that executes your code - more specifically to what context values are propagated and what not! Well, you have to pay attention to that for #Asynchronous methods too!
Related
In a Spring Boot application I'm using a class annotated with #KafkaListener as a message listener. I want to add a ConsumerRebalanceLister to my application to manage cached data on a rebalance.
How do I add a ConsumerRebalanceListener to a ConcurrentKafkaListenerContainerFactory. The documentation says that it should be set on a ContainerProperties object. It's not clear how to access that object in order to set it. Additionally, it looks like the ConcurrentKafkaListenerContainerFactory throws away the rebalance listener since it creates a new ContainerProperties object when creating a listener container instance.
I feel like I'm missing something really obvious here, before this commit there was a method to simply set the rebalance listener directly on the ConcurrentKafkaListenerContainerFactory.
Consider to use this method on the ConcurrentKafkaListenerContainerFactory:
/**
* Obtain the properties template for this factory - set properties as needed
* and they will be copied to a final properties instance for the endpoint.
* #return the properties.
*/
public ContainerProperties getContainerProperties() {
This is where you can add your ConsumerRebalanceListener. You #Autowired an auto-configured ConcurrentKafkaListenerContainerFactory and perform the mentioned injection:
#Autowired
private ConcurrentKafkaListenerContainerFactory containerFactory;
#PostConstruct
public void init() {
this.containerFactory.getContainerProperties()
.setConsumerRebalanceListener(myConsumerRebalanceListener());
}
#Bean
public ConsumerRebalanceListener myConsumerRebalanceListener() {
return new ConsumerRebalanceListener() {
...
};
}
we have mixed the usage of CDI and EJB in our application. At startup, we receive the error Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped.
We don't understand where exactly the problem is, so here is just the overall structure of the code:
#Stateless
public class SomeFacade {
#Inject
private SomeService someService;
}
#Stateless
public class SomeService {
#Inject
private SomeDao someDao;
}
#Stateless
public class SomeDao {
#Inject
private EntityManager entityManager;
}
#ApplicationScoped
public class EntityManagerProducer {
#Produces
#ApplicationScoped
public EntityManagerFactory createEntityManagerFactory() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("one");
return emf;
}
public void close(#Disposes EntityManagerFactory entityManagerFactory) {
entityManagerFactory.close();
}
#Produces
public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
}
Is there something we can change in general?
The error is raised because your code tries to access a request-scoped CDI bean in a moment when there's no request scope. Request scope is only created for incoming requests (HTTP requests via Servlet or JAX-RS, JMS MDBs, asynchronous EJB calls, etc.).
If you get this error during startup, I guess you access a request-scoped bean before CDI is fully started, e.g. from a singleton EJB. Try moving your code into a CDI that starts on start-up after CDI is initialized with:
#Dependent
public class CDIStartupBean {
public void startup(#Observes #Initialized(ApplicationScoped.class) Object event) {
// Start-up code here. The CDIStartupBean can inject request-scoped beans
}
}
Ondrej, your answer was helpful but was not quite the solution in my case.
First, I somehow resolved the start-up issues, but received the same error when handling arriving messages / REST requests. The solution was to annotate the service class with #ActivateRequestContext. This enabled CDI injections in all classes that are used by the servive.
A GenericServlet is a type of ServletConfig, also GenericServlet has a ServletConfig. What is logic in this? How should I understand this?
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
..
}
The ServletConfig is an interface and is implemented by services in order to pass configuration information to a servlet when it is first loaded.
GenericServlet implements ServletConfig. It's not a subclass of ServletConfig. Understand the difference between a subclass and interface.
GenericServlet class implements Servlet, ServletConfig and Serializable interfaces. It provides the implementation of all the methods of these interfaces except the service method.
GenericServlet class can handle any type of request so it is protocol-independent.
You may create a generic servlet by inheriting the GenericServlet class and providing the implementation of the service method.
Visit here for more
I'm fairly new to both Java EE and MVC. I have to develope a web application using Servlet, JSP, JB and EJB. As most applications mine too needs to interact with a RDBMS.
A friend of mine sent me a wep App he developed in which he has a
Serializable DbManager class
in which a
private transient Connection
exists as a member variable.
In all his servlets in which he needs DB access he has a DbManager variable. It is instantiate in the init method of the servlet and it is retrived like this :
this.manager = (DbManager)super.getServletContext().getAttribute("dbmanager");
All the queries are implemented as public methods of the DbManager Class.
I was wondering if this is a good way to implement such needs or if there is a better way to handle Db access and queries execution. I tought of implementing business logic and thus DB access as public methods in my EJBs.
Thanks for any help!
Homemade DbManager style classes are redundant when you are living in a JavaEE environment. You can make use of JPA for performing all your database queries from a stateless session bean that forms the "controller" part of your MVC architecture:
#Stateless
public class OrderController {
#PersistenceContext
private EntityManager em;
public void addNewOrder(Order order) {
em.persist(order)
}
public List<Order> findAllOrders() {
TypedQuery<Order> findAllOrdersQuery = em.createQuery("select o from Order o", Order.class);
return findAllOrdersQuery.list();
// In practice you would add pagination to this.
// It's not practical to return a million orders to your view.
}
...
}
This stateless EJB manages all transactions on your behalf, so you don't normally need to be concerned with beginning, committing and/or rolling back transactions.
The Order class is a component of your "model":
#Entity
public class Order {
#Id
private long id;
#Column
private String orderNumber;
#Column
private String description;
// other attributes
...
Order() { }
public Order(String orderNumber, String description) {
this.orderNumber = orderNumber;
this.description = description;
}
// setters and getters
...
// you must also override equals() and hashCode()
}
You will see many examples where developers introduce a so called DAO layer into their controller, but this is considered redundant as the EntityManager essentially satisfies that contract.
I have a stateful session bean where a list is maintained:
#Stateful
public class CartDAO{
private List<ShoppingCart> tempCart;
public void add(ShoppingCart shoppingCart){
tempCart.add(shoppingCart);
}
public List<ShoppingCart> getCart(){
return tempCart;
}
#PostConstruct
public void init(){
tempCart = new ArrayList<>();
}
}
Controller1 to add to the cart:
#Named
#SessionScoped
public class Controller1 implements Serializable {
#EJB
CartDAO cartDao;
public String addToShoppingCart() {
cartDao.add(shoppingCart);
}
}
Now, i want to ask you could i get the added items to the list from another cart?
#Named
#SessionScoped
public class Controller2 implements Serializable {
#EJB
CartDAO cartDao;
public String getShoppingCart() {
System.out.println(cartDao.getCart());//returns null
}
}
Obviously the above code returns null.
How do I retrieve the list from another controller. Any help will be much appreciated.
I don't see any obvious mistake here (are you sure that you don't call Controller2#getShoppingCart() before adding any items do your CartDAO?) but here are couple of my notions
you should have your CartDAO implement some interface or make it #LocalBean
all stateful beans should have method annotated with #Remove so you can clean the resources used in the bean (close datasources and son) and bean will be removed from the memory after this call
now it's recommended to use #Inject everywhere instead of #EJB, it's the same (you have to use #EJB only when you inject remote beans)
And also one point, if the System.out.println(cartDao.getCart()); returns null than it means the #PostConstruct haven't been called which is strange. Can you provide some more info about container and your environment?Also show us imports, this is big source of mistakes.