Posted on Leave a comment

Events In EJB Tutorial With Quarkus

Using events to pass messages in EJB can be an useful tool to simplify your business logic. Let’s learn how to fire and listen to events in EJB.

Create and listen to simple events

Let’s imagine that we have just opened a store and when someone visit our shop, we will have some fireworks.

So the logic for the event is: When someone come -> have some firework.

Our first step is to create an object named VisitorComesEvent:

package com.datmt.quarkus.events.events;

public class VisitorComesEvent {

}

It’s a simple object, nothing special.

Now, to fire that event, for example at a rest endpoint, we can do like this:

package com.datmt.quarkus.events;

import com.datmt.quarkus.events.events.VisitorComesEvent;

import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/store")
public class Store {

    @Inject
    Event<VisitorComesEvent> visitorComesEvent;
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        visitorComesEvent.fire(new VisitorComesEvent());
        return "Welcome to our shop!";
    }
}

As you can see, when someone visits our shop at /store, the event will be fired.

Now, let’s create a listener to handle the event:

package com.datmt.quarkus.events.events;

import javax.enterprise.event.Observes;

public class VisitorComesObserver {

    public void fireWork(@Observes VisitorComesEvent event) {
        System.out.println("Fireworks!!!!");
    }
}

It’s another simple object. However, the magic here is the annotation @Observer.

When you open the browser and visit /store, the log will says “Fireworks!!!”.

Extending events for specific cases

Now let’s imagine (again) that the store sells toys for kids. When a kid come to the store, in addition to showing the fireworks, we would like to offer our little customers some candies.

Let’s create another event extend the current event called YoungVisitorComes:

package com.datmt.quarkus.events.events;

public class YoungVisitorComesEvent extends VisitorComesEvent{
}

Let’s create another endpoint called /store/young that when someone visits this URL, we will fire YoungVisitorComesEvent instead of VisitorComesEvent:

    @GET
    @Path("/young")
    @Produces(MediaType.TEXT_PLAIN)
    public String hello_youngsters() {
        visitorComesEvent.fire(new YoungVisitorComesEvent());
        return "Welcome to our shop, youngster!";
    }

The VisitorComesObserver now look like this:

package com.datmt.quarkus.events.events;

import javax.enterprise.event.Observes;

public class VisitorComesObserver {

    public void fireWork(@Observes VisitorComesEvent event) {
        System.out.println("Fireworks!!!!");
    }

    public void candies(@Observes YoungVisitorComesEvent event) {
        System.out.println("Here are some candies!");
    }
}

Let’s visit the store as an young customer, we should see Fireworks and also get some candies:

Passing data to the event

Currently, our event objects are quite simple without any properties. Let’s say for example, before showing fireworks and offer candies, we ask the customer’s name so we can print her name on the candies.

Let’s modify YoungVisitorComesEvent like this:

package com.datmt.quarkus.events.events;

public class YoungVisitorComesEvent extends VisitorComesEvent{
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Now, when firing the event, we pass the customer’s name to the event object:

    @GET
    @Path("/young")
    @Produces(MediaType.TEXT_PLAIN)
    public String hello_youngsters() {
        YoungVisitorComesEvent event = new YoungVisitorComesEvent();
        event.setName("Jane");
        visitorComesEvent.fire(event);
        return "Welcome to our shop, youngster!";
    }

Here, I just hard coded the name of the customer. However, you should pass the name dynamically in real life scenario.

Now, in the event handler, we can get the name of the customer like so:

    public void candies(@Observes YoungVisitorComesEvent event) {
        System.out.println("Here are some candies!" + event.getName());
    }

Visit the URL again, we should get the messages as expected:

Posted on Leave a comment

Setting and Getting Custom Properties In Quarkus

Often time, when creating web application, you need to set some values in application settings and later, pull such values to display to users.

One of the most prevalent examples is the application’s name and/or application’s version. I’ll show you how to set such values in the app and later, display them in an example endpoint.

Setting custom properties in application.properties

One place you can set custom properties for the application is in application.properties file. For example, I set two properties as follow:

myapp.author=datmt
myapp.created_year=2021

Now, let’s create an endpoint and display those values.

Getting custom properties in REST endpoints

Setting properties was easy, getting them is no exception. Let’s see how I get those values in the follow snippets:

