Run Java EE CDI task with interval - wildfly

I need to run a task with interval once my application (WAR) starts, I am using WildFly 21.
The task should be initialized at startup and perform some work at some interval.
the class is below
#ApplicationScoped
#ActivateRequestContext
public class TaskRunner {
#Resource private ManagedScheduledExecutorService scheduler;
#Inject private ScheduledFuture<?> TaskRunnerScheduler;
private boolean initialized = false;
private void init(#Observes #Initialized(ApplicationScoped.class) Object init) {
if (initialized) return;
initialized = true;
try {
// Execute at startup
TaskRunner = scheduler.schedule(this::runSchedule, getSchedule());
} catch (Throwable throwable) {
}
}
private void runSchedule() {
//do some work
}
private Trigger getSchedule() {
return new Trigger() {
#Override
public Date getNextRunTime(LastExecution lastExecutionInfo, Date taskScheduledTime) {
return Date.from(
ZonedDateTime.now().withSecond(0).withNano(0).plusHours("4").toInstant());
}
#Override
public boolean skipRun(LastExecution lastExecutionInfo, Date scheduledRunTime)
{return false;}};
}
}
When trying to deploy the application, I am getting the following error
ERROR [org.jboss.msc.service.fail] (MSC service thread 1-6) MSC000001: Failed to start service jboss.deployment.unit."task-web.war".WeldStartService: org.jboss.msc.service.StartException in service jboss.deployment.unit."task-web.war".WeldStartService: Failed to start service
at org.jboss.msc#1.4.12.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.execute(ServiceControllerImpl.java:1731)
at org.jboss.msc#1.4.12.Final//org.jboss.msc.service.ServiceControllerImpl$ControllerTask.run(ServiceControllerImpl.java:1559)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type ScheduledFuture<?> with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject private TaskRunner.TaskRunnerScheduler
at TaskRunner.TaskRunnerScheduler(TaskRunner.java:0)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:378)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:290)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:143)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:164)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:526)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:64)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:62)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:62)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:55)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.JBossThread.run(JBossThread.java:513)
Any ideas what is the cause of this error?

