diff --git a/www-server/pom.xml b/www-server/pom.xml
index e331e74292668be858c45819f883e9a2b832d98a..e58d7e3e97621f64049b0dfb31a789f46e01d4fc 100644
--- a/www-server/pom.xml
+++ b/www-server/pom.xml
@@ -150,6 +150,11 @@
       <artifactId>hibernate-hikaricp</artifactId>
       <version>${hibernate.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j2-impl</artifactId>
+      <version>${log4j.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.postgresql</groupId>
       <artifactId>postgresql</artifactId>
@@ -201,6 +206,12 @@
       <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-jul</artifactId>
+      <version>${log4j.version}</version>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
@@ -255,8 +266,9 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
-            <configuration>
-              <argLine>
+          <configuration>
+            <argLine>
+-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
 --add-opens=java.base/java.lang=ALL-UNNAMED
 --add-opens=java.base/java.math=ALL-UNNAMED
 --add-opens=java.base/java.net=ALL-UNNAMED
@@ -264,7 +276,7 @@
 --add-opens=java.base/java.util=ALL-UNNAMED
 --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
 --add-opens=java.sql/java.sql=ALL-UNNAMED
-             </argLine>
+            </argLine>
           </configuration>
         </plugin>
         <plugin>
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java b/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java
index a50505510636975bc20a9251bfeca6ae98d14732..0b812a8e02a93c8fd0d2241fb4e8eadce5df1868 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java
@@ -27,6 +27,10 @@ public class AgroMetInfoConfiguration {
      * Keys for context.xml.
      */
     public enum ConfigurationKey {
+        /**
+         * The e-mail address used to send e-mails.
+         */
+        APP_EMAIL("app.email"),
         /**
          * The application URL.
          */
@@ -39,10 +43,6 @@ public class AgroMetInfoConfiguration {
          * Target environment (dev, preprod, prod).
          */
         ENVIRONMENT("environment"),
-        /**
-         * The e-mail address used to send e-mails.
-         */
-        APP_EMAIL("app.email"),
         /**
          * The e-mail address receiving the logs.
          */
@@ -51,6 +51,10 @@ public class AgroMetInfoConfiguration {
          * SMTP server name.
          */
         SMTP_HOST("smtp.host"),
+        /**
+         * SMTP password.
+         */
+        SMTP_PASSWORD("smtp.password"),
         /**
          * SMTP server port.
          */
@@ -59,10 +63,6 @@ public class AgroMetInfoConfiguration {
          * SMTP username.
          */
         SMTP_USER("smtp.user"),
-        /**
-         * SMTP password.
-         */
-        SMTP_PASSWORD("smtp.password"),
         /**
          * E-mail address for support.
          */
@@ -83,6 +83,16 @@ public class AgroMetInfoConfiguration {
         }
     }
 
+    /**
+     * Environment value.
+     */
+    private static final String ENVIRONMENT_DEV = "dev";
+
+    /**
+     * Environment value.
+     */
+    private static final String ENVIRONMENT_PROD = "prod";
+
     /**
      * Key prefix for the configuration in context.xml.
      */
@@ -133,17 +143,31 @@ public class AgroMetInfoConfiguration {
         }
         final var dir = new File(getCacheDirectory());
         if (!dir.exists()) {
-            LOGGER.info("Creating directory {}", dir.getAbsolutePath());
+            LOGGER.atInfo().log("Creating directory {}", dir.getAbsolutePath());
             if (!dir.mkdirs()) {
                 LOGGER.fatal("Cache directory {} failed to create!", dir.getAbsolutePath());
             }
         }
     }
 
+    /**
+     * @return if configuration is set to development.
+     */
+    public boolean isDevEnvironment() {
+        return ENVIRONMENT_DEV.equals(get(ConfigurationKey.ENVIRONMENT));
+    }
+
+    /**
+     * @return if configuration is set to production.
+     */
+    public boolean isProdEnvironment() {
+        return ENVIRONMENT_PROD.equals(get(ConfigurationKey.ENVIRONMENT));
+    }
+
     /**
      * Set value, only for testing purpose.
      *
-     * @param key key
+     * @param key   key
      * @param value value
      */
     public void set(@NonNull final ConfigurationKey key, final String value) {
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/ErrorHandlerServlet.java b/www-server/src/main/java/fr/agrometinfo/www/server/ErrorHandlerServlet.java
index d8ac555b2501e4d230d9aeb63bfced5478e86485..50792f3791aad44d4ee029fe285ef352953ee708 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/ErrorHandlerServlet.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/ErrorHandlerServlet.java
@@ -53,7 +53,7 @@ public final class ErrorHandlerServlet extends HttpServlet {
                 "target="_blank">la documentation</a>.</li>
                 <li>Obtenez de l'aide en écrivant une demande de support dans l'application ou <a href="
                 """ + appUrl + """
-                /contact.html\">contactez-nous</a>.</li>
+                /contact.html">contactez-nous</a>.</li>
                 </ul>
                 """;
             case HttpServletResponse.SC_INTERNAL_SERVER_ERROR ->
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/I18n.java b/www-server/src/main/java/fr/agrometinfo/www/server/I18n.java
index fac4a9558bee193672d6794da646624ff8905d51..1140dddb529ebfaffbf50af8df56e83446738341 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/I18n.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/I18n.java
@@ -10,7 +10,6 @@ import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.BiPredicate;
-import java.util.stream.Collectors;
 
 import lombok.Getter;
 import lombok.NonNull;
@@ -199,7 +198,7 @@ public class I18n {
         final var suffixes = getKeys().stream()
                 .filter(k -> k.startsWith(key + "[") && k.endsWith("]"))
                 .map(k -> k.substring(key.length() + 1, k.length() - 1))
-                .collect(Collectors.toList());
+                .toList();
         for (final String suf : suffixes) {
             if (matches(suf, plural)) {
                 keyWithSuffix = key + "[" + suf + "]";
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/SessionAttribute.java b/www-server/src/main/java/fr/agrometinfo/www/server/SessionAttribute.java
index 6d30da3787d85055e61e9d9ff4bbbf1612c8ae8a..1f09750cd87fb11ac17ef79e04290ee43f7518b0 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/SessionAttribute.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/SessionAttribute.java
@@ -1,7 +1,3 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Enum.java to edit this template
- */
 package fr.agrometinfo.www.server;
 
 /**
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/StartListener.java b/www-server/src/main/java/fr/agrometinfo/www/server/StartListener.java
index 59336c889891fa8ca11914013dfc2e0b171db631..80f4497a14bc510ec694d04980fd67ae515d4616 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/StartListener.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/StartListener.java
@@ -5,7 +5,8 @@ import java.util.List;
 
 import fr.agrometinfo.www.server.exception.AgroMetInfoException;
 import fr.agrometinfo.www.server.service.MailService;
-import fr.agrometinfo.www.server.util.AppVersion;
+import fr.agrometinfo.www.server.util.ST;
+import fr.agrometinfo.www.server.util.ST.Key;
 import jakarta.inject.Inject;
 import jakarta.servlet.ServletContextEvent;
 import jakarta.servlet.ServletContextListener;
@@ -20,6 +21,15 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 @WebListener
 public final class StartListener implements ServletContextListener {
+    /**
+     * E-mail template.
+     */
+    private static final String TEMPLATE = """
+            Bonjour <SUPPORT_EMAIL>,
+
+            AgroMetInfo-www-<VERSION> démarre.
+            <MESSAGE>
+            """;
     /**
      * Application configuration.
      */
@@ -34,18 +44,20 @@ public final class StartListener implements ServletContextListener {
     @Override
     public void contextInitialized(final ServletContextEvent event) {
         // Send an e-mail to log e-mail address at application start.
-        if (configuration.get(AgroMetInfoConfiguration.ConfigurationKey.ENVIRONMENT).equals("dev")) {
+        if (configuration.isDevEnvironment()) {
             LOGGER.trace("Environment is dev, e-mail isn't send");
             return;
         }
-        var mail = new MailService.Mail();
-        mail.setContent("Bonjour,\nAgroMetInfo-www-" + AppVersion.getVersion() + " démarre.\n" + LocalDateTime.now());
-        mail.setFromAddress(configuration.get(AgroMetInfoConfiguration.ConfigurationKey.APP_EMAIL));
+        final var mail = new MailService.Mail();
         mail.setSubject("Démarrage");
         mail.setToAddresses(List.of(configuration.get(AgroMetInfoConfiguration.ConfigurationKey.LOG_EMAIL)));
+        final ST st = new ST(TEMPLATE);
+        st.add(Key.SUPPORT_EMAIL, String.join(", ", mail.getToAddresses()));
+        st.add(Key.MESSAGE, String.valueOf(LocalDateTime.now()));
+        mail.setContent(st.render());
         try {
             mailService.send(mail);
-        } catch (AgroMetInfoException e) {
+        } catch (final AgroMetInfoException e) {
             LOGGER.info("failed to send e-mail : {}", e);
         }
     }
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyValueDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyValueDaoHibernate.java
index b417470b5966f48fa34553e07dcbd29db59494a6..84e4cbadb1007b83231fd85405f9f8fcc430f141 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyValueDaoHibernate.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyValueDaoHibernate.java
@@ -16,6 +16,7 @@ import jakarta.enterprise.context.ApplicationScoped;
  */
 @ApplicationScoped
 public class DailyValueDaoHibernate extends DaoHibernate<DailyValue> implements DailyValueDao {
+
     /**
      * Constructor.
      */
@@ -26,7 +27,7 @@ public class DailyValueDaoHibernate extends DaoHibernate<DailyValue> implements
     @Override
     public final List<DailyValue> find(final Indicator indicator, final LocalDate date) {
         final var jpql = "SELECT t FROM DailyValue AS t WHERE t.indicator=:indicator AND t.date=:date";
-        return super.findAllByJPQL(jpql, Map.of("indicator", indicator, "date", date), DailyValue.class);
+        return super.findAllByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date), DailyValue.class);
     }
 
     @Override
@@ -34,7 +35,7 @@ public class DailyValueDaoHibernate extends DaoHibernate<DailyValue> implements
         final var jpql = """
                 SELECT t FROM DailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date AND t.cell.department.region=:region""";
-        return super.findAllByJPQL(jpql, Map.of("indicator", indicator, "date", date, "region", region),
+        return super.findAllByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date, PARAM_REGION, region),
                 DailyValue.class);
     }
 
@@ -44,7 +45,7 @@ public class DailyValueDaoHibernate extends DaoHibernate<DailyValue> implements
                 SELECT AVG(t.comparedValue)
                 FROM DailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date), Double.class);
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date), Double.class);
     }
 
     @Override
@@ -55,7 +56,7 @@ public class DailyValueDaoHibernate extends DaoHibernate<DailyValue> implements
                 FROM DailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date AND t.cell.department.region.id=:region AND
                 t.computedValue IS NOT NULL""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date, "region", regionId),
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date, PARAM_REGION, regionId),
                 Double.class);
     }
 
@@ -65,7 +66,7 @@ public class DailyValueDaoHibernate extends DaoHibernate<DailyValue> implements
                 SELECT AVG(t.computedValue)
                 FROM DailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date), Double.class);
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date), Double.class);
     }
 
     @Override
@@ -76,7 +77,7 @@ public class DailyValueDaoHibernate extends DaoHibernate<DailyValue> implements
                 FROM DailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date AND t.cell.department.region.id=:region AND
                 t.computedValue IS NOT NULL""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date, "region", regionId),
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date, PARAM_REGION, regionId),
                 Double.class);
     }
 
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java
index 814045d288b32a62555e6afc2af565194392895f..856d1ff41dfe027e66320c99ced69fdf4020e990 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java
@@ -1,12 +1,5 @@
 package fr.agrometinfo.www.server.dao;
 
-import jakarta.persistence.NoResultException;
-import jakarta.persistence.Query;
-import jakarta.persistence.TypedQuery;
-import jakarta.persistence.criteria.CriteriaBuilder;
-import jakarta.persistence.criteria.CriteriaQuery;
-import jakarta.persistence.criteria.Order;
-import jakarta.persistence.criteria.Root;
 import java.math.BigDecimal;
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -14,8 +7,18 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.hibernate.Session;
+
+import jakarta.persistence.NoResultException;
+import jakarta.persistence.Query;
+import jakarta.persistence.TypedQuery;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Order;
+import jakarta.persistence.criteria.Root;
 import lombok.extern.log4j.Log4j2;
-import org.hibernate.engine.spi.SessionImplementor;
 
 /**
  * Common methods for DAO with Hibernate.
@@ -24,37 +27,27 @@ import org.hibernate.engine.spi.SessionImplementor;
  * @author Olivier Maury
  */
 @Log4j2
-public abstract class DaoHibernate<T> {
+class DaoHibernate<T> {
     /**
-     * Get the class name of JDBC driver.
-     *
-     * @param em Entity manager
-     * @return name of JDBC driver
+     * Order value.
      */
-    protected static final String getDriver(final ScopedEntityManager em) {
-        final SessionImplementor sessionImp = (SessionImplementor) em.getDelegate();
-        try {
-            final Connection conn = sessionImp.getJdbcConnectionAccess().obtainConnection();
-            return conn.getMetaData().getDriverName();
-        } catch (final SQLException e) {
-            return "";
-        }
-    }
-
+    private static final String ORDER_DESC = "DESC";
     /**
-     * Checks if the database is connected by a PostgreSQL, useful to call specific
-     * SQL.
-     *
-     * @param em Entity manager
-     * @return if the SGBD is PostgreSQL
+     * Statement parameter.
      */
-    protected static final boolean isPostgreSQLDriver(final ScopedEntityManager em) {
-        final var driverName = getDriver(em);
-        if (driverName == null || driverName.isBlank()) {
-            return false;
-        }
-        return driverName.startsWith("PostgreSQL");
-    }
+    protected static final String PARAM_REGION = "region";
+    /**
+     * Statement parameter.
+     */
+    protected static final String PARAM_DATE = "date";
+    /**
+     * Statement parameter.
+     */
+    protected static final String PARAM_INDICATOR = "indicator";
+    /**
+     * Statement parameter.
+     */
+    protected static final String PARAM_YEAR = "year";
 
     /**
      * Related class.
@@ -84,6 +77,7 @@ public abstract class DaoHibernate<T> {
             return 0L;
         }
     }
+
     /**
      * Delete all row in table.
      */
@@ -99,6 +93,22 @@ public abstract class DaoHibernate<T> {
         }
         LOGGER.traceExit();
     }
+
+    /**
+     * Use a function to execute direct operations on database with JDBC in a
+     * transaction.
+     *
+     * @param <U>      class of function result
+     * @param function function with JDBC operations
+     * @return function result
+     */
+    protected final <U> U doInJdbc(final Function<Connection, U> function) {
+        try (ScopedEntityManager em = getScopedEntityManager()) {
+            final Session session = em.unwrap(Session.class);
+            return session.doReturningWork(function::apply);
+        }
+    }
+
     /**
      * Use a consumer to execute JPA operations in a transaction.
      *
@@ -106,9 +116,7 @@ public abstract class DaoHibernate<T> {
      */
     protected final void doInJpaTransaction(final Consumer<ScopedEntityManager> consumer) {
         try (ScopedEntityManager em = getScopedEntityManager()) {
-            em.executeTransaction(() -> {
-                consumer.accept(em);
-            });
+            em.executeTransaction(() -> consumer.accept(em));
         }
     }
 
@@ -153,7 +161,7 @@ public abstract class DaoHibernate<T> {
             if (orders != null) {
                 final List<Order> orderList = new ArrayList<>();
                 orders.forEach((column, asc) -> {
-                    if ("DESC".equalsIgnoreCase(asc)) {
+                    if (ORDER_DESC.equalsIgnoreCase(asc)) {
                         orderList.add(cBuilder.desc(root.get(column)));
                     } else {
                         orderList.add(cBuilder.asc(root.get(column)));
@@ -174,7 +182,6 @@ public abstract class DaoHibernate<T> {
      * Find all matching entities using JPQL and parameters for entities of the
      * specified class.
      *
-     *
      * @param <U>    entity class
      * @param stmt   JPQL statement
      * @param params parameters for the JPQL statement
@@ -193,11 +200,11 @@ public abstract class DaoHibernate<T> {
             return new ArrayList<>();
         }
     }
+
     /**
      * Find all matching entities using SQL and parameters for entities of the
      * specified class.
      *
-     *
      * @param <U>    entity class
      * @param sql   SQL statement
      * @param params parameters for the SQL statement
@@ -236,7 +243,6 @@ public abstract class DaoHibernate<T> {
             return null;
         }
     }
-
     /**
      * Find the first result.
      *
@@ -279,6 +285,21 @@ public abstract class DaoHibernate<T> {
         }
     }
 
+    /**
+     * Get the class name of JDBC driver.
+     *
+     * @return name of JDBC driver
+     */
+    protected final String getDriver() {
+        return doInJdbc(conn -> {
+            try {
+                return conn.getMetaData().getDriverName();
+            } catch (final SQLException e) {
+                return "";
+            }
+        });
+    }
+
     /**
      * @return name of current schema.
      */
@@ -297,17 +318,17 @@ public abstract class DaoHibernate<T> {
      */
     public BigDecimal getSchemaSize(final String schema) {
         try (ScopedEntityManager em = getScopedEntityManager()) {
-            if (isPostgreSQLDriver(em)) {
+            if (isPostgreSQLDriver()) {
                 final String sql = """
-                            SELECT
-                            SUM(pg_total_relation_size(CONCAT(quote_ident(schemaname), '.', quote_ident(tablename))))
-                            FROM pg_catalog.pg_tables WHERE schemaname=:schema
-                            """;
+                        SELECT
+                        SUM(pg_total_relation_size(CONCAT(quote_ident(schemaname), '.', quote_ident(tablename))))
+                        FROM pg_catalog.pg_tables WHERE schemaname=:schema
+                        """;
                 final Query query = em.createNativeQuery(sql);
                 query.setParameter("schema", schema);
                 return (BigDecimal) query.getSingleResult();
             } else {
-                throw new UnsupportedOperationException("Database driver not handled! " + getDriver(em));
+                throw new UnsupportedOperationException("Database driver not handled! " + getDriver());
             }
         }
     }
@@ -318,6 +339,21 @@ public abstract class DaoHibernate<T> {
     protected final ScopedEntityManager getScopedEntityManager() {
         return PersistenceManager.getInstance().createScopedEntityManager();
     }
+
+    /**
+     * Checks if the database is connected by a PostgreSQL, useful to call specific
+     * SQL.
+     *
+     * @return if the SGBD is PostgreSQL
+     */
+    protected final boolean isPostgreSQLDriver() {
+        final var driverName = getDriver();
+        if (driverName == null || driverName.isBlank()) {
+            return false;
+        }
+        return driverName.startsWith("PostgreSQL");
+    }
+
     /**
      * Save a new entity in database.
      * @param object
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerFactoryHandler.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerFactoryHandler.java
index 0d1a8f2bcec09102634f32ebc1786e243e4a5527..c7b8950a0e8244cb85467f2e7334fecfd2eb96bb 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerFactoryHandler.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerFactoryHandler.java
@@ -46,24 +46,21 @@ public final class EntityManagerFactoryHandler implements InvocationHandler {
     private final EntityManagerFactory emf;
 
     @Override
-    public Object invoke(final Object o, final Method method, final Object[] os)
-            throws Throwable {
+    public Object invoke(final Object o, final Method method, final Object[] os) throws Throwable {
         LOGGER.traceEntry("enter {} {} {}", ScopedEntityManagerFactory.class.getCanonicalName(),
                 method.getName(), os);
         Object result;
         try {
             if (method.equals(CREATE_SCOPED_ENTITY_MANAGER)) {
-                final EntityManager target = (EntityManager) CREATE_ENTITY_MANAGER
-                        .invoke(emf, os);
+                final EntityManager target = (EntityManager) CREATE_ENTITY_MANAGER.invoke(emf, os);
                 result = Proxy.newProxyInstance(
-                        ScopedEntityManager.class.getClassLoader(),
+                        Thread.currentThread().getContextClassLoader(),
                         new Class[]{ScopedEntityManager.class},
                         new EntityManagerHandler(target));
             } else {
                 result = method.invoke(emf, os);
             }
-        } catch (final IllegalAccessException | IllegalArgumentException
-                | InvocationTargetException e) {
+        } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
             throw LOGGER.throwing(e);
         }
         if (method.getReturnType().getClass().equals(Void.class.getClass())) {
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerHandler.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerHandler.java
index a760d69f7907f883a66b864eba495a7245da80b1..9566e3eb5bfc4d824e2e0af659f0bdac99b45020 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerHandler.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/EntityManagerHandler.java
@@ -57,7 +57,7 @@ public final class EntityManagerHandler implements AutoCloseable, InvocationHand
             throws Throwable {
         LOGGER.traceEntry("enter {} {} {}", ScopedEntityManagerFactory.class.getCanonicalName(),
                 method.getName(), os);
-        Object result;
+        final Object result;
         try {
             if (method.equals(EXECUTE_TRANSACTION)
                     || method.equals(EXECUTE_VOID_TRANSACTION)) {
@@ -65,8 +65,7 @@ public final class EntityManagerHandler implements AutoCloseable, InvocationHand
             } else {
                 result = method.invoke(em, os);
             }
-        } catch (final IllegalAccessException | IllegalArgumentException
-                | InvocationTargetException e) {
+        } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
             throw LOGGER.throwing(e);
         }
         if (method.getReturnType().getClass().equals(Void.class.getClass())) {
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/PersistenceManager.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/PersistenceManager.java
index 2f58b77fed032a27d1e818891c94a87f6de40eaf..e7cedbb17bc74f2ae082cb6c470beb9d68e3f63c 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/PersistenceManager.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/PersistenceManager.java
@@ -63,7 +63,7 @@ public enum PersistenceManager {
         final EntityManagerFactory emf = Persistence.createEntityManagerFactory("agrometinfo");
         Objects.requireNonNull(emf, "EntityManagerFactory must be found for 'agrometinfo'!");
         semf = (ScopedEntityManagerFactory) Proxy.newProxyInstance(
-                ScopedEntityManagerFactory.class.getClassLoader(),
+                Thread.currentThread().getContextClassLoader(),
                 new Class[] {ScopedEntityManagerFactory.class},
                 new EntityManagerFactoryHandler(emf));
     }
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/PraDailyValueDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/PraDailyValueDaoHibernate.java
index 2759837ed44dd1c7267209b5c33aa055101f1c26..28a1044a98765ca0b736280b410d4943f088d352 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/PraDailyValueDaoHibernate.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/PraDailyValueDaoHibernate.java
@@ -29,6 +29,11 @@ import lombok.NonNull;
 @ApplicationScoped
 public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> implements PraDailyValueDao {
 
+    /**
+     * Statement parameter.
+     */
+    private static final String PARAM_START = "start";
+
     private static Float toFloat(final Tuple t, final String column) {
         if (t.get(column) == null) {
             return null;
@@ -36,7 +41,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
         return ((Number) t.get(column)).floatValue();
     }
 
-    private static PraDailyValue toPraDailyValue(final Object[] row) {
+    private static PraDailyValue toPraDailyValue(final Object... row) {
         final var value = new PraDailyValue();
         int i = 0;
         value.setDate(DateUtils.toLocalDate((Date) row[i++]));
@@ -76,7 +81,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
 
     @Override
     public final List<PraDailyValue> find(final Indicator indicator, final LocalDate date) {
-        final Map<String, Object> params = Map.of("indicator", indicator.getId(), "date", date);
+        final Map<String, Object> params = Map.of(PARAM_INDICATOR, indicator.getId(), PARAM_DATE, date);
         final var sql = """
                 SELECT
                 v.date,
@@ -95,12 +100,13 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
     @Override
     public final PraDailyValue find(final Indicator indicator, final LocalDate date, final Pra pra) {
         final var jpql = "SELECT t FROM PraDailyValue t WHERE t.indicator=:indicator AND t.date=:date AND t.pra=:pra";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date, "pra", pra), PraDailyValue.class);
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date, "pra", pra),
+                PraDailyValue.class);
     }
 
     @Override
     public final List<PraDailyValue> find(final Indicator indicator, final Region region, final LocalDate date) {
-        final Map<String, Object> params = Map.of("indicator", indicator.getId(), "date", date, "region",
+        final Map<String, Object> params = Map.of(PARAM_INDICATOR, indicator.getId(), PARAM_DATE, date, PARAM_REGION,
                 region.getId());
         final var sql = """
                 SELECT
@@ -124,7 +130,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 SELECT AVG(t.comparedValue)
                 FROM PraDailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date), Double.class);
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date), Double.class);
     }
 
     @Override
@@ -135,7 +141,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 FROM PraDailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date AND t.pra.department.region.id=:region AND
                 t.computedValue IS NOT NULL""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date, "region", regionId),
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date, PARAM_REGION, regionId),
                 Double.class);
     }
 
