Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Developing With CUBA: A Big Shift From Spring? (Part 2)

DZone's Guide to

Developing With CUBA: A Big Shift From Spring? (Part 2)

If you have a task for implementing data-centric intranet applications, you may want to try the CUBA platform. Check out this post to learn more about CUBA and the shift away from Spring Frameworks.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

In this second installment of using the CUBA Framework, we take a closer look at using the Pet Clinic with CUBA and more detail regarding the application of the framework. Let's get started!

Pet Clinic With CUBA

So, let's have a look at a Pet Clinic implementation with the CUBA Platform. Let's try to look at it in terms of our Spring knowledge and figure out where we can save some time and make the process more efficient.

Source code for the Pet Clinic implementation can be found on GitHub. Apart from that, the CUBA platform has great documentation, and you can find almost everything there (most cases are illustrated with examples and code snippets on GitHub). In this article, we will refer to the documentation quite often just to avoid re-explaining things.

CUBA Application Architecture

The CUBA application consists of the following modules (this can also be seen in the diagram above).

Global — This contains entities mapped to a database. CUBA views and service interfaces can be used in other modules.

Core — All service implementations that work with the application's database and implement business logic should be placed here. Please note that the Core classes are not available in other modules. This was done on purpose to provide a separate deploy of the Core and GUI modules to different servers for better scalability. To inject services from the Core module to other modules, you should use interfaces declared in the Global module.

GUI, Web, Desktop, Portal — These modules contain GUI-related classes (controllers, listeners, etc.) that are responsible for UI events and processing. You can create your own custom REST controllers here to complement out-of-the-box REST API that CUBA generates for you.

For a better developer's performance, CUBA has Studio. This is a nice, small GUI used to create and register entities that will change all the configs for you, as well as help with creating code stubs for services and has a WYSIWYG editor for GUI forms.

So, an application based on the CUBA Platform consists of two (or more) separate modules — Core and GUI(s) that can be deployed separately, and a cross-cutting Global module. Let's have a look at CUBA's Global and Core modules and their contents in greater detail.

Global Module

Entity Model

The Entity model in a CUBA application should be familiar to any developer who worked with JPA-compatible ORM Framework and Spring. It is just classes that are annotated with  @Table@Entity , etc. and registered in the persistence.xml file.

In the entity model for the Pet Clinic application, you can reuse the code from the Spring version, but you need to remember a couple of things:

  1. CUBA introduces a "namespace" for every application component created with this platform to prevent names that clash between different components. That's why there is a "petclinic$" prefix for every entity name.
  2. It is recommended to use a @NamePattern  annotation for entities to get a meaningful instance representation in UI.

The question is — what does CUBA gives us, apart from prefixes and declarative entity "stringified" representation? These additional features include:

  1. Base classes that support ID generation functionality: from Integer IDs to UUIDs
  2. A set of helpful (but optional) interfaces:
    • Versioned — to support entity versions.
    • SoftDelete — to support "soft"or "logical" delete for an entity.
    • Updatable — adds fields for entity update logging.
    • Creatable — adds fields for entity creation logging. You can read more about these interfaces in the documentation.
  3. Database schema creation and update scripts can be generated by the CUBA Studio automatically.

During the application development, I just copied the existing entities models from the Spring version and added the CUBA-specific features mentioned above, deleting the BaseEntity class from the reference version of the application.

Views

CUBA's "views" concept may be confusing, but it is quite easy to explain. A View is a declarative way to specify which data (attributes and nested instances/collections) should be extracted.

Let's assume that you need to fetch owners and their pets or vets with their specialties for displaying dependent entities along with "parent" data on the same UI screen. In case of pure Spring implementation, you need to define the JPA joins:

@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
public Owner findById(@Param("id") int id);


Or, you need to define the proper EAGER/LAZY fetch types to get dependent collections for an entity within a transaction context.

@ManyToMany(fetch = FetchType.EAGER) 
@JoinTable(name = "vet_specialties", 
joinColumns = @JoinColumn(name = "vet_id"),
inverseJoinColumns = @JoinColumn(name = "specialty_id")) 
private Set specialties;


