How to send dao object to new thread in Spring - java

I have some manager, where I have userDao, which is set by
#Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
I want start new thread in manager and pass this dao in constructor.
Like this:
new MyThread(userDao).start();
It is safe? Or possible? If no, how can I do this?
Thank you for your replye.

Create a function that accepts your DAO as a parameter. Annotate the function with #Aysnc
When calling the function keep in mind the following:
When you call an Async annotated function from within the same class the call will be synchronous (this is to do with proxied objects)
Async methods will not participate in the same transaction context as the caller
This approach encourages you to think about your class structure and is to be encouraged. For instance you might want to also wrap it with #Retryable in the case of failure.
Of course, you also do something like
ExecutorService executorService = Executors.newFixedThreadPool(3);
MyWorker worker = new MyWorker(UserDao userDao);
executorService.submit(worker);
private class MyWorker implements Callable {
private UserDao userDao
MyWorker(UserDao userDao){
this.userDao = userDao;
}
public void call() {
.. do something
}
}
But that's a lot more code.

Related

Catch Return Value of An Interceptor

I would like to retrieve the return value of this interceptor:
https://arjan-tijms.omnifaces.org/2012/01/cdi-based-asynchronous-alternative.html
#Interceptor
#Asynchronous
#Priority(PLATFORM_BEFORE)
public class AsynchronousInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
#Resource
private ManagedExecutorService managedExecutorService;
private static final ThreadLocal<Boolean> asyncInvocation = new ThreadLocal<Boolean>();
#AroundInvoke
public synchronized Object submitAsync(InvocationContext ctx) throws Exception {
if (TRUE.equals(asyncInvocation.get())) {
return ctx.proceed();
}
return new FutureDelegator(managedExecutorService.submit( ()-> {
try {
asyncInvocation.set(TRUE);
return ctx.proceed();
} finally {
asyncInvocation.remove();
}
}));
}
}
here is a CdiBean of mine profiting from AsynchronousInterceptor by letting data be loaded async..
public class SomeCDI {
#Asynchronous
public void loadDataAsync() {....}
}
this is how I use the cdi bean later in code:
#Inject
SomeCDI dataLoader;
dataLoader.loadDataAsync(); // the loading starts async but I never find out when is the Future class done???
so my question is how to retrieve return value (in my example from FutureDelegator)???
You won't. Asynchronous invocations on EJB and in the model suggested by Tijms are "fire and forget": you invoke them and let them do their job. Eventually, you can make the async method fire some event when it ends to "return" the result, observing this event to give user some response (websockets, maybe?).
Ideally, the asynchronous method should be void and do some callback lift.
Note that CDI 2.0 event model has the fireAsync method, which should be used instead of your own implementation, as it already have the proper contexts and can be enriched by transaction markers and custom options (when using NotificationOptions method signature).

Proper Hibernate nested transactions handling

I am sure that I am missing something, but I don't know exactly what...
Giving the following snippet:
#Service
public class MyClass {
private MyClass self;
private UserRepository userRepository;
private ApplicationContext applicationContext;
#PostConstruct
private void init() {
self = applicationContext.getBean(MyClass.class);
}
#Transactional
public void doA(User user) {
...
if (condition) {
self.doB(user);
throw new SecurityException();
}
user.setRandomField("x");
userRepository.save(user);
}
#Transactional(value = Transactional.TxType.REQUIRES_NEW)
public void doB(User user) {
...
userRepository.save(user);
}
}
What do I know about #Transactional is that if it is used, is redundant to call repository.save(entity).
What I am trying to do, is to process an entity from a transactional method, and if there is a breaking condition, call a new method (annotated with REQUIRES_NEW) that will update some fields of the entity and save it. The root method (doA) then throws an exception. FYI: the #Transactional(dontRollbackOn = SecurityException.class) is not an option in this situation.
For using this commiting mechanism, instead of creating a new bean just with one method I just injected the current bean into a variable just called self, therefore I can use the bean proxy for transaction management.
The odd thing is that if I am removing from doB the save call, when doA transaction is rollbacked because of the SecurityException, the changes performed by doB are rollbacked as well. But if I let it in there, this is working as expected.
Am I doing something wrong or am I missing something?
Thanks!
Try to do not pass User instance in the doB().
Pass an Id instead and read the User from the repo internally. I am not sure how the attached entity is handled between the different sessions.

How do I use JpaRepository in a backend thread?

