Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [cdi-dev] Guice to CDI migration

Hello again,

So finally, I have started the real migration. Thanks to this exercise with the test case first and some help from you guys, the migration is going smoothly so far.

As the application is using guice-servlet and guice-persist we followed the guice recommended way to integrate it and activated open-session-in-view pattern as described here (https://github.com/google/guice/wiki/JPA#web-environments-session-per-http-request).

This is an anti-pattern and we'll get rid of it but as a first step during migration I want to make it work first. What is the correct way to handle this case? I come up with this solution:

public class TransactionFilter implements Filter {

  @Inject
  private TransactionalWork work;

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    work.run(request, response, chain);
  }

  @ApplicationScoped
  public static class TransactionalWork {

    @Transactional
    public void run(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
      chain.doFilter(request, response);
    }
  }
}

And registered it on a path where we need transaction to avoid lazy initialization error from hibernate. It's working as expected so far. Any suggestion?

Regards
--
Amit Mendapara



On Wed, Apr 1, 2020 at 10:49 PM Amit MENDAPARA - Axelor <amit@xxxxxxxxxx> wrote:

On Wed, Apr 1, 2020 at 9:23 PM Matej Novotny <manovotn@xxxxxxxxxx> wrote:
The method work() is not itself @Transactional and you invoke those t1() and t2() methods directly.
This is *not* considered as business method invocation and such it won't trigger interceptors (which is how @Transactional is implemented) and so the context isn't active.

See this part of specification - https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#biz_method

So you'd need to perform an invocation via contextual reference to the bean (which for normal scoped beans is a proxy).
You could do that with self-injection, @Inject MyService and invoke the method on that.
However, self-injection, even though supported, is not a nice pattern. It'd be nicer and cleaner to instead mark work() method as transactional (if you can do that in one transaction), or use some other means of orchestrating two transactions manually.


Thank you Matej for the explanation.

The back tasks are long running tasks so current implementation is not following unit of work pattern for the entire work. In case of any task failed, we resume from there. But I figured out how to migrate this case. Thank you again for the reference. 
 
BTW, I have just tried this same example with a full J2EE server (TomEE) and I found that it doesn't throw any exception but the transaction behavior is not as expected. So I think weld is doing good here otherwise it could be very difficult to debug such issues, especially when migrating existing code.

Regards
--
Amit Mendapara

 
Regards
Matej

