AOP Using Around to avoid executing a method - java

I am using Spring AOP in my code to intercept the execution of a certain method. A simplified example of what I'm trying to do is below:
public void someMethod() {
//does something
}
#Around("execution( someMethod())")
public void anotherMethod(final ProceedingJoinPoint joinPoint) {
//i want to add this to a queue to get executed later on
addToWaitList(new Callable() {
#Override
public call() throws Exception {
joinPoint.proceed();
}
});
return;
}
Essentially, I want to hold off the execution of someMethod() until it is at the head of the list. However, the main thread blocks, even though I return at the end of anotherMethod(), so I am unable to add a new Callable to the list until the first one is done executing.
The documentation says you can shortcut the advised method execution by returning its own return value or throwing an exception. I don't want to throw an exception and am not really sure what "returning its own return value" means in this case. I want to be able to add the Callables to the list with the main thread and then have some other threadpool executing them.

What you wish to implement is the worker object pattern. I have created a small example for you showing how you can intercept method calls with by a certain naming pattern, but with variable return types and parameters. See my own answer there for a more complex example.
Driver application:
public class Application {
public static void main(String[] args) {
System.out.println("Starting up application");
Application app = new Application();
app.doThis(11);
app.doThat();
app.doThis(22);
System.out.println("Shutting down application");
}
public void doThis(int number) {
System.out.println("Doing this with number " + number);
}
public String doThat() {
String value = "lorem ipsum";
System.out.println("Doing that with text value '" + value + "'");
return value;
}
}
Aspect implementing worker object pattern:
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Callable;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class QueuedExecutionAspect {
Queue<Callable<Object>> waitList = new LinkedList<Callable<Object>>();
private void addToWaitList(Callable<Object> callable) {
waitList.add(callable);
}
#Around("execution(public * Application.do*(..))")
public Object anotherMethod(final ProceedingJoinPoint joinPoint) {
System.out.println(joinPoint + " -> adding to execution queue");
addToWaitList(new Callable<Object>() {
#Override
public Object call() throws Exception {
try {
joinPoint.proceed();
} catch (Throwable e) {
throw new Exception(e);
}
return null;
}
});
return null;
}
#After("execution(public * Application.main(..))")
public void doDelayedExecution(JoinPoint joinPoint) throws Exception {
System.out.println("\nDelayed executions:");
while (!waitList.isEmpty()) {
waitList.poll().call();
}
}
}
Output:
Starting up application
execution(void Application.doThis(int)) -> adding to execution queue
execution(String Application.doThat()) -> adding to execution queue
execution(void Application.doThis(int)) -> adding to execution queue
Shutting down application
Delayed executions:
Doing this with number 11
Doing that with text value 'lorem ipsum'
Doing this with number 22
As you can see from the output, the #Around advice terminates normally after having added the Callable worker object to the queue, application execution continues without proceed() having been called. For illustration I added another advice which runs all elements from the FIFO queue (other queue types can be used according to your needs) before the application exits.

Related

Why does reactive stream subscriber is executed in current thread?

subscribe documentation states:
Keep in mind that since the sequence can be asynchronous, this will
immediately return control to the calling thread. This can give the
impression the consumer is not invoked when executing in a main thread
or a unit test for instance.
So why do I see every element printed out? It means that lambda is executed in the main thread
import reactor.core.publisher.Flux;
import java.util.concurrent.TimeUnit;
public class ReactorMain {
public static void main(String[] args) {
Flux.just(1,2,3,4,5,6,7,8,9,10)
.limitRequest(5)
.skip(3)
.subscribe(value -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Value: " + value);
})
;
}
}
This is because the generation of values does not contain any asynchronous element. So when you subscribe to the Flux, it will use the current thread to do as many thing it can do, until an asynchronous element makes it wait and use the thread for something else.
If to produce your elements you are for example calling a web service in an asynchronous way, you will receive values in an asynchronous way.
You can test it by making the sequence delayed:
public static void main(String[] args) {
Flux.just(1,2,3,4,5,6,7,8,9,10)
.limitRequest(5)
.skip(3)
.delayElements(Duration.ofSeconds(2))
.subscribe(value -> {
System.out.println("Value: " + value);
})
;
}