@@ -145,7 +151,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 SELECT AVG(t.computedValue)
                 FROM PraDailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date), Double.class);
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date), Double.class);
     }
 
     @Override
@@ -156,7 +162,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 FROM PraDailyValue AS t
                 WHERE t.indicator=:indicator AND t.date=:date AND t.pra.department.region.id=:region AND
                 t.computedValue IS NOT NULL""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "date", date, "region", regionId),
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_DATE, date, PARAM_REGION, regionId),
                 Double.class);
     }
 
@@ -176,8 +182,8 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 ORDER BY t.date ASC
                 """;
         final Map<String, Object> params = Map.of(//
-                "indicator", indicator, //
-                "start", start, //
+                PARAM_INDICATOR, indicator, //
+                PARAM_START, start, //
                 "end", end);
         return findDailyValues(jpql, params);
     }
@@ -198,9 +204,9 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 ORDER BY t.date ASC
                 """;
         final Map<String, Object> params = Map.of(//
-                "indicator", indicator, //
+                PARAM_INDICATOR, indicator, //
                 "pra", pra, //
-                "start", start, //
+                PARAM_START, start, //
                 "end", end);
         return findDailyValues(jpql, params);
     }
@@ -221,9 +227,9 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 ORDER BY t.date ASC
                 """;
         final Map<String, Object> params = Map.of(//
-                "indicator", indicator, //
-                "region", region, //
-                "start", start, //
+                PARAM_INDICATOR, indicator, //
+                PARAM_REGION, region, //
+                PARAM_START, start, //
                 "end", end);
         return findDailyValues(jpql, params);
     }
@@ -236,7 +242,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
             }
             return query.getResultStream()//
                     .collect(Collectors.toMap(//
-                            t -> (LocalDate) t.get("date"), //
+                            t -> (LocalDate) t.get(PARAM_DATE), //
                             t -> {
                                 final Float[] values = new Float[SummaryDTO.Q95_INDEX + 1];
                                 values[SummaryDTO.COMPUTED_INDEX] = ((Number) t.get("value")).floatValue();
@@ -254,7 +260,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
     @Override
     public final List<Indicator> findIndicators(@NonNull final Integer year) {
         final var sql = "SELECT DISTINCT indicator FROM v_pra_dailyvalue WHERE EXTRACT(YEAR FROM date) = :year";
-        final List<Long> ids = super.findAllBySQL(sql, Map.of("year", year)).stream() //
+        final List<Long> ids = super.findAllBySQL(sql, Map.of(PARAM_YEAR, year)).stream() //
                 .map(i -> Long.valueOf((int) i)).toList();
         final var jpql = "SELECT i FROM Indicator AS i JOIN i.period WHERE i.id IN (:ids)";
         return super.findAllByJPQL(jpql, Map.of("ids", ids), Indicator.class);
@@ -266,7 +272,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                 SELECT MAX(t.date)
                 FROM PraDailyValue AS t
                 WHERE t.indicator=:indicator AND EXTRACT(YEAR FROM t.date) = :year""";
