Several Architectural Styles with Java EE 7

If you are like me, in your career you came across Architects who want to homogenize every single application in the company : from the smallest web app to the biggest application. All projects have to conform to the 542 pages In-house Architectural Guide and develop a 6 tier application (it could be 5, 6, 7 or 8 tiers, look like architects are paid by the tier). This is wrong. In fact, you should follow the good old saying : the right tool for the right job, or, the right architecture for the right project’s needs. And you could go even further : the right language for the right application and so on. Due to my Java EE background, I’m sticking to Java EE 7 in this post (JSF front end, EJBs services, JAX-RS endoints and JPA entities). So, how many architectural styles you can create with Java EE 7 ? An infinite ;o)

I’m writing this blog because I was showing the code generated by JBoss Forge to a colleague and he went “Forge doesn’t create a 5-tier web application“… and so what ? In this post I’ll explain the default code generated by JBoss Forge (which I call Horizontal Service Style) and the other variants you can create from it.

Horizontal Services Style

When JBoss Forge generates a JSF web application with a REST interface, both JSF backing beans and JAX-RS endpoints use the EntityManager to deal with JPA Entities. The architectural style is as follow :

Horizontal Services

I call this Horizontal Services style because if you need to add a SOAP Web Service interface, you will write a BookSOAP which will also use an EntityManager and directly invoke the entities. To have an idea of the dynamics in the code, I’ll show you an extract of some CRUD operation on both the JSF backing bean and the REST endpoint :

[sourcecode title=”JSF BookBean” language=”java” highlight=”1,2,3,12,18,26,29,44,45″]@Named
@Stateful
@ConversationScoped
public class BookBean implements Serializable {

// …

@Inject
private Conversation conversation;

@PersistenceContext(unitName = "sampleJavaEEHorizontalPU", type = PersistenceContextType.EXTENDED)
private EntityManager em;

// …

public Book findById(Long id) {

return em.find(Book.class, id);
}

public String update() {
conversation.end();

try {
if (id == null) {
em.persist(book);
return "search?faces-redirect=true";
} else {
em.merge(book);
return "view?faces-redirect=true&id=" + book.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
conversation.end();

try {
Book deletableEntity = findById(getId());

em.remove(deletableEntity);
em.flush();
return "search?faces-redirect=true";
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(e.getMessage()));
return null;
}
}
}[/sourcecode]

This backing bean deals with navigation (each method returns a String, which is the name of the page to navigate to) and creates, deletes, updates the Book entity. Now if you look at the REST endpoint, you will see that the responsibilities are quite similar : the BookEndpoint creates, deletes, updates the Book entity and returns a Response. This is the code of the BookEndpoint:

[code title=”JAX-RS BookEndpoint” language=”java” highlight=”1,2,8,16,29,40″]@Transactional
@Path("/books")
public class BookEndpoint {

// …

@PersistenceContext(unitName = "sampleJavaEEHorizontalPU")
private EntityManager em;

// …

@GET
@Path("/{id:[0-9][0-9]*}")
@Produces("application/xml")
public Response findById(@PathParam("id") Long id) {
TypedQuery findByIdQuery = em.createQuery("SELECT DISTINCT b FROM Book b LEFT JOIN FETCH b.authors WHERE b.id = :entityId ORDER BY b.id", Book.class);
findByIdQuery.setParameter("entityId", id);
Book entity = findByIdQuery.getSingleResult();
if (entity == null) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok(entity).build();
}

@PUT
@Path("/{id:[0-9][0-9]*}")
@Consumes("application/xml")
public Response update(Book entity) {
em.merge(entity);
return Response.noContent().build();
}

@DELETE
@Path("/{id:[0-9][0-9]*}")
public Response deleteById(@PathParam("id") Long id) {
Book deletableEntity = em.find(Book.class, id);
if (deletableEntity == null) {
return Response.status(Status.NOT_FOUND).build();
}
em.remove(deletableEntity);
return Response.noContent().build();
}
}[/code]

As you can see, the REST endpoint uses the new @Transactional annotation from Java EE 7 so it can handle the EntityManager in a transactional manner. So if you are like my colleague and don’t like this kind of architectural style, here is what I think of the pros/cons :

Advantages

  • This is a relatively flat architecture. You don’t have any extra layers, interfaces, or UselessAbstractSomethingFactory pattern.
  • Very quick to develop, you develop following your needs
  • Perfect for easy applications (no complex business logic)

Disadvantages