It looks like you want to run every 4 hours or so. Can I suggest a bit cleaner implementation?
#Startup
#Singleton
public class MyScheduler {
#PostConstruct
private void runAtStartup() {
// whatever makes sense here
}
#Schedule(hour = "*/4", persistent = false )
private void runSomething() {
// something here
}
}
This sets up an EJB to run at startup (#Startup), saying that there is only one instance of it (#Singleton). It then runs the runSomething() method every 4 hours. You can take a look at the Schedule Javadocs as there are many other ways to run this too. You may or may not need the #PostConstruct method if it previously only existed to setup the timer.
The persistent parameter tells Wildfly to remember when the last run was and, if restarted, continue to run on that schedule. If you don't care if your method runs again on restart then leave this false.
My only warning is that this mechanism doesn't handle overlaps. If you use this and a new schedule method is run before the last one finishes (in this example, 4 hours later) it can lead to errors in at least your log and the schedule not running the way you expect it to.

From your code snippet alone, simply remove the (unused) TaskRunnerScheduler field.

I found the issue, it was a typo in the following line
#Inject private ScheduledFuture<?> TaskRunnerScheduler;
the correct one is without the inject
private ScheduledFuture<?> TaskRunnerScheduler;

Related

Spring Batch Test Single Job

I am trying to write Integration test for spring batch aplication , in my project there are approx 10+jobs
I want to run only a single job but unable to achieve any Suggestion.
#SpringBatchTest
#RunWith(SpringRunner.class)
#ContextConfiguration(classes= MyApp.class)
#SpringBootTest
#Slf4j
public class JobATest {
JobLauncherTestUtils jobLauncherTestUtils = new JobLauncherTestUtils();
#Autowired
#Qualifier(JOB_A)
Job joba;
#Before
public void setUp() throws Exception {
log.debug("CAME HERE setUp {} ",joba.getName());
jobLauncherTestUtils.setJob(joba);
}
#After
public void tearDown() throws Exception {
}
#Test
public void processAJob() throws Exception {
jobLauncherTestUtils.launchJob();
}
}
ERROR
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'jobLauncherTestUtils': Unsatisfied dependency expressed
through method 'setJob' parameter 0; nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'org.springframework.batch.core.Job' available:
expected single matching bean but found 2: **joba,jobb**
When using #SpringBatchTest, it is expected that the test context contains a single job bean. This is mentioned in the javadoc of the annotation.
There is an open issue for that which we might consider for the next major release. Please upvote or add a comment if you have a suggestion for an improvement. I also invite you to check the thread on Multiple Job unit testing with #SpringBatchTest which could help you as well.

NullPointer while using JPA EntityManager in a ThredPoolExecutor

I'm implementing a JavaEE8 application using CDI and running on an Open Liberty (v20.0.0.4). The application has a event-triggered job, which runs some code in an separate thread using the ThreadPoolExecutor like this:
#Singleton
public class MyJobExecutorService {
#PostConstruct
public void init() {
thredPoolExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}
public void runJob(MyConfigs configs) {
thredPoolExecutor.submit(() -> new MyJobRunnable(configs).run());
}
}
The job gets data from the underlying sql database using an EntityManager, which is injected in the data access class and produced like following. My querys are written using querydsl (which should not be relevant).
public class EntityManagerProducer {
#PersistenceContext(unitName = "my-unit")
private EntityManager entityManager;
#Produces
#Dependent
public EntityManager getEntityManager() {
return entityManager;
}
}
My persistence.xml looks like this:
<persistence ...>
<persistence-unit name=my-unit">
<jta-data-source>jdbc/datasource</jta-data-source>
</persistence-unit>
</persistence>
I have no issues accessing the database from the main thred, but the job throws a NullPointerException with the following stacktrace (and no further information):
com.ibm.ws.jpa.management.JPATxEntityManager.getEMInvocationInfo(JPATxEntityManager.java:213)
com.ibm.ws.jpa.management.JPATxEntityManager.getEMInvocationInfo(JPATxEntityManager.java:164)
com.ibm.ws.jpa.management.JPAEntityManager.getDelegate(JPAEntityManager.java:402)
com.querydsl.jpa.impl.JPAProvider.getTemplates(JPAProvider.java:61)
com.querydsl.jpa.impl.JPAQuery.<init>(JPAQuery.java:48)
com.querydsl.jpa.impl.JPAQueryFactory.query(JPAQueryFactory.java:138)
com.querydsl.jpa.impl.JPAQueryFactory.select(JPAQueryFactory.java:81)
com.querydsl.jpa.impl.JPAQueryFactory.selectFrom(JPAQueryFactory.java:111)
my.application.MyRepository.getAll(DataAccess.java:67)
sun.reflect.GeneratedMethodAccessor1888.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.MyRepository$Repository$Serializable$925348889$Proxy$_$$_WeldClientProxy.getAll(UnknownSource)
sun.reflect.GeneratedMethodAccessor1887.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.DataAccess$587668909$Proxy$_$$_WeldClientProxy.getAllData(UnknownSource)
my.application.job.MyDefaultJob.runJob(MyDefaultJob.java:50)
sun.reflect.GeneratedMethodAccessor1886.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.job.MyJob$588111896$Proxy$_$$_WeldClientProxy.runJob(UnknownSource)
my.application.job.MyJobExecutorService$MyRunnable.run(MyJobExecutorService.java:59)
my.application.job.MyJobExecutorService.lambda$runJob$0(MyJobExecutorService.java:36)
my.application.job.MyJobExecutorService$$Lambda$280/00000000A8128A20.run(UnknownSource)
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:823)
Why am I getting this exception and how can I fix this? Activating the jpa an concurrency features in the server.xml of the application server didnt help. Thanks a lot.
Enabling the concurrent-1.0 feature alone doesn't do anything unless you are using the managed resources that it provides which capture the context of the application component (such as its java:comp name space and so forth) and makes it available when running the tasks that are submitted to it.
If you must use a ThreadPoolExecutor in order to manipulate its queue in some way beyond enforcing concurrency constraints (ManagedExecutorService can impose concurrency constraints via a configurable concurrencyPolicy), the simplest way to continue using a ThreadPoolExecutor is by supplying it with a ManagedThreadFactory,
#PostConstruct
public void init() {
ManagedThreadFactory threadFactory = InitialContext.doLookup(
"java:comp/DefaultManagedThreadFactory");
thredPoolExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),
threadFactory);
}
ManagedThreadFactory captures the context that is present on the thread from which it is initially looked up. You'll need to decide if there is a better place for it than your init() method based on what context you want it to provide to your ThreadPoolExecutor tasks.
You should also be aware that any use of ThreadPoolExecutor (even in combination with a ManagedThreadFactory or ContextService) bypasses use of the Liberty global thread pool.

