Is there a way to propagate SessionContext to a new thread (getting WELD-001303)? - jboss

there's a session scoped bean 'Identity' which I injected in a #Stateless bean which implements Runnable:
#Stateless
#LocalBean
public class Test implements Runnable {
#Inject
Identity identity;
#Inject
Logger log;
#Override
public void run() {
log.warn("Test: " + this + " " + identity.getAccount().getId());
}
}
There's also a bean which invokes the above Runnable asynchronously:
#Stateless
#LocalBean
public class BeanContextExecutor implements Executor {
#Asynchronous
#Override
public void execute(Runnable command) {
command.run();
}
}
and finally, the invocation looks like this:
#Stateless
public class OtherBean {
#Inject
BeanContextExecutor executor;
...
executor.execute(command);
...
}
When running this I'm getting the following error:
...
Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
...
Is there any way to propagate the SessionContext to the background thread?
I also tried to submit this Runnable to ManagedExecutorService and even to create a proxy for it with a ContextService and submit a proxy but still getting the same error.
Thanks for any help with this!

As a workaround in BeanContextExecutor I used BoundSessionContext to create a dummy session context for a new thread and also had to manually copy the required session bean to make its state available in the background thread:
#Inject
BoundSessionContext boundSessionContext;
// Backed by a ConcurrentHashMap<Runnable, Identity> which stores the state of the session scoped bean before spawning a new thread
#Inject
GlobalExecutionContext globalExecutionContext;
#Inject
Instance<Identity> identityInstance;
#Inject
Cloner cloner;
#Inject
private BeanManager beanManager;
#Asynchronous
#Override
public void execute(Runnable command) {
HashMap<String, Object> storage = new HashMap<>();
boundSessionContext.associate(storage);
boundSessionContext.activate();
Identity identity = globalExecutionContext.remove(command);
Bean<Identity> bean = (Bean<Identity>) beanManager.resolve(beanManager.getBeans(Identity.class));
Identity localIdentity = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean));
cloner.copyPropertiesOfInheritedClass(identity, localIdentity);
command.run();
boundSessionContext.invalidate();
boundSessionContext.deactivate();
boundSessionContext.dissociate(storage);
}
The example is intended to demonstrate the approach, it's possible to improve it like support passing beans of an arbitrary type. But I don't like this approach at all. There should be a better solution for context propagation problem.
Update:
I'd like to keep the caller identity in a background thread even if initial session is expired, it looks like the above solution is suitable for this.

Related

Spring Boot Hibernate Postgresql #Transactional does not rollback [duplicate]