In the CUBA version, you can use EntityManager and JPQL or views and  DataManager:

1. Define a view that specifies what we want to extract:

<view class="com.haulmont.petclinic.entity.Vet" extends="_minimal" name="vet-specialities-view">
  <property name="specialities" view="_minimal"></property>
</view>


2. Use the DataManager bean to get this data:

public Collection<Vet> findAll() {
   return dataManager.load(Vet.class)
           .query("select v from cubapetclinic$Vet v")
           .view("vet-specialities-view")
           .list();
}


You can create different views for different tasks by choosing which attributes you want to get, whether or not to fetch collections, and define how deep your object tree will be. To learn more about this, here is a great post about views from Mario David's blog.

In the Pet Clinic application, we defined six views for different cases. Those views are used mostly in UI forms, and one of them is used for fetching data in the service. This is demonstrated in the code snippet shown above.

Services Interfaces

Since Global module is a cross-cutting module of a CUBA-based application, you should define service interfaces in it to be able to use services in other modules by using Spring injections. All you need to do is to register services in the web-spring.xml file in the Web module. The CUBA platform creates proxies in application modules for transparent entities serialization and deserialization, using this Spring config XML file. This feature lets us call services that are implemented in Core from other modules, even in case of distributed deploy with a minimum of additional efforts.

So, in terms of Entity model development with CUBA, it is all the same as it is in pure Spring, but you shouldn't care about ID generation and retrieval entity's ID after insert, and you don't need to create extra code for entity versioning, soft delete, and entity changelog. Also, you can save some time on creating views instead of JPA joins.

Core Module

The Core module contains service implementations for interfaces declared in Global module. Every service in CUBA application is usually annotated with  @Service , but you can use all available Spring annotations to deal with beans. However, there are a couple of limitations due to CUBA's architecture:

  • You need to annotate your service with the @Service ,  if you want it to be exposed in the Web module.
  • It is recommended that you give a name for your service to avoid bean clash from different add-ons.

Other than that, your Core module codebase is a "pure" Spring-based backend application. You can fetch data from data store(s) and invoke 3rd party Web services as you did previously with Spring. The only significant difference is interaction with the database.

EntityManager and DataManager

The platform uses its own EntityManager that delegates part of its functionality to an actual  javax.persistence.EntityManager  instance. CUBA's EntityManager provides mostly low-level entity operations and does not support security features. In most cases, it is recommended to use the DataManager that gives extra functionality:

  1. Row-level and attribute-level security support.
  2. CUBA's entity views usage for fetching data.
  3. Dynamic attributes.

To learn more about DataManager  and EntityManager ,  you can find more in this documentation. Please note that you don't need to use those beans directly in GUI; there are Datasources for this.

Talking about PetClinic, I (almost) didn't write a lot of code in the Core module, since there was no complex business logic there.

Features From Spring Pet Clinic in CUBA

In the previous section, there was a list of extra functionality in the Spring-based Pet Clinic application; the same features are available in CUBA.

Caching

CUBA provides entity and query caches as built-in features. Those caches are described in details in this documentation and should be considered first, since they support all platform features like distributed deploy. In addition to this, you can enable caching by using Spring's @Cacheable and enabling caching as described in Spring's documentation.

Validator

CUBA uses the BeanValidation as a standard validation engine. If built-in validation is not enough, you can define the custom validation code. And, there is always an option to verify data in the UI by defining Validator class as described here.

Formatter

The CUBA platform provides several formatters for the GUI components, but you can define your own formatter, apart from the standard formatters. For default entity representation, the @NamePattern annotation is used.

I18n

The CUBA platform supports internationalization in the same way as other Java applications. This is done by using message.properties  files, so there is nothing new here.

Transaction management

The CUBA platform provides the following transaction management options:

  • Familiar Spring's @Transactional annotation
  • CUBA's Persistence interface can be used if you need a fine-grained transaction management in complex cases.