Overridden RabbitSourceConfiguration (app starters) does not work with Spring Cloud Edgware

I'm testing an upgrade of my Spring Cloud DataFlow services from Spring Cloud Dalston.SR4/Spring Boot 1.5.9 to Spring Cloud Edgware/Spring Boot 1.5.9. Some of my services extend source (or sink) components from the app starters. I've found this does not work with Spring Cloud Edgware.
For example, I have overridden org.springframework.cloud.stream.app.rabbit.source.RabbitSourceConfiguration and bound my app to my overridden version. This has previously worked with Spring Cloud versions going back almost a year.
With Edgware, I get the following (whether the app is run standalone or within dataflow):
***************************
APPLICATION FAILED TO START
***************************
Description:
Field channels in org.springframework.cloud.stream.app.rabbit.source.RabbitSourceConfiguration required a bean of type 'org.springframework.cloud.stream.messaging.Source' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.cloud.stream.messaging.Source' in your configuration.
I get the same behaviour with the 1.3.0.RELEASE and 1.2.0.RELEASE of spring-cloud-starter-stream-rabbit.
I override RabbitSourceConfiguration so I can set a header mapper on the AmqpInboundChannelAdapter, and also to perform a connectivity test prior to starting up the container.
My subclass is bound to the Spring Boot application with #EnableBinding(HeaderMapperRabbitSourceConfiguration.class). A cutdown version of my subclass is:
public class HeaderMapperRabbitSourceConfiguration extends RabbitSourceConfiguration {
public HeaderMapperRabbitSourceConfiguration(final MyHealthCheck healthCheck,
final MyAppConfig config) {
// ...
}
#Bean
#Override
public AmqpInboundChannelAdapter adapter() {
final AmqpInboundChannelAdapter adapter = super.adapter();
adapter.setHeaderMapper(new NotificationHeaderMapper(config));
return adapter;
}
#Bean
#Override
public SimpleMessageListenerContainer container() {
if (config.performConnectivityCheckOnStartup()) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Attempting connectivity with ...");
}
final Health health = healthCheck.health();
if (health.getStatus() == Status.DOWN) {
LOGGER.error("Unable to connect .....");
throw new UnableToLoginException("Unable to connect ...");
} else if (LOGGER.isInfoEnabled()) {
LOGGER.info("Connectivity established with ...");
}
}
return super.container();
}
}
You really should never do stuff like healthCheck.health(); within a #Bean definition. The application context is not yet fully baked or started; it may, or may not, work depending on the order that beans are created.
If you want to prevent the app from starting, add a bean that implements SmartLifecycle, put the bean in a late phase (high value) so it's started after everything else. Then put your code in start(). autStartup must be true.
In this case, it's being run before the stream infrastructure has created the channel.
Some ordering might have changed from the earlier release but, in any case, performing activity like this in a #Bean definition is dangerous.
You just happened to be lucky before.
EDIT
I just noticed your #EnableBinding is wrong; it should be Source.class. I can't see how that would ever have worked - that's what creates the bean for the channels field of type Source.
This works fine for me after updating stream and the binder to 1.3.0.RELEASE...
#Configuration
public class MySource extends RabbitSourceConfiguration {
#Bean
#Override
public AmqpInboundChannelAdapter adapter() {
AmqpInboundChannelAdapter adapter = super.adapter();
adapter.setHeaderMapper(new MyMapper());
return adapter;
}
}
and
#SpringBootApplication
#EnableBinding(Source.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
If that doesn't work, please edit the question to show your POM.

