Showing posts with label ejb. Show all posts
Showing posts with label ejb. Show all posts

Wednesday, November 21, 2012

CDI, when to break out the EJBs


I sometimes joke that CDI is basically EJB 4.0. While that's obviously not true there is a considerable amount of similarity and that does create a bit of confusion for people. Here is some general information on EJB and CDI as they relate to each together.

EJB >= CDI

Note that EJBs are CDI beans and therefore have all the benefits of CDI. The reverse is not true (yet). So definitely don't get into the habit of thinking "EJB vs CDI" as that logic really translates to "EJB+CDI vs CDI", which is an odd equation.
In future versions of Java EE we'll be continuing to align them. What aligning means is allowing people to do what they already can do, just without the@Stateful, @Stateless or @Singleton annotation at the top.

EJB and CDI in Implementation Terms

Ultimately, EJB and CDI share the same fundamental design of being proxied components. When you get a reference to an EJB or CDI bean, it isn't the real bean. Rather the object you are given is a fake (a proxy). When you invoke a method on this fake object, the call goes to the container who will send the call through interceptors, decorators, etc. as well as take care of any transaction or security checks. Once all that is done, the call finally goes to the real object and the result is passed back through the proxy to the caller.
The difference only comes in how the object to be invoked is resolved. By "resolved" we simply mean, where and how the container looks for the real instance to invoke.
In CDI the container looks in a "scope", which will basically be a hashmap that lives for a specific period of time (per request @RequestScoped, per HTTP Session @SessionScoped, per application @ApplicationScoped, JSF Conversation @ConversationScoped, or per your custom scope implementation).
In EJB the container looks also into a hashmap if the bean is of type @Stateful. An @Stateful bean can also use any of the above scope annotations causing it to live and die with all the other beans in the scope. In EJB @Stateful is essentially the "any scoped" bean. The @Stateless is basically an instance pool -- you get an instance from the pool for the duration of one invocation. The @Singleton is essentially @ApplicationScoped
So in a fundamental level, anything you can do with an "EJB" bean you should be able to do with a "CDI" bean. Under the covers it's awfully hard to tell them apart. All the plumbing is the same with the exception of how instances are resolved.
They aren't currently the same in terms of the services the container will offer when doing this proxying, but as I say we're working on it at the Java EE spec level.

Performance note

Disregard any "light" or "heavy" mental images you may have. That's all marketing. They have the same internal design for the most part. CDI instance resolution is perhaps a bit more complex because it is slightly more dynamic and contextual. EJB instance resolution is fairly static, dumb and simple by comparison.
I can tell you from an implementation perspective in TomEE, there's about zero performance difference between invoking an EJB vs invoking a CDI bean.

Default to POJOs, then CDI, then EJB

Of course don't use CDI or EJB when there is no benefit. Throw in CDI when you start to want injection, events, interceptors, decorators, lifecycle tracking and things like that. That's most the time.
Beyond those basics, there are a number of useful container services you only have the option to use if you make your CDI bean also an EJB by adding@Stateful, @Stateless, or @Singleton on it.
Here's a short list of when I break out the EJBs.

Using JAX-WS

Exposing a JAX-WS @WebService. I'm lazy. When the @WebService is also an EJB, you don't have to list it and map it as a servlet in the web.xml file. That's work to me. Plus I get the option to use any of the other functionality mentioned below. So it's a no-brainer for me.
Available to @Stateless and @Singleton only.

Using JAX-RS

Exposing a JAX-RS resource via @Path. I'm still lazy. When the RESTful service is also an EJB, again you get automatic discovery and don't have to add it to a JAX-RS Application subclass or anything like that. Plus I can expose the exact same bean as an @WebService if I want to or use any of the great functionality mentioned below.
Available to @Stateless and @Singleton only.

Startup logic

Load on startup via @Startup. There is currently no equivalent to this in CDI. Somehow we missed adding something like an AfterStartup event in the container lifecycle. Had we done this, you simply could have had an @ApplicationScoped bean that listened for it and that would be effectively the same as an @Singleton with @Startup. It's on the list for CDI 1.1.
Available to @Singleton only.