I want to read text data fixtures (CSV files) at the start on my application and put it in my database.
For that, I have created a PopulationService with an initialization method (#PostConstruct annotation).
I also want them to be executed in a single transaction, and hence I added #Transactional on the same method.
However, the #Transactional seems to be ignored :
The transaction is started / stopped at my low level DAO methods.
Do I need to manage the transaction manually then ?
Quote from legacy (closed) Spring forum:
In the #PostConstruct (as with the afterPropertiesSet from the InitializingBean interface) there is no way to ensure that all the post processing is already done, so (indeed) there can be no Transactions. The only way to ensure that that is working is by using a TransactionTemplate.
So if you would like something in your #PostConstruct to be executed within transaction you have to do something like this:
#Service("something")
public class Something {
#Autowired
#Qualifier("transactionManager")
protected PlatformTransactionManager txManager;
#PostConstruct
private void init(){
TransactionTemplate tmpl = new TransactionTemplate(txManager);
tmpl.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//PUT YOUR CALL TO SERVICE HERE
}
});
}
}
I think #PostConstruct only ensures the preprocessing/injection of your current class is finished. It does not mean that the initialization of the whole application context is finished.
However you can use the spring event system to receive an event when the initialization of the application context is finished:
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
// do startup code ..
}
}
See the documentation section Standard and Custom Events for more details.
As an update, from Spring 4.2 the #EventListener annotation allows a cleaner implementation:
#Service
public class InitService {
#Autowired
MyDAO myDAO;
#EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
event.getApplicationContext().getBean(InitService.class).initialize();
}
#Transactional
public void initialize() {
// use the DAO
}
}
Inject self and call through it the #Transactional method
public class AccountService {
#Autowired
private AccountService self;
#Transactional
public void resetAllAccounts(){
//...
}
#PostConstruct
private void init(){
self.resetAllAccounts();
}
}
For older Spring versions which do not support self-injection, inject BeanFactory and get self as beanFactory.getBean(AccountService.class)
EDIT
It looks like that since this solution has been posted 1.5 years ago developers are still under impression that if a method,
annotated with #Transactional, is called from a #PostContruct-annotated method invoked upon the Bean initialization, it won't be actually executed inside of Spring Transaction, and awkward (obsolete?) solutions get discussed and accepted instead of this very simple and straightforward one and the latter even gets downvoted.
The Doubting Thomases :) are welcome to check out an example Spring Boot application at GitHub which implements the described above solution.
What actually causes, IMHO, the confusion: the call to #Transactional method should be done through a proxied version of a Bean where such method is defined.
When a #Transactional method is called from another Bean, that another Bean usually injects this one and invokes its proxied (e.g. through #Autowired) version of it, and everything is fine.
When a #Transactional method is called from the same Bean directly, through usual Java call, the Spring AOP/Proxy machinery is not involved and the method is not executed inside of Transaction.
When, as in the suggested solution, a #Transactional method is called from the same Bean through self-injected proxy (self field), the situation is basically equivalent to a case 1.
#Platon Serbin's answer didn't work for me. So I kept searching and found the following answer that saved my life. :D
The answer is here No Session Hibernate in #PostConstruct, which I took the liberty to transcribe:
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
#Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
The transaction part of spring might not be initialized completely at #PostConstruct.
Use a listener to the ContextRefreshedEvent event to ensure, that transactions are available:
#Component
public class YourService
implements ApplicationListener<ContextRefreshedEvent> // <= ensure correct timing!
{
private final YourRepo repo;
public YourService (YourRepo repo) {this.repo = repo;}
#Transactional // <= ensure transaction!
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
repo.doSomethingWithinTransaction();
}
}
Using transactionOperations.execute() in #PostConstruct or in #NoTransaction method both works
#Service
public class ConfigurationService implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationService.class);
private ConfigDAO dao;
private TransactionOperations transactionOperations;
#Autowired
public void setTransactionOperations(TransactionOperations transactionOperations) {
this.transactionOperations = transactionOperations;
}
#Autowired
public void setConfigurationDAO(ConfigDAO dao) {
this.dao = dao;
}
#PostConstruct
public void postConstruct() {
try { transactionOperations.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(final TransactionStatus status) {
ResultSet<Config> configs = dao.queryAll();
}
});
}
catch (Exception ex)
{
LOG.trace(ex.getMessage(), ex);
}
}
#NoTransaction
public void saveConfiguration(final Configuration configuration, final boolean applicationSpecific) {
String name = configuration.getName();
Configuration original = transactionOperations.execute((TransactionCallback<Configuration>) status ->
getConfiguration(configuration.getName(), applicationSpecific, null));
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
}

JBoss AS7 #Inject bean into valve

Is it possible to #Inject a stateless session bean into a subclass of AuthenticatorBase?
I'm using JBoss as 7.1.1.
My code looks like this:
...
public class myValve extends AuthenticatorBase {
#Inject AuthController controller;
//some code ...
}
Using the controller object leads to NullPointerException.
If controller is null it means that the myValve object itself was not injected.
It is possible to add an existing object to the CDI context retroactively, for example with this code:
public <T> void addToCDI(T object) {
BeanManager beanManager = BeanManagerProvider.getInstance().getBeanManager();
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType((Class<T>)bject.getClass());
InjectionTarget<T> injectionTarget = beanManager.createInjectionTarget(annotatedType);
CreationalContext<T> context = beanManager.createCreationalContext(null);
injectionTarget.inject(object, context);
}
After the execution of this code the injections have been performed.

WickeTester - IllegalStateException: No CDI context bound to application

I have Wicket Form and ProjectNameValidator class:
#Inject
ProjectDao dao;
public ProjectNameValidator() {
CdiContainer.get().getNonContextualManager().inject(this);
}
the injection here is because the #Inject annotation works only in Wicket components or Behavior, here is null without the CdiContainer.get().getNonContextualManager().inject(this);
But when I have WicketTester, TestCreateprojectPage:
public class TestCreateProject {
private WicketTester tester;
#Before
public void setUp() throws Exception {
tester = new WicketTester();
}
#Test
public void createProjectPageRendersSuccessfully() {
tester.startPage(CreateProject.class);
tester.assertRenderedPage(CreateProject.class);
}
}
I'm getting exception on the Form in the CreateProject.java in ProjectNameValidator on this row:
CdiContainer.get().getNonContextualManager().inject(this);
IllegalStateException: No DCI Context bound to application.
You have a singleton CdiContainer in your application, that is not initialized in a test scope. So CdiContainer.get() is really null. Find out how to initialize CdiContainer test context, it depends on your implementation, and add it to test setUp().