How to create a test which waits for record appearance in the database?

I have a method which starts generating some report in another thread while the main thread returns a link to a google folder where created report should be uploaded. After report was created, it inserts a record with some information in the database.
public Link startReportCreation(ReportRequest reportRequest) {
Link link = /** some logic **/;
taskExecutor.execute(() -> {
/** report creation logic **/
});
return link;
So what is the best way to test the info of the inserted record without modifying the startReportCreation method?
Update
Currently I have while (taskExecutor.getActiveCount() != 0); kind of lock, which indicates that taskExecutor ended its execution and I can check the database. But I think there is a better approach.
Btw sry for misleading, that is not a unit test, it's just an executor to manually test methods on real data.
Solved
So I've managed to refactor my startReportCreation method and instead of simple taskExecutor I used CompletableFuture, so now it's looks like this:
public CompletableFuture<Link> startReportCreation(ReportRequest reportRequest) {
/** some logic **/
return CompletableFuture.supplyAsync(() -> {
Link link = /** some logic **/;
return link;
}, taskExecutor);
}
So in production code I use CompletableFuture.getNow() method and in tests I use CompletableFuture.get() to wait for the report creation.
First of all remember the FIRST principles of unit testing.
F: Fast
I: Independent
R: Repeatable
S: Small
T: Timely
Here you are a linik to review them in detail: https://github.com/ghsukumar/SFDC_Best_Practices/wiki/F.I.R.S.T-Principles-of-Unit-Testing
To achieve what you need, you must prepare the test in this way:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class ReportGeneratorTest {
//This is executed before each #Test, generally is used for prepare the ambient, instantiate services, start servers and so on.
#Before
public void setUp() throws IOException {
report = MyReportService.createReport();
}
//This is executed after each #Test generally this used for tear down your servers or data bases, or delete all the records inserted
#After
public void tearDown() {
MyReportService.deleteById(10);
}
#Test
public void verifyInsertion() throws Exception {
//Here you can verify that the record of your serive or logic it's ok
assertTrue(MyReportService.getLastId() > 10); //Or whatever
}
}
EDIT:
From the documentation of concurrent unit: https://github.com/jhalterman/concurrentunit/blob/master/src/test/java/net/jodah/concurrentunit/WaiterTest.java
You could create a Thread and wait for it.
#Test
public class WaiterTest {
#Test
public void shouldSupportMultipleThreads() throws Throwable {
final Waiter waiter = new Waiter();
for (int i = 0; i < 5; i++)
new Thread(new Runnable() {
public void run() {
waiter.assertTrue(true);
waiter.resume();
}
}).start();
waiter.await(0);
}

How to unit test java multiple thread

The issue is that I have a method starting a new thread for a time-consuming work. I want to test the callback result, but the child thread may still running, so as a result, what I get is not the right stub.
I think the code may explain itself:
public class JustAClass {
//it is a callback for async
public interface JustACallBack {
void callFunc(JustAResult result);
}
//this is the result interface
public interface JustAResult {
}
//this is a real class for the interface
public class JustAResultReal implements JustAResult{
public JustAResultReal(String content) {this.content = content;}
public String content;
}
//here is the key function
public void threadFunc(final JustACallBack callBack) {
BCCache.executorService.execute(new Runnable() {
#Override
public void run() {
//just to simulate a time-consuming task
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//now we callback
callBack.callFunc(new JustAResultReal("can you reach me"));
}
});
}
}
and the test function could be(I am using mockito):
#Test
public void testThreadFunc() throws Exception {
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = Mockito.mock(JustAClass.JustACallBack.class);
justAClass.threadFunc(callBack);
//add this line, we can get the expected result
Thread.sleep(1200);
Mockito.verify(callBack).callFunc(captor.capture());
System.out.println(((JustAClass.JustAResultReal)captor.getValue()).content);
}
I know we can add a sleep to wait and expect that the child thread would exit within the period, but could there be a better way? Actually how could I know how long the child thread would take? Setting a very long time can be an approach but just seems not very nice.
The general approach in #stalet's answer is close, but doesn't quite work since any assertion failures from a separate thread are not noticed by the main thread. Therefore your test will always pass, even when it shouldn't. Instead, try using ConcurrentUnit (which I authored):
#Test
public void testInvoke() throws Throwable {
Waiter waiter = new Waiter();
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = new JustAClass.JustACallBack() {
#Override
public void callFunc(final JustAClass.JustAResult result) {
waiter.assertNotNull(result);
waiter.assertTrue(result instanceof JustAClass.JustAResultReal);
waiter.resume();
}
};
justAClass.threadFunc(callBack);
waiter.await(1200, TimeUnit.SECONDS);
}
The key here is ConcurrentUnit's Waiter will properly report any assertions failures to the main test thread and the test will pass or fail as it should.
I aggree with #Gimbys comment about this is no longer a unit-test when you start testing the the threading aspect.
Nevertheless it is interesting as a way to integration-test a asynchronous invokation.
To avvoid sleep i tend to use the class CountDownLatch to wait for invokations.
In order to count down you need an actuall implementation of the callback interface - so in my example I have made a mock implementation of this.
Since there is no actual methods to fetch the data - i am just testing that it is in fact a instance of the JustAReal interface.
#Test
public void testInvoke() throws Exception {
final CountDownLatch countDownLatch = new CountDownLatch(1); //1 is how many invokes we are waiting for
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = new JustAClass.JustACallBack() {
#Override
public void callFunc(final JustAClass.JustAResult result) {
assertNotNull("Result should not be null", result);
assertTrue("Result should be instance of JustAResultReal", result instanceof JustAClass.JustAResultReal);
countDownLatch.countDown();
}
};
justAClass.threadFunc(callBack);
if(!countDownLatch.await(1200, TimeUnit.MILLISECONDS)){
fail("Timed out, see log for errors");
}
}

How to send multiple asynchronous requests to different web services?

I need to send multiple requests to many different web services and receive the results. The problem is that, if I send the requests one by one it takes so long as I need to send and process all individually.
I am wondering how I can send all the requests at once and receive the results.
As the following code shows, I have three major methods and each has its own sub methods.
Each sub method sends request to its associated web service and receive the results;therefore, for example, to receive the results of web service 9 I have to wait till all web services from 1 to 8 get completed, it takes a long time to send all the requests one by one and receive their results.
As shown below none of the methods nor sub-methods are related to each other, so I can call them all and receive their results in any order, the only thing which is important is to receive the results of each sub-method and populate their associated lists.
private List<StudentsResults> studentsResults = new ArrayList();
private List<DoctorsResults> doctorsResults = new ArrayList();
private List<PatientsResults> patientsResults = new ArrayList();
main (){
retrieveAllLists();
}
retrieveAllLists(){
retrieveStudents();
retrieveDoctors();
retrievePatients();
}
retrieveStudents(){
this.studentsResults = retrieveStdWS1(); //send request to Web Service 1 to receive its list of students
this.studentsResults = retrieveStdWS2(); //send request to Web Service 2 to receive its list of students
this.studentsResults = retrieveStdWS3(); //send request to Web Service 3 to receive its list of students
}
retrieveDoctors(){
this.doctorsResults = retrieveDocWS4(); //send request to Web Service 4 to receive its list of doctors
this.doctorsResults = retrieveDocWS5(); //send request to Web Service 5 to receive its list of doctors
this.doctorsResults = retrieveDocWS6(); //send request to Web Service 6 to receive its list of doctors
}
retrievePatients(){
this.patientsResults = retrievePtWS7(); //send request to Web Service 7 to receive its list of patients
this.patientsResults = retrievePtWS8(); //send request to Web Service 8 to receive its list of patients
this.patientsResults = retrievePtWS9(); //send request to Web Service 9 to receive its list of patients
}
That is a simple fork-join approach, but for clarity, you can start any number of threads and retrieve the results later as they are available, such as this approach.
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Callable<String>> tasks = new ArrayList<>();
tasks.add(new Callable<String>() {
public String call() throws Exception {
Thread.sleep((new Random().nextInt(5000)) + 500);
return "Hello world";
}
});
List<Future<String>> results = pool.invokeAll(tasks);
for (Future<String> future : results) {
System.out.println(future.get());
}
pool.shutdown();
UPDATE, COMPLETE:
Here's a verbose, but workable solution. I wrote it ad hoc, and have not compiled it.
Given the three lists have diffent types, and the WS methods are individual, it is not
really modular, but try to use your best programming skills and see if you can modularize it a bit better.
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Callable<List<StudentsResults>>> stasks = new ArrayList<>();
List<Callable<List<DoctorsResults>>> dtasks = new ArrayList<>();
List<Callable<List<PatientsResults>>> ptasks = new ArrayList<>();
stasks.add(new Callable<List<StudentsResults>>() {
public List<StudentsResults> call() throws Exception {
return retrieveStdWS1();
}
});
stasks.add(new Callable<List<StudentsResults>>() {
public List<StudentsResults> call() throws Exception {
return retrieveStdWS2();
}
});
stasks.add(new Callable<List<StudentsResults>>() {
public List<StudentsResults> call() throws Exception {
return retrieveStdWS3();
}
});
dtasks.add(new Callable<List<DoctorsResults>>() {
public List<DoctorsResults> call() throws Exception {
return retrieveDocWS4();
}
});
dtasks.add(new Callable<List<DoctorsResults>>() {
public List<DoctorsResults> call() throws Exception {
return retrieveDocWS5();
}
});
dtasks.add(new Callable<List<DoctorsResults>>() {
public List<DoctorsResults> call() throws Exception {
return retrieveDocWS6();
}
});
ptasks.add(new Callable<List<PatientsResults>>() {
public List<PatientsResults> call() throws Exception {
return retrievePtWS7();
}
});
ptasks.add(new Callable<List<PatientsResults>>() {
public List<PatientsResults> call() throws Exception {
return retrievePtWS8();
}
});
ptasks.add(new Callable<List<PatientsResults>>() {
public List<PatientsResults> call() throws Exception {
return retrievePtWS9();
}
});
List<Future<List<StudentsResults>>> sresults = pool.invokeAll(stasks);
List<Future<List<DoctorsResults>>> dresults = pool.invokeAll(dtasks);
List<Future<List<PatientsResults>>> presults = pool.invokeAll(ptasks);
for (Future<List<StudentsResults>> future : sresults) {
this.studentsResults.addAll(future.get());
}
for (Future<List<DoctorsResults>> future : dresults) {
this.doctorsResults.addAll(future.get());
}
for (Future<List<PatientsResults>> future : presults) {
this.patientsResults.addAll(future.get());
}
pool.shutdown();
Each Callable returns a list of results, and is called in its own separate thread.
When you invoke the Future.get() method you get the result back onto the main thread.
The result is NOT available until the Callable have finished, hence there is no concurrency issues.
So just for fun I am providing two working examples. The first one shows the old school way of doing this before java 1.5. The second shows a much cleaner way using tools available within java 1.5:
import java.util.ArrayList;
public class ThreadingExample
{
private ArrayList <MyThread> myThreads;
public static class MyRunnable implements Runnable
{
private String data;
public String getData()
{
return data;
}
public void setData(String data)
{
this.data = data;
}
#Override
public void run()
{
}
}
public static class MyThread extends Thread
{
private MyRunnable myRunnable;
MyThread(MyRunnable runnable)
{
super(runnable);
setMyRunnable(runnable);
}
/**
* #return the myRunnable
*/
public MyRunnable getMyRunnable()
{
return myRunnable;
}
/**
* #param myRunnable the myRunnable to set
*/
public void setMyRunnable(MyRunnable myRunnable)
{
this.myRunnable = myRunnable;
}
}
public ThreadingExample()
{
myThreads = new ArrayList <MyThread> ();
}
public ArrayList <String> retrieveMyData ()
{
ArrayList <String> allmyData = new ArrayList <String> ();
if (isComplete() == false)
{
// Sadly we aren't done
return (null);
}
for (MyThread myThread : myThreads)
{
allmyData.add(myThread.getMyRunnable().getData());
}
return (allmyData);
}
private boolean isComplete()
{
boolean complete = true;
// wait for all of them to finish
for (MyThread x : myThreads)
{
if (x.isAlive())
{
complete = false;
break;
}
}
return (complete);
}
public void kickOffQueries()
{
myThreads.clear();
MyThread a = new MyThread(new MyRunnable()
{
#Override
public void run()
{
// This is where you make the call to external services
// giving the results to setData("");
setData("Data from list A");
}
});
myThreads.add(a);
MyThread b = new MyThread (new MyRunnable()
{
#Override
public void run()
{
// This is where you make the call to external services
// giving the results to setData("");
setData("Data from list B");
}
});
myThreads.add(b);
for (MyThread x : myThreads)
{
x.start();
}
boolean done = false;
while (done == false)
{
if (isComplete())
{
done = true;
}
else
{
// Sleep for 10 milliseconds
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
public static void main(String [] args)
{
ThreadingExample example = new ThreadingExample();
example.kickOffQueries();
ArrayList <String> data = example.retrieveMyData();
if (data != null)
{
for (String s : data)
{
System.out.println (s);
}
}
}
}
This is the much simpler working version:
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadingExample
{
public static void main(String [] args)
{
ExecutorService service = Executors.newCachedThreadPool();
Set <Callable<String>> callables = new HashSet <Callable<String>> ();
callables.add(new Callable<String>()
{
#Override
public String call() throws Exception
{
return "This is where I make the call to web service A, and put its results here";
}
});
callables.add(new Callable<String>()
{
#Override
public String call() throws Exception
{
return "This is where I make the call to web service B, and put its results here";
}
});
callables.add(new Callable<String>()
{
#Override
public String call() throws Exception
{
return "This is where I make the call to web service C, and put its results here";
}
});
try
{
List<Future<String>> futures = service.invokeAll(callables);
for (Future<String> future : futures)
{
System.out.println (future.get());
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (ExecutionException e)
{
e.printStackTrace();
}
}
}
You can ask your jax-ws implementation to generate asynchronous bindings for the web service.
This has two advantages that I can see:
As discussed in Asynchronous web services calls with JAX-WS: Use wsimport support for asynchrony or roll my own? , jax-ws will generate well-tested (and possibly fancier) code for you, you need not instantiate the ExecutorService yourself. So less work for you! (but also less control over the threading implementation details)
The generated bindings include a method where you specify a callback handler, which may suit your needs better than synchronously get() ting all response lists on the thread calling retrieveAllLists(). It allows for per-service-call error handling and will process the results in parallel, which is nice if processing is non-trivial.
An example for Metro can be found on the Metro site. Note the contents of the custom bindings file custom-client.xml :
<bindings ...>
<bindings node="wsdl:definitions">
<enableAsyncMapping>true</enableAsyncMapping>
</bindings>
</bindings>
When you specify this bindings file to wsimport, it'll generate a client which returns an object that implements javax.xml.ws.Response<T>. Response extends the Future interface that others also suggest you use when rolling your own implementation.
So, unsurprisingly, if you go without the callbacks, the code will look similar to the other answers:
public void retrieveAllLists() throws ExecutionException{
// first fire all requests
Response<List<StudentsResults>> students1 = ws1.getStudents();
Response<List<StudentsResults>> students2 = ws2.getStudents();
Response<List<StudentsResults>> students3 = ws3.getStudents();
Response<List<DoctorsResults>> doctors1 = ws4.getDoctors();
Response<List<DoctorsResults>> doctors2 = ws5.getDoctors();
Response<List<DoctorsResults>> doctors3 = ws6.getDoctors();
Response<List<PatientsResults>> patients1 = ws7.getPatients();
Response<List<PatientsResults>> patients2 = ws8.getPatients();
Response<List<PatientsResults>> patients3 = ws9.getPatients();
// then await and collect all the responses
studentsResults.addAll(students1.get());
studentsResults.addAll(students2.get());
studentsResults.addAll(students3.get());
doctorsResults.addAll(doctors1.get());
doctorsResults.addAll(doctors2.get());
doctorsResults.addAll(doctors3.get());
patientsResults.addAll(patients1.get());
patientsResults.addAll(patients2.get());
patientsResults.addAll(patients3.get());
}
If you create callback handers such as
private class StudentsCallbackHandler
implements AsyncHandler<Response<List<StudentsResults>>> {
public void handleResponse(List<StudentsResults> response) {
try {
studentsResults.addAll(response.get());
} catch (ExecutionException e) {
errors.add(new CustomError("Failed to retrieve Students.", e.getCause()));
} catch (InterruptedException e) {
log.error("Interrupted", e);
}
}
}
you can use them like this:
public void retrieveAllLists() {
List<Future<?>> responses = new ArrayList<Future<?>>();
// fire all requests, specifying callback handlers
responses.add(ws1.getStudents(new StudentsCallbackHandler()));
responses.add(ws2.getStudents(new StudentsCallbackHandler()));
responses.add(ws3.getStudents(new StudentsCallbackHandler()));
...
// await completion
for( Future<?> response: responses ) {
response.get();
}
// or do some other work, and poll response.isDone()
}
Note that the studentResults collection needs to be thread safe now, since results will get added concurrently!
Looking at the problem, you need to integrate your application with 10+ different webservices.While making all the calls asynchronous. This can be done easily with Apache Camel. It is a prominent framework for enterprise integration and also supports async processing. You can use its CXF component for calling webservices and its routing engine for invocation and processing results. Look at the following page regarding camel's async routing capability. They have also provided a complete example invoking webservices async using CXF, it available at its maven repo. Also see the following page for more details.
You might consider the following paradigm in which you create work (serially), but the actual work is done in parallel. One way to do this is to: 1) have your "main" create a queue of work items; 2) create a "doWork" object that queries the queue for work to do; 3) have "main" start some number of "doWork" threads (can be same number as number of different services, or a smaller number); have the "doWork" objects put add their results to an object list (whatever construct works Vector, list...).
Each "doWork" object would mark their queue item complete, put all results in the passed container and check for new work (if no more on the queue, it would sleep and try again).
Of course you will want to see how well you can construct your class model. If each of the webservices is quite different for parsing, then you may want to create an Interface that each of your "retrieveinfo" classes promises to implement.
It has got various option to develop this.
JMS : quality of service and management, e.g. redelivery attempt, dead message queue, load management, scalability, clustering, monitoring, etc.
Simply using the Observer pattern for this. For more details OODesign and How to solve produce and consumer follow this Kodelog**

Java Threads design

I have thread application which process heavy task, i would like to trigger forcibly stop thread upon external flag information. I have tried following design,
public class HeavyTaskThread implements Runnable
{
private boolean forceStop;
public void run()
{
..
..
..
..
}
}
Another fact is i do not have control of logic flow implemented into method run(); which simply call some third-party program. I was trying with light inner thread class and calling method interrupt() on parent thread, but this does not work.
Please suggest any pattern....
The recommended way to handle the activity of third-party code that you have no control over is to launch it as a different process instead. Then simply kill the process when you need to forcibly stop the code. It's much more clean and safe than killing a thread, since it does not affect the parent process and the OS will take care of the cleanup duty.
If the third party program doesn't respond to an interrupt or setting a condition, an icky option is to try to kill it by nulling a key variable, closing a socket or file, etc. And hoping that it terminates gracefully. Like I said, icky but sometimes you gotta do what you gotta do...
If whatever third-party program you call in run() never returns, you're out of luck. If it returns periodically, you can make it loop, checking against a volatile forceStop boolean and exiting the loop when it's true:
private volatile boolean forceStop;
public void run()
{
while(!forceStop) {
..
..
}
}
While I'd vote for Tudor's answer, in the extreme and if you're desperate:
Option A - Reconstruct problem code.
Use your favorite java decompiler & re-create problem class.
Add check for Thread.currentThread().isInterrupted() into run.
Compile, place your modified class before original library in the classpath.
If the original jar was signed you may have to eliminate related signature artifacts.
Option B - Aspect J
Examine source for the run method, use your favorite java decompiler if necessary.
Identify a some reasonable point in the inner loop for stepping in and stopping.
Examine exception handling in code. Any loop-holes?
Inject code: throw exceptions, catch exceptions, etc. as needed to back out and return from run.
Here is final analysis...for killing thread.
Using Thread to control the execution of Program B. But then stopping a process means via a thread is not allowed as the related methods are deprecated (stop/suspend etc.,)
Using ThreadGroup ( to have only one thread as its member) and calling 'destroy' on the group. But it again falls on the same track as every thread should be stopped before the destroy operation is attempeted.
Process/ProcessBuilder via Runtime seems to be the better way to obtain a process reference and call destroy(), waitFor() etc. as user #Tudor mentioned.
Here is exact outlined code i have tried and it fails to kill, commented line while(isValid()) represents my another java program invoke.
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
class TaskWorker implements Callable {
private final int number;
public TaskWorker(int number) {
this.number = number;
}
public Boolean call() throws InterruptedException {
while (!Thread.currentThread().isInterrupted()) {
myBusyFunction();
}
return true;
}
private boolean isValid() {
return true;
}
private void myBusyFunction() {
//while (isValid()) {
System.out.println(number + ">....Working.....");
//}
}
}
public class Test {
public static void main(final String[] args) {
CompletionService cs = new ExecutorCompletionService(Executors.newFixedThreadPool(1));
Collection tasks = new ArrayList(10);
tasks.add(new TaskWorker(1));
List> futures = new ArrayList>(tasks.size());
try {
for (Callable task : tasks) {
futures.add(cs.submit(task));
}
//----
for (int t = 0; t result = cs.poll(10, TimeUnit.SECONDS);
if (result == null) {
System.out.println(new Date() + ":Worker Timedout:");
//So lets cancel the first futures we find that havent completed
for (Future future : futures) {
System.out.println("Checking future");
if (future.isDone()) {
continue;
} else {
future.cancel(true);
System.out.println("Cancelled");
break;
}
}
continue;
} else {
try {
if (result.isDone() && !result.isCancelled() && result.get()) {
System.out.println(new Date() + ":Worker Completed:");
} else if (result.isDone() && !result.isCancelled() && !result.get()) {
System.out.println(new Date() + ":Worker Failed");
}
} catch (ExecutionException ee) {
ee.printStackTrace(System.out);
}
}
}
} catch (InterruptedException ie) {
} finally {
//Cancel by interrupting any existing tasks currently running in Executor Service
for (Future f : futures) {
f.cancel(true);
}
}
System.out.println(new Date() + ":Done");
}
}

Categories

Resources