From 4ee50e257b32f6ec0f72907305d1f2b1212808a4 Mon Sep 17 00:00:00 2001
From: Joaquín Reñé <jrene@curisit.net>
Date: Fri, 27 Mar 2026 15:07:12 +0000
Subject: [PATCH] #4479 - upgrade SecurisServer to Java 21

---
 securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java |  202 ++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 162 insertions(+), 40 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java b/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
index 2417954..dcc89b9 100644
--- a/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
+++ b/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
@@ -81,18 +81,67 @@
      */
     @Override
     public void filter(ContainerRequestContext requestContext) throws IOException {
-        EntityManager em = emProvider.getEntityManager();
-        LOG.debug("GETTING EM: {}", em);
+    	
+    	Method method = resourceInfo != null ? resourceInfo.getResourceMethod() : null;
+        if (method == null) {
+            LOG.warn("RequestsInterceptor: resource method is null");
+            return;
+        }
 
-        // Store EntityManager for later retrieval (writer interceptor)
-        requestContext.setProperty(EM_CONTEXT_PROPERTY, em);
+        boolean securable = method.isAnnotationPresent(Securable.class);
+        boolean ensureTransaction = method.isAnnotationPresent(EnsureTransaction.class);
 
-        Method method = resourceInfo.getResourceMethod();
+        // Only require injected helpers when the endpoint actually needs them
+        if (securable) {
+            if (tokenHelper == null || cache == null || emProvider == null) {
+                LOG.error(
+                    "RequestsInterceptor is not fully initialized for secured endpoint '{}'. " +
+                    "tokenHelper={}, cache={}, emProvider={}",
+                    method.getName(), tokenHelper, cache, emProvider
+                );
+                requestContext.abortWith(
+                    Response.status(Status.INTERNAL_SERVER_ERROR)
+                            .entity("Security infrastructure not initialized")
+                            .build()
+                );
+                return;
+            }
 
-        if (checkSecurableMethods(requestContext, method)) {
-            if (method.isAnnotationPresent(EnsureTransaction.class)) {
-                LOG.debug("Beginning transaction");
-                em.getTransaction().begin();
+            if (!checkSecurableMethods(requestContext, method)) {
+                return;
+            }
+        }
+
+        // Only open/use EM when needed
+        if (ensureTransaction || securable) {
+            EntityManager em = getEntityManagerSafely();
+            if (em == null) {
+                LOG.error("No EntityManager available for method '{}'", method.getName());
+                requestContext.abortWith(
+                    Response.status(Status.INTERNAL_SERVER_ERROR)
+                            .entity("Persistence infrastructure not initialized")
+                            .build()
+                );
+                return;
+            }
+
+            LOG.debug("GETTING EM: {}", em);
+            requestContext.setProperty(EM_CONTEXT_PROPERTY, em);
+
+            if (ensureTransaction) {
+                try {
+                    if (!em.getTransaction().isActive()) {
+                        LOG.debug("Beginning transaction");
+                        em.getTransaction().begin();
+                    }
+                } catch (Exception e) {
+                    LOG.error("Error beginning transaction for method '{}'", method.getName(), e);
+                    requestContext.abortWith(
+                        Response.status(Status.INTERNAL_SERVER_ERROR)
+                                .entity("Could not begin transaction")
+                                .build()
+                    );
+                }
             }
         }
     }
@@ -107,9 +156,11 @@
     * @return true if request can proceed; false when aborted
     */
     private boolean checkSecurableMethods(ContainerRequestContext ctx, Method method) {
-        if (!method.isAnnotationPresent(Securable.class)) return true;
+        if (!method.isAnnotationPresent(Securable.class)) {
+            return true;
+        }
 
-        String token = servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PÀRAM);
+        String token = servletRequest != null ? servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PÀRAM) : null;
         if (token == null || !tokenHelper.isTokenValid(token)) {
             LOG.warn("Access denied, invalid token");
             ctx.abortWith(Response.status(Status.UNAUTHORIZED).build());
@@ -126,11 +177,30 @@
             return false;
         }
 
-        BasicSecurityContext sc = new BasicSecurityContext(username, roles, servletRequest.isSecure());
+        boolean secure = servletRequest != null && servletRequest.isSecure();
+        BasicSecurityContext sc = new BasicSecurityContext(username, roles, secure);
         sc.setOrganizationsIds(getUserOrganizations(username));
         sc.setApplicationsIds(getUserApplications(username));
         ctx.setSecurityContext(sc);
         return true;
+    }
+
+    /**
+     * getEntityManagerSafely<p>
+     * Get the entity manager in a safely way
+     * 
+     * @return entityManager
+     */
+    private EntityManager getEntityManagerSafely() {
+        try {
+            if (emProvider == null) {
+                return null;
+            }
+            return emProvider.getEntityManager();
+        } catch (Exception e) {
+            LOG.error("Error obtaining EntityManager from provider", e);
+            return null;
+        }
     }
 
     // -------------------------------------------------------------
