JAKARTA EE FOR JUNIOR DEVELOPERS - Lesson 12 Creating Events

 

INTRODUCTION

In this Jakarta EE for Junior Developers lesson, we will trigger an event in the final step of the employee registration process by sending a JSON message to a message broker.

EVENTS

According to the Jakarta EE CDI specification (https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#events), the Event<> mechanism is useful for loosely coupled communication between components. It allows different parts of an application to communicate without direct dependencies, making the system more flexible, scalable, and maintainable.

Instead of one component directly calling another, it can fire an event, and any interested component can observe it. This means producers don’t need to know who is consuming the event.

Also, new event listeners can be added without modifying existing code. Different parts of the system can respond to the same event independently.

Finally, with the use of CDI qualifiers we can filter events dynamically.

INITIATING EVENTS

To fire an event, you inject an instance of Event<T> where T is the event type. The event type is a class that we need to create and in our case it will be related to employee. So, let's create a new class with the name RegistrationInfo which will hold user registration information.

RegistrationInfo.java


package com.mycompany.beans;

import com.mycompany.jakartaee.entities.Employee;
import java.io.Serializable;


public class RegistrationInfo implements Serializable {

    private Employee employee;

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

}

 

Now, we can inject an instance of Event<RegistrationInfo> in the EmployeeInfoController class, which will allow us to fire events. In other words, we will be able to fire events of type RegistrationInfo, which other parts of the application can observe.

 @Inject
    private Event<RegistrationInfo> registrationEvent;

We can fire an event using registrationEvent.fire(new RegistrationInfo(...)), triggering any observer methods listening for RegistrationInfo.

 RegistrationInfo registrationInfo = new RegistrationInfo();
        registrationInfo.setEmployee(employee);
        registrationEvent.fire(registrationInfo);


The complete code of the EmployeeInfoController class is the following:

EmployeeInfoController.java


package com.mycompany.beans;

import com.mycompany.jakartaee.entities.Department;
import com.mycompany.jakartaee.entities.Employee;
import com.mycompany.jakartaee.entities.Location;
import com.mycompany.services.DepartmentAssignment;
import com.mycompany.services.ITAssignment;
import jakarta.annotation.Resource;
import jakarta.enterprise.context.Conversation;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.event.Event;
import jakarta.enterprise.inject.Default;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.SystemException;
import jakarta.transaction.UserTransaction;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

@Named
@RequestScoped
public class EmployeeInfoController implements Serializable {
   
     @PersistenceContext
    private EntityManager em;

    @Resource
    private UserTransaction userTransaction;
   
    @Inject
    private Conversation conversation;
   
    @Inject
    EmployeeInfo employeeInfo;
   
    @Inject
    private Event<RegistrationInfo> registrationEvent;
   
     private static final Logger logger =
             Logger.getLogger(EmployeeInfoController.class.getName());
   
    @Inject
    @Default
    @ITAssignment
    DepartmentAssignment departmentAssignment;

    public String employeeInfoEntry() {
        conversation.begin();
        System.out.println(employeeInfo);
        return "personal";
    }

    public String employeePersonalInfo() {
        System.out.println(employeeInfo);
        return "address";
    }
   
    public String employeePersonalBackInfo() {
        System.out.println(employeeInfo);
        return "personal";
    }

    public String employeeConfirmationPage() throws java.text.ParseException,
            NotSupportedException, SystemException,
            RollbackException, HeuristicMixedException,
            HeuristicRollbackException {
       
       
       
        System.out.println(employeeInfo);
       
         Employee employee = new Employee();
      Department department = new Department();
      Location location = new Location();
     
     
     if ("None".equals(employeeInfo.getDept())) {
            department.setDept_id(departmentAssignment.generateDepartment());
        } else {
            switch (employeeInfo.getDept()) {
                case "HR" ->
                    department.setDept_id(1L);
                case "IT" ->
                    department.setDept_id(2L);
                case "Finance" ->
                    department.setDept_id(3L);
                case "Marketing" ->
                    department.setDept_id(4L);
                default -> {
                }
            }
        }

        employee.setFirstName(employeeInfo.getFirstName());
        employee.setLastName(employeeInfo.getLastName());
        employee.setMonthlySalary(employeeInfo.getMonthlySalary());
        Date dt = null;
        dt = new SimpleDateFormat("yyyy-MM-dd").parse(employeeInfo.getDate());
        employee.setHireDate(dt);
        employee.setEmail(employeeInfo.getEmail());
        employee.setPhoneNumber(employeeInfo.getPhoneNumber());
       
       location.setCity(employeeInfo.getCity());
       location.setPostal_code(employeeInfo.getPostal_code());
       location.setState_province(employeeInfo.getState_province());
       location.setStreet_address(employeeInfo.getStreet_address());

      employee.setAddress(location);
      employee.setDepartment(department);
      System.out.println(employeeInfo.toString());
       try {
            userTransaction.begin();
            em.persist(employee);
            userTransaction.commit();
            logger.log(Level.INFO,
                    "Transaction has been completed with employee id: {0}",
                    employee.getEmployee_id());
        } catch (NotSupportedException
                | SystemException | RollbackException
                | HeuristicMixedException | HeuristicRollbackException
                | SecurityException | IllegalStateException ex) {
            Logger.getLogger(EmployeeInfoController.class.getName())
                    .log(Level.SEVERE, null, ex);
        }
       
        RegistrationInfo registrationInfo = new RegistrationInfo();
        registrationInfo.setEmployee(employee);
        registrationEvent.fire(registrationInfo);
     
        conversation.end();
        return "confirmation";
    }
}


 According to the Jakarta EE CDI Specification (https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#events) A CDI bean can fire an event using Event<T> whereas another CDI bean can listen for that event. The specification states that any method with @Observes annotation and a matching event type will automatically receive the event. The @Observes annotation in Jakarta EE CDI (Contexts and Dependency Injection) is used to mark a method parameter as an observer of events. It allows CDI beans to listen for and respond to events fired elsewhere in the application. In our example we need to create a method that listens for CDI events of type RegistrationInfo. When an event of this type is fired elsewhere in the application, this method will be triggered.

When the method is trigged, it will first convert the RegistrationInfo object to a JSON string with the help of the Jackson Library. Then We will create a producer that can send messages to a JMS queue. Wildfly contains a Message Broker so all we need to do is to create the Queues. At this point just concentrate on the event and not on the actual code related to JMS. We will analyze this to a future lesson.

RegistrationEventListener.java

 

package com.mycompany.beans;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.enterprise.context.SessionScoped;
import jakarta.enterprise.event.Observes;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSContext;
import jakarta.jms.JMSProducer;
import jakarta.jms.Queue;
import java.io.Serializable;


@SessionScoped
public class RegistrationEventListener implements Serializable {
   
        @Resource(lookup = "java:/jms/queue/QueueA")
        private Queue queue;
       
        @Resource(lookup = "java:/JmsXA")
        private ConnectionFactory connectionFactory;

    public void handleNavigationEvent(@Observes RegistrationInfo registrationInfo) throws JsonProcessingException {
       
        ObjectMapper mapper = new ObjectMapper();
        String jsonString = mapper.writeValueAsString(registrationInfo);
       
        try (JMSContext context = connectionFactory.createContext()) {
            JMSProducer producer = context.createProducer();
            producer.send(queue, jsonString);
       
    }
    }
}



WILDFLY CONFIGURATION

 We need to properly configure our environment so it can accept the messages from the event. To get started, we need to create a queue. The easier way is to open the configuration file (standalone-full.xml) and add the new queue configurations.

standalone-full.xml

 We want to be able to visually see the messages stored inside Wildfly. The Web console that Wildfly comes with just shows the number of messages but not the actual content of the message. We will deploy the ActiveMQ Artemis console on the Wildfly to give us that extra feature.

In the same configuration file that you have opened, please add the following two configurations as well.

standalone-full.xml 

 

standalone-full.xml 

 

Also we need to add the Jackson Library dependency to our pom.xml file. 

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.18.2</version>
        </dependency>

Finally, go to the ActiveMQ Artemis site (https://activemq.apache.org/components/artemis-console/), download the Web Console and rename the file to console. Then just place it to the deployment folder of the Wildfly get deployed.

 


We are ready now to deploy and start our application.

 

 

 

 

 

 

 


 

Within the Wildfly Admin console, we can see the number of messages stored inside a Queue.

 http://localhost:9990/console


Using the ActiveMQ Console we get the real message.

http://localhost:8080/console


full-width



full-width

Post a Comment

0 Comments