How to access same ClassPathXmlApplicationContext instance from 2 main methods - spring

I've to write a quartz scheduler to run a job in Spring. I've to also add another function to pause the same job. This code is present inside a single standalone batch.
To trigger these 2 functions:
1. start the job
2. pause the job
I've written 2 classes with main() which does the execution.
The issue is when I trigger the main() for pauseJob, it starts the different applicationContext instead of using the same one. I've used a Singleton pattern for applicationContext initialization.
Singleton class for ApplicationContext initialization
public class AppContext {
private static ApplicationContext INSTANCE = null;
private AppContext() {
}
public static ApplicationContext getIntance() {
if (INSTANCE == null) {
String[] contexts = new String[] {"classpath:/applicationContext.xml"};
INSTANCE = new ClassPathXmlApplicationContext(contexts);
}
return INSTANCE;
}
}
Class to start the Job
public class StartJobQuartzMain {
public static void main(String[] args) throws Exception {
AppContext.getIntance();
}
}
Class to pause the job
public class PauseJobQuartzMain {
public static void main(String[] args) throws Exception {
((TestPauseJob) AppContext.getIntance().getBean("testPauseJob")).pauseJob();
}
}
Kindly guide me on how to fetch the same applicationContext instance in PauseJobQuartzMain.java. Thanks.

Making it a singleton has nothing to do with it (it is in a way required)... The two 'java' main classes will run independent of each other, as in, they are two different programs, with their own Java Virtual Machine, and will not be able to share your application context with each other.
You can use database or an external file (accessible by both) or something to achieve this...
Hope this helps...

You can’t do that from another main class because you run it definitely from a fresh JVM. So each of them has their own Singleton. You can consider to use some shared resource between two these apps: db, file, JMS queue finally etc. or you can call some managed operation over JMX. But two JVMs can’t share memory, especially Java objects, when application context is one of them.

Related

How to get previous task local variables of a running process instance in activiti

