:toc: macro toc::[] :idprefix: :idseparator: - ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: :important-caption: :heavy_exclamation_mark: :caution-caption: :fire: :warning-caption: :warning: endif::[] = Components image::images/devon4j/4.Components/architecture.png[Architecture, 700] When working with _devon4j_ the recommended approach for designing an applications is _Component Oriented Design_. Each component will represent a significant part (or feature) of our application related to _CRUD_ operations. Internally, the components will be divided into three layers (`service`, `logic`, and `dataaccess`) and will communicate in two directions: service with database or -- in the _logic_ layer -- a component with another component. == Principles The benefits of dividing our application into components are: - https://en.wikipedia.org/wiki/Separation_of_concerns[separation of concerns] - https://en.wikipedia.org/wiki/Reusability[reusability] - to avoid https://en.wikipedia.org/wiki/Redundant_code[redundant code] - https://en.wikipedia.org/wiki/Information_hiding[information hiding] - self contained, descriptive and stable component https://en.wikipedia.org/wiki/Application_programming_interface[APIs] - https://en.wikipedia.org/wiki/Data_consistency[data consistency] (a component is responsible for its data and changes to this data shall only happen via the component) === Component Structure A component consists of three packages, which correspond to the three layers defined by the _devon4j_ architecture: `service`, `logic` and `dataaccess`. image::images/devon4j/4.Components/layers.png[Component Layers, 300] * _Service_ layer: exposes the REST API to exchange information with client applications * _Logic_ layer: in charge of hosting the business logic of the application * _Data Access_ layer: communicates with the database Apart from that, most components will have a fourth package -- _common_ -- to store shared elements, which will be used by all layers of the component. It will contain common _interfaces_, _constants_, _exceptions_ or _enumerations_. === Component Core As we mentioned earlier, each component will be related to a functionality. This functionality will be represented in code by an _Entity_ that defines all the properties needed to wrap the logic of that feature. This _Entity_ represents the "core" of the component and will be located in the `dataaccess.api` package. The naming convention for these entities in _devon4j_ is: ---- [Target]Entity ---- "Target" should match the name of the related table in the database -- although this is not mandatory. Basically, each _Entity_ is a https://en.wikipedia.org/wiki/Plain_old_Java_object[POJO] (plain old Java object) that will be mapped to a table in the database and represent each column via a suitable property. .An entity and its corresponding table in the DB (taken from another application). [caption="Example: "] image::images/devon4j/4.Components/example_entity.png[Example Entity, 800] == Create your Components We are now going to create our first app components. Our example application needs to provide two basic functionalities: * register a user (returning an access code) * show registered queue members To accomplish this we are going to work with three entities; _Visitor_, _Queue_ and `_AccessCode_`: image::images/devon4j/4.Components/jtq_entities.png[JumpTheQueue Entities, 750] The components will be defined as follows: [caption=""] |=== |Visitor | Access Code | Daily Queue |`username` |`ticketNumber` |`name` |`name` |`creationTime` |`logo` |`password` |`startTime` |`password` |`phoneNumber` |`endTime` |`currentNumber` |`acceptedCommercial` |-- |`attentionTime` |`acceptedTerms` |-- |`minAttentionTime` |`userType` |-- |`active` |-- |-- |`customers` |=== In addition, we will have to represent two relationships: 1. The https://en.wikipedia.org/wiki/One-to-one_(data_model)[one to one] relation between _Visitor_ and _Access Code_. 2. The https://en.wikipedia.org/wiki/One-to-many_(data_model)[one to many] relation between _Daily Queue_ and _Access Code_. Now is the moment to decide about the components of our app. The low complexity of the functionality would allow us to create only one component for managing all entities. In order to clarify the example we are going to create three managing components however; one for _Visitor_, one for _Access Code_ and one for _Daily Queue_. [NOTE] ==== If you feel more comfortable managing all the entities in a single component, you could also do it this way. The result will be the same, the only difference will be the structure of some elements and the distribution of code inside the packages. ==== === The Database Projects created with the _devon4j_ archetype already contain a pre-defined database schema, which we can use as a basis to create our own. We are going to utilize the http://www.h2database.com/html/main.html[H2 Database Engine], because our generated _devon4j_ application uses it by default. There are four pre-defined database schemas: ``` jtqj-core/src/main/resources/db/type/h2/V0001__Create_Sequence.sql jtqj-core/src/main/resources/db/type/h2/V0002__Create_RevInfo.sql jtqj-core/src/main/resources/db/type/h2/V0003__Create_BinaryObject.sql jtqj-core/src/main/resources/db/migration/1.0/V0004__Add_blob_data.sql ``` [NOTE] ==== May be you need to install some SQL editor from eclipse marketplace, or use an external one. ==== ==== _Visitor_ Table We are going to create our own table for _Visitor(s)_ by right-clicking the folder `/jtqj-core/src/main/resources/db/migration/1.0` and selecting `New > File`. Following the naming scheme we are going to call it: ``` V0005__Create_Visitor.sql ``` A visitor will provide: `username`, `name`, `password`, `phoneNumber`, `acceptedCommercial` and `acceptedTerms` in order to obtain an _Access Code_. We need to represent this data in our table: [source, sql] ---- create table Visitor( id BIGINT NOT NULL AUTO_INCREMENT, modificationCounter INTEGER NOT NULL, username VARCHAR(255), name VARCHAR(255), password VARCHAR(255), phoneNumber VARCHAR(255), acceptedCommercial BOOL DEFAULT '0', acceptedTerms BOOL NOT NULL DEFAULT '0', userType BOOL DEFAULT '0', CONSTRAINT PK_Visitor PRIMARY KEY(id) ); ---- * `id`: The `ID` of each visitor. * `modificationCounter`: Used internally by https://en.wikipedia.org/wiki/Java_Persistence_API[JPA] to take care of https://en.wikipedia.org/wiki/Optimistic_concurrency_control[optimistic locking] for us. * `username`: The visitors email address. * `name`: The visitors name. * `password`: The visitors password. * `phoneNumber`: The visitors phone number. * `acceptedCommercial`: A `boolean` to denote if the visitor has the accepted commercial agreements. * `acceptedTerms`: A `boolean` to denote if the visitor has accepted the terms & conditions. * `userType`: Denotes the type of user. ==== _Daily Queue_ Table In a second table we will represent the _Daily Queue_, which will contain `name`, `logo`, `currentNumber`, `attentionTime`, `minAttentionTime`, `active` and `customers`. This table will be created in `/jtqj-core/src/main/resources/db/type/h2`, and is called: ``` V0006__Create_Queue.sql ``` It will contain the following declarations: [source, sql] ---- create table DailyQueue( id BIGINT NOT NULL AUTO_INCREMENT, modificationCounter INTEGER NOT NULL, name VARCHAR(255), logo VARCHAR(255), currentNumber VARCHAR(255), attentionTime TIMESTAMP, minAttentionTime TIMESTAMP NOT NULL DEFAULT '60000', active BOOL NOT NULL DEFAULT '1', customers INTEGER NOT NULL DEFAULT '0', CONSTRAINT PK_DailyQueue PRIMARY KEY(id) ); ---- * `id`: The `ID` of each queue. * `modificationCounter`: Used internally by https://en.wikipedia.org/wiki/Java_Persistence_API[JPA] to take care of https://en.wikipedia.org/wiki/Optimistic_concurrency_control[optimistic locking] for us. * `name`: The queues name. * `logo`: The queues logo. * `currentNumber`: the queue's number being attended. * `attentionTime`: Average time required to attend a visitor. * `minAttentionTime`: Minimum time required to attend a visitor, set by default. * `active`: A `boolean` to denote if the queue is active. * `customer`: The queues total number of customers. ==== _Access Code_ Table The third table will represent the _Access Code_ and contain the `ticketNumber`, `creationTime`, `startTime` and `endTime`. This table will be created in `/jtqj-core/src/main/resources/db/type/h2`, and is called: ``` V0007__Create_Access_Code.sql ``` It will contain the following declarations: [source, sql] ---- CREATE TABLE AccessCode( id BIGINT NOT NULL AUTO_INCREMENT, modificationCounter INTEGER NOT NULL, ticketNumber VARCHAR(5), creationTime TIMESTAMP, startTime TIMESTAMP, endTime TIMESTAMP, idVisitor BIGINT NOT NULL, idQueue BIGINT NOT NULL, CONSTRAINT PK_AccessCode PRIMARY KEY(id), CONSTRAINT FK_AccessCode_idVisitor FOREIGN KEY(idVisitor) REFERENCES Visitor(id), CONSTRAINT FK_AccessCode_idQueue FOREIGN KEY(idQueue) REFERENCES DailyQueue(id) ); ---- * `id`: The `ID` of each code. * `modificationCounter`: Used internally by https://en.wikipedia.org/wiki/Java_Persistence_API[JPA] to take care of https://en.wikipedia.org/wiki/Optimistic_concurrency_control[optimistic locking] for us. * `ticketNumber`: The number of the ticket for a queue. * `creationTime`: The date and time of creation. * `startTime`: The date and time, from which the code is valid. * `endTime`: The date and time, when the code expires. * `idVisitor`: The relation with the _Visitor_ table. * `idQueue`: The relation with the `_DailyQueue_` table. ==== Mock Data Finally we are going to provide a certain amount of mock data, which will be available right from the start in our application. Create a new SQL script in `/jtqj-core/src/main/resources/db/migration/1.0/`, called: ``` V0008__Master_data.sql ``` Copy and paste the following data into it: [source,sql] ---- INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (0, 1, 'mike@mail.com', 'test', '1', '123456789', '0', '1', '1'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (1, 1, 'peter@mail.com', 'test', '1', '123456789', '1', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (2, 1, 'pablo@mail.com', 'test', '1', '123456789', '0', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (3, 1, 'test1@mail.com', 'test', '1', '123456789', '0', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (4, 1, 'test2@mail.com', 'test', '1', '123456789', '1', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (5, 1, 'test3@mail.com', 'test', '1', '123456789', '0', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (6, 1, 'test4@mail.com', 'test', '1', '123456789', '0', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (7, 1, 'test5@mail.com', 'test', '1', '123456789', '1', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (8, 1, 'test6@mail.com', 'test', '1', '123456789', '0', '1', '0'); INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (9, 1, 'test7@mail.com', 'test', '1', '123456789', '0', '1', '0'); INSERT INTO DailyQueue (id, modificationCounter, name, logo, currentNumber, attentionTime, minAttentionTime, active, customers) VALUES (1, 1, 'Day2', 'C:/logos/Day1Logo.png', 'Q001', NULL, '1970-01-01 00:01:00', TRUE, 9); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (1, 1, 'Q001', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, 1, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (2, 1, 'Q002', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 2, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (3, 1, 'Q003', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 3, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (4, 1, 'Q004', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 4, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (5, 1, 'Q005', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 5, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (6, 1, 'Q006', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 6, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (7, 1, 'Q007', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 7, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (8, 1, 'Q008', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 8, 1); INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (9, 1, 'Q009', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 9, 1); ---- === The Core of the Components Now that we have defined the database for our entities, we should start creating the code of the related components. We are going to use CobiGen to generate the component structure. That means that -- as already commented -- we can generate all the structure and layers starting from a _core_ element: a simple _Plain Old Java Object_ that represents our _Entity_. So, in order to use CobiGen, we have to create our entities in the expected locations (as you will see in the following section): `.dataaccess.api`. ==== _Visitor_ Component To implement the component we will need to define a `_VisitorEntity_` to connect and manage the data of the _Visitor_ table in the database. The name of this component will be `visitormanagement`, the entity will be called `VisitorEntity`. Right-click on the root folder of the project `/jtqj-core/src/main/java`, select `New > Package` and create the following package: ``` com.devonfw.application.jtqj.visitormanagement.dataaccess.api ``` image::images/devon4j/4.Components/new_package_1.png[New Package Creation Step 1, 500] image::images/devon4j/4.Components/new_package_2.png[New Package Creation Step 2, 500] Now create a new Java class in this package and call it `VisitorEntity`: image::images/devon4j/4.Components/new_class.png[New Class Creation, 500] We are going to need fields, which represent the data model, so our entity should contain the following code: [source,java] ---- ... private String username; private String name; private String phoneNumber; private String password; private Boolean acceptedCommercial; private Boolean acceptedTerms; private Boolean userType; ... ---- [NOTE] ==== We are not adding `id` or `modificationCounter`, because CobiGen will generate these fields for us. ==== Now we need to declare our entity as a `JPA` entity with the `@Entity` annotation (`javax.persistence.Entity`) at class level. To map the entity to the database table, we will use the `@Table` annotation (`javax.persistence.Table`) defining the `name` of our already created _Visitor_ table (also at class level): [source, java] ---- ... @Entity @Table(name = "Visitor") public class VisitorEntity { ... ---- Now we have to declare the _getter_ and _setter_ methods for the fields of our entity. We can do this manually or automatically generate them using Eclipse: image::images/devon4j/4.Components/getter_setter.png[Generating Getter and Setter Methods with Eclipse] The resulting implementation of our `_VisitorEntity_` class should now look like this: [source,java] ---- package com.devonfw.application.jtqj.visitormanagement.dataaccess.api; import javax.persistence.Entity; import javax.persistence.Table; @Entity @Table(name = "Visitor") public class VisitorEntity { private String username; private String name; private String phoneNumber; private String password; private Boolean acceptedCommercial; private Boolean acceptedTerms; private Boolean userType; /** * @return the username */ public String getUsername() { return username; } /** * @param username the username to set */ public void setUsername(String username) { this.username = username; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the phoneNumber */ public String getPhoneNumber() { return phoneNumber; } /** * @param phoneNumber the phoneNumber to set */ public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * @return the acceptedCommercial */ public Boolean getAcceptedCommercial() { return acceptedCommercial; } /** * @param acceptedCommercial the acceptedCommercial to set */ public void setAcceptedCommercial(Boolean acceptedCommercial) { this.acceptedCommercial = acceptedCommercial; } /** * @return the acceptedTerms */ public Boolean getAcceptedTerms() { return acceptedTerms; } /** * @param acceptedTerms the acceptedTerms to set */ public void setAcceptedTerms(Boolean acceptedTerms) { this.acceptedTerms = acceptedTerms; } /** * @return the userType */ public Boolean getUserType() { return userType; } /** * @param userType the userType to set */ public void setUserType(Boolean userType) { this.userType = userType; } } ---- ==== `_AccessCode_` component We are going to repeat the same process for the `_AccessCode_` component. Create these packages in `/jtqj-core/src/main/java`: ``` com.devonfw.application.jtqj.accesscodemanagement.dataaccess.api ``` \... and create a class called `AccessCodeEntity` inside of them. + We will end up with the following structure: image::images/devon4j/4.Components/accesscode_entity.png[`AccessCode` Entity, 250] The contents of `_AccessCodeEntity_` before using CobiGen will be: [source,java] ---- package com.devonfw.application.jtqj.accesscodemanagement.dataaccess.api; import java.sql.Timestamp; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.validation.constraints.Size; import com.devonfw.application.jtqj.visitormanagement.dataaccess.api.VisitorEntity; @Entity @Table(name = "AccessCode") public class AccessCodeEntity { @Size(min = 2, max = 5) private String ticketNumber; @Temporal(TemporalType.TIMESTAMP) private Timestamp creationTime; @Temporal(TemporalType.TIMESTAMP) private Timestamp startTime; @Temporal(TemporalType.TIMESTAMP) private Timestamp endTime; private VisitorEntity visitor; private QueueEntity queue; /** * @return the ticketNumber */ public String getTicketNumber() { return ticketNumber; } /** * @param ticketNumber the ticketNumber to set */ public void setTicketNumber(String ticketNumber) { this.ticketNumber = ticketNumber; } /** * @return the creationTime */ public Timestamp getCreationTime() { return creationTime; } /** * @param creationTime the creationTime to set */ public void setCreationTime(Timestamp creationTime) { this.creationTime = creationTime; } /** * @return the startTime */ public Timestamp getStartTime() { return startTime; } /** * @param startTime the startTime to set */ public void setStartTime(Timestamp startTime) { this.startTime = startTime; } /** * @return the endTime */ public Timestamp getEndTime() { return endTime; } /** * @param endTime the endTime to set */ public void setEndTime(Timestamp endTime) { this.endTime = endTime; } /** * @return the visitor */ @OneToOne(cascade = CascadeType.DETACH, fetch = FetchType.EAGER) @JoinColumn(name = "idVisitor") public VisitorEntity getVisitor() { return visitor; } /** * @param visitor the visitor to set */ public void setVisitor(VisitorEntity visitor) { this.visitor = visitor; } /** * @return the queue */ @ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.EAGER) @JoinColumn(name = "idQueue") public QueueEntity getQueue() { return queue; } /** * @param queue the queue to set */ public void setQueue(QueueEntity queue) { this.queue = queue; } } ---- [WARNING] ==== Eclipse will report some errors related to `QueueEntity`. + These will be resolved, when we create the corresponding class in the next step. ==== ==== _Queue_ Component Finally, we are going to repeat the same process for our last entity `_QueueEntity_` component. Create these packages in `/jtqj-core/src/main/java`: ``` com.devonfw.application.jtqj.queuemanagement.dataaccess.api ``` \... and create a class called `QueueEntity` inside of them. + We will end up with the following structure: image::images/devon4j/4.Components/queue_entity.png[Queue Entity, 250] The contents of `_QueueEntity_` before using CobiGen will be: [source,java] ---- package com.devonfw.application.jtqj.queuemanagement.dataaccess.api; import java.sql.Timestamp; import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @Entity @Table(name = "DailyQueue") public class QueueEntity { private String name; private String logo; private String currentNumber; @Temporal(TemporalType.TIMESTAMP) private Timestamp attentionTime; @Temporal(TemporalType.TIMESTAMP) private Timestamp minAttentionTime; private Boolean active; private int customers; /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the logo */ public String getLogo() { return logo; } /** * @param logo the logo to set */ public void setLogo(String logo) { this.logo = logo; } /** * @return the currentNumber */ public String getCurrentNumber() { return currentNumber; } /** * @param currentNumber the currentNumber to set */ public void setCurrentNumber(String currentNumber) { this.currentNumber = currentNumber; } /** * @return the attentionTime */ public Timestamp getAttentionTime() { return attentionTime; } /** * @param attentionTime the attentionTime to set */ public void setAttentionTime(Timestamp attentionTime) { this.attentionTime = attentionTime; } /** * @return the minAttentionTime */ public Timestamp getMinAttentionTime() { return minAttentionTime; } /** * @param minAttentionTime the minAttentionTime to set */ public void setMinAttentionTime(Timestamp minAttentionTime) { this.minAttentionTime = minAttentionTime; } /** * @return the active */ public Boolean getActive() { return active; } /** * @param active the active to set */ public void setActive(Boolean active) { this.active = active; } /** * @return the customers */ public int getCustomers() { return customers; } /** * @param customers the customers to set */ public void setCustomers(int customers) { this.customers = customers; } } ---- Now we have finished preparing the _core_ of our components and can start using CobiGen to generate the remaining structure (services, layers, DAOs, ...). [IMPORTANT] ==== Now we can resolve the compilation errors related to `QueueEntity` in the `AccessCodeEntity.java` by applying the suggestions of the IDE. To do this, open the offending file, click the first red light bulb on the left border of the editor and select `Import 'QueueEntity' (com.devonfw. ...)`. Or just manually add this line to your import statements: ``` import com.devonfw.application.jtqj.queuemanagement.dataaccess.api.QueueEntity; ``` ==== === The Component Structure (using CobiGen) Once we are finished creating the _core_ of our components we could continue to create the structure and all elements manually, but we are going to use CobiGen for these tasks, since we can save a significant amount of time and effort this way. First however, we need to make sure that the CobiGen plugin is installed in our Eclipse instance: image::images/devon4j/4.Components/cobigen_plugin_check.png[CobiGen Plugin Check, 550] If you don't see this option in the dropdown menu, close Eclipse (remember to save all your progress) and in the `jump-the-queue` folder right-click to `Open a Devon `CMD` shell here`. Now enter and execute: ---- devon eclipse add-plugin cobigen ---- \... and re-open Eclipse via the `eclipse-main.bat` script. ==== CobiGen Health Check When using CobiGen for the first time it's recommended to check the health of the tool. + To do so, right-click one of our entities and select `CobiGen > Health Check...`. image::images/devon4j/4.Components/cobigen_health_1.png[CobiGen Health Check 1, 550] The next dialogs will show us if there are outdated templates. In that case just click the "Update" button. You can also run an _Advanced Health Check_ to see exactly which CobiGen templates are available for this project. image::images/devon4j/4.Components/cobigen_health_2.png[CobiGen Health Check 2, 550] image::images/devon4j/4.Components/cobigen_health_3.png[CobiGen Health Check 3, 400] In case you receive an error like this: image::images/devon4j/4.Components/templates_not_found.png[CobiGen Health Check 3, 400] You need to force download of templates as in the following image: image::images/devon4j/4.Components/adapt-templates.png[CobiGen Health Check 3, 550] Now the templates should be downloaded, and you will see a new folder in the workspace: image::images/devon4j/4.Components/cobigen-folder.png[CobiGen Health Check 3, 400] ==== _Queue_ Component Structure (Entity without Relations) In order to create the whole structure of a component with CobiGen we only need to right-click our component core entity (`_QueueEntity_`) and select `CobiGen > Generate`. image::images/devon4j/4.Components/cobigen1.png[CobiGen Generate, 550] Now we'll get to choose which packages we want to generate with the tool. To get the needed functionalities for our component we are going to select *all* of the following packages *at the same time*: image::images/devon4j/4.Components/cobigen3_allpackages.png[CobiGen Package Selection] By default, all files will be selected for generation (which is what we want in this case), but you _could_ also change which files will be generated by clicking `Customize`. For now just click `Finish` and let CobiGen do its work. [NOTE] ==== In detail the selected options do the following: * _CRUD `SpringData` Repository_: Generates the entity repository (that contains the CRUD operations) in the data access layer. image::images/devon4j/4.Components/cobigen2_crud_springdata_repository.png[CobiGen CRUD Spring Data Repository, 650] * _CRUD REST Services_: Generates a complete service layer with CRUD operations for our entity exposed as a REST service. image::images/devon4j/4.Components/cobigen2_crud_rest_services.png[CobiGen CRUD REST Services, 650] * _CRUD `UC` Logic_: Generates the logic layer dividing the implementation in different use cases. image::images/devon4j/4.Components/cobigen2_crud_uc_logic.png[CobiGen CRUD UC Logic, 650] * _Entity Infrastructure_: Creates the entity main interface and edits (by a merge) the current entity to extend the devon classes. image::images/devon4j/4.Components/cobigen2_entity_infrastructure.png[CobiGen Entity Infrastructure, 650] * _TO's_: Generates the related _Transfer Objects_, that we will explain in next chapters of this tutorial. image::images/devon4j/4.Components/cobigen2_to.png[CobiGen Transfer Objects, 650] ==== During the process CobiGen will show a message asking us to review some ambiguous references, which we will get to right away. For now just click `Continue`. image::images/devon4j/4.Components/cobigen4_review_imports.png[CobiGen Import Review] Once CobiGen has finished generating the new classes, we will check for and fix those ambiguous references if we need to introduce manual adjustments. First, we need to adjust manually some imports related to _Timestamp_ in: *`jtqj-core`:* * `queuemanagement.dataaccess.api.repo.QueueRepository` *`jtqj-api`:* * `queuemanagement.common.api.Queue` * `queuemanagement.logic.api.to.QueueEto` * `queuemanagement.logic.api.to.QueueSearchCriteriaTo` We can fix these errors manually by adding `*import* java.sql.Timestamp` to the affected Java files: image::images/devon4j/4.Components/cobigen5_manual_import.png[CobiGen Manual Import] ==== `_AccessCode_` Component Structure (Entity with Relations) We repeat this process on our `_AccessCodeEntity_`, but in this case -- since its an entity with relations -- we are going to have to select different CobiGen options: image::images/devon4j/4.Components/cobigen-accesscode-new.png[CobiGen New `AccessCode`] After CobiGen has finished generating, fix the issues regarding `*import* java.sql.Timestamp` (as you did in the last step) in the following files: *`jtqj-core`:* * `accesscodemanagement.dataaccess.api.repo.AccessCodeRepository` *`jtqj-api`:* * `accesscodemanagement.common.api.AccessCode` * `accesscodemanagement.logic.api.to.AccessCodeEto` * `accesscodemanagement.logic.api.to.AccessCodeSearchCriteriaTo` There will be some compilation errors left. This is because we have some dependencies on _Queue_ and _Visitor_ component elements, that are not created yet. These compilation errors will be fixed in the next steps. image::images/devon4j/4.Components/cobigen6_expected_errors.png[CobiGen Expected Errors] ==== _Visitor_ Component Structure (Entity without Relations) Finally we are going to generate the same classes that we generated for the `_QueueEntity_` component for our `_VisitorEntity_` component: image::images/devon4j/4.Components/cobigen-visitor-new.png[CobiGen New Visitor] Once CobiGen has finished we can fix the rest of the compilation errors related to `VisitorEto` by manually importing the class into: *`jtqj-core`:* * `accesscodemanagement.logic.impl.usecase.UcFindAccessCodeImpl` *`jtqj-api`:* * `accesscodemanagement.logic.api.to.AccessCodeCto` ==== Run the App If all compilation errors are solved run the app (right-click `SpringBootApp.java > Run As > Java Application`). The back-end should launch without errors. *Congratulations!* + You have created your first devon4j components. You should be able to access the login screen via http://localhost:8081/jumpthequeue[localhost:8081/jumpthequeue]. You can login with the username and password "*waiter*". In the next chapter we will show and explain each of the created elements in detail. ''' *Next Chapter*: link:devon4j-layers[devon4j Structure]