#Bean
public EventHandler eventHandler(){
EventHandler handler= new EventHandler(session());
session().registerEventListener(handler);
return handler;
}
public class EventHandler implements EventListener{
#Override
#Async
public void notify(Event event) {
//do work
}
}
I'm trying to create an async handler and register it...Doesnt seem to work as I believe Spring will only create the async wrappers after it creates a proxy object around the bean after the bean has been created....how do I work around this?
I had a similar problem where I couldn't call an #Override method with #Async - it would always be called synchronously.
My workaround was to declare another #Service bean with a direct (non-#Override) interface to forward the call to the bean I was calling via an #Override interface.
I figure the proxying just doesn't work via base class calls.
Related
After reading some articles about the CDI and Java FX integration, and the source codes of javafx-weaver spring integration.
I decided to add CDI integration to Java FX via the existing javafx-weaver work to simplify the integration work.
The source code can be found here.
I added a simple producer to expose FxWeaver to the CDI context.
#ApplicationScoped
public class FxWeaverProducer {
private static final Logger LOGGER = Logger.getLogger(FxWeaverProducer.class.getName());
#Produces
FxWeaver fxWeaver(CDIControllerFactory callback) {
var fxWeaver = new FxWeaver((Callback<Class<?>, Object>) callback,
() -> LOGGER.log(Level.INFO, "calling FxWeaver shutdown hook")
);
return fxWeaver;
}
public void destroyFxWeaver(#Disposes FxWeaver fxWeaver) {
LOGGER.log(Level.INFO, "destroying FxWeaver bean...");
fxWeaver.shutdown();
}
}
The problem is when using fxWeaver.loadView to load view, the controller did not work as expected.
#ApplicationScoped
#FxmlView("HandlingReport.fxml")
public class HandlingReportController {
private final static Logger LOGGER = Logger.getLogger(HandlingReportController.class.getName());
#Inject
private HandlingReportService handlingReportService;
//fxml properties...
#FXML
private void onSubmit(){...}
}
As above codes, the dependent service handlingReportService in the controller class is null(not injected) when performing an action like onSubmit, it seems when JavaFX handles the #FXML properties binding it always used java reflection API.
If I change the method to public void onSubmit()( use public modifier), all FX fields become null when pressing the onSubmit button.
Any idea to fix this issue?
Marked the controller class as #Dependentscope to resolve the problem.
#Dependent
public class HandlingReportController { ...}
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!
I am using #Async tag inside a method in Anonymous class. Does Spring AOP support this:
private void scheduleProcessing(final SomePojo somepojo) {
taskScheduler.schedule(new Runnable() {
#Override
#Async("myThreadPoolTaskExecutor")
public void run() {
// biz logic
}
}, 20, TimeUnit.SECONDS);
}
Apparently methods denoted with spring annotations like #Async, #Transactional etc should be called from outside the class (AOP Proxy). Here run will be called somewhere internally when the Thread starts hence not applying the async-ness to the method.
When I intentionally throw an exception within an Objectify transaction, my transaction is not being rolled back. What am I doing wrong?
#Inject
Dao dao
...
public void testTransaction(){
dao.transact(new VoidWork() {
#Override
public void vrun() {
Key aclKey= dao.save().entity(acl).now(); //expecting this to be rolled back
//throw exception
if(true) throw new IllegalArgumentException();
//expecting rollback of acl save
}
});
}
I am using a setup like this:
#Singleton
public class DaoFactory extends ObjectifyFactory {
private Injector injector;
#Inject
public DaoFactory(Injector injector) {
this.injector = injector;
registerEntities();
}
private void registerEntities() {
}
#Override
public <T> T construct(Class<T> type) {
return injector.getInstance(type);
}
#Override
public Objectify begin() {
Dao dao = new Dao(this);
return dao;
}
}
Where:
public class Dao extends ObjectifyImpl<Dao> {
#Inject
public Dao(ObjectifyFactory fact) {
super(fact);
}
}
and
public class DaoService {
#Inject
public static void setObjectifyFactory(DaoFactory fact) {
ObjectifyService.setFactory(fact);
}
}
are all injected using Guice for DI.
I stepped through the code, and objectify does call txnOfy.getTransaction().rollback(); in TransactorNo.class
but, when I check app-engine local db, I see a an entity created for the acl (sometimes taking a few seconds longer to show up)
Transaction state is attached to a specific ObjectifyImpl instance. You're starting a transaction (which makes a new ObjectifyImpl available via the static ofy() method) and then re-using the old, nontransactional ObjectifyImpl instance.
So even though you are rolling back the transaction, your save operation utilized the nontransactional Objectify impl from outside the transaction.
This is why the documentation suggests that you never hold on to an Objectify instance in a variable; always use the static ofy() method. You can make your own static ofy() (or whatever) method that returns your Dao type instead. Look at the example code for http://www.motomapia.com/
Because transaction and sessions states are thread-local concerns, injecting persistence contexts is just a bad idea, even under JPA.
I need to audit invocations of ejb beans. Saying audit I mean write informations such as current logged user, method name, additional description to a database. I decided to do it by use of CDI decorator:
#Decorator
public class AccountServiceBeanDecorator implements AccountService {
#Inject
#Delegate
#Any
AccountService accountService;
#EJB
private AuditService auditService;
#Override
public Account createAccount(Account account) {
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
and the decorated class:
#Stateless
public class AccountServiceBean implements AccountService {
#Override
public Account createAccount(Account account) {
...
}
}
Now if I call AccountService from another ejb stateless bean, what will happen with transaction?:
#Stateless
public ApplicationFacadeBean implements ApplicationFacade {
#EJB
private AccountService accountService;
#Override
public Account createAccount(Account account) {
return accountService.createAccount(account);
}
}
I wanted to log transaction status in decorator (AccountServiceBeanDecorator) and decorated class (AccountServiceBean), so I injected TransactionSynchronizationRegistry as a resource in both classes:
#Decorator
public class AccountServiceBeanDecorator implements AccountService {
#Inject
#Delegate
#Any
AccountService accountService;
#EJB
private AuditService auditService;
#Resource
private TransactionSynchronizationRegistry reg;
#Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
and
#Stateless
public class AccountServiceBean implements AccountService {
#Resource
private TransactionSynchronizationRegistry reg;
#Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
...
}
}
I received strange behavior:
log from decorator
tx (0): JavaEETransactionImpl: txId=6 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization#68fb15d0]]]
NullPointerException on second log (reg is null).
Can anybody explain it to me? Wheter AccountServiceBean class is called within the same transaction as ApplicationFacade?
Thank you
first: i would not mixing ejbs with cdi interceptors. ejbs has it on interceptor implementations.
second: interceptors are executed in the same transaction as the ejb where the interceptor is around.
possible solution:
create a correct ejb interceptor
put the interceptor around the method / class
create a second ejb (MyLoggerBean) with a method like this logToDatabase(String message) and annotate this method with #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
inside the interceptor create a class member like this: #EJB private MyLoggerBean loggerBean
inside your #AroundInvoke annotated method you could call loggerBean. logToDatabase(...)
this would create a new transaction from inside the current transaction of the ejb where the interceptor is around
--> i know my english is not very good. but i hope that you understand what i think should work. if i have the time, i make e example on github...
Hmm... what container are you using? Generally I wouldn't suspect a CDI decorator to work on an EJB... I can't think of anything in the JEE spec that I've encountered that would give evidence either way.
Faced with your problem though, I did this with an interceptor, not a decorator. These are supported by the EJB spec... Anyway, here's my code, you would need to grab the variables from the context in your case:
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
public class InvocationCountInterceptor {
#Inject
private InvocationCounter counter;
#AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
Object returnValue = ctx.proceed();
Class<? extends Object> className = ctx.getTarget().getClass();
Method methodName = ctx.getMethod();
counter.incrementCounter(className, methodName);
return returnValue;
}
}
Then whatever EJB or EJB Method you want to audit, I just added this: #Interceptors(InvocationCountInterceptor.class)