Using #EJB injection in an Application Client, both in same EAR

I've searched now for days to find some solution for my, in my opinion not too hard but obviously unsolvable problem.
I have an EAR project containing Some EJB, a web client (works fine) and now I added an Application Client Module.
As everything is in the same project, I thought a simple #EJB injection in the main class of the application client would do. I also tried a JNDI lookup.
I use eclipse and glassfish as a server and tried to run the application 1. in eclipse (there my injected bean is just null) and 2. downloaded the client-stub from the glassfish administration and tried to start it with sh appclient -client (or -jar) OmazanClient.jar (and also the other two jars hidden in the client-stub folder). There I get mostly a "ClassNotFoundExeption:Main" like
java.lang.ClassNotFoundException: Main
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.glassfish.appclient.client.acc.ACCClassLoader.findClass(ACCClassLoader.java:212)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at org.glassfish.appclient.client.acc.FacadeLaunchable.getMainClass(FacadeLaunchable.java:262)
at org.glassfish.appclient.client.acc.AppClientContainer.setClient(AppClientContainer.java:324)
at org.glassfish.appclient.client.acc.AppClientContainerBuilder.createContainer(AppClientContainerBuilder.java:185)
at org.glassfish.appclient.client.acc.AppClientContainerBuilder.newContainer(AppClientContainerBuilder.java:172)
at org.glassfish.appclient.client.AppClientFacade.createContainerForAppClientArchiveOrDir(AppClientFacade.java:492)
at org.glassfish.appclient.client.AppClientFacade.createContainer(AppClientFacade.java:454)
at org.glassfish.appclient.client.AppClientFacade.prepareACC(AppClientFacade.java:269)
at org.glassfish.appclient.client.acc.agent.AppClientContainerAgent.premain(AppClientContainerAgent.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:323)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:338)
So for the injection, my code looks like:
public class Main {
#EJB (mappedName="ejb/customerBean")
public static CustomerInterface customerBean;
#EJB (mappedName="ejb/productBean")
public static ProductInterface productBean;
public static void main(String[] args) {
try{
Main m = new Main();
m.runDialog();
}
catch (Exception e){
e.printStackTrace();
}
}
/* (non-Java-doc)
* #see java.lang.Object#Object()
*/
public Main() {
super();
}
private void runDialog() throws Exception{
System.out.println("Test");
List<ProductDTO> productList = productBean.getAllProducts();
...
My remote interface looks like this:
#Remote
public interface ProductInterface {
public int addProduct(String productName);
public void deleteProduct(int prodid);
public void updateProduct(int prodid, String newName);
List<ProductDTO> getAllProducts();
...
My implementation is this:
/**
* Session Bean implementation productInterface
* */
#Stateless(mappedName="ejb/productBean")
#LocalBean
#WebService
public class ProductBean implements ProductInterface {
#EJB ProductEAO eao;
#EJB Conversion conv;
/**
* Default constructor.
*/
public ProductBean() {
// TODO Auto-generated constructor stub
}
#Override
public int addProduct(String prodName) {
return eao.addProduct(prodName);
}
#Override
public List<ProductDTO> getAllProducts() {
List<ProductDTO> result = new ArrayList<ProductDTO>();
List<Product> allProducts = eao.allProducts();
for (Product pr : allProducts) {
ProductDTO ci = conv.fromProduct(pr);
result.add(ci);
}
return result;
}
... and so on (all methods required by the interface are implemented, just try to keep it shorter here)
and the MANIFEST.MF is just
Manifest-Version: 1.0
Main-Class: Main
I've tried a lot like JNDI lookup, giving the bean names (see example) etc. But either the interface is not found (lookup) or the bean simply null.
How ever I am also not quite sure how to run the application client. I thought glassfishs appclient is the right starting point? It shall be a console-interaction so no swing components or anything similar.
Now I'd be thankful for any suggestions what I might have missed.
Cheers :)
Found a solution. Somehow, JNDI works now. Another problem was that my db query returned an Object and not primitive value or string - this caused a buffer error.
However, I am still confused on how to export an run an application client correctly. Maybe someone has an idea?!
There is a good example here: Create and Run a JEE6 Client Application with Netbeans 6.8 and Glassfish V3 - Part 2: Enhancing and Deploying the Application. It is a few years old, but it does give a pretty good overview.

Java EE6 (with JBoss7): automatically roll back the transaction

I want to test the automatically rolling back of an transaction. Therefore, I implemented a simple bean[src] that throws an system exception which should result in an automatically roll back[1]. I also implemented the interface SessionSynchronization so I can affect the rollback with the method afterCompletion. But the argument of this method is true which I expect to be false in regards to the specs[2].
Am I missing something or is this a bug in JBoss 7? I already searched the bug tracker but did not find anything ... maybe I used the wrong words?
If this is not a bug: are there any settings regarding to set the afterCompletion parameter to false if a system or an application exception occures?
[1]: "There are two ways to roll back a container-managed transaction. First, if a system exception is thrown, the container will automatically roll back the transaction. Second, by invoking the setRollbackOnly method of the EJBContext interface, the bean method instructs the container to roll back the transaction. If the bean throws an application exception, the rollback is not automatic but can be initiated by a call to setRollbackOnly." http://docs.oracle.com/javaee/6/tutorial/doc/bncij.html
[2]: "The afterCompletion method notifies a stateful session bean instance that a transaction commit protocol has completed, and tells the instance whether the transaction has been committed or rolled back." http://docs.oracle.com/javaee/6/api/javax/ejb/SessionSynchronization.html
[src]:
#Stateful
#LocalBean
public class RollbackTestBean implements RollbackTest, SessionSynchronization {
int counter = 0;
int counterBuffer = 0;
private final Logger logger = Logger.getLogger(this.getClass().getName());
#Override
public int getCounter() {
return counter;
}
#Override
public void throwSystemException() throws SystemException {
counter++;
throw new SystemException();
}
#Override
public void afterBegin() throws EJBException, RemoteException {
logger.info("[TX]: after begin");
counterBuffer = counter;
}
#Override
public void afterCompletion(boolean success) throws EJBException, RemoteException {
logger.info("[TX]: after completion: " + success);
if (!success)
counter = counterBuffer;
}
#Override
public void beforeCompletion() throws EJBException, RemoteException {
logger.info("[TX]: before completion");
}
}
There are two SystemExceptions
org.omg.CORBA.SystemException subclass of RuntimeException
javax.transaction.SystemException subclass of Exception
I hope you are using org.omg.CORBA.SystemException
EJB3.1 spec says, if its RuntimeException or ApplicationException, the transaction needs to be rolled back.
As far as I can see, ApplcationException is handled correctly in JBoss 7.1.1, but not RuntimeException.
With RuntimeException, there is a similar issue reported when remove() is called on Statefull bean, reference here. I am getting the same error message when I try to throw RuntimeException. Its fixed in Verion 7.1.3 I think. But I have not tested myself.
You can try 7.1.3, if you are looking for a fix. If you have your Exception and wants transaction rollback, use
#ApplicationException(rollback=true)
Maddy