Working in Parallel

@Asynchronous method invocation. Starting threads is a no-no in any server-side environment. Having too many threads is a serious performance killer. This annotation allows you to parallelize things you do using the container's thread pool. This is awesome.
Available to @Stateful, @Stateless and @Singleton.

Scheduling work

@Schedule or ScheduleExpression is basically a cron or Quartz functionality. Also very awesome. Most containers just use Quartz under the covers for this. Most people don't know, however, that scheduling work in Java EE is transactional! If you update a database then schedule some work and one of them fails, both will automatically cleaned up. If the EntityManager persist call fails or there is a problem flushing, there is no need to un-schedule the work. Yay, transactions.
Available to @Stateless and @Singleton only.

Using EntityManagers in a JTA transaction

The above note on transactions of course requires you to use a JTA managed EntityManager. You can use them with plain "CDI", but without the container-managed transactions it can get really monotonous duplicating the UserTransaction commit/rollback logic.
Available to all Java EE components including CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilter, etc. The@TransactionAttribute annotation, however, is available to @Stateful, @Stateless and @Singleton only.

Keeping JTA managed EntityManager

The EXTENDED managed EntityManager allows you to keep an EntityManager open between JTA transactions and not lose the cached data. Good feature for the right time and place. Use responsibly :)
Available to @Stateful only.

Easy synchronization

When you need synchronization, the @Lock(READ) and @Lock(WRITE) annotations are pretty excellent. It allows you to get concurrent access management for free. Skip all the ReentrantReadWriteLock plumbing. In the same bucket is @AccessTimeout, which allows you to say how long a thread should wait to get access to the bean instance before giving up.
Available to @Singleton beans only.

Friday, September 30, 2011

JavaOne 2011 schedule

JavaOne is next week and as usual I will be there.  I'm a bit busier than usual this year, but as always I'm more than happy to get together with anyone.  In fact it's my favorite part of JavaOne, so please do reach out.

Here's my speaking schedule:


Session ID: 23166
Session Title: Meet the Experts: EJB 3.2 Expert Group
Venue / Room: Hilton San Francisco - Imperial Ballroom A
Date and Time: 10/3/11, 21:00 - 21:45

Session ID: 25244
Session Title: EJB with Meta-annotations
Venue / Room: Parc 55 - Powell I/II-
Date and Time: 10/4/11, 17:30 - 18:15

Session ID: 23423
Session Title: The Road to Java EE 7: Is It All About the Cloud?
Venue / Room: Hilton San Francisco - Imperial Ballroom A
Date and Time: 10/5/11, 11:30 - 12:30

Session ID: 25209
Session Title: Fun with EJB 3.1 and OpenEJB
Venue / Room: Hilton San Francisco - Golden Gate 3/4/5
Date and Time: 10/5/11, 13:00 - 14:00

Session ID: 19941
Session Title: CDI Today and Tomorrow
Venue / Room: Hilton San Francisco - Imperial Ballroom A
Date and Time: 10/6/11, 12:30 - 13:30

Session ID: 23680
Session Title: Apache TomEE Java EE 6 Web Profile
Venue / Room: Hilton San Francisco - Golden Gate 3/4/5
Date and Time: 10/6/11, 11:00 - 12:00

Friday, October 1, 2010

EJB.next Connector/Bean API : JAX-RS and beyond

It isn't commonly known that MessageDrivenBeans (MDBs) are not directly tied to the Java Message Service (JMS). In fact, they are tied to the Java EE Connector Architecture. It's even less commonly known that MDBs are not necessarily asynchronous. It's really the Connector that drives the communication style.
Overall, it is a very cool model that does allow for some pretty impressive and standard extension to any compliant Java EE platform. It is, however, incredibly underused. With a few changes to the model, it could be made to support even things like JAX-RS. Let's break it down.
The touchpoints between the Connector and the MDB are the ActivationSpec/ActivationConfig and the MessageListener interface. Using a fictitious "Email" Connector idea, let's see how this looks.
EmailConsumer (MessageListener) interface*
package org.superemail.connector;

