Containerize a Spring Boot application with Podman Desktop

FONT: https://developers.redhat.com/articles/2023/10/19/containerize-spring-boot-application-podman-desktop#running_the_containerized_application

You are here

Containerize a Spring Boot application with Podman Desktop

October 19, 2023

Cedric Clyburn Related topics: ContainersJavaKubernetesSpring Boot Related products: Podman DesktopRed Hat Enterprise Linux

Share:

Spring and Spring Boot are developer favorites for building Java applications that run in the cloud. Spring is known for being production-ready, complimenting containerization very well. According to the State of Spring 2022 report, Kubernetes has become the dominant platform for running Spring apps. So, how can we take a Spring application, containerize it, and run it locally? Let’s explore this by using Podman Desktop, an open-source tool to seamlessly work with containers and Kubernetes from your local environment.

Prerequisites

  • Spring Boot Application: For this article, we’ll use the popular Spring PetClinic sample application on GitHub (Figure 1). Feel free to also use your own project or start from the Spring Initializr.
A screenshot of the Spring Pet clinic Repository on Github
Figure 1: The Spring Petclinic repository on Github.
  • Podman Desktop: Let’s use Podman Desktop, the powerful GUI-based tool for deploying and managing containers using the Podman container engine. Once installed, you’ll be ready to start containerizing your Spring application (Figure 2).
A screenshot of the Podman Desktop dashboard.
Figure 2: The Podman Desktop dashboard.

Containerizing the Spring Boot application

Let’s get started by cloning the application’s source code if using the PetClinic repository.

git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic

While we can use Maven to build a jar file and run it, let’s jump straight into creating a Containerfile in the project’s root directory, which will serve as the blueprint for the container image we’ll create later (analogous to Docker’s Dockerfile). You can create the file with the command touch Containerfile or simply create it from your IDE. Let’s see what the Containerfile will look like for this sample Spring Boot application:

# Start with a base image that has Java 17 installed.
FROM eclipse-temurin:17-jdk-jammy

# Set a default directory inside the container to work from.
WORKDIR /app

# Copy the special Maven files that help us download dependencies.
COPY .mvn/.mvn

# Copy only essential Maven files required to download dependencies.
COPY mvnw pom.xml./

# Download all the required project dependencies.
RUN ./mvnw dependency:resolve

# Copy our actual project files (code, resources, etc.) into the container.
COPY src./src

# When the container starts, run the Spring Boot app using Maven.
CMD ["./mvnw", "spring-boot:run"]

Let’s take a deeper look at the components that make up this Containerfile:

  • FROM eclipse-temurin:17-jdk-jammy:
    • Purpose: This line sets the foundation for our container.
    • Deep Dive: It tells Podman to use a pre-existing image that already has Java 17 installed. Think of it as choosing a base flavor for a cake before adding more ingredients. We use the eclipse-temurin image because it’s a trusted source for Java installations.
  • WORKDIR /app:
    • Purpose: Designates a working space in our container.
    • Deep Dive: Containers have their own file system. Here, we’re telling Podman to set up a folder named ‘app’ and make it the default location for any subsequent operations.
  • COPY commands:
    • Purpose: They transfer files from our local system into the container.
    • Deep Dive: The first COPY grabs Maven’s configuration, a tool Java developers use to manage app dependencies. The second copies over the main files of our app: the Maven wrapper (mvnw) and the project’s details (pom.xml).
  • RUN ./mvnw dependency:resolve:
    • Purpose: Downloads necessary libraries and tools for the app.
    • Deep Dive: This command activates Maven to fetch everything our app needs to run. By doing this in the Containerfile, we ensure the container has everything packaged neatly.
  • COPY src./src:
    • Purpose: Add our actual application code.
    • Deep Dive: Our app’s logic, features, and resources reside in the src directory. We’re moving it into the container so that when the container runs, it has our complete app.
  • CMD [“./mvnw”, “spring-boot:run”]:
    • Purpose: Start our application!
    • Deep Dive: This command is the final step. This line tells Podman to run our Spring Boot application using Maven when our container launches.

This Containerfile is ready to be used with Podman Desktop to create a container image of our Spring Boot application (Figure 3). Before building the image for this application, let’s double check the directory structure and Containerfile in our IDE of choice.

