Skip to content

Latest commit

 

History

History
336 lines (212 loc) · 10.5 KB

File metadata and controls

336 lines (212 loc) · 10.5 KB

devon4j component layers

As we already mentioned in the introduction to devon4j the components of our Java backend apps will be divided in three layers: service, logic and dataaccess.

  • Service Layer: will contain the REST services to exchange information with the client applications.

  • Logic Layer: the layer in charge of hosting the logic of the application (validations, authorization control, business logic, etc.).

  • Data Access Layer: the layer to communicate with the data base.

Layers implementation

dependency injection

Following the devon4j recommendations for Dependency Injection in MyThaiStar’s layers we will find:

  • Separation of API and implementation: Inside each layer we will separate the elements in different packages: api and impl. The api will store the interface with the methods definition and inside the impl we will store the class that implements the interface.

layer api impl
  • Usage of JSR330: The Java standard set of annotations for dependency injection (@Named, @Inject, @PostConstruct, @PreDestroy, etc.) provides us with all the needed annotations to define our beans and inject them.

@Named
public class MyBeanImpl implements MyBean {
  @Inject
  private MyOtherBean myOtherBean;

  @PostConstruct
  public void init() {
    // initialization if required (otherwise omit this method)
  }

  @PreDestroy
  public void dispose() {
    // shutdown bean, free resources if required (otherwise omit this method)
  }
}

Communication between layers

The communication between layers is solved using the described Dependency Injection pattern, based on Spring and the Java standards: java.inject (JSR330) combined with JSR250.

layers impl

Service layer - Logic layer

import javax.inject.Inject;
import javax.inject.Named;

import io.oasp.application.mtsj.bookingmanagement.logic.api.Bookingmanagement;

@Named("BookingmanagementRestService")
public class BookingmanagementRestServiceImpl implements BookingmanagementRestService {

  @Inject
  private Bookingmanagement bookingmanagement;

  @Override
  public BookingCto getBooking(long id) {
    return this.bookingmanagement.findBooking(id);
  }

  ...

}

Logic layer - Data Access layer

import javax.inject.Inject;
import javax.inject.Named;

import io.oasp.application.mtsj.bookingmanagement.dataaccess.api.dao.BookingDao;

@Named
public class BookingmanagementImpl extends AbstractComponentFacade implements Bookingmanagement {

  @Inject
  private BookingDao bookingDao;

  @Override
  public boolean deleteBooking(Long bookingId) {

    BookingEntity booking = this.bookingDao.find(bookingId);
    this.bookingDao.delete(booking);
    return true;
  }

  ...

}

Service layer

As we mentioned at the beginning, the Service layer is where the services of our application (REST or SOAP) will be located.

In devon4j applications the default implementation for web services is based on Apache CXF, a services framework for Java apps that supports web service standards like SOAP (implementing JAX-WS) and REST services (JAX-RS).

In this tutorial we are going to focus only in the REST implementation of the services.

Service definition

The services definition is done by the service interface located in the service.api.rest package. In the boooking component of My Thai Star application we can see a service definition statement like the following

@Path("/bookingmanagement/v1")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface BookingmanagementRestService {

  @GET
  @Path("/booking/{id}/")
  public BookingCto getBooking(@PathParam("id") long id);

  ...

}

JAX-RS annotations:

  • @Path: defines the common path for all the resources of the service.

  • @Consumes and @Produces: declares the type of data that the service expects to receive from the client and the type of data that will return to the client as response.

  • @GET: annotation for HTTP get method.

  • @Path: the path definition for the getBooking resource.

  • @PathParam: annotation to configure the id received in the url as a parameter.

Service implementation

The service implementation is a class located in the service.impl.rest package that implements the previous defined interface.

@Named("BookingmanagementRestService")
public class BookingmanagementRestServiceImpl implements BookingmanagementRestService {

  @Inject
  private Bookingmanagement bookingmanagement;

  @Override
  public BookingCto getBooking(long id) {

    return this.bookingmanagement.findBooking(id);
  }

  ...
}

As you can see this layer simply delegates in the logic layer to resolve the app requirements regarding business logic.

Logic layer

In this layer we will store all the custom implementations to resolve the requirements of our applications. Including:

  • business logic.

  • Delegation of the transaction management to Spring framework.

  • object mappings.

  • validations.

  • authorizations.