  • No separation of concerns, one class does several things (e.g. the BookBean manages JSF navigation as well as handles entities)
  • Code duplication. The findById method is implemented the same way on both BookBean and BookEndpoint
  • Heavy refactoring. If your application grows in complexity, you might end up refactoring and moving to an EJB Centric architectural style

EJB Centric Style

This is the most common architectural style : it uses separation of concerns. The EJB layer deals with the EntityManager and other complex business logic, while the BookBean and BookEndpoint only deal with respectively JSF and REST concerns. This looks like this :

EJB Centric
The BookEJB is a stateless session bean that does all the database access and orchestrates other external services. The code looks like this :

[code title=”BookEJB” language=”java” highlight=”1,5,10,14,18″]@Stateless
public class BookEJB {

@PersistenceContext(unitName = "sampleJavaEEEJBCentricPU")
private EntityManager em;

// …

public Book findById(Long id) {
return em.find(Book.class, id);
}

public void update(Book entity) {
em.merge(entity);
}

public void delete(Book deletableEntity) {
em.remove(em.merge(deletableEntity));
}
}[/code]

Both the BookBean and BookEndpoint get a BookEJB injected and delegate all the entity management. The REST endpoint can then look like this :

[code title=”BookEndpoint” language=”java” highlight=”1,5,13,24,31,35″]@Path("/books")
public class BookEndpoint {

@Inject
private BookEJB bookService;

// …

@GET
@Path("/{id:[0-9][0-9]*}")
@Produces("application/xml")
public Response findById(@PathParam("id") Long id) {
Book entity = bookService.findByIdWithRelations(id);
if (entity == null) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok(entity).build();
}

@PUT
@Path("/{id:[0-9][0-9]*}")
@Consumes("application/xml")
public Response update(Book entity) {
bookService.update(entity);
return Response.noContent().build();
}

@DELETE
@Path("/{id:[0-9][0-9]*}")
public Response deleteById(@PathParam("id") Long id) {
Book deletableEntity = bookService.findById(id);
if (deletableEntity == null) {
return Response.status(Status.NOT_FOUND).build();
}
bookService.delete(deletableEntity);
return Response.noContent().build();
}
}[/code]

As you can see, the BookEndpoint deals with all the REST interactions (building a Response, error status…) and delegates the other concerns to the EJB. I’m not showing the BookBean code but it would look very similar.

Advantages

  • Seperation of concerns, each class does it’s own job
  • If you add another type of interface (let’s say a SOAP Web Servies), you reuse the EJB layer
  • Perfect for complex applications
  • Scales better than the previous architectural style

Disadvantages

  • Adds an extra layer to the application, but thanks to the no-interface view, in most cases you don’t even need to add an interface (so it’s just one class to add)

Rest Centric Style

Thanks to JAX-RS 2.0, we have now a Client API, meaning that we can finally invoke a REST web service in a standard way. We can then put the REST endpoint in the center of our application and the BookBean will use the JAX-RS Client API to invoke it :

REST centric

In this configuration the REST endpoint becomes the central point of your external invocations, deals with the EntityManager and do all the complex business logic. The BookEndpoint code looks similar to what I’ve showed you so far. The interesting part is in the BookBean that uses the Client API extensively:

[code title=”BookBean” language=”java” highlight=”1,2,7,8,21,29,32,46″]@Named
@ConversationScoped
public class BookBean implements Serializable {

// …

private Client client = ClientBuilder.newClient();
private WebTarget target;

@PostConstruct
private void setWebTarget() {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String restEndointURL = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/rest/books/";
target = client.target(restEndointURL);
}

// …

public Book findById(Long id) {

return target.path("{id}").resolveTemplate("id", id).request(MediaType.APPLICATION_XML).get(Book.class);
}

public String update() {
conversation.end();

try {
if (id == null) {
target.request().post(Entity.entity(book, MediaType.APPLICATION_XML));
return "search?faces-redirect=true";
} else {
target.request().put(Entity.entity(book, MediaType.APPLICATION_XML));
return "view?faces-redirect=true&id=" + book.getId();
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(e.getMessage()));
return null;
}
}

public String delete() {
conversation.end();

try {

target.path("{id}").resolveTemplate("id", getId()).request(MediaType.APPLICATION_XML).delete();

return "search?faces-redirect=true";
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(e.getMessage()));
return null;
}
}
}[/code]

As you can see, the Client and WebTarget are used to do GET, POST, PUT and DELETE operations on the REST endpoint.

Advantages

  • Enforces a RESTful style
  • Perfect if you have several external REST clients
  • Eat your own dog food (your JSF backing beans are the first consumers of your REST endpoints)

Disadvantages

  • Your JSF backing beans spend most of their time marshalling/unmarshalling the entities into/from XML (or JSon)

Conclusion

There is no good or bad architecture, there are several use cases and you can create the appropriate style for your needs. Here I just explain 3 different ways of writing the same thing with Java EE 7 but there are many more (another one would be to have several concerns into a single class, such as the Monster Component, another one is to create an extra (useless?) DAO layer…) :

  • Horizontal Services : each service (JSF, REST, SOAP…) deals with the EntityManager, accesses the database and does the business logic
  • EJB Centric : each interface (JSF, REST, SOAP…) accesses an EJB layer that does most of the processing
  • REST Centric : the front views (JSF, Javascript…) access a REST layer that does all the processing