I have an interface as follows:
public interface PackageRepository extends JpaRepository<DocPackage, String> {
}
Now I'm able to use this without any problem from my REST services by using:
#Resource
PackageRepository repo;
I can make transactional calls on it with no problem.
However when I try to load this from a worker thread:
public class MyWorker implements Runnable {
#Resource
PackageRepository repo;
#Transactional
private void doSomething() {
DocPackage pck = repo.findOne("key");
pck.setStatus(2);
repo.saveAndFlush(pck);
}
public void run() {
//stuff
doSomething();
//other stuff
}
}
new Thread(new MyWorker()).start();
I'm able to do reads on this repo just fine, but whenever I save and flush I get the exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
Is there any way to get this done correctly?
Spring, by default, use proxies. This mean #Transaction works only when method called from outside of class.
To fix it extract you method to service. Inject your service in MyWorker and call it.
I think you need to add the #Transactional annotation to your method

Change CDI sessionscoped bean in a Runnable submitted to ManagedExecutorService from a different thread throws a ContextNotActiveException

I have the following method called in a REST service which needs to return immediatly:
#Inject
private ScheduleManager scheduleManager;
#Resource(name = "DefaultManagedExecutorService")
ManagedExecutorService executor;
public String solveSchedule(#PathParam("conferenceId") Long conferenceId) {
executor.submit(new SolverCallable());
return "Solved started.";
}
It submits this inner class to be executed on another thread
private class SolverCallable implements Runnable {
public void run() {
Schedule bestSchedule = ...; // do some long computation
scheduleManager.setSchedule(bestSchedule); // throws ContextNotActiveException
}
}
How can I change the session scoped bean in the Runnable with the result of a long computation?
You can't. Even if you pass a reference, the reference will be lost since all you get is a proxy. The proxy is meant to look at active threads and do work on those threads. When it's getting to your managed executor, the thread isn't part of the original HTTP session and as a result, you get the ContextNotActiveException.
Technically speaking, HTTP sessions aren't well understood for JAX-RS, there's no actual requirement in the spec that a JAX-RS resource participates in an HTTP session.
The most common workaround I recommend to people is to have some centralized location to store these types of big results and have the session scoped object read from there. Have the executor talk to that component as well. That could be as simple as a hashmap keyed off of HTTP session id.
To get the session id, just call HttpSession.getId(). You can also destroy the map reference by using a #PreDestroy method in one of your #SessionScoped beans to call the central spot and destroy the reference.
As far as the thread goes, I can't think of any way to kill it other than to be able to inject a reference to the runnable from your session scoped bean (or make the runnable your session scoped bean) and tell it to cease the thread from there.
#SessionScoped
public class SessionBean implements Runnable,Serializable {
private HttpSession httpSession;
#PostConstruct
public void init() {
httpSession = CDI.current().select(HttpSession.class).get();
// register the session
}
#Override
public void run() {
}
#PreDestroy
public void unregister() {
// unregister the session
// kill the thread.
}
}

SessionContext getBusinessObject creates new bean

I am using jboss 5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634). And need to get business interface of the bean. That is necessary for transaction management.
So I have:
#Local
public interface MyBeanInterface {
void transactionalMethod();
}
#Stateless
public class MyBean implements MyBeanInterface {
#Resource
private SessionContext context;
private int aState;
public void someMethod() {
aState = 42;
context.getBusinessObject(MyBeanInterface.class).transactionalMethod();
}
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void transactionalMethod() {
System.out.println(aState); // 0!!!!!
}
}
For some reason I do not get the same bean, but new bean is created. That is disastrous as transactionalMethod needs the state variable value to execute correctly.
What am I doing wrong, or that is a bug of jboss? By the way there is a bug which affects ability to get business object via bean's class: https://issues.jboss.org/browse/EJBTHREE-2126. Not sure however if it relates to my issue.
The best solution is this:
#Stateless
public class MyBean implements MyBeanInterface {
#Resource private TransactionManager tm;
private int aState;
public void someMethod() {
aState = 42;
Transaction transaction = tm.suspend();
transactionalMethod();
tm.resume(transaction);
}
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void transactionalMethod() {
System.out.println(aState); // 0!!!!!
}
}
When you call a published interface method from the same istance, passing by ejb context, the resource is:
If it is #Stateless, a new instance is created.
If it is #Stateful, a new session is created for the first call, then other call are same as #Singleton.
If it is #Singleton, the caller waits for the resource to be freed, in case it calls itself, a deadlock is created. If the method is annotated with #Read, calling yourself does not create any deadlocks.
I don't have time to see if the syntax is perfect but you could try:
InitialContext jndiContext = new InitialContext();
Object ref = jndiContext.lookup("projname/MyBeanInterface/local");
MyBeanInterfaceLocal m = (MyBeanInterfaceLocal) ref;
However I saw that you have a SessionContext field, so maybe for you the code should be a little bit different. Maybe it would be:
Object ref = SessionContext.lookup("projname/MyBeanInterface/local");
MyBeanInterfaceLocal m = (MyBeanInterfaceLocal) ref;
Let me know if this helps!

Categories

Resources