    @ConfigProperty(name = "myapp.author")
    String author;

    @ConfigProperty(name = "myapp.created_year")
    String createdYear;


    @GET
    @Path("info")
    @Produces(MediaType.TEXT_PLAIN)
    public String info() {

        return "App created by " + author + " in the year " + createdYear;

    }

When accessing the URL in my browser, this is the result:

custom properties set in application properties file displayed.

As you can see, the values I set in application.properties file were displayed correctly in the browser.

Setting default fallback value

There are times you want to set a default value for a specific property in case it is not available. You can do that easily with default in @ConfigProperty.

For example, I’ll try to access a property that didn’t set in application.properties file called myapp.language. In @ConfigProperty, besides setting name, I also set a default value:

    @ConfigProperty(name = "myapp.language", defaultValue = "French")
    String language;

In the info method above, I updated the return string to be like so:

    @GET
    @Path("info")
    @Produces(MediaType.TEXT_PLAIN)
    public String info() {

        return "App created by " + author + " in the year " + createdYear + " in " + language;

    }

When viewing on my browser, I got the language displayed as French since there wasn’t any setting for that property in application.properties file:

Getting default property value in JAX-RS

Setting multiple values for property

As you’ve seen above, I set only String to the properties. However, if you want, you can set a list as one property.

myapp.programming_languages=Java,PHP,JavaScript,Go

I created a new endpoint called language-info with the following details:

    @GET
    @Path("language-info")
    @Produces(MediaType.TEXT_PLAIN)
    public String languageInfo() {

        return  String.join(",", languages);
    }

Sure enough, when visiting the endpoint, I got the expected result:

In case you have multiple properties and don’t want to inject each property separately, you can inject Config object:

    @Inject
    Config config;

and get the value using getValue.

String appLanguage = config.getValue("myapp.language", String.class);
Posted on Leave a comment

How To Return File Download In JAX-RS Application

When developing JAX-RS applications, most of the time, you return JSON to the client. However, there are times you need to return file download. For example, your client may require that when an user access a certain URL, the application must prompt a save file dialog.

If you have trouble with this requirement, look no further. I’m going to show you exactly how to return file download in JAX-RS application.

How to return file download

Let’s consider the following rest enpoint:

    @GET
    @Path("file")
    @Produces(MediaType.TEXT_PLAIN)
    public String download() {
        return "directly to browser";
    }

If you access the URL from the browser, I’m sure you can guess the result. It’s the text “directly to browser” just like this:

Text printed directly to the browser

Now, what if you want instead of print the content to the browser, when an user visit the URL, a file is downloaded instead?

Consider the following code:

    @GET
    @Path("file")
    @Produces(MediaType.TEXT_PLAIN)
    public Response download() {
        return Response.ok("directly to browser")
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;")
                .build();
    }

If you visit the browser right now following the same URL as above, a file is downloaded instead.

You may wonder why the name of the file is file.txt? The reason is quite simple: Since I didn’t specify the file name (I’ll show you how later) and from the annotation, I set @Produce to TEXT_PLAIN, so JAX-RS was smart enough to get the path name and the content type to create the file name.

Let’s change the path to something else and change @Produce to XML.

    @GET
    @Path("file-other")
    @Produces(MediaType.APPLICATION_XML)
    public Response download() {
        return Response.ok("directly to browser")
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;")
                .build();
    }

Sure enough, the file name is now:

Change file name for the file downloaded

Let’s say now your client is very happy with the progress so far. However, she wants the name of the file to be something else and she doesn’t want to change the URL. What can you do?

Specify the download file’s name

If you need to set name for the downloaded file, simply set it in the header like so:

    @GET
    @Path("file")
    @Produces(MediaType.APPLICATION_XML)
    public Response download() {
        return Response.ok("directly to browser")
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=great_file.xml")
                .build();
    }

Now, if I visit the URL, I’ll get a file named great_file.xml

Specify file name for download file in JAX-RS

Conclusion

Returning file download is a common requirement in web projects. As you can see, by adding Content-Disposition header and set it to attachment, you can make a request return a file download instead of printing out text to the browser. You can also set name for the download file, if you like by specifying filename field.