I hope JBoss Forge 2 will be able to easily generate such diversity, I’ll contribute to make it happen… feel free to join the discussion.

Any other style that you use ? What about the ones I’ve presented here, any other ideas ? Download the code and do not hesitate to contribute to it.

15 thoughts on “Several Architectural Styles with Java EE 7

  1. 5 or 6 layers would definitely look like the old days of J2EE. Call me conservative, but I still don’t feel comfortable with a single layer, like the first option. I always go with the second, “EJB centric” style 🙂

  2. Can’t you use the BookEndpoint as CDI bean and just inject it in BookBean? I think can solve the marshalling problem. thanks.

    1. Yes, technically you could. You would get a Response back, and still have to use the JAX-RS Client API to read the entity from the Response. But the idea was to show how you can interact a JSF Backing Bean with a REST endpoint.

  3. To me, the nicest pattern is the RESTful one. REST doesn’t imply no business logic – it just implies putting already processed resources on the wire, plus specifying operations via http verbs – you’d mostly use PATCH (besides POST) for things which are not CRUD, I suppose (these two verbs being the only ones allowed not to be idempotent).

    Having a RESTful API makes your API not just reusable from a wide variety of clients, but also readable – and that’s what actually makes an API capable of survival – if consumers of your API constantly complain of how cumbersome it is, chances of a rewrite being approved are high. Of course, replacing it with yet another RPC-ish API won’t solve the problem. REST, OTOH, will make it easy and readable by making it narrow.

  4. Many considerations emerge from this article, one being you haven’t understood REST. The big problem with Java architects is our resistance to innovation in the name of stability, but we never have got stability!

    We have written tons of lines of code for the sake of fulfilling pattern we didn’t need with the promise that some day we would have needed it. At the same time we have been forced to think to application optimization upfront, at design stage, where we didn’t knew a dime about the bottlenecks or performance issues: caching, session, lazy loading…

    All this has infused so many bad practices into us we aren’t able to see the real problem any more and we keep engineering our software the same way, no matter what are the requirements, just because “we feel confident” with one approach or another.

    Reality is we never needed EJB and Spring demonstrated that.

    1. I’m glad you understand REST. As for me, I don’t understand your sentence “Reality is we never needed EJB and Spring demonstrated that”. An EJB is a façade to allow bean manipulation, transaction and security demarcation. The same as Spring, isn’t it ? Or maybe I didn’t understand Spring (I’m glad you do).

      1. I apologize if I sounded rude, but I believe you didn’t get REST because of the example you made and the use you are doing of the REST service: you are creating the URL with string concatenation and you are using the REST service as blackened for JSF components. Using REST is such fashion is poor use of technology capabilities.

        With regards to my sentence regarding EJB and Spring you said that yourself: EJBs can be replaced with POJOs and a lot less cumbersome handling of infrastructural features. Do you still use EJBs? I’ve stopped using EJBs long time ago and I don’t miss them: the only EJB flavor I found useful was MessageDriven.

        If you go enterprise you should use real enterprise solutions that doesn’t lock your capabilities: enterprise integration patterns and a framework to support you on that like Spring Integration. EJBs are the Java DCOM clone, a leftover from the past.

      2. I’m using JBoss Forge, so I’m commenting on what JBoss Forge generates. Being Java EE centric, it generates a JSF front-end. I’m actually having a closer look at AngularJS. Hopefully I will blog about generating a REST back-end with Forge with an AngularJS Front end.

        As for EJBs, I really need to blog about it too. Imagine a table with 3 columns : POJOs, CDI Beans, EJBs. Then, on each line, imagine a service (managed, injection, life-cycle management, transactions, security…). Then, it’s just a matter of ticking the right cells. EJBs have extra-services, that’s all. If you don’t need them, use a CDI Bean (a POJO with @Transactional for eg.). In EJB 3.2 we wanted to externalize all the EJB services into a different spec (so they could be used by other specs). I hope we will be able to do so in the next release. If we do, then @Stateless will just be a stereotype aggregating several services. You will even be able to create your own annotation : imagine if you had @Service that aggregates @Stateless, will you be happier ? Because, at the end of the day, a @Service Spring bean, is just a @Stateless (then both need a container to run, and this container provides a set of services).

  5. Antonio,

    Regarding the “REST Centric” style, what do you think about letting the REST layer itself be transactional? That is, as if the REST service would have a @Transacional annotation of some sort. Does that sound like a good idea, or is it better to just leave that “transaction” responsability to the next layer in the chain (EJB/Spring business layer)?

  6. Why cant we expose BookEJB as REST service. The job done by BookEndPoint should be done by BookEJB. If we can expose one EJB as REST and SOAP service, we remove several layers. And this more power to EJB bean

  7. .getSingleResult() throws a NoResultException if there is no result.

    Good article, BTW.

Leave a Reply