// other imports...
    
public interface EmailConsumer {
    public void receiveEmail(Properties headers, String body);
}
EmailAccountInfo (ActivationSpec) class
package org.superemail.connector;
    
/**
 * This class is basically an old-style JavaBean with get/set for each property
 */
public class EmailAccountInfo implements javax.resource.spi.ActivationSpec {

    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void validate() throws InvalidPropertyException {
    }
}
That's it for the Connector (aside from the Connector itself). I have left out a little detail on the ActivationSpec, we'll cover that later.
Now for the MDB's side of things. The MDB needs to implement the Connector's EmailConsumer interface and configure the Connector'sEmailAccountInfo JavaBean which is done via the activation-config tag of the ejb-jar.xml or via @ActivationConfigPropertyannotations in the @MessageDriven declaration.
@MessageDriven(activationConfig = 
        {@ActivationConfigProperty(
                propertyName = "address", 
                propertyValue = "dblevins@apache.org")
        })
public class EmailBean implements EmailConsumer {

    @PostConstruct
    public void init() {
    }

    public void receiveEmail(Properties headers, String body) {
        // do your thing!
    }
}
Done. Those are the basics. The Connector supplies a MessageListener interface and an ActivationConfig JavaBean, the MDB implements the interface and configures the JavaBean via the loosely-typed @ActivationConfigProperty.
There are a few things that prevent this model from reaching its true potential:
  • Metadata is loosely typed in the bean code
  • Only class-level metadata is allowed, not method-level
  • Requiring an interface can limit expressiveness
Let's see how life might look if we eliminate the JavaBean and allow the Connector to instead supply an annotation.
package org.superemail.connector;
    
@Target(TYPE)
@Retention(RUNTIME)
@javax.resource.annotation.ActivationSpec
public @interface EmailAccountInfo {
    String address();
}
Side Note: The original javax.resource.spi.ActivationSpec interface has a 'validate()' method on it to validate the JavaBean. A clear update to that part of the API would be to instead use the Bean Validation API.
Which gives us a bean that might look like this:
@MessageDriven
@EmailAccountInfo(address = "dblevins@apache.org")
public static class EmailBean implements EmailConsumer {

    @PostConstruct
    public void init() {
    }

    public void receiveEmail(Properties headers, String body) {
        // do your thing!
    }
}
Now we're getting somewhere!
Ok, let's get rid of that message listener interface and image our Email Connector uses a very JAX-RS inspired API for consuming emails. If you know a little JAX-RS you'll see where I'm going with this.
@MessageDriven
@EmailAccountInfo(address = "dblevins@apache.org")
public static class EmailBean {

    @PostConstruct
    public void init() {
    }

    @Deliver @Header("Subject: {subject}")
    public void receiveEmail(@HeaderParam("subject") String subject, @Body String body) {
        // do your thing!
    }
}
Pretty neat, huh?
Side note: For the rare few of you that speak Connector implementation, instead of giving your Resource Adapter a MessageEndpoint that is a proxy that only implements the MessageListener interface and the standard MessageEndpoint interface, the Container would instead give you an @LocalBean proxy that also implements MessageEndpoint. If you're thinking that an API like that would be great to use... imagine with the above changes you could make that API ... and use it in any compliant Java EE platform. Maybe even submit your own JSR if you came up with something great.
Truthfully speaking, it's the Connector who controls the lifecycle of the bean (MDB). The Connector API already allows for the Connector to say to the Container, "create me a bean" and "destroy this bean". So really, we don't need @MessageDriven anymore. Instead we can do this:
import javax.annotation.ManagedBean;