How to access EJB from a Quartz Job

Well, I'm using Quartz to schedule some jobs that I need in my application. But, I need some way to access a Stateful SessionBean on my Job. I knew that I can't inject it with #EJB. Can anyone help me?
Thanks.
I used the EJB3InvokerJob to invoke the methods of my EJB. Then I created my jobs that extends the EJB3InvokerJob, put the parameters of what EJB and method it should call and then call the super.execute().
The EJB3InvokerJob can be found here: http://jira.opensymphony.com/secure/attachment/13356/EJB3InvokerJob.java
My Job is looking like this:
public class BuscaSistecJob extends EJB3InvokerJob implements Job{
private final Logger logger = Logger.getLogger(this.getClass());
#Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap dataMap = jobExecutionContext.getMergedJobDataMap();
dataMap.put(EJB_JNDI_NAME_KEY, "java:app/JobService");
dataMap.put(EJB_INTERFACE_NAME_KEY, "br.org.cni.pronatec.controller.service.JobServiceLocal");
dataMap.put(EJB_METHOD_KEY, "buscaSistec");
Object[] arguments = new Object[1];
arguments[0] = jobExecutionContext.getTrigger().getStartTime();
dataMap.put(EJB_ARGS_KEY, arguments);
Class[] argumentTypes = new Class[1];
argumentTypes[0] = Date.class;
dataMap.put(EJB_ARG_TYPES_KEY, argumentTypes);
super.execute(jobExecutionContext);
}
}
And my EJB is like this:
#Stateless
#EJB(name="java:app/JobService", beanInterface=JobServiceLocal.class)
public class JobService implements JobServiceLocal {
#PersistenceContext
private EntityManager entityManager;
#Resource
private UserTransaction userTransaction;
#Override
public void buscaSistec(Date dataAgendamento) {
// Do something
}
I expect to help someone.
A simple solution would be to lookup the EJB via JNDI in the Job implementation.
final Context context = new InitialContext();
myService= (MyService) context
.lookup("java:global/my-app/myejbmodule-ejb/MyService");
I have done this in a current application I am developing on Glassfish 3.1.
you can do that simply by lookup the EJB via JNDI in the Job implementation. In particular, the JNDI name will be:
mappedName#name_of_businessInterface
where name_of_businessInterface is the fully qualified name of the business interface of this session bean. For example, if you specify mappedName="bank" and the fully qualified name of the business interface is com.CheckingAccount, then the JNDI of the business interface is bank#com.CheckingAccount.
Code Example:
Context context = new InitialContext();
MyService myService= (MyService) context.lookup("MyService#com.test.IMyService");

Server side session management in GWTP

Hello I am using GWTP for my application development. In the application I am in need to server side session instance to put some data in that session instance. I saw some examples of GWT where there is Action class which extends ActionSupport class.
There are some method in the examples through which we can have the server side session instance.Like below :
public HttpServletRequest getRequest() {
return ServletActionContext.getRequest();
}
public HttpServletResponse getResponse() {
return ServletActionContext.getResponse();
}
public HttpSession getSession() {
HttpSession session = getRequest().getSession();
return session;
}
But I am not getting the similar thing in GWTP. Please help me out. Thanks in Advance.
Finally I got some thing which is helping me.I am sharing this here.
private Provider<HttpServletRequest> requestProvider;
private ServletContext servletContext;
#Inject
public LoginCallerActionHandler(
Provider<HttpServletRequest> requestProvider,
ServletContext servletContext) {
super();
this.requestProvider = requestProvider;
this.servletContext = servletContext;
}
Here is my action handler class.In which i can use session.
servletContext.setAttribute(SessionKeys.LOGGEDIN_USER.toString(), returnObject.getLoggedInUser());
If you are using Spring or Guice on your server side you can get Request/Response injected into your Action. For example, if your are using GWTP's DispatchServletModule, you can use features of Guice's ServletModule as:
DispatchServletModule extends Guice ServletModule and maps request
URLs to handler classes.
Here's an example from Guice wiki:
#RequestScoped
class SomeNonServletPojo {
#Inject
SomeNonServletPojo(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
...
}
}
I am not sure if GWTP binds the handlers in Singleton scope or not. If it does bind it in singleton you should inject a Provider instead.