A screenshot of the Containerfile in VSCode.
Figure 3: The Containerfile in VSCode.

Building the container image with Podman Desktop

We can now build our container image with Podman Desktop by first heading to the Images section of Podman Desktop and selecting the Build an Image button in the top-right corner (Figure 4).

A screenshot of the Podman Desktop with the build image button highlighted.
Figure 4: The Podman Desktop Build Image is highlighted.

This will open a menu where you can select the path to our previously created Containerfile, which should be in the root directory of the spring-petclinic folder. With the Containerfile selected, we can also give our container image a name, for example, petclinic. Now, click on Build, and you’ll see each of the layers of the image being created. You can find this in your local image registry (the Image section in Figure 5).

A screenshot of the Podman Desktop build image menu.
Figure 5: The Podman Desktop Build Image menu.

Running the containerized application

Fantastic! Let’s return to the Images section to see the containerized Spring Boot application, now built and tagged as an image, as well as the eclipse-temurin base image that was downloaded to build our petclinic image. We can easily run this image as a container on our system using the Run icon to the right of our container image (Figure 6).

A screenshot of the Podman Desktop run container.
Figure 6: The Podman Desktop showing where to run the container.

Under Port Mapping, make sure to assign port 8080 of the container to port 8080 of the host. Feel free to leave all other settings as default. Click Start Container to launch the containerized instance of your Spring Boot application (Figure 7).

A screenshot showing the start container button in the Podman Desktop menu.
Figure 7: Click the start container button in the Podman Desktop menu.

Now, with the container up and running, let’s open the container’s URL in the browser using the handy open browser button within the Podman Desktop user interface (Figure 8).

A screenshot of the Podman Desktop highlighting the open browser button.
Figure 8: The Podman Desktop highlighting the open browser button.

Perfect, looks like our Spring Boot application is running, thanks to the startup command in our Containerfile, as well as the port mapping we configured in Podman Desktop (Figure 9).

A screenshot showing the Spring Boot application is running in Chrome.
Figure 9: The Spring Boot application is running in Chrome.

Now we can see this PetClinic application running in our browser, but that’s not all. For more features that may involve bringing out the terminal, we can now use Podman Desktop instead (Figure 10). This may include, SSH’ing into a container for debugging and modifying settings, maybe viewing the logs of a container, or inspecting environment variables. This can all be done under the Container Details section that opens automatically after starting the container.

A screenshot of the Podman Desktop terminal.
Figure 10: The Podman Desktop terminal.

Wrapping up

We have gone from local Spring Boot code to containerizing the application and running it with Podman Desktop! Now, as a container, we can share this application across environments using registries like Quay.io and Docker Hub and deploy it using Kubernetes and OpenShift to a variety of different cloud providers.Last updated: January 15, 2025

Related Posts

Recent Posts

What’s up next?

Read Podman in Action for easy-to-follow examples to help you learn Podman quickly, including steps to deploy a complete containerized web service. LinkedInYouTubeTwitterFacebook

RED HAT DEVELOPER

Build here. Go anywhere.

We serve the builders. The problem solvers who create careers with code.

Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

Sign me up

© 2025 Red Hat

https://www.google.com/recaptcha/api2/bframe?hl=en&v=Lu6n5xwy2ghvnPNo3IxkhcCb&k=6LfI4RApAAAAAF0FZDNh0WxeTb5vW26PPphSO9CR&bft=0dAFcWeA4cWuzQUGkfsrWOK2bL2tgkxlHUWBM7aegdByjKYGUp9Bscf1mdedF5sLmoYL8ru6xp1vPOFU6FF0l_bIY8xaZM4xN2sg

Liferay Portal

Instal·lació de Liferay Portal per a Intranet/Extranet amb WildFly, PostgreSQL i Debian 12

Aquesta guia detallada us ajudarà a configurar un entorn Liferay per a la vostra organització amb les característiques sol·licitades.

1. Requisits previs

1.1. Requisits del sistema

  • Servidor Debian 12 (recomanat mínim 8GB RAM, 4 cores, 100GB d’emmagatzematge)
  • Java JDK 11 (recomanat OpenJDK)
  • WildFly 26+
  • PostgreSQL 14+
  • Liferay DXP 7.4 (recomanat última versió estable)

1.2. Paquets necessaris