@ManagedBean
@EmailAccountInfo(address = "dblevins@apache.org")
public static class EmailBean {
 // ....
}
That's a little more modern and perhaps a bit clearer.
At this point, we have a generic API to hook arbitrary "Connectors" up to arbitrary "Beans" that are managed by a container. Were this the case when JAX-RS was created, they wouldn't have had to put so much effort into duplicating all the services that people who have managed beans expect: injection of resources, lifecycle callbacks, interceptors.
Summary: A few improvements to the expressiveness of the metadata passed between a Bean and its Connector could kick the MDB/Connector model into the mainstream as was the intention of the API from the beginning. New specifications could be created based on this model and be introduced incrementally as they are developed and needed.
The impact of fully opening up the Bean metadata to the Connector is quite deep and wide and likely not something that will scream at you immediately. Ask yourself, could something like the new EJB 3.1 @Schedule API have been done with a Connector/Bean model like this? To some extent probably it could. Certainly there already existed a few Quartz Connectors out there prior to the introduction of @Schedule.
Take a moment to daydream. What kind of Connectors could you create with this model?


UPDATE - Feb 7th, 2013

Save this proposal.  Without more voices it will be delayed till Java EE 8.  Let's not wait 4 years!  Take action and celebrate the Java Community Process openness by showing your support for including this in Java EE 7.  Act now.

VOTE AND COMMENT HERE http://java.net/jira/browse/EJB_SPEC-60




Friday, September 24, 2010

Interceptor Advisor Pattern

Your standard CDI/EJB Interceptor example uses a logger as an around advice. Generally this gives you an interceptor that looks like so:

@Log
public class LoggingInterceptor {

    private java.util.logging.Logger logger =
            java.util.logging.Logger.getLogger("theLogger");

    @AroundInvoke
    public Object intercept(InvocationContext context) throws Exception {
        logger.info("" + context.getMethod().getName());
        return context.proceed();
    }
}

As of the Interceptors 1.1 spec, you can bind that to a bean via creating our own javax.interceptor.InterceptorBinding annotation. In our example, we've created one called @Log:

@InterceptorBinding
@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
}

Now we just apply that to the bean as follows.

@Log
public class FooBean {

    public void somethingCommon(){
        //...
    }

    public void somethingImportant() {
        //...
    }

    public void somethingNoteworthy() {
        //...
    }
}

Great! Now we are done. Every time that bean is invoked, the LoggerInterceptor will issue a log message on info level. Aren't interceptors wonderful! End of story, right? Not quite.

Fundamentally, our example is still very contrived. Who wants to log everything on the same level?

Here is a little pattern that you can use to better advise your LoggerInterceptor around advice. First, we create a couple new annotations for log levels: @Fine and @Info

@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Fine {
}

@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Info {
}

Then we apply those to the bean...

@Log
public class FooBean {

    public void somethingCommon(){
        //...
    }

    @Info
    public void somethingImportant() {
        //...
    }

    @Fine
    public void somethingNoteworthy() {
        //...
    }
}

Now we alter our LoggerInterceptor to check for our new annotations and alter its behavior.

@Log
public class LoggingInterceptor {

    private java.util.logging.Logger logger =
            java.util.logging.Logger.getLogger("theLogger");

    @AroundInvoke
    public Object intercept(InvocationContext context) throws Exception {
        final Method method = context.getMethod();
        if (method.isAnnotationPresent(Info.class)) {
            return info(context);
        } else if (method.isAnnotationPresent(Fine.class)) {
            return fine(context);
        } else {
            return finest(context);
        }
    }

    public Object info(InvocationContext context) throws Exception {
        logger.info("" + context.getMethod().getName());
        return context.proceed();
    }

    public Object fine(InvocationContext context) throws Exception {
        logger.finest("" + context.getMethod().getName());
        return context.proceed();
    }

    public Object finest(InvocationContext context) throws Exception {
        logger.finest("" + context.getMethod().getName());
        return context.proceed();
    }
}

Done! Now we have a pattern to advise our interceptor!

This will totally work today. But this pattern is so simple and elegant what if we could support it right inside the container? Imagine how cool it would be if we could just do this in our interceptor and the container would just figure it out.

@Log
public class LoggingInterceptor {

    private java.util.logging.Logger logger =
            java.util.logging.Logger.getLogger("theLogger");

    @Info
    public Object info(InvocationContext context) throws Exception {
        logger.info("" + context.getMethod().getName());
        return context.proceed();
    }