@@ -145,18 +215,31 @@
     * @return userRoles
     */
     private int getUserRoles(String username) {
-        if (username == null) return 0;
-        Integer cached = cache.get("roles_" + username, Integer.class);
-        if (cached != null) return cached;
+        if (username == null || cache == null) {
+            return 0;
+        }
 
-        EntityManager em = emProvider.getEntityManager();
+        Integer cached = cache.get("roles_" + username, Integer.class);
+        if (cached != null) {
+            return cached;
+        }
+
+        EntityManager em = getEntityManagerSafely();
+        if (em == null) {
+            LOG.error("Cannot resolve user roles: EntityManager is not available");
+            return 0;
+        }
+
         User user = em.find(User.class, username);
         int roles = 0;
         if (user != null) {
             List<Integer> r = user.getRoles();
-            if (r != null) for (Integer role : r) roles += role;
+            if (r != null) {
+                for (Integer role : r) {
+                    roles += role;
+                }
+            }
             cache.set("roles_" + username, roles, 3600);
-            // also warm some caches
             cache.set("orgs_" + username, user.getOrgsIds(), 3600);
         }
         return roles;
@@ -171,10 +254,22 @@
     * @return userOrganizations
     */
     private Set<Integer> getUserOrganizations(String username) {
-        Set<Integer> cached = cache.getSet("orgs_" + username, Integer.class);
-        if (cached != null) return cached;
+        if (username == null || cache == null) {
+            return Set.of();
+        }
 
-        User user = emProvider.getEntityManager().find(User.class, username);
+        Set<Integer> cached = cache.getSet("orgs_" + username, Integer.class);
+        if (cached != null) {
+            return cached;
+        }
+
+        EntityManager em = getEntityManagerSafely();
+        if (em == null) {
+            LOG.error("Cannot resolve user organizations: EntityManager is not available");
+            return Set.of();
+        }
+
+        User user = em.find(User.class, username);
         if (user != null) {
             Set<Integer> result = user.getAllOrgsIds();
             cache.set("orgs_" + username, result, 3600);
@@ -192,10 +287,22 @@
     * @return userApplications
     */
     private Set<Integer> getUserApplications(String username) {
-        Set<Integer> cached = cache.getSet("apps_" + username, Integer.class);
-        if (cached != null) return cached;
+        if (username == null || cache == null) {
+            return Set.of();
+        }
 
-        User user = emProvider.getEntityManager().find(User.class, username);
+        Set<Integer> cached = cache.getSet("apps_" + username, Integer.class);
+        if (cached != null) {
+            return cached;
+        }
+
+        EntityManager em = getEntityManagerSafely();
+        if (em == null) {
+            LOG.error("Cannot resolve user applications: EntityManager is not available");
+            return Set.of();
+        }
+
+        User user = em.find(User.class, username);
         if (user != null) {
             Set<Integer> result = user.getAllAppsIds();
             cache.set("apps_" + username, result, 3600);
@@ -218,30 +325,45 @@
      */
     @Override
     public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
-        context.proceed();
-
-        EntityManager em = (EntityManager) context.getProperty(EM_CONTEXT_PROPERTY);
-        if (em == null) return;
-
         try {
-            if (em.getTransaction().isActive()) {
-                if (servletResponse.getStatus() == Status.OK.getStatusCode()) {
-                    em.getTransaction().commit();
-                    LOG.debug("Transaction committed");
-                } else {
-                    em.getTransaction().rollback();
-                    LOG.debug("Transaction rolled back");
-                }
-            }
+            context.proceed();
         } finally {
-            if (em.isOpen()) {
+            EntityManager em = (EntityManager) context.getProperty(EM_CONTEXT_PROPERTY);
+            if (em == null) {
+                return;
+            }
+
+            try {
+                if (em.getTransaction() != null && em.getTransaction().isActive()) {
+                    int status = servletResponse != null ? servletResponse.getStatus() : Status.INTERNAL_SERVER_ERROR.getStatusCode();
+                    if (status >= 200 && status < 300) {
+                        em.getTransaction().commit();
+                        LOG.debug("Transaction committed");
+                    } else {
+                        em.getTransaction().rollback();
+                        LOG.debug("Transaction rolled back");
+                    }
+                }
+            } catch (Exception e) {
+                LOG.error("Error finalizing transaction", e);
                 try {
-                    em.close();
+                    if (em.getTransaction() != null && em.getTransaction().isActive()) {
+                        em.getTransaction().rollback();
+                    }
+                } catch (Exception rollbackEx) {
+                    LOG.error("Error rolling back transaction", rollbackEx);
+                }
+            } finally {
+                try {
+                    if (em.isOpen()) {
+                        em.close();
+                    }
                 } catch (Exception e) {
                     LOG.error("Error closing EntityManager", e);
                 }
             }
         }
     }
+
 }
 

--
Gitblit v1.3.2