Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Add the message producers and listeners

You will next add the code required to send and receive messages to the visits service. The message-emulator will send a PetClinicMessageRequest to the visits-requests queue. The visits service will need to listen to this queue and each time a VisitRequest message is submitted, it will create a new Visit for the pet ID referenced in the message. The visits service will also send back a VisitResponse as a confirmation to the visits-confirmations queue. This is the queue the message-emulator is listening to.

Step by step guidance

  1. In the spring-petclinic-visits-service directory, create a new src/main/java/org/springframework/samples/petclinic/visits/entities subdirectory and add a VisitRequest.java class file containing the following code:

    package org.springframework.samples.petclinic.visits.entities;
       
    import java.io.Serializable;
    import java.util.Date;
       
    public class VisitRequest implements Serializable {
        private static final long serialVersionUID = -249974321255677286L;
       
        private Integer requestId;
        private Integer petId;
        private String message;
       
        public VisitRequest() {
        }
       
        public Integer getRequestId() {
            return requestId;
        }
       
        public void setRequestId(Integer id) {
            this.requestId = id;
        }
       
        public Integer getPetId() {
            return petId;
        }
       
        public void setPetId(Integer petId) {
            this.petId = petId;
        }
       
        public String getMessage() {
            return message;
        }
       
        public void setMessage(String message) {
            this.message = message;
        }
    }
    
  2. In the same directory, add a VisitResponse.java class containing the following code:

    package org.springframework.samples.petclinic.visits.entities;
       
    public class VisitResponse {
        Integer requestId;
        Boolean confirmed;
        String reason;
       
        public VisitResponse() {
        }
           
        public VisitResponse(Integer requestId, Boolean confirmed, String reason) {
            this.requestId = requestId;
            this.confirmed = confirmed;
            this.reason = reason;
        }    
       
        public Boolean getConfirmed() {
            return confirmed;
        }
       
        public void setConfirmed(Boolean confirmed) {
            this.confirmed = confirmed;
        }
       
        public String getReason() {
            return reason;
        }
       
        public void setReason(String reason) {
            this.reason = reason;
        }
       
        public Integer getRequestId() {
            return requestId;
        }
       
        public void setRequestId(Integer requestId) {
            this.requestId = requestId;
        }
    }
    
  3. In the spring-petclinic-visits-service directory, create a new src/main/java/org/springframework/samples/petclinic/visits/config subdirectory and add a MessagingConfig.java class file containing the following code:

    package org.springframework.samples.petclinic.visits.config;
       
    import java.util.HashMap;
    import java.util.Map;
       
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
    import org.springframework.jms.support.converter.MessageConverter;
    import org.springframework.samples.petclinic.visits.entities.VisitRequest;
    import org.springframework.samples.petclinic.visits.entities.VisitResponse;
       
    @Configuration
    public class MessagingConfig {
       
        @Bean
        public MessageConverter jackson2Converter() {
            MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
       
            Map<String, Class<?>> typeMappings = new HashMap<String, Class<?>>();
            typeMappings.put("visitRequest", VisitRequest.class);
            typeMappings.put("visitResponse", VisitResponse.class);
            converter.setTypeIdMappings(typeMappings);
            converter.setTypeIdPropertyName("messageType");
            return converter;
        }
    }
    
  4. In the same directory, add a QueueConfig.java class file containing the following code:

    package org.springframework.samples.petclinic.visits.config;
    
    import org.springframework.beans.factory.annotation.Value;
    
    public class QueueConfig {
        @Value("${spring.jms.queue.visits-requests:visits-requests}")
        private String visitsRequestsQueue;
    
        public String getVisitsRequestsQueue() {
            return visitsRequestsQueue;
        }   
    }
    
  5. In the spring-petclinic-visits-service directory, create a new src/main/java/org/springframework/samples/petclinic/visits/service subdirectory and add a VisitsReceiver.java class file containing the following code:

    package org.springframework.samples.petclinic.visits.service;
       
    import java.util.Date;
       
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.jms.annotation.JmsListener;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.samples.petclinic.visits.entities.VisitRequest;
    import org.springframework.samples.petclinic.visits.entities.VisitResponse;
    import org.springframework.samples.petclinic.visits.model.Visit;
    import org.springframework.samples.petclinic.visits.model.VisitRepository;
    import org.springframework.stereotype.Component;
       
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
       
    @Component
    @Slf4j
    @RequiredArgsConstructor
    public class VisitsReceiver {
        private final VisitRepository visitsRepository;
           
        private final JmsTemplate jmsTemplate;
       
        @JmsListener(destination = "visits-requests")
        void receiveVisitRequests(VisitRequest visitRequest) {
            log.info("Received message: {}", visitRequest.getMessage());
            try {
                Visit visit = new Visit(null, new Date(), visitRequest.getMessage(),
                        visitRequest.getPetId());
                visitsRepository.save(visit);
                jmsTemplate.convertAndSend("visits-confirmations", new VisitResponse(visitRequest.getRequestId(), true, "Your visit request has been accepted"));
            } catch (Exception ex) {
                log.error("Error saving visit: {}", ex.getMessage());
                jmsTemplate.convertAndSend("visits-confirmations", new VisitResponse(visitRequest.getRequestId(), false, ex.getMessage()));
            }
        }
       
    }
    

    This VisitsReceiver service is listening to the visits-requests queue. Each time a message is present on the queue, it will dequeue this message and save a new Visit in the database. In the next step, you will verify it by having it sent a confirmation message to the visits-confirmations queue.

  6. Rebuild the spring-petclinic-visits-service microservice

    cd ..
    mvn clean package -DskipTests -rf :spring-petclinic-visits-service
    
  7. Navigate to the staging-acr directory, copy the jar file of the visit-service and rebuild the container.

    cd staging-acr
    rm spring-petclinic-visits-service-$VERSION.jar
       
    cp ../spring-petclinic-visits-service/target/spring-petclinic-visits-service-$VERSION.jar spring-petclinic-visits-service-$VERSION.jar
    docker build -t $MYACR.azurecr.io/spring-petclinic-visits-service:$VERSION \
        --build-arg ARTIFACT_NAME=spring-petclinic-visits-service-$VERSION.jar \
        --build-arg APP_PORT=8080 \
        --build-arg AI_JAR=ai.jar \
        .
    
    docker push $MYACR.azurecr.io/spring-petclinic-visits-service:$VERSION
    
  8. Navigate to the kubernetes folder and replace the spring-petclinic-visits-service.yml file with the contents of the spring-petclinic-visits-service.yml file. You can again curl the updates for these files and then fill out the correct container registry name.

    cd ../kubernetes
    curl -o spring-petclinic-visits-service.yml https://raw.githubusercontent.com/Azure-Samples/java-microservices-aks-lab/main/docs/05_lab_messaging/spring-petclinic-visits-service.yml
    
    IMAGE=${MYACR}.azurecr.io/spring-petclinic-visits-service:$VERSION
    sed -i "s|#image#|$IMAGE|g" spring-petclinic-visits-service.yml
    
  9. Inspect the new contents of this file. The file has:

    • An additional SPRING_JMS_SERVICEBUS_CONNECTIONSTRING environment variable mapped to the sbsecret on lines 47 to 51.
    • An additional volumes definition on lines 19 to 25.
    • An additional volumeMounts definition on lines 52 to 55.
  10. Reapply the yaml definition on the AKS cluster.

    kubectl apply -f spring-petclinic-visits-service.yml
    
  11. Double check that the visits-service started up correctly.

    kubectl get pods -w
    
  12. To validate the resulting functionality, in the Azure Portal, navigate back to the page of the visits-requests queue of the Service Bus namespace you deployed earlier in this lab.

  13. On the Overview page of the visits-requests queue, verify that there are no active messages.

  14. In the web browser window, open another tab and navigate to the public endpoint of the api-gateway service.

  15. On the Welcome to Petclinic page, select Owners and, in the drop-down menu, select All.

  16. In the list of owners, select the first entry (George Franklin).

  17. On the Owner Information page, in the Pets and Visits section, verify the presence of an entry representing the message you submitted earlier in this lab.