Develop your Tomcat App with Docker Compose Watch
Tags: docker, java, tomcat, development
Published: 2024-04-15 23:35:37

> Today we will see how <u>Build</u>, <u>Run</u>, <u>Deploy</u> and <u>Modify</u> in immediate mode a simple Java App deployed on Tomcat via the **Docker Compose Watch** feature.

The purpose of this article is not to introduce the development of some Tomcat App via Spring or whatever platform but instead of that to explain how we can use the Docker's tools to make easier it.

💡A Docker Compose stack is ready to run on my github.com/ulrich space available in the repository : https://github.com/ulrich/develop-java-app-with-compose-watch

### Docker Compose Watch in few words

This tool has been released in the Docker Compose v2.22.0 by my favorite ❤️ team at Docker. Quickly when you use Compose during your developments, it can useful to synchronize your local changes with your deployed App running in his container. Before the Watch feature you were forced to use a workaround like Bind mount for getting a hot reloaded capability and it was OK. But in many cases in many technologies, it's not a good idea to work like this because for example in Java (in particular Java WAR App based model) technology, we don't want to deploy our App after a simple modification. You understood, a Java WAR App needs many resources which can slow down the inner loop development experience.

Docker Compose Watch offers an another approach for developers by using of new properties allowing to synchronize with a fine-grained level each piece of your App. By the way, a couple of new commands (develop/watch/action) will help you to define what/when/how I have to synchronize one piece of code (file, directory, module...).

You will find more information in the following source [here](https://www.docker.com/blog/announcing-docker-compose-watch-ga-release/).

### Craft a simple Java WAR App

Add a simple Spring Boot app with the convenience dependencies.

The best way, for generating a ready-to-run application in Java you can use the [Spring Boot Initializr](https://start.spring.io/) tool.

We will need to enroll the following dependencies:

- spring-boot-starter-tomcat
- spring-boot-starter-web
- spring-boot-starter-thymeleaf
- spring-boot-starter-data-jpa

These followings for this introduction will use Java 21 and Maven.

There is nothing of special to be noted for this application which use the classic architecture from Java App. The data layer is fed by a pre-initialized Postgres Compose service.

After running the Docker Compose services you will access to the `students.html` page from the following URL : `http://localhost:8080/app-for-compose-watch-0.0.1-SNAPSHOT/students/all` (figure 1)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ckpt01gbi8g8ug7tag2h.png)
<center>Fig. 1</center>

---

### Run the App with --watch flag

In this introduction, we will see two ways to synchronize our application.

For running the App with the Compose Watch enabled, we have to launch like this :

```shell
❯ docker compose up --build --watch
```

This command will build and run the App with the Compose Watch observer enabled (figure 2).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i9ognmoov3u93yugecsm.png)
<center>Fig. 2</center>

---

👋 This way to start the services is interesting because in this case, we ask to build, run and watch the expected service with the logs enabled in the console.

#### When I want to create or modify the Java code

In Java WAR App based on Tomcat, the easiest way to test the inner-loop development is to instruct Compose Watch for rebuilding and deploying the App when a "witness" file has changed. The following Compose configuration allows this development round-trip :

```Docker
  app:
    image: app:latest
    build: ./
    develop:
      watch:
        - action: rebuild
          path: deploy.watch
    ports:
      - 8080:8080
```

The notable point to consider there is the path instruction used to trigger a rebuild action when the developer considers it. As I explained previously, we don't want to trigger a rebuild action for each Java file modifications, so we can consider that when we want to test our modifications, the developer have to update this spy file.

For my part I use a IntelliJ Shell script which update the **deploy.watch** file located in the root path with this kind of configuration (figure 3).


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dey7g9cwvyblytvlqqtq.png)
<center>Fig. 3</center>

---

When the Deploy App command is triggered, we can see the Docker Compose Watch feature take the hand and making the expected actions (build, deploy and restart Tomcat). PTAL the following sample of logs after executing the command (figure 4).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/et73dif768yttcuwp8sp.png)
<center>Fig. 4</center>

---

> Practical and inexpensive!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d87a41fzg7qosd7w9vz4.gif)

#### When I want to modify a HTML file

The solution to synchronize not compiled sources like Thymeleaf files (for example) is to use the **sync** action. When we use this feature the Docker Compose doesn't restart the App but only copy and past the files denoted by the couple path/targer. Let's take a look of the following configuration used to (hot) update the **students.html** file located in `src/main/resources/templates/` path.

```Docker
  app:
    image: app:latest
    build: ./
    develop:
      watch:
        - action: rebuild
          path: deploy.watch
        - action: sync
          path: src/main/resources/templates/
          target: /usr/local/tomcat/webapps/app-for-compose-watch-0.0.1-SNAPSHOT/WEB-INF/classes/templates/
    ports:
      - 8080:8080
```

The main difference with the previous declaration is the necessity to declare a target path.

Please take a look to the following resource : [/students/adults](http://localhost:8080/app-for-compose-watch-0.0.1-SNAPSHOT/students/adults) (figure 5).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uc7wop9qw2zg3xzua6ob.png)
<center>Fig. 5</center>

---

If I modify the template by adding some information, the modification should instantly happened (figure 6).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/djfndpr0jy116xyacp54.png)
<center>Fig. 6</center>

---

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2qpxevx4ey7at5xormst.png)
<center>Fig. 7</center>

---

### Conclusion

Finally we can consider the Docker Compose Watch tool while developing a Java WAR App on Tomcat. Given that I think is a good alternative from the classical development stack like IntelliJ Plugin or others. All parts of the inner-loop developments can be make in the image itself and no need to install third party tooling.

Have a good day.

Image par <a href="https://pixabay.com/fr/users/jackmac34-483877/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1882817">jacqueline macou</a> de <a href="https://pixabay.com/fr//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1882817">Pixabay</a>