Within the logic layer we must avoid including code related to services or data access, we must delegate those tasks in the suitable layer.

Logic layer definition

As in the service layer, the logic implementation will be defined by an interface located in a logic.api package.

public interface Bookingmanagement {

  BookingCto findBooking(Long id);

  ...
}

Logic layer implementation

In a logic.impl package a Impl class will implement the interface of the previous section.

@Named
@Transactional
public class BookingmanagementImpl extends AbstractComponentFacade implements Bookingmanagement {

  /**
   * Logger instance.
   */
  private static final Logger LOG = LoggerFactory.getLogger(BookingmanagementImpl.class);

  /**
   * @see #getBookingDao()
   */
  @Inject
  private BookingDao bookingDao;

  /**
   * The constructor.
   */
  public BookingmanagementImpl() {

    super();
  }

  @Override
  public BookingCto findBooking(Long id) {

    LOG.debug("Get Booking with id {} from database.", id);
    BookingEntity entity = getBookingDao().findOne(id);
    BookingCto cto = new BookingCto();
    cto.setBooking(getBeanMapper().map(entity, BookingEto.class));
    cto.setOrder(getBeanMapper().map(entity.getOrder(), OrderEto.class));
    cto.setInvitedGuests(getBeanMapper().mapList(entity.getInvitedGuests(), InvitedGuestEto.class));
    cto.setOrders(getBeanMapper().mapList(entity.getOrders(), OrderEto.class));
    return cto;
  }

  public BookingDao getBookingDao() {
    return this.bookingDao;
  }

  ...
}

In the above My Thai Star logic layer example we can see:

  • business logic and/or object mappings.

  • Delegation of the transaction management through the Spring’s @Transactional annotation.

Transfer objects

In the code examples of the logic layer section you may have seen a BookingCto object. This is one of the Transfer Objects defined in devon4j to be used as transfer data element between layers.

Main benefits of using TO’s:

  • Avoid inconsistent data (when entities are sent across the app changes tend to take place in multiple places).

  • Define how much data to transfer (relations lead to transferring too much data).

  • Hide internal details.

In devon4j we can find two different _Transfer Objects:

Entity Transfer Object (ETO)

  • Same data-properties as entity.

  • No relations to other entities.

  • Simple and solid mapping.

Composite Transfer Object(CTO)

  • No data-properties at all.

  • Only relations to other TOs.

  • 1:1 as reference, else Collection(List) of TOs.

  • Easy to manually map reusing ETO’s and CTO’s.

Data Access layer

The third, and last, layer of the devon4j architecture is the one responsible for store all the code related to connection and access to data base.

For mapping java objects to the data base devon4j use the Java Persistence API(JPA). And as JPA implementation devon4j use hibernate.

Apart from the Entities of the component, in the dataaccess layer we are going to find the same elements that we saw in the other layers: definition (an interface) and implementation (a class that implements that interface).

However, in this layer the implementation is slightly different, the [Target]DaoImpl extends general.dataaccess.base.dao.ApplicationDaoImpl that provides us (through io.oasp.module.jpa) with the basic implementation dataaccess methods: save(Entity), findOne(id), findAll(ids), delete(id), etc.

Because of that, in the [Target]DaoImpl implementation of the layer we only need to add the custom methods that are not implemented yet. Following the My Thai Star component example (bookingmanagement) we will find only the paginated findBookings implementation.

Data Access layer definition

public interface BookingDao extends ApplicationDao<BookingEntity> {
  PaginatedListTo<BookingEntity> findBookings(BookingSearchCriteriaTo criteria);
}

Data Access layer implementation

@Named
public class BookingDaoImpl extends ApplicationDaoImpl<BookingEntity> implements BookingDao {

  @Override
  public PaginatedListTo<BookingEntity> findBookings(BookingSearchCriteriaTo criteria) {

    BookingEntity booking = Alias.alias(BookingEntity.class);
    EntityPathBase<BookingEntity> alias = Alias.$(booking);
    JPAQuery query = new JPAQuery(getEntityManager()).from(alias);

    ...

  }
}

The implementation of the findBookings uses queryDSL to manage the dynamic queries.