When I was developing the Pet Clinic, I thought about transactions only once. During development of the form that allowed editing owners, pets and adding visits on the same screen. I needed to understand when to commit a transaction and refresh a UI to display data in a consistent way.

Pet Clinic in Just a Few Hours, Really!

I was able to create an application with the same functionality as the Spring's Pet Clinic with a "standard" CUBA UI in less than a day. I wouldn't say I'm an expert in CUBA (it's been just several weeks since I started), but I have a long history of using Spring. Let's have a look at a CUBA-based app with Spring architecture in mind:

Domain Model — These are entities in the Global module. Creating an entity model was a well-known routine. Kudos to the BaseIntegerIdEntity  class for saving some time on ID generation.

Repository Layer — I didn't need repositories — not even an interface. I just created some views using CUBA Studio GUI. With this tool, I didn't need to write XML in configs. 

Service Layer — In our application, we have only two services to export vets in JSON and XML format with the cacheable result. I put interfaces to Global and implementations to Core as per documentation. Then, it was just a "normal" development, apart from reading about  DataManager  a bit to get familiar with its API.

Controllers Layer — The CUBA Pet Clinic contains only one custom REST controller for JSON and XML feed in Web module. No surprises here, it was just a Spring controller with familiar annotations. 

Application GUI — Creating "standard" CRUD forms with CUBA Studio was a breeze. 
I didn't think about passing entities to Web UI and form submissions — there are no controllers and repositories. CUBA provided me a proper grid and a component for data filtering, so no more parsing query strings and fuss with Pageable. I spent most of the time implementing proper UI flow, renderers, and applying styles.

My personal experience is shown in the table:

Easy to Understand and Develop Need to Read Documentation
Entities Entity Modelling
DB Creation Scripts
Standard base classes
Additional features for soft delete, etc.
Repositories EntityManager
Views
DataManager
Services Beans management
Transaction management
Security and user management
Persistence interface
Controllers Custom REST Controllers
Request URL mapping
Service methods publishing
UI Standard forms

UI customization


Obviously, the Pet Clinic application does not use all CUBA features. The full list can be found on the site where you will see other common tasks that can be solved by the platform.

My personal opinion is that CUBA simplifies backend implementation and does great if you use its "standard" GUI. Even if you need a fancy UI, CUBA will save you time on the backend development, for sure.

So Many Pros! What About the Cons?

Well, there are some things that I would like to mention in this section. These things are not game-changing, however, I found them quite unwanted at the first steps of getting familiar with CUBA.

  • In the introduction section, I was told that the CUBA platform comes with its own IDE that simplifies project creation and management. Sometimes, switching between Studio and your IDE might be a bit irritating, but we're redeveloping it now, so Studio will transform into IDEA's plugin soon.
  • In CUBA, we use a bit more XML config files than in typical Spring Boot application because of more services provided by the platform.
  • There are no "friendly" URLs for each of the application's UI form — yet. You can access screens directly using screen links, but they are not very "human-readable."
  • You have to deal with CUBA's DataManager and EntityManager and learn their API rather than Spring JPA or JDBC (but they can still use them if needed).
  • You will achieve the best development performance with CUBA when using relational databases. As for NoSQL, CUBA performs as well as Spring does; it requires the same amount of code.

Conclusion

If you have a task for implementing data-centric intranet application that uses RDBMS as a data storage, you may want to try CUBA platform as a basis because:

  1. CUBA is transparent. The source code is available, and you can debug everything.
  2. CUBA is flexible (up to some limit). You can inherit and inject your own beans instead of standard CUBA beans, publish custom REST API, and use your own UI framework to interact with the user.
  3. CUBA is Spring. 80 percent of your back-end code will be a pure Spring application.
  4. You can start fast. An application is ready for use right after the first entity and UI screen creation.
  5. A lot of the routine work is done for you.

So, by using CUBA, you will save some time on routine tasks for the real fun dealing with complex business-related algorithms and non-trivial integrations with other applications.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
java ,cuba platform ,springframework ,rad ,tutorial ,spring boot ,frameworks

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}