    @Fine
    public Object fine(InvocationContext context) throws Exception {
        logger.finest("" + context.getMethod().getName());
        return context.proceed();
    }

    @AroundInvoke
    public Object finest(InvocationContext context) throws Exception {
        logger.finest("" + context.getMethod().getName());
        return context.proceed();
    }
}

Definitely something I plan to propose for the next round of specifications....

As always, comments welcome.

Tuesday, September 21, 2010

EJB.next Interceptor Improvements - Method signatures

Interceptors are great, but some parts of them are odd when applied practically. For as fundamentally reflective as interceptors are, it isn't possible to pass all interceptable calls through a single method, like so:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.interceptor.AroundInvoke;
import javax.interceptor.AroundTimeout;
import javax.interceptor.InvocationContext;
import java.util.concurrent.TimeUnit;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

public class StatsInterceptor {

    @PostConstruct
    @PreDestroy
    @PrePassivate
    @PostActivate
    @AroundInvoke
    @AroundTimeout
    public Object intercept(InvocationContext context) throws Exception {
        final long start = System.nanoTime();
        try {
            return context.proceed();
        } finally {
            final long nanos = System.nanoTime() - start;
            final long millis = MILLISECONDS.convert(nanos, NANOSECONDS);
            System.out.println("invoke time "+ millis +" milleseconds");
        }
    }
}

This looks very nice, but currently is not legal. The spec currently requires different formats for callback-based interception vs business-method-based interception. This sounds like a nice safe and conservative rule, but is it benefiting users? Not really. Let's see what we have to do to our interceptor to make it compliant.

First, callback intercept methods are not allowed to return anything and must have a void return type. The logic here is that since callbacks have no return value, interceptors should know this. So fine, let's work around that and just make a new method:

    @PostConstruct
    @PreDestroy
    @PrePassivate
    @PostActivate
    @AroundInvoke
    public void callback(InvocationContext context) throws Exception {
        intercept(context);
    }

Second, callback intercept methods are not allowed to throw any exceptions. Again the rationale is that callbacks aren't allowed to throw checked exceptions, so interceptors should be aware of that as well. The trick is we can't simply remove the 'throws Exception' clause without doing any extra work. The InvocationContext.proceed() method throws java.lang.Exception but we can't, so we are forced to take responsibility for it. If we just catch and ignore the exception all hell will break loose, so instead we should at least wrap it as a RuntimeException.

    @PostConstruct
    @PreDestroy
    @PrePassivate
    @PostActivate
    @AroundTimeout
    public void callback(InvocationContext context) {
        try {
            intercept(context);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

We've just made a mistake. Did you see it? If there are several interceptors in the chain and all of them wrap the exception like this, when an actual exception is thrown it will end up wrapped N times -- once per interceptor -- before finally reaching the container. Instead, we should at least check if the exception needs wrapping and hope that other interceptors do the same:

    @PostConstruct
    @PreDestroy
    @PrePassivate
    @PostActivate
    @AroundTimeout
    public void callback(InvocationContext context) {
        try {
            intercept(context);
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            } else{
                throw new RuntimeException(e);
            }
        }
    }

Now we're done. Summary: all of the above is boilerplate code you need in any well implemented callback-based interceptor.

What have we achieved? Not much.

In terms of user code, it doesn't help you any to have these restrictions. If you wanted special logic for callback-based interceptor methods you can easily put that annotation on a separate method.

In terms of container code, there's little gain as well. Ultimately, most containers use reflection to kick off the interceptor chain. The java.lang.reflect.Method.invoke() method returns Object and throws InvocationTargetException. Restricting users from returning Object and throwing Exception have no real impact on the container code. It's a callback. Ultimately all exceptions, checked or not, go into the log file and no further and return values are simply ignored.

Summary: The restriction on returning void and throwing Exception should be lifted. For backwards compatibility we can just say this former requirement is now optional and allow interceptor signatures of 'Object <method>(InvocationContext c) throws Exception' even if what is being intercepted is a callback.