I am developing a spring boot application with activiti as the workflow engine. The activiti-spring-boot-starter dependency version is 7.1.0.M6 and spring-boot-starter-parent version is 2.6.7.
I have defined a BPMN 2.0 diagram using activiti-modelling-app and I am now starting the process instance. After completing a task, I want to access its task local variables when processing the next task. I am unable to figure out the api for it.
I tried using the historyService as below but with no luck. I get the result list as empty everytime with different apis (finished(), unfinished() etc)
HistoricTaskInstance acceptMobile = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.taskName("my-task1")
.singleResult();
Can someone guide me on what could be the right api to use to get the local variables of a previously completed task?
Thanks.
The best way to transfer variables between tasks is to use execution variables with DelegateExecution
execution variables are specific pointers to where the process is active, for more information, see apiVariables
Let say you have Task-A and Task-B with different listeners
here's how to use execution variable from Task-A to Task-B:
#Component("TaskListenerA")
public class TaskListenerA implements TaskListener {
#Override
public void notify(DelegateTask task) {
DelegateExecution execution = task.getExecution();
if("complete".equals(task.getEventName()) {
String myTaskVar = (String) task.getVariable("taskAvariable")
execution.setVariable("exeVariable", myTaskVar);
}
}
}
#Component("TaskListenerB")
public class TaskListenerB implements TaskListener {
#Override
public void notify(DelegateTask task) {
DelegateExecution execution = task.getExecution();
String myVariable = execution.get("exeVariable");
}
}

Do JASON internal actions work with Spring Autowire?

I am developing an application using JADE, JASON (Agent frameworks) and Spring Boot. Basically what I have is a JADE Container where Both Jade and Jason Agents are registered in. And Since I am using Spring, I tend to Autowire services. In that case I am in need to access some services, inside some of my Jason internal actions (which I custom wrote extending DefaultInternalAction class). which seems not working. I have the idea how to Autowire and how the Beans work. My doubt is whether those internal actions are in the spring context or not. I guess they are not. Thats why may be the Autowire thing is not working. Can someone please explain me about the real action inside the jade container and internal actions so that I can think differently about using Autowire inside jason internal actions.
As far as I know, internal actions is created by jason, not spring that is why you cant autowire services. Personnaly, I create factory and use it for getting instance of a service. Something like this:
public class SpringPluginFactory {
private static final SpringPluginFactory INSTANCE = new SpringPluginFactory();
private ApplicationContext applicationContext;
private SpringPluginFactory(){}
private <T> T createPlugin(Class<T> iface) {
if(applicationContext == null){
throw new IllegalStateException("applicationContext cannot be null");
}
try {
return applicationContext.getBean(iface);
} catch (Exception e) {
throw new RuntimeException("factory unable to construct instance of " + iface.getName());
}
}
public static <T> T getPlugin(Class<T> iface){
return INSTANCE.createPlugin(iface);
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
then I create bean in order to set aplicationContext:
#Bean
public SpringPluginFactory pluginFactory(ApplicationContext applicationContext){
SpringPluginFactory pluginFactory = SpringPluginFactory.INSTANCE;
pluginFactory.setApplicationContext(applicationContext);
return pluginFactory;
}
and use the factory in any behaviours or internal actions
SpringPluginFactory.getPlugin(YouService.class).doSomething();
Maybe it will help.

How to initialize SpringContext once and share across tasks?

I am trying to initialize spring context in my Spark application. I want the context in my slave nodes as well as I want to re-use the beans. Here is the code for the same:-
shipperRD2.foreach(shipper->{
AmazonS3 amazonS3Client = AmazonS3ClientBuilder.standard().build();
FileSystemXmlApplicationContext context2 = new FileSystemXmlApplicationContext("https://s3.console.aws.amazon.com/s3/object/spring-configuration/app-context.xml");
PersistenceWrapper persistenceWrapper = context.getBean(PersistenceWrapper.class);
});
However, this is leading to context refresh every time a new task runs on the slave node. Is there any way to avoid this behavior. basically, just initialize the context on the first task run, and re-use that context in the subsequent tasks.
As mentioned by Jacek, I tried the singleton pattern and it worked.
public class SpringInit {
private static FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(fileName);
private SpringInit(){
}
public static FileSystemXmlApplicationContext getInstance(){
return context;
}
}
From the spark,
shipperRD2.foreach(shipper->{
FileSystemXmlApplicationContext context = SpringInit.getInstance();
PersistenceWrapper persistenceWrapper = context.getBean(PersistenceWrapper.class);
});

#Lock(LockType.READ) Singleton Ejb in java 8

Using Java 7 with Jboss7 the following code used to work.
#Singleton
public class OperacaoServiceImpl implements OperacaoService {
private Operacao operacaoEmAndamento;
#Override
#Lock(LockType.READ)
public Operacao getOperacaoEmAndamento() {
return operacaoEmAndamento;
}
#Override
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void geraEIniciaOperacao() throws CoreException {
geraOperacao();
iniciaOperacao();
}
}
Now I've migrated to Java 8 with Wildfly it stopped working. If geraEIniciaOperacao is still running, I can't access getOperacaoEmAndamento.
" javax.ejb.ConcurrentAccessTimeoutException: WFLYEJB0241: EJB 3.1
PFD2 4.8.5.5.1 concurrent access timeout on OperacaoServiceImpl -
could not obtain lock within 5000MILLISECONDS at
org.jboss.as.ejb3.concurrency.ContainerManagedConcurrencyInterceptor.processInvocation(ContainerManagedConcurrencyInterceptor.java:106)
..."
I couldn't understand why something like this used to work. But what I've found is: with container managed concurrency the semantics is "concurrent reads are allowed as long as no writing is going on". What I need is "concurrent reads are allowed, also while writing goes on, but only one thread will be writing at a time". To achieve that I've changed the class to
#Lock(LockType.READ)
#Singleton
public class OperacaoServiceImpl implements OperacaoService {
and the method
public void geraEIniciaOperacao() throws CoreException {
to
syncronized public void geraEIniciaOperacao() throws CoreException {
Reference: EJB 3.1 container managed concurrency vs. synchronized

How are Spring <task:scheduled> objects represented at runtime?

I have an app that uses the "task:scheduler" and "task:scheduled-tasks" elements (the latter containing "task:scheduled" elements). This is all working fine.
I'm trying to write some code that introspects the "application configuration" to get a short summary of some important information, like what tasks are scheduled and what their schedule is.
I already have a class that has a bunch of "#Autowired" instance variables so I can iterate through all of this. It was easy enough to add a "List" to get all of the TaskScheduler objects. I only have two of these, and I have a different set of scheduled tasks in each of them.
What I can't see in those TaskScheduler objects (they are actually ThreadPoolTaskScheduler objects) is anything that looks like a list of scheduled tasks, so I'm guessing the list of scheduled tasks is recorded somewhere else.
What objects can I use to introspect the set of scheduled tasks, and which thread pool they are in?
This functionality will be available in Spring 4.2
https://jira.spring.io/browse/SPR-12748 (Disclaimer: I reported this issue and contributed code towards its solution).
// Warning there may be more than one ScheduledTaskRegistrar in your
// application context. If this is the case you can autowire a list of
// ScheduledTaskRegistrar instead.
#Autowired
private ScheduledTaskRegistrar scheduledTaskRegistrar;
public List<Task> getScheduledTasks() {
List<Task> result = new ArrayList<Task>();
result.addAll(this.scheduledTaskRegistrar.getTriggerTaskList());
result.addAll(this.scheduledTaskRegistrar.getCronTaskList());
result.addAll(this.scheduledTaskRegistrar.getFixedRateTaskList());
result.addAll(this.scheduledTaskRegistrar.getFixedDelayTaskList());
return result;
}
// You can this inspect the tasks,
// so for example a cron task can be inspected like this:
public List<CronTask> getScheduledCronTasks() {
List<CronTask> cronTaskList = this.scheduledTaskRegistrar.getCronTaskList();
for (CronTask cronTask : cronTaskList) {
System.out.println(cronTask.getExpression);
}
return cronTaskList;
}
If you are using a ScheduledMethodRunnable defined in XML:
<task:scheduled method="run" cron="0 0 12 * * ?" ref="MyObject" />
You can access the underlying target object:
ScheduledMethodRunnable scheduledMethodRunnable = (ScheduledMethodRunnable) task.getRunnable();
TargetClass target = (TargetClass) scheduledMethodRunnable.getTarget();
I have a snippet for pre spring 4.2 since it is still sitting at release candidate level.
The scheduledFuture interface is implemented by every runnable element in the BlockingQueue.
Map<String, ThreadPoolTaskScheduler> schedulers = applicationContext
.getBeansOfType(ThreadPoolTaskScheduler.class);
for (ThreadPoolTaskScheduler scheduler : schedulers.values()) {
ScheduledExecutorService exec = scheduler.getScheduledExecutor();
ScheduledThreadPoolExecutor poolExec = scheduler
.getScheduledThreadPoolExecutor();
BlockingQueue<Runnable> queue = poolExec.getQueue();
Iterator<Runnable> iter = queue.iterator();
while (iter.hasNext()) {
ScheduledFuture<?> future = (ScheduledFuture<?>) iter.next();
future.getDelay(TimeUnit.MINUTES);
Runnable job = iter.next();
logger.debug(MessageFormat.format(":: Task Class is {0}", JobDiscoverer.findRealTask(job)));
}
Heres a reflective way to get information about which job class is in the pool as threadPoolNamePrefix didn't return a distinct name for me:
public class JobDiscoverer {
private final static Field syncInFutureTask;
private final static Field callableInFutureTask;
private static final Class<? extends Callable> adapterClass;
private static final Field runnableInAdapter;
private static Field reschedulingRunnable;
private static Field targetScheduledMethod;
static {
try {
reschedulingRunnable = Class
.forName(
"org.springframework.scheduling.support.DelegatingErrorHandlingRunnable")
.getDeclaredField("delegate");
reschedulingRunnable.setAccessible(true);
targetScheduledMethod = Class
.forName(
"org.springframework.scheduling.support.ScheduledMethodRunnable")
.getDeclaredField("target");
targetScheduledMethod.setAccessible(true);
callableInFutureTask = Class.forName(
"java.util.concurrent.FutureTask$Sync").getDeclaredField(
"callable");
callableInFutureTask.setAccessible(true);
syncInFutureTask = FutureTask.class.getDeclaredField("sync");
syncInFutureTask.setAccessible(true);
adapterClass = Executors.callable(new Runnable() {
public void run() {
}
}).getClass();
runnableInAdapter = adapterClass.getDeclaredField("task");
runnableInAdapter.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
} catch (SecurityException e) {
throw new PiaRuntimeException(e);
} catch (ClassNotFoundException e) {
throw new PiaRuntimeException(e);
}
}
public static Object findRealTask(Runnable task) {
if (task instanceof FutureTask) {
try {
Object syncAble = syncInFutureTask.get(task);
Object callable = callableInFutureTask.get(syncAble);
if (adapterClass.isInstance(callable)) {
Object reschedulable = runnableInAdapter.get(callable);
Object targetable = reschedulingRunnable.get(reschedulable);
return targetScheduledMethod.get(targetable);
} else {
return callable;
}
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
throw new ClassCastException("Not a FutureTask");
}
With #Scheduled based configuration the approach from Tobias M’s answer does not work out-of-the-box.
Instead of autowiring a ScheduledTaskRegistrar instance (which is not available for annotation based configuration), you can instead autowire a ScheduledTaskHolder which only has a getScheduledTasks() method.
Background:
The ScheduledAnnotationBeanPostProcessor used to manage #Scheduled tasks has an internal ScheduledTaskRegistrar that’s not available as a bean. It does implement ScheduledTaskHolder, though.
Every Spring XML element has a corresponding BeanDefinitionReader. For <task:scheduled-tasks>, that's ScheduledTasksBeanDefinitionParser.
This uses a BeanDefinitionBuilder to create a BeanDefinition for a bean of type ContextLifecycleScheduledTaskRegistrar. Your scheduled tasks will be stored in that bean.
The tasks will be executing in either a default TaskScheduler or one you provided.
I've given you the class names so you can look at the source code yourself if you need more fine grained details.

Resources