sudo apt update
sudo apt install -y openjdk-11-jdk postgresql postgresql-client unzip

2. Instal·lació de PostgreSQL

2.1. Configuració de la base de dades

sudo -u postgres psql

Dins de PostgreSQL:

CREATE DATABASE liferaydb WITH ENCODING 'UTF8';
CREATE USER liferayuser WITH PASSWORD 'P@ssw0rdComplex';
GRANT ALL PRIVILEGES ON DATABASE liferaydb TO liferayuser;
\q

2.2. Configuració de PostgreSQL

Editeu /etc/postgresql/14/main/postgresql.conf:

max_connections = 500
shared_buffers = 2GB
work_mem = 16MB

Reiniciar PostgreSQL:

sudo systemctl restart postgresql

3. Instal·lació de WildFly

3.1. Descarrega i instal·lació

wget https://download.jboss.org/wildfly/26.1.1.Final/wildfly-26.1.1.Final.zip
unzip wildfly-26.1.1.Final.zip
sudo mv wildfly-26.1.1.Final /opt/wildfly

3.2. Configuració com a servei

sudo groupadd -r wildfly
sudo useradd -r -g wildfly -d /opt/wildfly -s /sbin/nologin wildfly
sudo chown -R wildfly:wildfly /opt/wildfly

Creeu /etc/systemd/system/wildfly.service:

[Unit]
Description=WildFly Application Server
After=syslog.target network.target

[Service]
User=wildfly
Group=wildfly
ExecStart=/opt/wildfly/bin/standalone.sh -b=0.0.0.0 -bmanagement=0.0.0.0
Restart=on-abnormal

[Install]
WantedBy=multi-user.target

Inicieu el servei:

sudo systemctl daemon-reload
sudo systemctl enable wildfly
sudo systemctl start wildfly

4. Instal·lació de Liferay DXP

4.1. Preparació de l’entorn

wget https://repository.liferay.com/nexus/service/local/repositories/liferay-public-releases/content/com/liferay/portal/liferay-portal-tomcat-bundle/7.4.3.112-ga113/liferay-portal-tomcat-bundle-7.4.3.112-ga113.zip
unzip liferay-portal-tomcat-bundle-7.4.3.112-ga113.zip
mv liferay-portal-7.4.3.112-ga113 /opt/liferay

4.2. Configuració per a WildFly

Copieu els arxius WAR necessaris al directori de desplegament de WildFly:

cp /opt/liferay/osgi/war/*.war /opt/wildfly/standalone/deployments/

4.3. Configuració de Liferay

Creeu /opt/liferay/portal-ext.properties:

jdbc.default.driverClassName=org.postgresql.Driver
jdbc.default.url=jdbc:postgresql://localhost:5432/liferaydb
jdbc.default.username=liferayuser
jdbc.default.password=P@ssw0rdComplex

liferay.home=/opt/liferay

4.4. Iniciar Liferay

/opt/liferay/tomcat-9.0.56/bin/startup.sh

5. Integració amb Active Directory

5.1. Configuració inicial

  1. Accediu a http://localhost:8080
  2. Completeu l’assistent d’instal·lació inicial
  3. Anar a Control Panel → Configuration → System Settings → Authentication

5.2. Configuració LDAP

  1. A System Settings, busqueu “LDAP”
  2. Configureu les connexions LDAP:
  • Enabled: Yes
  • Base Provider URL: ldap://your-ad-server:389
  • Base DN: DC=yourdomain,DC=com
  • Principal: CN=ldapuser,OU=ServiceAccounts,DC=yourdomain,DC=com
  • Credentials: password
  • User Mapping:
    • Screen Name: sAMAccountName
    • Email Address: mail
    • First Name: givenName
    • Last Name: sn
  • Group Mapping:
    • Group Name: cn
  • Import Method: User Groups
  • User Custom Attributes: (map any additional needed attributes)

5.3. Sincronització de grups

  1. A LDAP Groups, configureu:
  • Group Search Filter: (objectClass=group)
  • Groups DN: OU=Organitzacio,DC=yourdomain,DC=com
  • Group Name: cn
  • Import Group: Yes
  • Create Role per Group Type: Yes

5.4. Configuració d’autenticació

  1. A System Settings → Authentication → LDAP, configureu:
  • Required: Yes
  • Password Policy: Use LDAP Password Policy
  • Import on Login: Yes

6. Configuració dels llocs departamentals

6.1. Plantilla de lloc

  1. Creeu una plantilla de lloc (Site Template) per als llocs públics:
  • Control Panel → Sites → Site Templates
  • Creeu una plantilla amb les pàgines necessàries (Home, News, Resources, etc.)
  1. Creeu una altra plantilla per als llocs privats

6.2. Automatització de creació de llocs

Podeu utilitzar un script Groovy per automatitzar la creació de llocs:

import com.liferay.portal.kernel.service.*
import com.liferay.portal.kernel.model.*

// Obtenir serveis
groupLocalService = GroupLocalServiceUtil
roleLocalService = RoleLocalServiceUtil
userGroupLocalService = UserGroupLocalServiceUtil

// Obtenir plantilles
publicTemplate = groupLocalService.getGroup(companyId, "PUBLIC_TEMPLATE_NAME")
privateTemplate = groupLocalService.getGroup(companyId, "PRIVATE_TEMPLATE_NAME")

// Obtenir tots els grups LDAP que comencen amb "Organitzacio_"
ldapGroups = userGroupLocalService.getUserGroups(-1, -1).findAll { 
    it.name.startsWith("Organitzacio_") 
}

ldapGroups.each { group ->
    deptName = group.name.replace("Organitzacio_", "")

    // Crear lloc públic
    publicSite = groupLocalService.addGroup(
        userId, GroupConstants.DEFAULT_PARENT_GROUP_ID, 
        Group.class.getName(), 0, GroupConstants.DEFAULT_LIVE_GROUP_ID,
        "Organització ${deptName}", null, 0, true, 
        GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, 
        "/${deptName.toLowerCase()}", true, true, null)

    // Crear lloc privat
    privateSite = groupLocalService.addGroup(
        userId, GroupConstants.DEFAULT_PARENT_GROUP_ID, 
        Group.class.getName(), 0, GroupConstants.DEFAULT_LIVE_GROUP_ID,
        "Organització ${deptName} (Privat)", null, 0, true, 
        GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, 
        "/private-${deptName.toLowerCase()}", true, true, null)

    // Aplicar plantilles
    LayoutLocalServiceUtil.copyLayouts(
        publicTemplate.getGroupId(), false, publicSite.getGroupId(), false)
    LayoutLocalServiceUtil.copyLayouts(
        privateTemplate.getGroupId(), false, privateSite.getGroupId(), false)

    // Assignar permisos
    // (afegiu aquí la lògica per assignar permisos als grups LDAP corresponents)
}

7. Creació del Theme personalitzat

7.1. Crear un nou theme

cd /opt/liferay
blade create -t theme my-custom-theme
cd my-custom-theme

7.2. Configuració del theme

Editeu src/WEB-INF/liferay-plugin-package.properties:

name=My Custom Theme
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Your Name
licenses=LGPL
liferay-versions=7.4.3.112
theme.parent=classic

7.3. Implementació del menú dinàmic

Editeu src/META-INF/resources/_diffs/templates/portal_normal.ftl:

<#assign public_sites = restClient.get("/sites?filter=name+eq+'Organització*'&fields=name,friendlyURL") />
<#assign user_sites = restClient.get("/user/me/sites?fields=name,friendlyURL") />

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="collapse navbar-collapse">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="#" id="publicSitesDropdown" role="button" data-toggle="dropdown">
                    Departaments Públics
                </a>
                <div class="dropdown-menu">
                    <#list public_sites.items as site>
                        <a class="dropdown-item" href="${site.friendlyURL}">${site.name}</a>
                    </#list>
                </div>
            </li>
            <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="#" id="privateSitesDropdown" role="button" data-toggle="dropdown">
                    Els meus espais
                </a>
                <div class="dropdown-menu">
                    <#list user_sites.items as site>
                        <a class="dropdown-item" href="${site.friendlyURL}">${site.name}</a>
                    </#list>
                </div>
            </li>
        </ul>
    </div>
</nav>

7.4. Desplegar el theme

blade deploy

8. Configuració de les condicions d’ús

8.1. Crear un formulari personalitzat

  1. Anar a Control Panel → Forms
  2. Creeu un nou formulari amb els camps necessaris (Acceptació de condicions)

8.2. Configuració del procés d’acceptació

  1. Creeu un hook personalitzat per interceptar el primer login:
@Component(
    immediate = true,
    service = ServletContextFilter.class
)
public class TermsAcceptanceFilter implements ServletContextFilter {
    @Override
    public void doFilter(
        ServletRequest servletRequest, ServletResponse servletResponse,
        FilterChain filterChain)
        throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        try {
            User user = PortalUtil.getUser(request);

            if (user != null && !isTermsAccepted(user)) {
                if (!request.getRequestURI().contains("/accept-terms")) {
                    response.sendRedirect("/accept-terms");
                    return;
                }
            }
        } catch (Exception e) {
            _log.error(e);
        }

        filterChain.doFilter(servletRequest, servletResponse);
    }

    private boolean isTermsAccepted(User user) {
        // Implementar lògica per comprovar si l'usuari ha acceptat les condicions
    }

    private static final Log _log = LogFactoryUtil.getLog(TermsAcceptanceFilter.class);
}

8.3. Pàgina d’acceptació de condicions

Creeu una pàgina personalitzada amb el formulari i la lògica per registrar l’acceptació.

9. Configuració de notificacions

9.1. Crear un servei de notificacions

Implementeu un servei per gestionar notificacions:

@Component(service = NotificationService.class)
public class NotificationServiceImpl implements NotificationService {

    @Reference
    private UserNotificationEventLocalService _userNotificationEventLocalService;

    public void sendNotification(long userId, String message) {
        JSONObject payload = JSONFactoryUtil.createJSONObject();
        payload.put("message", message);

        _userNotificationEventLocalService.addUserNotificationEvent(
            userId,
            "notification-portlet",
            System.currentTimeMillis(),
            userId,
            payload.toString(),
            false,
            null);
    }

    public void markAsRead(long notificationId) {
        UserNotificationEvent notification = 
            _userNotificationEventLocalService.getUserNotificationEvent(notificationId);

        notification.setArchived(true);
        _userNotificationEventLocalService.updateUserNotificationEvent(notification);
    }
}

9.2. Registrar acceptacions

Creeu una taula personalitzada per registrar les acceptacions de notificacions:

CREATE TABLE notification_acceptance (
    acceptanceId BIGSERIAL PRIMARY KEY,
    userId BIGINT NOT NULL,
    notificationId BIGINT NOT NULL,
    acceptanceDate TIMESTAMP NOT NULL,
    FOREIGN KEY (userId) REFERENCES User_(userId)
);

10. Configuració final

10.1. Configuració de seguretat

  1. Assegureu-vos que totes les pàgines requereixen autenticació:
  • Control Panel → Configuration → System Settings → Security → SSO
  • Marqueu “Require Authentication to Access the Site”

10.2. Configuració de memòria per a WildFly

Editeu /opt/wildfly/bin/standalone.conf:

JAVA_OPTS="-Xms4g -Xmx8g -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=1024M"

10.3. Reiniciar i verificar

sudo systemctl restart wildfly
/opt/liferay/tomcat-9.0.56/bin/shutdown.sh
/opt/liferay/tomcat-9.0.56/bin/startup.sh

11. Manteniment i monitorització

11.1. Tasques programades

Configureu tasques programades per:

  • Sincronització regular amb AD
  • Neteja de notificacions antigues
  • Backups regulars

11.2. Monitorització

Configureu eines com:

  • Prometheus + Grafana per a mètriques
  • ELK Stack per a logs
  • Alertes per a problemes de rendiment

Aquesta configuració proporcionarà una plataforma robusta per a la vostra intranet/extranet amb totes les característiques sol·licitades. Recordeu adaptar les contrasenyes i els valors específics del vostre entorn AD abans de posar en producció el sistema.

Step-by-step RESTful web service example in Java using Eclipse and TomEE Plus

Published: 01 Jan 2019

Related Videos

https://www.youtube.com/embed/Tpr4UfkX9e4

TheServerSide has published a number of articles on the tenets of effective RESTful web service design, along with examples of how to actually create a cloud-native application using Spring Boot and Spring Data APIs. In this JAX-RS tutorial, we will go back to basics by developing the exact same application, except this time we’ll use standard Java EE APIs and the extended, enterprise version of Tomcat, TomEE Plus, as our deployment target. This step-by-step JAX-RS RESTful web service example in Java using Eclipse and TomEE Plus will get you up to speed on modern web service development techniques in less than 15 minutes. 

Prerequisites

This tutorial uses Eclipse Oxygen as the development environment, the underlying JDK is at version 1.8, and the deployment target is TomEE Plus. You can download TomEE Plus from the project’s Apache home page.

Why are we using TomEE Plus, and not Tomcat or the standard TomEE offering? Sadly, the basic Java web profile, which Tomcat 9 implements, does not support JAX-RS, it does not include the javax.ws.rs.* packages, and without playing with POM files or adding JAR files to the Eclipse project’s \lib directory, RESTful web services simply won’t work. The standard TomEE offering doesn’t include JAX-RS libraries either. On the other hand, the TomEE Plus server does include various enterprise packages, including JAX-RS, so RESTful web services will deploy right out of the box, making this RESTful web services example much simpler.

Step 1: The dynamic web project

The first step in this JAX-RS tutorial is to kick off the dynamic web project creation wizard in Eclipse. 

JAX-RS project creation
This JAX-RS tutorial utilizes a dynamic web project in Eclipse.

When the dynamic web project wizard appears, name the project restful-java, choose Apache Tomcat 8.5 as the target runtime (even though we are using TomEE Plus, not Tomcat), specify 3.1 as the dynamic web module version and choose a minimal configuration for the project. When these options are set, click Finish.

Note that you need to install TomEE Plus prior to doing this JAX-RS tutorial. You can also use any other application server that supports Java EE and JAX-RS for this RESTful web service example in Java using Eclipse.

Where is the web.xml file?

If you look at this project in GitHub (link below), you’ll notice that there isn’t a web.xml file. That makes traditional enterprise developers nervous, but so long as everything is annotated, there’s no need for one in version 3.x of the Servlet and JSP spec. In older REST implementations you would need to configure a Jersey Servlet and perform a REST Servlet mapping, but that is no longer necessary. In this case, TomEE Plus will process all of the annotations on the classes in the Java web project and make RESTful web sevices available accordingly. It should be noted that on some servers, you do need to reference your JAX-RS classes explicility, which you can do through an Application class. That process is addressed in the JAX-RS problems section towards the end.

JAX-RS project settings
Specify project settings for the RESTful web service example in Java using Eclipse.

Step 2: Create the Score class

This restful web service example in Java using Eclipse models a score counter for an online rock-paper-scissors application, so the first requirement is to create a class named Score that keeps track of wins, losses and ties.

package com.mcnz.restful.java.example;
public class Score {
     public static int WINS, LOSSES, TIES;
}

To keep things simple, we won’t add any setters or getters. Furthermore, we are going to make the properties of the Score class static, as that will enable the Java virtual machine (JVM) to simulate persistence between stateless calls to the web service. This approach will enable us to run and test the application on a single JVM. However, you should manage application state in this way only as a proof of concept. It’s better to persist data with Hibernate and Java Persistence API or save information to a NoSQL database, but that is beyond the scope of this JAX-RS tutorial.

Step 3: Code the JAX-RS Service class

A class named ScoreService is the heart and soul of this RESTful web service example in Java using Eclipse. As such, decorate it with an ApplicationPath annotation that defines the base URL of the web service.

package com.mcnz.restful.java.example;
import javax.ws.rs.*;
 
@ApplicationPath("/")
public class ScoreService {  }

This class will contain three getter methods that enable RESTful web clients to query the number of wins, losses or ties. These methods are invoked through an HTTP GET invocation and return the current win, loss or tie count as plain text. As such, these methods each have a JAX-RS @GET annotation, a @Produces annotation indicating they return a text string and a @Path annotation indicating the URL clients need to use in order to invoke the method:

@GET @Path("/score/wins")@Produces("text/plain")
public int getWins() {return Score.WINS;}
    
@GET @Path("/score/losses")@Produces("text/plain")
public int getLosses() {return Score.LOSSES;}
    
@GET @Path("/score/ties")@Produces("text/plain")
public int getTies() {return Score.TIES;}

The increase methods of this JAX-RS tutorial’s ScoreService follow a similar pattern, with the exception of the fact that each method is triggered through an HTTP POST invocation:

@POST @Path("/score/wins")@Produces("text/plain")
public int increaseWins() { return Score.WINS++; }
    
@POST @Path("/score/ties")@Produces("text/plain")     
public int increaseTies() { return Score.WINS++;}
    
@POST @Path("/score/losses")@Produces("text/plain")        
public int increaseLosses() {return Score.LOSSES++;}

The final two methods of the ScoreService class enable users to get the JSON-based representation of the complete score or pass query parameters to the web service to update the static properties of the Score class. Both methods use the /score path, and both produce JSON. But the getScore method is invoked through an HTTP GET request, while the update method is invoked through a PUT.

Just for the record, there is an easier way to return JSON from a RESTful web service than by using the String.format call. You can use @Producer annotations and simply return JavaBeans, but because we are using static variables in our Score class, doing that gets a bit messy. We will save that for a future RESTful web services tutorial with Eclipse.

@GET
@Path("/score")
@Produces("application/json")
public String getScore() {
   String pattern =
      "{ \"wins\":\"%s\", \"losses\":\"%s\", \"ties\": \"%s\"}";
   return String.format(pattern,  Score.WINS, Score.LOSSES, Score.TIES );  
}
 
@PUT
@Path("/score")
@Produces("application/json")
public String update(@QueryParam("wins") int wins,
                        @QueryParam("losses") int losses,
                        @QueryParam("ties")   int ties) {
   Score.WINS   = wins;
   Score.TIES   = ties;
   Score.LOSSES = losses;
   String pattern =
      "{ \"wins\":\"%s\", \"losses\":\"%s\", \"ties\": \"%s\"}";
   return String.format(pattern,  Score.WINS, Score.LOSSES, Score.TIES );  
}

Step 4: Deploy the JAX-RS web service

Now that you’ve coded the JAX-RS tutorial’s ScoreService, it’s time for this RESTful web service example in Java using Eclipse to move into the testing stage. Remember that we are using TomEE Plus as our target server, not Tomcat. Tomcat doesn’t provide built in JAX-RS support.

To test the application, first right-click on the restful Java project, and choose Run As > Run on server. This will deploy the web project and start the Apache TomEE Plus server that hosts the application.

Eclipse JAX-RS deployment
Run the RESTful web services example in Java on Tomcat.

Step 5: Test the JAX-RS web service example

When you deploy the JAX-RS tutorial app, there are a number of different ways to test it. One way is to simply type the URL of the RESTful web service example into a web browser. A call to the following URL will trigger a GET invocation and a JSON string representing the initial score should be displayed:

http://localhost:8080/restful-java/score
JSON string output
Test the JAX-RS tutorial app by invoking it into a web browser.

To test the increaseTies method, run the following two curl commands in a Bash shell:

$ curl -X POST "http://localhost:8080/restful-java/score/ties"
$ curl -X GET "http://localhost:8080/restful-java/score/"

The JSON string returned from the second command indicates that the number of ties has indeed been incremented by one:

{ "wins":"0", "losses":"0", "ties": "1"}

Now, use curl to trigger a PUT invocation with query parameters:

$ curl -X PUT "http://localhost:8080/restful-java/score?wins=1&losses=2&ties=3"

This PUT invocation will return the following JSON string:

{ "wins":"1", "losses":"2", "ties": "3"}

Fixing common JAX-RS problems

In this example, the ScoreService class is annotated with @ApplicationPath. This works fine with TomEE Plus, but on other servers or older implementations, the @ApplicationPath annotation is placed on a separate class that extends the JAX-RS Application class. This often solves the problem of RESTful URLs simply not being recognized and triggering a 404: The origin server did not find a current representation for the target resource error when an attempt is made to invoke them.

 import javax.ws.rs.core.Application;

@ApplicationPath("/")
public class ScoreApplication extends Application {
public Set<Class<?>> getClasses() { return new
HashSet<Class<?>>(Arrays.asList(ScoreService.class));
}
}

On servers where the implementation is Jersey based, the class can be replaced with one that is a bit easier to understand, although it calls on Jersey APIs explicitly, so it will only work with a Jersey based implementation. You just tell it the names of the various packages where JAX-RS annotated web services reside, and it ensures they are loaded:

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("/")
public class ScoreApplication extends ResourceConfig {

public ScoreApplication() {
packages("com.mcnz.restful.java.example");
}
}

And of course, you must ensure you are using TomEE Plus and not Tomcat. As was mentioned earlier, a standard Tomcat installation will not run RESTful web services without a JAX-RS implementation added to the \lib directory, Gradle build script or Maven POM.

And that’s a complete, step-by-step JAX-RS RESTful web service example in Java using Eclipse and TomEE Plus.

The full source code for this example can be downloaded from GitHub.

Create a JAX-RS web service with Tomcat, Eclipse

If you used TomEE in an attempt to create a JAX-RS web service and ran into issues, watch this new video that instead uses Tomcat and Eclipse to create this RESTful web service.

Configurant hostname presentat a HELO amb Debian i EXIM.

Intentant subscriure al maillist de tomcat users, rebem el següent error:

  users-subscribe@tomcat.apache.org
    host mx1-ec2-va.apache.org [34.199.147.133]
    SMTP error from remote mail server after RCPT TO:<users-subscribe@tomcat.apache.org>:
    504 5.5.2 <debian>: Helo command rejected: need fully-qualified hostnam

Motiu: El nostre sistema de correu no s’identifica correctament, comprovem amb :

exim -bP primary_hostname

si el hostname és correcte… Haiuria de coincidir amb:

hostname -f

Si no ho fa: corregir.

Crear Clúster amb tomcat amb apache mod_proxy com a load balancer.

Començarem pel final: Optimització del Tomcat :

Copiant la info de : https://rimuhosting.com/knowledgebase/linux/java/libtcnative

Home > Support > HOWTO List > libtcnative install

In most cases we recomend using the mod_proxy /apache combination as a frontend to tomcat. However for those looking to squeeze extra performance out of a bare tomcat installation the following may be useful

Apache Portable Runtime (APR) and Tomcat

Per http://apr.apache.org/ Tomcat can use the Apache Portable Runtime to provide superior scalability, performance, and better integration with native server technologies.

Installing the JNI wrappers for APR used by Tomcat (libtcnative)

You can now grab the latest tcnative wrapper from http://tomcat.apache.org/native-doc/ and drop that into the tomcat libs folder (eg /usr/local/tomcat/libs).

We recommend you use the package install methods shown on the above link to obtain the libraries noted. Those should be available using either yum or apt-get depending on your installed distribution.

You should be able to just grab the jar file and drop that into the tomcat libs folder (check in case it is already present).

Remeber to restart tomcat to make that load the updated/new libraries. And check in the tomcat logs to confirm they have been imported correctly.

I seguim:

Segons: https://tomcat.apache.org/tomcat-10.0-doc/config/http.html

Cal utilitzar el connector? : Java Nio2 Connector NIO2

Instal·lació bàsica del tomcat a debian:

Instal·larem només el paquets tomcat9 necessaris…

apt-get install tomcat9 tomcat9-admin tomcat9-docs tomcat9-examples
apt-get install libtcnative-1
apt-get install ca-certificates-java
apt-get install libapr1 libaprutil1 libaprutil1-dbd-mysql libaprutil1-dbd-odbc libaprutil1-dbd-pgsql libaprutil1-dbd-sqlite3 libaprutil1-ldap libwinpr2-2
cd /usr/lib
ln -s /usr/lib/x86_64-linux-gnu/libtcnative-1.so

Nota recordatoria; De la documentació de Tomcat:

CATALINA_HOME and CATALINA_BASE

Throughout the documentation, there are references to the two following properties:

CATALINA_HOME: Represents the root of your Tomcat installation, for example /home/tomcat/apache-tomcat-9.0.10 or C:\Program Files\apache-tomcat-9.0.10.

CATALINA_BASE: Represents the root of a runtime configuration of a specific Tomcat instance. If you want to have multiple Tomcat instances on one machine, use the CATALINA_BASE property.

If you set the properties to different locations, the CATALINA_HOME location contains static sources, such as .jar files, or binary files. The CATALINA_BASE location contains configuration files, log files, deployed applications, and other runtime requirements.

En el cas de Debian:

CATALINA_HOME: /usr/share/tomcatX

CATALINA_BASE: /var/lib/tomcatX