-        return super.findOneByJPQL(jpql, Map.of("indicator", indicator, "year", year), LocalDate.class);
+        return super.findOneByJPQL(jpql, Map.of(PARAM_INDICATOR, indicator, PARAM_YEAR, year), LocalDate.class);
     }
 
     private List<PraDailyValue> findPraDailyValues(final String sql, final Map<String, Object> params) {
@@ -305,7 +311,7 @@ public class PraDailyValueDaoHibernate extends DaoHibernate<PraDailyValue> imple
                     JOIN d.region AS r
                 WHERE EXTRACT(YEAR FROM t.date) = :year
                 ORDER BY r.name""";
-        return super.findAllByJPQL(jpql, Map.of("year", year), Region.class);
+        return super.findAllByJPQL(jpql, Map.of(PARAM_YEAR, year), Region.class);
     }
 
     @Override
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/exception/ErrorMessage.java b/www-server/src/main/java/fr/agrometinfo/www/server/exception/ErrorMessage.java
index 8f472784fcfccdbd145d9ebce92ff35047d1fca8..4d530a7284ea201828728e606484d84f01d63361 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/exception/ErrorMessage.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/exception/ErrorMessage.java
@@ -1,9 +1,10 @@
 package fr.agrometinfo.www.server.exception;
 
-import fr.agrometinfo.www.server.I18n;
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Locale;
+
+import fr.agrometinfo.www.server.I18n;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
@@ -98,11 +99,10 @@ public final class ErrorMessage implements Serializable {
      */
     public String toJSON() {
         final var sb = new StringBuilder();
-        sb.append("{");
-        sb.append("\"bundleName\": \"").append(bundleName).append("\", ");
-        sb.append("\"errorCode\": \"").append(type.getFullCode()).append("\", ");
-        sb.append("\"errorName\": \"").append(type.getName()).append("\", ");
-        sb.append("\"arguments\": [");
+        sb.append("{\"bundleName\": \"").append(bundleName);
+        sb.append("\", \"errorCode\": \"").append(type.getFullCode());
+        sb.append("\", \"errorName\": \"").append(type.getName());
+        sb.append("\", \"arguments\": [");
         if (arguments != null) {
             boolean first = true;
             for (final Object arg : arguments) {
@@ -111,11 +111,11 @@ public final class ErrorMessage implements Serializable {
                 } else {
                     sb.append(", ");
                 }
-                sb.append("\"")
+                sb.append('"')
                 .append(arg.toString()
                         .replace("\"", "\\\"")
                         .replace("'", "\\'"))
-                .append("\"");
+                .append('"');
             }
         }
         sb.append("]}");
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Cell.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Cell.java
index acd8208548a871d9f11020eed1911393fefe2559..e42fa28058e60cb650a359d1dd46846fd827995a 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Cell.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Cell.java
@@ -21,6 +21,10 @@ import lombok.Data;
 @Entity
 @Table(name = "cell")
 public class Cell {
+    /**
+     * Column definition.
+     */
+    private static final String NUMERIC_16_14 = "NUMERIC(16,14)";
     /**
      * Creation date.
      */
@@ -46,22 +50,22 @@ public class Cell {
     /**
      * Latitude of point 1 [°N].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lat1;
     /**
      * Latitude of point 2 [°N].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lat2;
     /**
      * Latitude of point 3 [°N].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lat3;
     /**
      * Latitude of point 4 [°N].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lat4;
     /**
      * Longitude of cell center [°E].
@@ -70,22 +74,22 @@ public class Cell {
     /**
      * Longitude of point 1 [°E].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lon1;
     /**
      * Longitude of point 2 [°E].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lon2;
     /**
      * Longitude of point 3 [°E].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lon3;
     /**
      * Longitude of point 4 [°E].
      */
-    @Column(columnDefinition = "NUMERIC(16,14)")
+    @Column(columnDefinition = NUMERIC_16_14)
     private Double lon4;
 
 }
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java
index 860128907cf0084cd64ef306a464e6c60bbe8531..4783deeb54c8acd5bf464d2052f1f31a36a614fb 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java
@@ -61,6 +61,40 @@ import lombok.extern.log4j.Log4j2;
 @Path(IndicatorService.PATH)
 @RequestScoped
 public class IndicatorResource implements IndicatorService {
+    /**
+     * Query parameter.
+     */
+    private static final String PARAM_COMPARISON = "comparison";
+
+    /**
+     * Query parameter.
+     */
+    private static final String PARAM_ID = "id";
+
+    /**
+     * Query parameter.
+     */
+    private static final String PARAM_INDICATOR = "indicator";
+
+    /**
+     * Query parameter.
+     */
+    private static final String PARAM_LEVEL = "level";
+
+    /**
+     * Query parameter.
+     */
+    private static final String PARAM_PERIOD = "period";
+
+    /**
+     * Query parameter.
+     */
+    private static final String PARAM_REGION = "region";
+
+    /**
+     * Query parameter.
+     */
+    private static final String PARAM_YEAR = "year";
 
     /**
      * Get the date related to the year.
@@ -141,10 +175,10 @@ public class IndicatorResource implements IndicatorService {
     private CacheService cacheService;
 
     /**
-     * DAO for {@link PraDailyValue}.
+     * HTTP headers for response.
      */
-    @Inject
-    private PraDailyValueDao praDailyValueDao;
+    @Context
+    private HttpHeaders httpHeaders;
 
     /**
      * Information for HTTP servlet.
@@ -158,6 +192,12 @@ public class IndicatorResource implements IndicatorService {
     @Inject
     private IndicatorDao indicatorDao;
 
+    /**
+     * DAO for {@link PraDailyValue}.
+     */
+    @Inject
+    private PraDailyValueDao praDailyValueDao;
+
     /**
      * DAO for {@link Pra}.
      */
@@ -176,12 +216,6 @@ public class IndicatorResource implements IndicatorService {
     @Context
     private Request request;
 
-    /**
-     * HTTP headers for response.
-     */
-    @Context
-    private HttpHeaders httpHeaders;
-
     /**
      * @param collection collection to annotate
      * @param indicator  indicator with metadata to add
@@ -213,13 +247,7 @@ public class IndicatorResource implements IndicatorService {
      */
     private void checkRequired(final Object value, final String queryParamName) {
         if (value instanceof final String str && str.isBlank() || value == null) {
-            final var status = Response.Status.BAD_REQUEST;
-            throw new WebApplicationException(//
-                    Response.status(status) //
-                    .entity(ErrorResponseDTO.of(status.getStatusCode(), //
-                            status.getReasonPhrase(), //
-                            queryParamName + " parameter is mandatory")) //
-                    .build());
+            throwWebApplicationException(Response.Status.BAD_REQUEST, queryParamName + " parameter is mandatory");
         }
     }
 
@@ -235,7 +263,7 @@ public class IndicatorResource implements IndicatorService {
     @Path(PATH_LIST)
     @Produces(MediaType.APPLICATION_JSON)
     @Override
-    public List<PeriodDTO> getPeriods(@QueryParam(value = "year") @NonNull final Integer year) {
+    public List<PeriodDTO> getPeriods(@QueryParam(value = PARAM_YEAR) @NonNull final Integer year) {
         LOGGER.traceEntry();
         final var locale = LocaleUtils.getLocale(httpServletRequest);
         // HTTP cache headers
@@ -279,7 +307,7 @@ public class IndicatorResource implements IndicatorService {
     @Path(PATH_REGIONS)
     @Produces(MediaType.APPLICATION_JSON)
     @Override
-    public Map<String, String> getRegions(@QueryParam(value = "year") @NonNull final Integer year) {
+    public Map<String, String> getRegions(@QueryParam(value = PARAM_YEAR) @NonNull final Integer year) {
         // HTTP cache headers
         cacheService.setCacheKey(PATH, PATH_REGIONS, year);
         cacheService.setHeaders(httpHeaders);
@@ -303,14 +331,14 @@ public class IndicatorResource implements IndicatorService {
     @Path(PATH_SUMMARY)
     @Produces(MediaType.APPLICATION_JSON)
     @Override
-    public SummaryDTO getSummary(@QueryParam(value = "indicator") final String indicatorUid,
-            @QueryParam(value = "period") final String periodCode,
-            @QueryParam(value = "level") @NonNull final FeatureLevel level,
-            @QueryParam(value = "id") final String id,
-            @QueryParam(value = "year") final Integer year) {
-        checkRequired(indicatorUid, "indicator");
-        checkRequired(periodCode, "period");
-        checkRequired(year, "year");
+    public SummaryDTO getSummary(@QueryParam(value = PARAM_INDICATOR) final String indicatorUid,
+            @QueryParam(value = PARAM_PERIOD) final String periodCode,
+            @QueryParam(value = PARAM_LEVEL) @NonNull final FeatureLevel level,
+            @QueryParam(value = PARAM_ID) final String id,
+            @QueryParam(value = PARAM_YEAR) final Integer year) {
+        checkRequired(indicatorUid, PARAM_INDICATOR);
+        checkRequired(periodCode, PARAM_PERIOD);
+        checkRequired(year, PARAM_YEAR);
         final var locale = LocaleUtils.getLocale(httpServletRequest);
         // HTTP cache headers
         cacheService.setCacheKey(PATH, PATH_SUMMARY, locale, indicatorUid, periodCode,
@@ -419,13 +447,14 @@ public class IndicatorResource implements IndicatorService {
     @Path(PATH_VALUES)
     @Produces("application/geo+json")
     @Override
-    public FeatureCollection getValues(@QueryParam(value = "indicator") final String indicatorUid,
-            @QueryParam(value = "period") final String periodCode, @QueryParam(value = "region") final Integer regionId,
-            @QueryParam(value = "year") final Integer year,
-            @QueryParam(value = "comparison") final Boolean comparison) {
-        checkRequired(indicatorUid, "indicator");
-        checkRequired(periodCode, "period");
-        checkRequired(year, "year");
+    public FeatureCollection getValues(@QueryParam(value = PARAM_INDICATOR) final String indicatorUid,
+            @QueryParam(value = PARAM_PERIOD) final String periodCode,
+            @QueryParam(value = PARAM_REGION) final Integer regionId,
+            @QueryParam(value = PARAM_YEAR) final Integer year,
+            @QueryParam(value = PARAM_COMPARISON) final Boolean comparison) {
+        checkRequired(indicatorUid, PARAM_INDICATOR);
+        checkRequired(periodCode, PARAM_PERIOD);
+        checkRequired(year, PARAM_YEAR);
         final var locale = LocaleUtils.getLocale(httpServletRequest);
         cacheService.setCacheKey(PATH, PATH_VALUES, indicatorUid, periodCode,
                 regionId, year, comparison, locale);
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java
index 6be1db7adb1d9500df5ab3a5d3411024a87c21cd..d837927fe30d23cb06329c2d77ffa305c144c2ab 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java
@@ -2,7 +2,6 @@ package fr.agrometinfo.www.server.rs;
 
 import java.time.LocalDateTime;
 import java.util.List;
-import java.util.stream.Collectors;
 
 import fr.agrometinfo.www.server.AgroMetInfoConfiguration;
 import fr.agrometinfo.www.server.dao.SurveyOptionDao;
@@ -41,17 +40,6 @@ import lombok.extern.log4j.Log4j2;
 @Path(SurveyFormService.PATH)
 @RequestScoped
 public class SurveyFormResource implements SurveyFormService {
-    /**
-     * Convert {@link SurveyQuestion} entity to dto.
-     * @param question entity
-     * @return dto
-     */
-    static SurveyQuestionDTO toDto(final SurveyQuestion question) {
-        final SurveyQuestionDTO dto = new SurveyQuestionDTO();
-        dto.setId(question.getId());
-        dto.setDescription(question.getDescription());
-        return dto;
-    }
     /**
      * Convert {@link SurveyOption} entity to dto.
      * @param response entity
@@ -65,15 +53,15 @@ public class SurveyFormResource implements SurveyFormService {
         return dto;
     }
     /**
-     * Convert {@link SurveyQuestionDTO} dto to entity.
-     * @param dto question
-     * @return entity
+     * Convert {@link SurveyQuestion} entity to dto.
+     * @param question entity
+     * @return dto
      */
-    private static SurveyQuestion toEntity(final SurveyQuestionDTO dto) {
-        final SurveyQuestion question = new SurveyQuestion();
-        question.setId(dto.getId());
-        question.setDescription(dto.getDescription());
-        return question;
+    static SurveyQuestionDTO toDto(final SurveyQuestion question) {
+        final SurveyQuestionDTO dto = new SurveyQuestionDTO();
+        dto.setId(question.getId());
+        dto.setDescription(question.getDescription());
+        return dto;
     }
     /**
      * Convert {@link SurveyOptionDTO} dto to entity.
@@ -87,6 +75,17 @@ public class SurveyFormResource implements SurveyFormService {
         response.setDescription(dto.getDescription());
         return response;
     }
+    /**
+     * Convert {@link SurveyQuestionDTO} dto to entity.
+     * @param dto question
+     * @return entity
+     */
+    private static SurveyQuestion toEntity(final SurveyQuestionDTO dto) {
+        final SurveyQuestion question = new SurveyQuestion();
+        question.setId(dto.getId());
+        question.setDescription(dto.getDescription());
+        return question;
+    }
     /**
      * Application configuration.
      */
@@ -131,7 +130,7 @@ public class SurveyFormResource implements SurveyFormService {
                             badRequest.getStatusCode(),
                             badRequest.getReasonPhrase(),
                             queryParamName + " parameter is mandatory")
-                        ).build());
+                            ).build());
         }
     }
 
@@ -140,8 +139,7 @@ public class SurveyFormResource implements SurveyFormService {
     @Produces(MediaType.APPLICATION_JSON)
     @Override
     public List<SurveyOptionDTO> getResponses() {
-        return responsesDao.findAll().stream()
-                .map(SurveyFormResource::toDto).collect(Collectors.toList());
+        return responsesDao.findAll().stream().map(SurveyFormResource::toDto).toList();
     }
 
     @POST
@@ -165,9 +163,9 @@ public class SurveyFormResource implements SurveyFormService {
             }
 
             final Long qRef = dto.getId();
-            List<SurveyOptionDTO> associatedResponses = data.getResponses()
+            final List<SurveyOptionDTO> associatedResponses = data.getResponses()
                     .stream().filter(f -> f.getQuestion().getId() == qRef)
-                    .collect(Collectors.toList());
+                    .toList();
 
             for (final SurveyOptionDTO rDto : associatedResponses) {
                 final SurveyOption r = toEntity(rDto);
@@ -188,7 +186,7 @@ public class SurveyFormResource implements SurveyFormService {
 
         // once everything is inserted, send an email to support
         try {
-        this.mailService.send(toMail(data));
+            this.mailService.send(toMail(data));
         } catch (final AgroMetInfoException e) {
             LOGGER.info("Failed to send e-mail: {}", "");
         }
@@ -211,17 +209,20 @@ public class SurveyFormResource implements SurveyFormService {
         builder.append("Un utilisateur vient de remplir le formulaire d'enquête d'AgroMetInfo à l'instant.\n\n");
         builder.append("Il a répondu à ").append(data.getQuestions().size()).append(" question(s) :\n");
 
-        data.getQuestions().forEach((q) -> {
+        data.getQuestions().forEach(q -> {
             builder.append("\t• « ").append(q.getDescription()).append(" » :\n");
             data.getResponses().stream().filter(f -> f.getQuestion().getId() == q.getId())
-                .collect(Collectors.toList())
-                .forEach((r) -> builder.append("\t\t- ").append(r.getDescription()).append("\n"));
+            .forEach(r -> builder.append("\t\t- ") //
+                    .append(r.getDescription()) //
+                    .append('\n'));
 
             if (data.getOtherTextMap().containsKey(q.getId())
                     && data.getOtherTextMap().get(q.getId()) != null) {
-                builder.append("\t\t- Réponse libre : « ").append(data.getOtherTextMap().get(q.getId())).append(" »\n");
+                builder.append("\t\t- Réponse libre : « ") //
+                .append(data.getOtherTextMap().get(q.getId())) //
+                .append(" »\n");
             }
-            builder.append("\n");
+            builder.append('\n');
         });
         mail.setContent(builder.toString());
         return mail;
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/filter/LogFilter.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/filter/LogFilter.java
index 94c4974d26634d6daf4b65b3b4c86802061e7e4a..33d7d08d1cf427a6746f77548767d84b7eec3a3c 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/filter/LogFilter.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/filter/LogFilter.java
@@ -46,10 +46,10 @@ public class LogFilter implements ContainerRequestFilter, ContainerResponseFilte
      */
     private void log(final String context, final UriInfo uriInfo, final MultivaluedMap<String, ?> reqHeaders,
             final MultivaluedMap<String, ?> resHeaders) {
-        LOGGER.trace("{}\nPath: {}", context, uriInfo.getPath());
-        LOGGER.trace("HTTP headers of the request: {}", reqHeaders);
+        LOGGER.atTrace().log("{}\nPath: {}", context, uriInfo.getPath());
+        LOGGER.atTrace().log("HTTP headers of the request: {}", reqHeaders);
         if (resHeaders != null) {
-            LOGGER.trace("HTTP headers of the response: {}", resHeaders);
+            LOGGER.atTrace().log("HTTP headers of the response: {}", resHeaders);
         }
     }
 }
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/scheduled/BackgroundJobManager.java b/www-server/src/main/java/fr/agrometinfo/www/server/scheduled/BackgroundJobManager.java
index 6e3f718acc40af6d3cdb7be37f43e1fe6cecdd7d..a70b4b81f3a1addafcff0bad1a6a168d7e97f37b 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/scheduled/BackgroundJobManager.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/scheduled/BackgroundJobManager.java
@@ -1,5 +1,6 @@
 package fr.agrometinfo.www.server.scheduled;
 
+import java.math.BigDecimal;
 import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -15,7 +16,6 @@ import jakarta.inject.Inject;
 import jakarta.servlet.ServletContextEvent;
 import jakarta.servlet.ServletContextListener;
 import jakarta.servlet.annotation.WebListener;
-import java.math.BigDecimal;
 import lombok.extern.log4j.Log4j2;
 
 /**
@@ -103,8 +103,8 @@ public class BackgroundJobManager implements ServletContextListener {
      */
     private void scheduleEveryDayAt(final Runnable runnable, final int hour, final int minute, final int second) {
         final long initDelay = initialDelay(hour, minute, second);
-        LOGGER.trace("Scheduling {} after {}s at {}:{}:{}", runnable.getClass().getCanonicalName(), initDelay, hour,
-                minute, second);
+        LOGGER.atTrace().log("Scheduling {} after {}s at {}:{}:{}", runnable.getClass().getCanonicalName(), initDelay,
+                hour, minute, second);
         scheduler.scheduleAtFixedRate(runnable, initDelay, DAY_IN_SECONDS, TimeUnit.SECONDS);
     }
 
@@ -117,7 +117,7 @@ public class BackgroundJobManager implements ServletContextListener {
      *            period between 2 runs (in seconds)
      */
     private void scheduleEveryPeriod(final Runnable runnable, final int period) {
-        LOGGER.trace("Scheduling {} after {}s.", runnable.getClass().getCanonicalName(), period);
+        LOGGER.atTrace().log("Scheduling {} after {}s.", runnable.getClass().getCanonicalName(), period);
         scheduler.scheduleAtFixedRate(runnable, period, period, TimeUnit.SECONDS);
     }
 
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/CacheService.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/CacheService.java
index 316ef21dc0652abb7ac900e6e9f916a9168564a1..58e95b2101db4dec6e13735d201559d240bc4fa1 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/service/CacheService.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/CacheService.java
@@ -1,12 +1,11 @@
 package fr.agrometinfo.www.server.service;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.Date;
@@ -52,7 +51,7 @@ public class CacheService {
     /**
      * Number of milliseconds in a day.
      */
-    private static final long MILLISECONDS_IN_A_DAY = 60 * 60 * 24 * 1_000;
+    private static final long MILLISECONDS_IN_A_DAY = 60 * 60 * 24 * 1_000L;
 
     /**
      * Cache directory path.
@@ -62,11 +61,11 @@ public class CacheService {
     @Named("cacheDirectory")
     private String cacheDirectory;
 
-
     /**
      * Key related to object to cache.
      */
     private String cacheKey;
+
     /**
      * Date of last modification of indicators values in database.
      */
@@ -101,7 +100,8 @@ public class CacheService {
         if (!cacheFile.exists()) {
             return null;
         }
-        try (FileInputStream fis = new FileInputStream(cacheFile); FSTObjectInput in = new FSTObjectInput(fis)) {
+        try (FSTObjectInput in = new FSTObjectInput(
+                Files.newInputStream(cacheFile.toPath(), StandardOpenOption.READ))) {
             return in.readObject();
         } catch (final IOException | ClassNotFoundException e) {
             LOGGER.fatal(e);
@@ -119,7 +119,7 @@ public class CacheService {
         final var cc = new CacheControl();
         final LocalDateTime dayAfter = lastModification.plusDays(nbOfDays);
         final Long maxAge = ChronoUnit.SECONDS.between(LocalDateTime.now(), dayAfter);
-        // max age = time inn seconds
+        // max age = time in seconds
         cc.setMaxAge(maxAge.intValue());
         return cc;
     }
@@ -170,8 +170,7 @@ public class CacheService {
         LOGGER.traceEntry("{}", object);
         final File cacheFile = getCacheFile();
         LOGGER.info("file Path = {}", cacheFile);
-        try (FileOutputStream fos = new FileOutputStream(cacheFile);
-                FSTObjectOutput out = FSTCONF.getObjectOutput(fos)) {
+        try (FSTObjectOutput out = FSTCONF.getObjectOutput(Files.newOutputStream(cacheFile.toPath()))) {
             out.writeObject(object);
             out.flush();
         } catch (final IOException e) {
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java
index 230a40cca59be0d53d7058a95df01a456ea49752..bc7264f14006b2e56fce9d39c9b90894b751fac8 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java
@@ -47,6 +47,44 @@ import lombok.Getter;
 @ApplicationScoped
 public class MailServiceImpl implements MailService {
 
+    /**
+     * Log4j2 appender to send error logs by e-mail.
+     */
+    private class MailAppender extends AbstractAppender {
+
+        /**
+         * Logger name.
+         */
+        private static final String NAME = "MailAppender";
+
+        /**
+         * Constructor.
+         *
+         * @param filter           The Filter to associate with the Appender.
+         * @param layout           The layout to use to format the event.
+         * @param ignoreExceptions If true, exceptions will be logged and suppressed. If
+         *                         false errors will be logged and then passed to the
+         *                         application.
+         */
+        MailAppender(final Filter filter, final Layout<? extends Serializable> layout, final boolean ignoreExceptions) {
+            super(NAME, filter, layout, ignoreExceptions, null);
+        }
+
+        @Override
+        public void append(final LogEvent event) {
+            final var mail = new Mail();
+            mail.setFromAddress("agrometinfo@inrae.fr");
+            mail.setSubject("AgroMetInfo - error log");
+            mail.setContent(super.toSerializable(event).toString());
+            mail.setToAddresses(List.of(configuration.get(ConfigurationKey.LOG_EMAIL)));
+            try {
+                send(mail);
+            } catch (final AgroMetInfoException e) {
+                // do nothing
+                LOGGER.atInfo().log("Cannot send email: {}", e.getMessage());
+            }
+        }
+    }
 
     /**
      * Keys from messages.properties used to warn about errors.
@@ -97,42 +135,15 @@ public class MailServiceImpl implements MailService {
     }
 
     /**
-     * Log4j2 appender to send error logs by e-mail.
+     * @param addresses e-mail addresses
+     * @return string representation of addresses
      */
-    private class MailAppender extends AbstractAppender {
-
-        /**
-         * Logger name.
-         */
-        private static final String NAME = "MailAppender";
-
-        /**
-         * Constructor.
-         *
-         * @param filter           The Filter to associate with the Appender.
-         * @param layout           The layout to use to format the event.
-         * @param ignoreExceptions If true, exceptions will be logged and suppressed. If
-         *                         false errors will be logged and then passed to the
-         *                         application.
-         */
-        MailAppender(final Filter filter, final Layout<? extends Serializable> layout, final boolean ignoreExceptions) {
-            super(NAME, filter, layout, ignoreExceptions, null);
-        }
-
-        @Override
-        public void append(final LogEvent event) {
-            final var mail = new Mail();
-            mail.setFromAddress("agrometinfo@inrae.fr");
-            mail.setSubject("AgroMetInfo - error log");
-            mail.setContent(super.toSerializable(event).toString());
-            mail.setToAddresses(List.of(configuration.get(ConfigurationKey.LOG_EMAIL)));
-            try {
-                send(mail);
-            } catch (final AgroMetInfoException e) {
-                // do nothing
-                LOGGER.info("Cannot send email: {}", e.getMessage());
-            }
+    private static String toString(final Address[] addresses) {
+        final var sj = new StringJoiner(", ");
+        for (final Address addr : addresses) {
+            sj.add(addr.toString());
         }
+        return sj.toString();
     }
 
     /**
@@ -215,17 +226,16 @@ public class MailServiceImpl implements MailService {
         }
         try {
             Transport.send(message);
-        } catch (final MessagingException e) {
-            if (e instanceof final SendFailedException sfe) {
-                final Address[] invalid = sfe.getInvalidAddresses();
-                if (invalid != null) {
-                    throw new AgroMetInfoException(MailErrorType.SEND_FAILED_INVALID, subject, toString(invalid));
-                }
-                final Address[] validUnsent = sfe.getValidUnsentAddresses();
-                if (validUnsent != null) {
-                    throw new AgroMetInfoException(MailErrorType.SEND_FAILED_VALID, subject, toString(validUnsent));
-                }
+        } catch (final SendFailedException sfe) {
+            final Address[] invalid = sfe.getInvalidAddresses();
+            if (invalid != null) {
+                throw new AgroMetInfoException(MailErrorType.SEND_FAILED_INVALID, subject, toString(invalid));
             }
+            final Address[] validUnsent = sfe.getValidUnsentAddresses();
+            if (validUnsent != null) {
+                throw new AgroMetInfoException(MailErrorType.SEND_FAILED_VALID, subject, toString(validUnsent));
+            }
+        } catch (final MessagingException e) {
             throw new AgroMetInfoException(MailErrorType.SEND_FAILED, subject, recipients, e.getMessage());
         }
     }
@@ -251,7 +261,7 @@ public class MailServiceImpl implements MailService {
                 to.add(new InternetAddress(addr));
             }
             message.setRecipients(Message.RecipientType.TO, to.toArray(InternetAddress[]::new));
-            if ("prod".equals(environment)) {
+            if (configuration.isProdEnvironment()) {
                 message.setSubject("AgroMetInfo : " + mail.getSubject());
             } else {
                 message.setSubject("AgroMetInfo " + environment + " : " + mail.getSubject());
@@ -265,16 +275,4 @@ public class MailServiceImpl implements MailService {
         }
     }
 
-    /**
-     * @param addresses e-mail addresses
-     * @return string representation of addresses
-     */
-    private String toString(final Address[] addresses) {
-        final var sj = new StringJoiner(", ");
-        for (final Address addr : addresses) {
-            sj.add(addr.toString());
-        }
-        return sj.toString();
-    }
-
 }
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java b/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java
index 7c22f781de48d1b8eb4c29f73b23917950a2068f..4928a0b60fc3960d6e293da69635ddb25a7e0e69 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java
@@ -23,7 +23,7 @@ public final class AppVersion {
      * @return Date of application build
      */
     public static Date getBuildDate() {
-        final var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        final var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
         try {
             return sdf.parse(getString("build.date"));
         } catch (final ParseException e) {
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/I18nTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/I18nTest.java
index 2f94f124e22f1c80e049d595632339b0ba1ebfa6..185fa50a5abe4764a989fe6a69a385c14788fc53 100644
--- a/www-server/src/test/java/fr/agrometinfo/www/server/I18nTest.java
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/I18nTest.java
@@ -24,6 +24,8 @@ import fr.agrometinfo.www.server.I18n.Operator;
 class I18nTest {
 
 
+    private static final String KEY_CATS = "cats";
+    private static final String KEY_COMPARISON = "comparison";
     /**
      * Key for plural messages to test.
      */
@@ -45,15 +47,15 @@ class I18nTest {
                 Arguments.of(3, KEY, "Il y a 3 produits dans votre panier, ce qui est peu."), //
                 Arguments.of(42, KEY, "Il y a 42 produits dans votre panier, ce qui est un nombre spécial."), //
                 Arguments.of(101, KEY, "Il y a 101 produits dans votre panier, ce qui est beaucoup."), //
-Arguments.of(1_314, KEY, "Il y a 1 314 produits dans votre panier, ce qui est beaucoup."), //
-                Arguments.of(1, "cats", "Un chat"), //
+                Arguments.of(1_314, KEY, "Il y a 1 314 produits dans votre panier, ce qui est beaucoup."), //
+                Arguments.of(1, KEY_CATS, "Un chat"), //
                 // Variation is not present, default value.
-                Arguments.of(2, "cats", "2 chats"), //
-                Arguments.of(1, "comparison", "Valeur == 1"), //
-                Arguments.of(10, "comparison", "Valeur >= 10"), //
-                Arguments.of(11, "comparison", "Valeur > 10"), //
-                Arguments.of(-10, "comparison", "Valeur <= -10"), //
-                Arguments.of(-101, "comparison", "Valeur < -100") //
+                Arguments.of(2, KEY_CATS, "2 chats"), //
+                Arguments.of(1, KEY_COMPARISON, "Valeur == 1"), //
+                Arguments.of(10, KEY_COMPARISON, "Valeur >= 10"), //
+                Arguments.of(11, KEY_COMPARISON, "Valeur > 10"), //
+                Arguments.of(-10, KEY_COMPARISON, "Valeur <= -10"), //
+                Arguments.of(-101, KEY_COMPARISON, "Valeur < -100") //
                 );
     }
 
@@ -65,14 +67,14 @@ Arguments.of(1_314, KEY, "Il y a 1 314 produits dans votre panier, ce qui est
     @Test
     void contructorWithResourceBundle() {
         final var bundle = ResourceBundle.getBundle(NAME, Locale.FRENCH);
-        final var res = new I18n(bundle);
+        final var i18n = new I18n(bundle);
         String actual;
         String expected;
-        actual = res.get("error.title");
+        actual = i18n.get("error.title");
         expected = "Erreur";
         assertEquals(expected, actual);
 
-        actual = res.get("not.translated");
+        actual = i18n.get("not.translated");
         expected = "This message is not translated.";
         assertEquals(expected, actual);
     }
@@ -154,8 +156,8 @@ Arguments.of(1_314, KEY, "Il y a 1 314 produits dans votre panier, ce qui est
         operators.put("<0", I18n.Operator.CINF);
         operators.put("<=0", I18n.Operator.BINFEQ);
         operators.forEach((comparison, expected) -> {
-            final Optional<Operator> res = I18n.Operator.extract(comparison);
-            final I18n.Operator actual = res.orElse(null);
+            final Optional<Operator> optional = I18n.Operator.extract(comparison);
+            final I18n.Operator actual = optional.orElse(null);
             assertEquals(expected, actual, expected + " must be extracted from " + comparison);
         });
     }
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/dao/CellDaoHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/dao/CellDaoHibernateTest.java
index ac37e1bbaa773b334af9a844debd30eedac61921..3a35e2f9b860c6db1a65df0117f737baffe22d79 100644
--- a/www-server/src/test/java/fr/agrometinfo/www/server/dao/CellDaoHibernateTest.java
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/dao/CellDaoHibernateTest.java
@@ -11,7 +11,7 @@ public class CellDaoHibernateTest {
     /**
      * Total number of cells in the table.
      */
-    public static final long COUNT = 8_602;
+    public static final long EXPECTED_COUNT = 8_602;
     /**
      * DAO to test.
      */
@@ -23,7 +23,7 @@ public class CellDaoHibernateTest {
     @Test
     void count() {
         final long actual = dao.count();
-        assertEquals(COUNT, actual);
+        assertEquals(EXPECTED_COUNT, actual);
     }
 
     /**
@@ -32,6 +32,6 @@ public class CellDaoHibernateTest {
     @Test
     void findAll() {
         final var actual = dao.findAll();
-        assertEquals(COUNT, actual.size());
+        assertEquals(EXPECTED_COUNT, actual.size());
     }
 }
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/dao/DaoHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/dao/DaoHibernateTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..48e5e13c030d0980ac629a0d776cbc3edc8bad1f
--- /dev/null
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/dao/DaoHibernateTest.java
@@ -0,0 +1,24 @@
+package fr.agrometinfo.www.server.dao;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+import fr.agrometinfo.www.server.model.Cell;
+
+/**
+ * Test internal or common methods of Dao Hibernate implementation.
+ */
+class DaoHibernateTest {
+
+    /**
+     * DAO to test.
+     */
+    private final DaoHibernate<Cell> dao = new DaoHibernate<Cell>(Cell.class);
+
+    @Test
+    void getDriver() {
+        final String actual = dao.getDriver();
+        assertEquals("H2 JDBC Driver", actual);
+    }
+}
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/dao/PraDaoHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/dao/PraDaoHibernateTest.java
index ca1875e3d9e0a1e02a615ece060d48f1082ec89d..925b519c46e49438005a576311b5641c0e71f0a7 100644
--- a/www-server/src/test/java/fr/agrometinfo/www/server/dao/PraDaoHibernateTest.java
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/dao/PraDaoHibernateTest.java
@@ -12,7 +12,7 @@ public class PraDaoHibernateTest {
     /**
      * Total number of PRAs in the table.
      */
-    public static final long COUNT = 714;
+    public static final long EXPECTED_COUNT = 714;
     /**
      * DAO to test.
      */
@@ -24,7 +24,7 @@ public class PraDaoHibernateTest {
     @Test
     void count() {
         final var actual = dao.count();
-        assertEquals(COUNT, actual);
+        assertEquals(EXPECTED_COUNT, actual);
     }
 
     /**
@@ -33,7 +33,7 @@ public class PraDaoHibernateTest {
     @Test
     void findAll() {
         final var actual = dao.findAll();
-        assertEquals(COUNT, actual.size());
+        assertEquals(EXPECTED_COUNT, actual.size());
         final var first = actual.get(0);
         assertNotNull(first.getCoordinates());
         final int expected = 58;
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/GeometryResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/GeometryResourceTest.java
index 59b69f6df7df1f21734b455df8b1a4bd3c33b9ee..8c87f72378b3bca7102662f5eac810fac96478a2 100644
--- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/GeometryResourceTest.java
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/GeometryResourceTest.java
@@ -67,7 +67,7 @@ class GeometryResourceTest extends JerseyTest {
                 .request()//
                 .get(FeatureCollection.class);
         assertNotNull(actual);
-        final Integer expected = (int) PraDaoHibernateTest.COUNT;
+        final Integer expected = (int) PraDaoHibernateTest.EXPECTED_COUNT;
         assertEquals(expected, actual.getFeatures().size());
     }
 }
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/IndicatorResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/IndicatorResourceTest.java
index 23a483341aed631a6806c05f2b5860879de74214..abeb82bca2ac14e6eec312454bd58c2b56c55f78 100644
--- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/IndicatorResourceTest.java
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/IndicatorResourceTest.java
@@ -42,6 +42,14 @@ import jakarta.ws.rs.core.Application;
  * @author Olivier Maury
  */
 class IndicatorResourceTest extends JerseyTest {
+    private static final String PARAM_LEVEL = "level";
+
+    private static final String PARAM_PERIOD = "period";
+
+    private static final String PARAM_INDICATOR = "indicator";
+
+    private static final String PARAM_YEAR = "year";
+
     /**
      * Path separator.
      */
@@ -96,11 +104,11 @@ class IndicatorResourceTest extends JerseyTest {
     @Test
     void getSummary() {
         final var actual = target(IndicatorService.PATH + SEP + IndicatorService.PATH_SUMMARY)//
-                .queryParam("indicator", "rainsum") //
-                .queryParam("period", "year") //
-                .queryParam("level", "PRA") //
+                .queryParam(PARAM_INDICATOR, "rainsum") //
+                .queryParam(PARAM_PERIOD, "year") //
+                .queryParam(PARAM_LEVEL, "PRA") //
                 .queryParam("id", "59325") //
-                .queryParam("year", "2023") //
+                .queryParam(PARAM_YEAR, "2023") //
                 .request()//
                 .get(SummaryDTO.class);
         assertNotNull(actual, "response must not be null!");
@@ -115,10 +123,10 @@ class IndicatorResourceTest extends JerseyTest {
     @Test
     void getValues() {
         final var actual = target(IndicatorService.PATH + SEP + IndicatorService.PATH_VALUES)//
-                .queryParam("indicator", "rainsum") //
-                .queryParam("period", "year") //
+                .queryParam(PARAM_INDICATOR, "rainsum") //
+                .queryParam(PARAM_PERIOD, "year") //
                 .queryParam("compare", "false") //
-                .queryParam("year", "2023") //
+                .queryParam(PARAM_YEAR, "2023") //
                 .request()//
                 .get(FeatureCollection.class);
         assertNotNull(actual);
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java
index c20c4e2f7274bb03b56abbc3db47140a6d865c71..380f18006ce9575c261c7d49a1dfefba05dd72cf 100644
--- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java
@@ -54,7 +54,7 @@ import lombok.extern.log4j.Log4j2;
  * @author jdecome
  */
 @Log4j2
-public class SurveyFormResourceTest extends JerseyTest {
+class SurveyFormResourceTest extends JerseyTest {
     /**
      * Mock class for mail service.
      *
@@ -104,7 +104,7 @@ public class SurveyFormResourceTest extends JerseyTest {
     }
     /** Testing response retrieval from webservice. */
     @Test
-    public void getResponses() {
+    void getResponses() {
         try {
             // get all questions from DAO for verification.
             final List<SurveyQuestion> questions = questionsDao.findAll();
@@ -123,7 +123,7 @@ public class SurveyFormResourceTest extends JerseyTest {
                 assertTrue(questions.contains(r.getQuestion()), "Question of the answer « " + r.getDescription() + " » is not contained in the list of questions");
             }
         } catch (final JsonProcessingException e) {
-            log.info(e.getMessage());
+            LOGGER.atInfo().log(e.getMessage());
         }
     }
     /**
@@ -151,7 +151,7 @@ public class SurveyFormResourceTest extends JerseyTest {
 
     /** Test by setting answers for questions. */
     @Test
-    public void testWithJsonResponses() {
+    void testWithJsonResponses() {
         this.resetUserResponses();
         final List<SurveyQuestion> questionsList = questionsDao.findAll();
         final List<SurveyQuestionDTO> questionsDTO = questionsList.stream().map(SurveyFormResource::toDto).toList();
@@ -175,21 +175,21 @@ public class SurveyFormResourceTest extends JerseyTest {
         assertEquals(data.getQuestions(), questionsDTO, "List of questions in LoginFormData object does not match with original list");
         assertEquals(data.getResponses(), responsesDTO, "List of responses in LoginFormData object does not match with the original list");
         assertEquals(data.getOtherTextMap(), otherTextMap, "List of free responses in LoginFormData object does not match with the original list");
-        var ret = target(SurveyFormService.PATH + SEP + SurveyFormService.PATH_INSERT_RESPONSE)
+        final var ret = target(SurveyFormService.PATH + SEP + SurveyFormService.PATH_INSERT_RESPONSE)
                 .request(MediaType.APPLICATION_JSON).post(Entity.entity(data, MediaType.APPLICATION_JSON));
         assertEquals(ret.getStatus(), jakarta.ws.rs.core.Response.Status.OK.getStatusCode(), "The insert entry point should return status code 200 (OK)");
         // Retrieves all answers for all questions
-        List<UserResponse> list = new ArrayList<>();
+        final List<UserResponse> list = new ArrayList<>();
         for (final SurveyQuestion q : questionsDao.findAll()) {
             final List<UserResponse> responsesByQuestion = userResponsesDao.findAllByQuestion(q.getId());
             assertNotNull(responsesByQuestion, "The user's answer list for the question « " + q.getId() + " » must not be null");
-            responsesByQuestion.forEach((ur) -> {
+            responsesByQuestion.forEach(ur -> {
                 assertEquals(ur.getQuestion(), q, "The question in the answer does not match the original question « " + q.getDescription() + " »");
             });
             list.addAll(responsesByQuestion);
         }
         // Test on all answers
-        list.forEach((ur) -> {
+        list.forEach(ur -> {
             assertNotNull(ur.getDateTime(), "The response timestamp must not be null");
             assertTrue(ur.getId() > 0, "Reference of the user response must be greater than 0");
             if (ur.getOption() != null) {
@@ -201,20 +201,23 @@ public class SurveyFormResourceTest extends JerseyTest {
             }
         });
         // Check if all records has the same datetime
-        assertEquals(list.stream().map((u) -> u.getDateTime()).distinct().count(), 1, "Not all answers have the same datetime");
-        final LocalDateTime datetimeResponse = list.stream().map((u) -> u.getDateTime()).distinct().findFirst().get();
+        assertEquals(1, list.stream().map(UserResponse::getDateTime).distinct().count(),
+                "Not all answers have the same datetime");
+        final LocalDateTime datetimeResponse = list.stream().map(UserResponse::getDateTime).distinct().findFirst()
+                .get();
         assertNotNull(datetimeResponse, "The datetime read in the responses is null");
         // in this case, email address has inserted
         final List<UserEmail> emails = this.userEmailDao.getEmailAddressList();
         assertNotNull(emails, "The email list is not initialized (= null)");
         assertFalse(emails.isEmpty(), "Email list is empty");
-        emails.forEach((e) -> {
-            assertTrue((e.getId() > 0), "The object id must be greater than 0");
+        emails.forEach(e -> {
+            assertTrue(e.getId() > 0, "The object id must be greater than 0");
             assertNotNull(e.getDatetime(), "The timestamp of the question must not be null");
             assertNotNull(e.getEmail(), "The email address contained in the subject must not be null");
         });
-        assertEquals(emails.stream().map((e) -> e.getDatetime()).distinct().count(), 1, "Not all email addresses have the same datetime");
-        final LocalDateTime datetimeEmail = emails.stream().map((e) -> e.getDatetime()).distinct().findFirst().get();
+        assertEquals(1, emails.stream().map(e -> e.getDatetime()).distinct().count(),
+                "Not all email addresses have the same datetime");
+        final LocalDateTime datetimeEmail = emails.stream().map(e -> e.getDatetime()).distinct().findFirst().get();
         assertNotNull(datetimeEmail, "The datetime read in emails is null");
         assertEquals(datetimeResponse, datetimeEmail, "The two datetimes are not identical");
         // Check mail sended to support, when user filled survey form
diff --git a/www-server/src/test/java/lombok.config b/www-server/src/test/java/lombok.config
new file mode 100644
index 0000000000000000000000000000000000000000..aa03b2b4b29cc30538b9ff4aedb0ad557b5e0156
--- /dev/null
+++ b/www-server/src/test/java/lombok.config
@@ -0,0 +1,2 @@
+# configuration directives for Lombok. These apply to all source files in this directory and all child directories.
+lombok.log.fieldName = LOGGER
\ No newline at end of file
diff --git a/www-server/src/test/resources/log4j2.xml b/www-server/src/test/resources/log4j2.xml
index b72949cd6ad91cb5444cd5554c1e7dae4ac2d122..b83f6e6144e5fe7e769a34e80326bb50bed9bd4d 100644
--- a/www-server/src/test/resources/log4j2.xml
+++ b/www-server/src/test/resources/log4j2.xml
@@ -4,7 +4,7 @@
         <Appenders>
                 <Console name="console" target="SYSTEM_OUT">
                         <PatternLayout>
-                                <pattern>dev-cas | %d | %-5p | %c#%M() | %L - %m%n</pattern>
+                                <pattern>%d | %-5p | %c#%M() | %L - %m%n</pattern>
                         </PatternLayout>
                 </Console>
         </Appenders>
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ChoiceDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ChoiceDTO.java
index 40cf0a0d479fa2f9a6b17b14d95446f4982c1c10..e0a155b1c19f640d19b570890d9c79f3a198f602 100644
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ChoiceDTO.java
+++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ChoiceDTO.java
@@ -1,12 +1,13 @@
 package fr.agrometinfo.www.shared.dto;
 
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+
 import java.io.Serializable;
 
 import org.dominokit.jackson.annotation.JSONMapper;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
-import static java.lang.Boolean.FALSE;
-import static java.lang.Boolean.TRUE;
 
 /**
  * Choice from user to get indicators.
@@ -96,8 +97,8 @@ public final class ChoiceDTO implements Serializable {
      */
     @JsonIgnore
     public boolean isValid() {
-        return period != null && !period.trim().isEmpty() //
-                && indicator != null && !indicator.trim().isEmpty() //
+        return period != null && !period.isBlank() //
+                && indicator != null && !indicator.isBlank() //
                 && year != null;
     }
 
diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/IndicatorService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/IndicatorService.java
index 01525cecef5ff72048fe73ec0f0380de823ab09b..3ff1658ae7365b9284c450758819e10205052a27 100644
--- a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/IndicatorService.java
+++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/IndicatorService.java
@@ -22,6 +22,10 @@ import jakarta.ws.rs.QueryParam;
 @RequestFactory
 @Path(IndicatorService.PATH)
 public interface IndicatorService {
+    /**
+     * Same string for all.
+     */
+    String PARAM_YEAR = "year";
     /**
      * Service base path.
      */
@@ -66,7 +70,7 @@ public interface IndicatorService {
      */
     @GET
     @Path(PATH_LIST)
-    List<PeriodDTO> getPeriods(@QueryParam(value = "year") Integer year);
+    List<PeriodDTO> getPeriods(@QueryParam(value = PARAM_YEAR) Integer year);
 
     /**
      * @param year the year of indicator values
@@ -74,7 +78,7 @@ public interface IndicatorService {
      */
     @GET
     @Path(PATH_REGIONS)
-    Map<String, String> getRegions(@QueryParam(value = "year") Integer year);
+    Map<String, String> getRegions(@QueryParam(value = PARAM_YEAR) Integer year);
 
     /**
      * @param indicator indicator code
@@ -88,7 +92,7 @@ public interface IndicatorService {
     @Path(PATH_SUMMARY)
     SummaryDTO getSummary(@QueryParam(value = "indicator") String indicator,
             @QueryParam(value = "period") String period, @QueryParam(value = "level") FeatureLevel level,
-            @QueryParam(value = "id") String id, @QueryParam(value = "year") Integer year);
+            @QueryParam(value = "id") String id, @QueryParam(value = PARAM_YEAR) Integer year);
 
     /**
      * @param indicator  indicator code
@@ -102,7 +106,7 @@ public interface IndicatorService {
     @Path(PATH_VALUES)
     FeatureCollection getValues(@QueryParam(value = "indicator") String indicator,
             @QueryParam(value = "period") String period, @QueryParam(value = "region") Integer region,
-            @QueryParam(value = "year") Integer year, @QueryParam(value = "comparison") Boolean comparison);
+            @QueryParam(value = PARAM_YEAR) Integer year, @QueryParam(value = "comparison") Boolean comparison);
 
     /**
      * @return list of computed years.
diff --git a/www-shared/src/main/java/org/geojson/Feature.java b/www-shared/src/main/java/org/geojson/Feature.java
index 30dbbef3f20de8f9c9d39f7b8f8d9825f2e168dd..70beafb51252c087534a4c133ad19906d8b708ee 100644
--- a/www-shared/src/main/java/org/geojson/Feature.java
+++ b/www-shared/src/main/java/org/geojson/Feature.java
@@ -17,7 +17,6 @@ public final class Feature extends GeoJsonObject {
      */
     private static final long serialVersionUID = 5820780438006585201L;
 
-
     /**
      * Geometric attribute of the feature.
      */
@@ -27,6 +26,7 @@ public final class Feature extends GeoJsonObject {
      * A unique identifier for the feature, never <code>null</code>.
      */
     private String id;
+
     /**
      * Associated properties.
      */
diff --git a/www-shared/src/main/java/org/geojson/MultiPolygon.java b/www-shared/src/main/java/org/geojson/MultiPolygon.java
index 2f9dca456643e39ccbbeaed2822c84ac88e1ad19..456b5792b51ab56b47e61102125872815cbb1d9c 100644
--- a/www-shared/src/main/java/org/geojson/MultiPolygon.java
+++ b/www-shared/src/main/java/org/geojson/MultiPolygon.java
@@ -11,7 +11,7 @@ import org.dominokit.jackson.annotation.JSONMapper;
  * @author Olivier Maury
  */
 @JSONMapper
-public class MultiPolygon extends GeoJsonObject {
+public final class MultiPolygon extends GeoJsonObject {
 
     /**
      * GeoJSON object type.