----- Original Message -----
> From: "Amit MENDAPARA - Axelor" <amit@xxxxxxxxxx>
> To: "cdi developer discussions" <cdi-dev@xxxxxxxxxxx>
> Sent: Wednesday, April 1, 2020 5:01:54 PM
> Subject: Re: [cdi-dev] Guice to CDI migration
>
> Hello again,
>
> I am seeing one strange behavior with transactions. The case is actually rare
> and we can fix it but I wonder why it is like this. Here is a sample
> service:
>
> public class MyService {
>
> @Inject private Event<Long> event1;
>
> @Inject private Event<Integer> event2;
>
> @Inject private Event<Short> event3;
>
> private final StringBuilder sb = new StringBuilder();
>
> @Transactional
> public void t1() {
> event1.fire(1L);
> event2.fire(2);
> event3.fire((short) 3);
> }
>
> @Transactional
> public void t2() {
> event1.fire(1L);
> event2.fire(2);
> event3.fire((short) 3);
> }
>
> public void observesLong(@Observes(during =
> TransactionPhase.AFTER_COMPLETION) Long event) {
> sb.append(event);
> sb.append("}");
> }
>
> public void observeInteger(@Observes(during =
> TransactionPhase.BEFORE_COMPLETION) Integer event) {
> sb.append(event);
> }
>
> public void observesShort(@Observes(during = TransactionPhase.IN_PROGRESS)
> Short event) {
> sb.append("{");
> sb.append(event);
> }
>
> public void work() {
> t1();
> t2();
> }
>
> public String getResult() {
> return sb.toString();
> }
> }
>
> Generally, most of our services follow unit of work pattern and mostly called
> from a request scoped JAX-RS resources. However, there are couple of cases
> like this for some backoffice tasks where multiple transactional methods are
> called like this `work` method. In this case, I am expecting two
> transactions execute independently and the `getResult()` return "{321}{321}"
> but instead, I am seeing following error:
>
> WELD-001303: No active contexts for scope type
> javax.transaction.TransactionScoped
> org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active
> contexts for scope type javax.transaction.TransactionScoped
> at
> org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:647)
> at
> org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:89)
> at
> org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
> at
> org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:87)
> at
> org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105)
> at
> org.jboss.weldx.transaction.Transaction$1568017494$Proxy$_$$_WeldClientProxy.getStatus(Unknown
> Source)
> at
> io.helidon.integrations.jta.weld.NarayanaTransactionServices.isTransactionActive(NarayanaTransactionServices.java:192)
> at
> org.jboss.weld.module.jta.TransactionalObserverNotifier.notifyTransactionObservers(TransactionalObserverNotifier.java:77)
> at org.jboss.weld.event.ObserverNotifier.notify(ObserverNotifier.java:274)
> at org.jboss.weld.event.EventImpl.fire(EventImpl.java:96)
> at com.example.MyService.t1(MyService.java:46)
> at com.example.MyService$Proxy$_$$_WeldSubclass.t1(Unknown Source)
> at com.example.MyService.work (MyService.java:75)
> at com.example.MyService$Proxy$_$$_WeldSubclass.work(Unknown Source)
> at com.example.MyService$Proxy$_$$_WeldClientProxy.work(Unknown Source)
> at com.example.MyTest.test(MyTest.java:45)
>
> Strange thing is that if I call those two methods `t1` and `t2` from some
> another service, it works as expected. Am I missing something?
>
> Regards
> --
> Amit Mendapara
>
>
> On Mon, Mar 30, 2020 at 11:58 PM Reza Rahman < reza_rahman@xxxxxxxxx > wrote:
>
>
>
> Cool. Honestly really looking forward to the write-up once this is all
> properly squared away. Good folks over at the Helidon team. I am sure they
> will do what they can to support you.
>
> Reza Rahman
> Jakarta EE Ambassador, Author, Blogger, Speaker
>
> Please note views expressed here are my own as an individual community member
> and do not reflect the views of my employer.
>
> On 3/30/2020 1:59 PM, Amit MENDAPARA - Axelor wrote:
>
>
>
> Thank you Matej for looking into it.
>
> I finally found a better solution by using helidon jta-cdi integration.
> Initially I thought that helidon may not work as part of a war application
> deployed on tomcat but I was wrong. It integrates really well and provides
> Jakarta-EE-compatible JTA integration that we can use with or without
> request scope. So far the integration looks good. I have few doubts though
> which I am checking with Laird Nelson, the creator of the helidon jta cdi
> integration.
>
> I will share the test case application once I cover a couple of more cases.
> It was really a great learning experience for me. I will try to write about
> it by this weekend.
>
> Thank you all.
>
> Regards
> --
> Amit Mendapara
>
>
> On Mon, Mar 30, 2020 at 6:37 PM Matej Novotny < manovotn@xxxxxxxxxx > wrote:
>
>
> I am not familiar with Narayana enough to tell you the exact problem.
> But I'd try debugging through some of its bits, namely
> https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/cdi/classes/com/arjuna/ats/jta/cdi/JTASupplier.java#L77
> which is used in NarayanaTransactionManager to create the bean. It uses JNDI
> and then a fallback. I suppose there is no JNDI in your case, so a fallback
> is what should happen.
> Instead you seem to be getting an exception from the JNDI resolution which is
> weird...
>
> Regards
> Matej
>
> ----- Original Message -----
> > From: "Amit MENDAPARA - Axelor" < amit@xxxxxxxxxx >
> > To: "cdi developer discussions" < cdi-dev@xxxxxxxxxxx >
> > Sent: Friday, March 27, 2020 6:50:01 PM
> > Subject: Re: [cdi-dev] Guice to CDI migration
> >
> >
> >
> > On Fri, Mar 27, 2020 at 9:04 PM Matej Novotny < manovotn@xxxxxxxxxx >
> > wrote:
> >
> >
> >
> >
> > ----- Original Message -----
> > > From: "Amit MENDAPARA - Axelor" < amit@xxxxxxxxxx >
> > > To: "cdi developer discussions" < cdi-dev@xxxxxxxxxxx >
> > > Sent: Friday, March 27, 2020 8:27:01 AM
> > > Subject: Re: [cdi-dev] Guice to CDI migration
> > >
> > > Hi all,
> > >
> > > So finally I made some progress in my efforts to migrate from guice to
> > > cdi.
> > > I
> > > choose to use weld-servlet, resteasy and narayana-jta and integrated it
> > > with
> > > embedded tomcat. Most of the cases are resolved but one where I need to
> > > run
> > > some initialization steps when application starts and it requires
> > > transaction.
> > >
> > > Can someone point me how this can be done? I have tried `@Observes
> > > @Initialized(ApplicationScoped.class) ServletContext context` event but
> > > here
> > > transaction manager is still not available.
> >
> > Observing @Initialized(ApplicationScoped.class) is a correct way to perform
> > something once the app is started.
> > What do you mean by "transaction manager is still not available"? How are
> > you
> > obtaining that and what exception are you seeing?
> >
> >
> > I am getting following error:
> >
> > Caused by: javax.naming.NameNotFoundException: Name [TransactionManager] is
> > not bound in this Context. Unable to find [TransactionManager].
> > at org.apache.naming.NamingContext.lookup(NamingContext.java:833)
> > at org.apache.naming.NamingContext.lookup(NamingContext.java:174)
> > at org.apache.naming.SelectorContext.lookup(SelectorContext.java:163)
> > at javax.naming.InitialContext.lookup(InitialContext.java:417)
> > at com.arjuna.ats.jta.cdi.JTASupplier.get(JTASupplier.java:100)
> > at
> > com.arjuna.ats.jta.cdi.NarayanaTransactionManager.getDelegate(NarayanaTransactionManager.java:246)
> >
> > This is happening only with `@Observes
> > @Initialized(ApplicationScoped.class)
> > ServletContext context` event. Transactions are working fine with JAX-RS
> > resources as well as with junit5 tests (using weld-junit5).
> >
> > For the moment, I workaround the issue by injecting `UserTransaction`.
> >
> > I have followed this narayana quickstart example:
> > https://github.com/jbosstm/quickstart/tree/master/jta-and-hibernate-standalone
> > as one requirement is to keep our current tomcat based deployment workflow.
> >
> > Regards
> > --
> > Amit Mendapara
> >
> >
> >
> > >
> > > For a context,
> > >
> > > There is an `EntityManagerProducer` that produces `RequestScoped`
> > > EntityManager.
> > > There is an implementation of `TransactionServices` as per weld
> > > standalone
> > > quickstart example.
> > >
> > > With Guice, we did this with a special eager singleton Servlet and
> > > overriding
> > > it's `init` method.
> > >
> > > Regards
> > > --
> > > Amit Mendapara
> > >
> > >
> > > On Thu, Mar 12, 2020 at 12:28 AM Emily Jiang < emijiang6@xxxxxxxxxxxxxx >
> > > wrote:
> > >
> > >
> > >
> > > Glad it works for you Amit! You are welcome! +1 on the blog idea from
> > > Reza!
> > >
> > > Thanks
> > > Emily
> > >
> > > On Wed, Mar 11, 2020 at 3:27 PM Amit MENDAPARA - Axelor < amit@xxxxxxxxxx
> > > >
> > > wrote:
> > >
> > >
> > >
> > > Hi all,
> > >
> > > So finally after going through CDI docs (Weld documentation), I gave it a
> > > try
> > > and found that `@Specializes` is the exact replacement for Guice linked
> > > binding. However, `@Alternative` with `@Priority` can do the same and we
> > > can
> > > have much better control. So that's a better option. Thanks Emily, Matej
> > > for
> > > the hints.
> > >
> > > Regards
> > > --
> > > Amit Mendapara
> > >
> > > Axelor India
> > > 604, Luxuria Business Hub,
> > > Near V. R. Mall, Dumas Road,
> > > Surat - 395007 (India)
> > > Phone: (+91) 261 297 7840
> > >
> > >
> > > On Wed, Mar 11, 2020 at 8:34 PM Amit MENDAPARA - Axelor < amit@xxxxxxxxxx
> > > >
> > > wrote:
> > >
> > >
> > >
> > > Thanks Reza,
> > >
> > > You are the motivation I am here on this mailing list to discuss this
> > > migration and I think it can be a good case study for others too. I will
> > > share my experience for sure. Thank you again.
> > >
> > > Regards
> > > --
> > > Amit Mendapara
> > >
> > > Axelor India
> > > 604, Luxuria Business Hub,
> > > Near V. R. Mall, Dumas Road,
> > > Surat - 395007 (India)
> > > Phone: (+91) 261 297 7840
> > >
> > >
> > > On Wed, Mar 11, 2020 at 8:28 PM reza_rahman < reza_rahman@xxxxxxxxx >
> > > wrote:
> > >
> > >
> > >
> > > Just a small suggestion - it would be awesome if after the migration is
> > > done,
> > > you could consider writing a blog entry on it. I believe it would be
> > > highly
> > > appreciated in the community. If you gave me a heads up, I would be
> > > delighted to spread the word on it.
> > >
> > > Reza Rahman
> > > Jakarta EE Ambassador, Author, Blogger, Speaker
> > >
> > > Please note views expressed here are my own as an individual community
> > > member
> > > and do not reflect the views of my employer.
> > >
> > > Sent via the Samsung Galaxy S7, an AT&T 4G LTE smartphone
> > >
> > >
> > > -------- Original message --------
> > > From: Amit MENDAPARA - Axelor < amit@xxxxxxxxxx >
> > > Date: 3/11/20 1:38 AM (GMT-05:00)
> > > To: cdi developer discussions < cdi-dev@xxxxxxxxxxx >
> > > Subject: Re: [cdi-dev] Guice to CDI migration
> > >
> > > Hi Emily,
> > >
> > >
> > >
> > >
> > >
> > >
> > > I have tried using "@Alternative" but I have to use qualifiers to inject
> > > this
> > > alternative. Is there any way we can make the CDI container use the
> > > "EnhancedGreetingServiceImpl" automatically without any qualifiers
> > > (without
> > > any changes in module-a or app itself).
> > > I don't think you need to use any qualifier here. You need to use
> > > `@Priority`
> > > to enable the alternative. The other way to completely override a bean,
> > > you
> > > can use `@Specializes`. By the way, I am not 100% sure what your use case
> > > is. A working example helps if you need further assistance.
> > >
> > >
> > > I never used CDI before so it's new to me and I don't know many of it's
> > > concepts (I know guice very well so at least DI and AOP concepts might be
> > > similar). So I will try your suggestion but on twitter one user
> > > recommended
> > > me to check `@Specializes` and that seems the proper solution as per it's
> > > javadoc.
> > >
> > > The project I am going to migrate is relatively complex and there are few
> > > more cases I would like to discuss here. I will try to provide a test
> > > case
> > > example that covers some of them.
> > >
> > > Regards
> > > --
> > > Amit Mendapara
> > > _______________________________________________
> > > cdi-dev mailing list
> > > cdi-dev@xxxxxxxxxxx
> > > To unsubscribe from this list, visit
> > > https://www.eclipse.org/mailman/listinfo/cdi-dev
> > > _______________________________________________
> > > cdi-dev mailing list
> > > cdi-dev@xxxxxxxxxxx
> > > To unsubscribe from this list, visit
> > > https://www.eclipse.org/mailman/listinfo/cdi-dev
> > >
> > >
> > > --
> > > Thanks
> > > Emily
> > >
> > > _______________________________________________
> > > cdi-dev mailing list
> > > cdi-dev@xxxxxxxxxxx
> > > To unsubscribe from this list, visit
> > > https://www.eclipse.org/mailman/listinfo/cdi-dev
> > >
> > > _______________________________________________
> > > cdi-dev mailing list
> > > cdi-dev@xxxxxxxxxxx
> > > To unsubscribe from this list, visit
> > > https://www.eclipse.org/mailman/listinfo/cdi-dev
> > >
> >
> > _______________________________________________
> > cdi-dev mailing list
> > cdi-dev@xxxxxxxxxxx
> > To unsubscribe from this list, visit
> > https://www.eclipse.org/mailman/listinfo/cdi-dev
> >
> > _______________________________________________
> > cdi-dev mailing list
> > cdi-dev@xxxxxxxxxxx
> > To unsubscribe from this list, visit
> > https://www.eclipse.org/mailman/listinfo/cdi-dev
> >
>
> _______________________________________________
> cdi-dev mailing list
> cdi-dev@xxxxxxxxxxx
> To unsubscribe from this list, visit
> https://www.eclipse.org/mailman/listinfo/cdi-dev
>
> _______________________________________________
> cdi-dev mailing list cdi-dev@xxxxxxxxxxx To unsubscribe from this list, visit
> https://www.eclipse.org/mailman/listinfo/cdi-dev
>
>
>
> _______________________________________________
> cdi-dev mailing list
> cdi-dev@xxxxxxxxxxx
> To unsubscribe from this list, visit
> https://www.eclipse.org/mailman/listinfo/cdi-dev
>
> _______________________________________________
> cdi-dev mailing list
> cdi-dev@xxxxxxxxxxx
> To unsubscribe from this list, visit
> https://www.eclipse.org/mailman/listinfo/cdi-dev
>

_______________________________________________
cdi-dev mailing list
cdi-dev@xxxxxxxxxxx
To unsubscribe from this list, visit https://www.eclipse.org/mailman/listinfo/cdi-dev

Back to the top