using #schedule in EJB timer,not able to pass the schedule details from database - ejb

using #schedule in EJB timer, i want to pass the schedule details from database. but it is not allowing passing values. What should i do. In #timeout also i'm not able to start the thread automatically at server start time. #Postconstruct is not working.

You might have to use #Timeout, #Singleton, #Startup and #ConcurrencyManagement
#Singleton(name = "...", mappedName = "")
#Startup
#ConcurrencyManagement(ConcurrencyManagementType.BEAN) // this is threadsafe!!!
public class .......
Inject the TimerService for configuration
#Resource
private TimerService timerService;
Inject the EntityManager for db-access
#PersistenceUnit(..)
private EntityManager entityManager
Use #Timeout instead of #Schedule
#Timeout
void timer() { .... }
Configure the timer
#PostConstruct
void postConstruct() {
entityManager.createQuery(....);
.
.
timerService.createIntervalTimer(....);
}
except usage of EntityManager, this works at our site.

Related

Running a task in background on jsf form submit

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!

Adding ConsumerRebalanceListener to the ConcurrentKafkaListenerContainerFactory

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() {
...
};
}

Mixing CDI and EJB results in error at start

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.

Mockito failure: Actually, there were zero interactions with this mock

I'm trying to test a spring rest controller class using JUnit, Mockito, Spring test and Spring Security test. The following is my rest controller class for which i'm performing the test;
#RestController
public class EmployeeRestController {
#Autowired
private EmployeeService employeeService;
#PreAuthorize("hasAnyRole('ROLE_EMPSUPEADM')")
#RequestMapping(value = "/fetch-timezones", method = RequestMethod.GET)
public ResponseEntity<List<ResponseModel>> fetchTimeZones() {
List<ResponseModel> timezones = employeeService.fetchTimeZones();
return new ResponseEntity<>(timezones, HttpStatus.OK);
}
}
The following is my test class;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringConfiguration.class})
#WebAppConfiguration
public class EmployeeRestControllerUnitTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private EmployeeService employeeService;
#InjectMocks
private EmployeeRestController employeeRestController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
}
#Test
#WithMockUser(roles = {"EMPSUPEADM"})
public void testFetchTimezones() {
try {
mockMvc.perform(get("/fetch-timezones"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(4)));
verify(emploeeService, times(1)).fetchTimeZones();
verifyNoMoreInteractions(employeeService);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I made the above test class by refering many tutorials. The problem is i'm not able to understand everything clearly. so, i'm having the following doubts.
I'm creating a mock of EmployeeService and injecting it into EmployeeRestController using #InjectMocks, then why i'm getting the following failure;
Wanted but not invoked:
careGroupService.fetchTimeZones();
-> at com.example.api.test
.restcontroller.EmployeeRestControllerUnitTest
.testFetchTimezones(EmployeeRestControllerUnitTest.java:73)
Actually, there were zero interactions with this mock.
How does MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); works exactly.
I know that MockMvcBuilders.standaloneSetup(employeeRestController) is for testing individual controller classes and spring configuration will not be available for this method. How can we provide spring configuraton for this method, is it possible.
Finally, how does this piece of code: Mockito.reset(employeeService); works.
1) you do verify for
verify(emploeeService, times(1)).fetchTimeZones();
but you didn't setup mock behaviour for it (before you call mockMvc.perform(get("/fetch-timezones"))).
List<ResponseModel> timezones = new ArrayList<>();
when(emploeeService.fetchTimeZones()).thenReturn(timezones );
2) create MockMvc from context. mockmvc emulates web container, use mock for all where is possible but supports http call and gave the possibility to call controller.
It stands up the Dispatcher Servlet and all required MVC components,
allowing us to test an endpoint in a proper web environment, but
without the overhead of running a server.
3) when you use:
#MockBean private EmployeeService employeeService;
you override real service. remove it from test class real service will be used in testing. Instead of use #Mock use #MockBean. #MockBean it's override by container, with #Mock you need to inject this into controller by reflection
or without spring boot with reflection:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
EmployeeRestController employeeRestController=
webAppContext.getBean(EmployeeRestController.class);
ReflectionTestUtils.setField(employeeRestController,
"employeeService",
employeeService);
}
4) Mockito.reset(employeeService);- you reset all behaviors that you setupped before. Mock contains information from when(), verify() and controls it , call reset - it's clean all information.

Can two stateless EJB's share the same request scoped entity manager?

I've decided to use a request scoped container managed EntityManager and I've created a producer for that reason:
#RequestScoped
public class EntityManagerProducer {
#PersistenceContext(unitName = "PU", type = PersistenceContextType.TRANSACTION)
private EntityManager entityManager;
#Produces
public EntityManager getEntityManager() {
return entityManager;
}
}
I've got two EJB's that expose a remote client view:
#Remote
public interface EJB1 {
void createPerson(int id, String firstName, String lastName);
}
#Remote
public interface EJB2 {
void containsEntity(Person person);
}
#Stateless
public class EJB1Impl implements EJB1 {
#Inject
private EntityManager entityManager;
#EJB
private EJB2 ejb2;
#Override
public void createPerson(final int id, final String firstName, final String lastName) {
Person person = new Person();
person.setId(id);
person.setFirstName(firstName);
person.setLastName(lastName);
entityManager.persist(person);
System.out.println("EJB1Impl: persistence context contains entity: " + entityManager.contains(person));
ejb2.containsEntity(person);
}
}
#Stateless
public class EJB2Impl implements EJB2 {
#Inject
private EntityManager entityManager;
#Override
public void containsEntity(final Person person) {
System.out.println("EJB2Impl: PersistenceContext contains entity: " + entityManager.contains(entity));
person.setLastName("new name");
//entityManager.merge(person);
}
}
The EJB's are deployed on WildFly 10. I access them by a remote client using this tutorial. The current version throws this exception: org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped. If I remove the #RequestScoped annotation from the producer, I don't get an exception but the EntityManager injected into the second EJB returns false when asked if it contains the entity and if I want the changes made to the entity (the change of the last name) to have any effect, I have to call entityManager.merge(person), which apparently means that the entity is detached. I'm sure that the second EJB executes withing the same transaction because if I inject an EJBContext and call setRollbackOnly() the transaction started in EJB1 is rolled back and a new person is not inserted into the data base.
The documentation of javax.enterprise.context.RequestScoped says that the request scope is active during any remote method invocation of any EJB, so what gives? How can I share an EntityManager during a request across multiple EJB's

Resources