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.

Thursday, November 15, 2012

Meta-Annotations


Meta-Annotations

Meta-Annotations are an experiment in annotation inheritance, abstraction and encapsulation with a Java SE mindset
A meta-annotation is any annotation class annotated with @Metatype. The other annotations used on the meta-annotation become part of its definition. If any of those annotations happen to also be meta-annotations, they are unrolled as well and their annotations become part of the definition.

@Metatype

The recursion that is the meta-annotation concept only happens when an annotation is marked as a @javax.annotation.Metatype.
When @Metatype is seen the basic contract is "carry the surrounding annotations forward". When a class, method or other target uses an annotation annotated with @Metatype the annotations on that annotation are "unrolled" or carried forward and effectively placed on that class, method or other target as if they were explicitly declared.
If any of the annotations that are carried forward also are annotated with @Metatype the recursion continues. The result is a simple algorithm or design pattern that provides inheritance or reuse in a way that is not specific to any domain, API, or specification.
APIs and specifications can choose to formally adopt annotation reuse in this fashion, but the core concept and implementations of@Metatype do not need to be expanded to support these APIs or specifications.
The simple elegance of this not being domain specific is that it could be used to combine several annotations from different specifications into one reusable annotation. Say JAX-RS @PathParam("id") with Bean Validation @NotNull to create a new annotation called @ValidId.

Creating Meta-Annotations

If the annotation in question can be applied to ElementType.ANNOTATION_TYPE or ElementType.TYPE, creating a meta-annotation version of it is quite easy.
@TransactionManagement(TransactionManagementType.CONTAINER)
@Metatype
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ContainerManagedTransactions {
}
When the annotation in question cannot be applied to ElementType.ANNOTATION_TYPE or ElementType.TYPE, things get interesting. This is where meta-annotations depart from things like @Stereotype. The goal of meta-annotations is to be completely generic and not specific to any one domain or API. A such, you cannot really require all existing APIs change to allow for meta-annotations. The goal is that meta-annotations can be used generically and do not need to be "designed" into an API.
To allow annotations that apply to FIELDMETHODPARAMETERCONSTRUCTORLOCAL_VARIABLE, or PACKAGE, as well as any other location where annotations may be applied in the future a compromise is made.
import javax.ejb.Schedule;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Metatype
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)

public @interface Daily {
    public static class $ {

        @Daily
        @Schedule(second = "0", minute = "0", hour = "0", month = "*", dayOfWeek = "*", year = "*")
        public void method() {
        }
    }
}
An inner class named $. This is enough to bind together the @Daily and @Schedule in the context to which they both apply.
Ugly but effective. Alternate proposals welcome.
The above is considered the public API portion of the meta-annotation concept.
The concept itself is born out of standards based systems like EJB and CDI where annotation processing is invisible to the application itself. In those settings the above is enough and no additional APIs would be needed to support meta-annotations in standard APIs.

Under the covers

The "guts" of this particular implementation is designed to look and feel as much like the reflection API as possible. Obviously, with VM level control, you could do much better. A clean Java SE API might be just what is needed and its very possible that meta-annotations should really be a Java SE concept.
Here's a glimpse as to how things can look under the covers:
final java.lang.reflect.AnnotatedElement annotated = new org.metatype.MetaAnnotatedClass(Triangle.class);
assertNotNull(annotated);

assertTrue(annotated.isAnnotationPresent(Color.class));
assertTrue(annotated.getAnnotation(Color.class) != null);
assertTrue(!contains(Color.class, annotated.getDeclaredAnnotations()));
assertTrue(contains(Color.class, annotated.getAnnotations()));
assertEquals("red", annotated.getAnnotation(Color.class).value());

assertTrue(annotated.isAnnotationPresent(Red.class));
assertTrue(annotated.getAnnotation(Red.class) != null);
assertTrue(!contains(Red.class, annotated.getDeclaredAnnotations()));
assertTrue(contains(Red.class, annotated.getAnnotations()));

assertTrue(annotated.isAnnotationPresent(Crimson.class));
assertTrue(annotated.getAnnotation(Crimson.class) != null);
assertTrue(contains(Crimson.class, annotated.getDeclaredAnnotations()));
assertTrue(contains(Crimson.class, annotated.getAnnotations()));
The application classes would look like so:
@Crimson
// -> @Red -> @Color
public static class Triangle {

}

@Metatype
@Color("red")
// one level deep
@Target(value = {TYPE})
@Retention(value = RUNTIME)
public static @interface Red {
}

@Metatype
@Red
// two levels deep
@Target(value = {TYPE})
@Retention(value = RUNTIME)
public static @interface Crimson {
}

Best Practices
It is recommended to have an api package or some other package where "approved' annotations are defined and to prohibit usage of the non-meta versions of those annotations. All the real configuration will then be centralized in the api package and changes to the values of those annotations will be localized to that package and automatically be reflected throughout the application.
An interesting side-effect of this approach is that if the api package where the meta-annotation definitions exist is kept in a separate jar as well, then one can effectively change the configuration of an entire application by simply replacing the api jar.

Future concepts

XML Overriding

The unrolling of meta-annotations happens under the covers. In that same vein, so could the concept of overriding.
The above @Red annotation might theoretically be overridden via xml as follows:

<org.superbiz.api.Red>
  <org.superbiz.api.Color value="dark red"/>
</org.superbiz.api.Red>
Or take more complex meta-annotation definition like the following:
package org.superbiz.corn.meta.api;

import javax.ejb.Schedule;
import javax.ejb.Schedules;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Metatype
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)

public @interface PlantingTime {
    public static interface $ {

        @PlantingTime
        @Schedules({
                @Schedule(month = "5", dayOfMonth = "20-Last", minute = "0", hour = "8"),
                @Schedule(month = "6", dayOfMonth = "1-10", minute = "0", hour = "8")
        })
        public void method();
    }
}
This might theoretically be overridden as:

<org.superbiz.corn.meta.api.PlantingTime>
  <javax.ejb.Schedules>
    <value>
      <javax.ejb.Schedule month="5" dayOfMonth="15-Last" minute="30" hour="5"/>
      <javax.ejb.Schedule month="6" dayOfMonth="1-15" minute="30" hour="5"/>
    </value>
  </javax.ejb.Schedules>
</org.superbiz.corn.meta.api.PlantingTime>

Merging or Aggregating definitions
Certain annotations take lists and are designed to be multiples. In the current definition of meta-annotations, the following is illegal.
@RolesAllowed({"Administrator", "SuperUser"})
@Metatype
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Admins {
}

@RolesAllowed({"Employee", "User"})
@Metatype
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Users {
}


public static class MyBean {

    @Admin
    @User
    public void doSomething() {
        // ...
    }
}
Here the @Admin and @User annotation each resolve to @RolesAllowed. Since only one @RolesAllowed annotation is allowed on the method per the Java language specification, this results in an error.
The intention is clear however and aggregating metadata together in this way is natural.
A theoretical way to support something like this is with an annotation to describe that this aggregation is intended and desired. Note the addition of the theoretical @Merge annotation.
@RolesAllowed({"Administrator", "SuperUser"})
@Metatype
@Merge
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Admins {
}

@RolesAllowed({"Employee", "User"})
@Metatype
@Merge
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Users {
}


public static class MyBean {

    @Admin
    @User
    public void doSomething() {
        // ...
    }
}
A new @RolesAllowed annotation would be created containing the list {"Administrator", "SuperUser", "Employee", "User"} and that would represent the final @RolesAllowed usage for the doSomething() method.