From 146a0fb8b0e90f9196e569152f649baf60d6cc8f Mon Sep 17 00:00:00 2001
From: Joaquín Reñé <jrene@curisit.net>
Date: Tue, 07 Oct 2025 14:52:57 +0000
Subject: [PATCH] #4410 - Comments on classes

---
 securis/src/main/java/net/curisit/securis/services/ApplicationResource.java |  405 ++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 225 insertions(+), 180 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java b/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java
index e9b2776..f004acd 100644
--- a/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java
@@ -1,3 +1,6 @@
+/*
+ * Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved.
+ */
 package net.curisit.securis.services;
 
 import java.util.Date;
@@ -42,204 +45,246 @@
 import net.curisit.securis.utils.TokenHelper;
 
 /**
- * Application resource, this service will provide methods to create, modify and
- * delete applications
- * 
- * @author roberto <roberto.sanchez@curisit.net>
+ * ApplicationResource
+ * <p>
+ * REST endpoints to list, fetch, create, update and delete {@link Application}s.
+ * Security:
+ * <ul>
+ *   <li>Listing filters by user's accessible application IDs unless ADMIN.</li>
+ *   <li>Create/Modify/Delete restricted to ADMIN.</li>
+ * </ul>
+ * Side-effects:
+ * <ul>
+ *   <li>Manages {@link ApplicationMetadata} lifecycle on create/update.</li>
+ *   <li>Propagates metadata changes via {@link MetadataHelper}.</li>
+ * </ul>
+ *
+ * Author: roberto &lt;roberto.sanchez@curisit.net&gt;<br>
+ * Last reviewed by JRA on Oct 5, 2025.
  */
 @Path("/application")
 public class ApplicationResource {
 
-	@Inject
-	TokenHelper tokenHelper;
+    @Inject TokenHelper tokenHelper;
+    @Inject MetadataHelper metadataHelper;
 
-	@Inject
-	MetadataHelper metadataHelper;
+    @Context EntityManager em;
 
-	@Context
-	EntityManager em;
+    private static final Logger LOG = LogManager.getLogger(ApplicationResource.class);
 
-	private static final Logger LOG = LogManager.getLogger(ApplicationResource.class);
+    /**
+     * ApplicationResource<p>
+     * Constructor
+     */
+    public ApplicationResource() {}
 
-	public ApplicationResource() {
-	}
+    /**
+     * index<p>
+     * List applications visible to the current user.
+     *
+     * @param bsc security context
+     * @return 200 with list (possibly empty) or 200 empty if user has no app scope
+     */
+    @GET
+    @Path("/")
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Securable
+    public Response index(@Context BasicSecurityContext bsc) {
+        LOG.info("Getting applications list ");
+        em.clear();
 
-	/**
-	 * 
-	 * @return the server version in format majorVersion.minorVersion
-	 */
-	@GET
-	@Path("/")
-	@Produces({ MediaType.APPLICATION_JSON })
-	@Securable
-	public Response index(@Context BasicSecurityContext bsc) {
-		LOG.info("Getting applications list ");
+        TypedQuery<Application> q;
+        if (bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+            q = em.createNamedQuery("list-applications", Application.class);
+        } else {
+            if (bsc.getApplicationsIds() == null || bsc.getApplicationsIds().isEmpty()) {
+                return Response.ok().build();
+            }
+            q = em.createNamedQuery("list-applications-by_ids", Application.class);
+            q.setParameter("list_ids", bsc.getApplicationsIds());
+        }
+        List<Application> list = q.getResultList();
+        return Response.ok(list).build();
+    }
 
-		// EntityManager em = emProvider.get();
-		em.clear();
+    /**
+     * get<p>
+     * Fetch a single application by ID.
+     *
+     * @param appid string ID
+     * @return 200 + entity or 404 if not found
+     * @throws SeCurisServiceException when ID is invalid or not found
+     */
+    @GET
+    @Path("/{appid}")
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Securable
+    public Response get(@PathParam("appid") String appid) throws SeCurisServiceException {
+        LOG.info("Getting application data for id: {}: ", appid);
+        if (appid == null || "".equals(appid)) {
+            LOG.error("Application ID is mandatory");
+            return Response.status(Status.NOT_FOUND).build();
+        }
 
-		TypedQuery<Application> q;
-		if (bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
-			q = em.createNamedQuery("list-applications", Application.class);
-		} else {
-			if (bsc.getApplicationsIds() == null || bsc.getApplicationsIds().isEmpty()) {
-				return Response.ok().build();
-			}
-			q = em.createNamedQuery("list-applications-by_ids", Application.class);
+        em.clear();
+        Application app = null;
+        try {
+            LOG.info("READY to GET app: {}", appid);
+            app = em.find(Application.class, Integer.parseInt(appid));
+        } catch (Exception e) {
+            LOG.info("ERROR GETTING app: {}", e);
+        }
+        if (app == null) {
+            LOG.error("Application with id {} not found in DB", appid);
+            throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "Application not found with ID: " + appid);
+        }
+        return Response.ok(app).build();
+    }
 
-			q.setParameter("list_ids", bsc.getApplicationsIds());
-		}
-		List<Application> list = q.getResultList();
+    /**
+     * create<p>
+     * Create a new application with optional metadata entries.
+     *
+     * @param app application payload
+     * @param token auth token (audited externally)
+     * @return 200 + persisted entity
+     */
+    @POST
+    @Path("/")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces({ MediaType.APPLICATION_JSON })
+    @EnsureTransaction
+    @Securable(roles = Rol.ADMIN)
+    @RolesAllowed(BasicSecurityContext.ROL_ADMIN)
+    public Response create(Application app, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+        LOG.info("Creating new application");
+        app.setCreationTimestamp(new Date());
+        em.persist(app);
 
-		return Response.ok(list).build();
-	}
+        if (app.getApplicationMetadata() != null) {
+            for (ApplicationMetadata md : app.getApplicationMetadata()) {
+                md.setApplication(app);
+                md.setCreationTimestamp(new Date());
+                em.persist(md);
+            }
+        }
+        LOG.info("Creating application ({}) with date: {}", app.getId(), app.getCreationTimestamp());
+        return Response.ok(app).build();
+    }
 
-	/**
-	 * 
-	 * @return the server version in format majorVersion.minorVersion
-	 * @throws SeCurisServiceException
-	 */
-	@GET
-	@Path("/{appid}")
-	@Produces({ MediaType.APPLICATION_JSON })
-	@Securable
-	public Response get(@PathParam("appid") String appid) throws SeCurisServiceException {
-		LOG.info("Getting application data for id: {}: ", appid);
-		if (appid == null || "".equals(appid)) {
-			LOG.error("Application ID is mandatory");
-			return Response.status(Status.NOT_FOUND).build();
-		}
+    /**
+     * modify<p>
+     * Update core fields and reconcile metadata set:
+     * <ul>
+     *   <li>Removes missing keys, merges existing, persists new.</li>
+     *   <li>Propagates metadata if there were changes.</li>
+     * </ul>
+     *
+     * @param appid path ID
+     * @param app   new state
+     */
+    @PUT
+    @POST
+    @Path("/{appid}")
+    @EnsureTransaction
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Securable(roles = Rol.ADMIN)
+    @RolesAllowed(BasicSecurityContext.ROL_ADMIN)
+    public Response modify(Application app, @PathParam("appid") String appid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+        LOG.info("Modifying application with id: {}", appid);
+        Application currentapp = em.find(Application.class, Integer.parseInt(appid));
+        if (currentapp == null) {
+            LOG.error("Application with id {} not found in DB", appid);
+            return Response.status(Status.NOT_FOUND)
+                    .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Application not found with ID: " + appid)
+                    .build();
+        }
 
-		em.clear();
+        currentapp.setCode(app.getCode());
+        currentapp.setName(app.getName());
+        currentapp.setLicenseFilename(app.getLicenseFilename());
+        currentapp.setDescription(app.getDescription());
 
-		Application app = null;
-		try {
-			LOG.info("READY to GET app: {}", appid);
-			app = em.find(Application.class, Integer.parseInt(appid));
-		} catch (Exception e) {
-			LOG.info("ERROR GETTING app: {}", e);
-		}
-		if (app == null) {
-			LOG.error("Application with id {} not found in DB", appid);
-			throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "Application not found with ID: " + appid);
-		}
+        Set<ApplicationMetadata> newMD = app.getApplicationMetadata();
+        Set<ApplicationMetadata> oldMD = currentapp.getApplicationMetadata();
+        boolean metadataChanges = !metadataHelper.match(newMD, oldMD);
+        if (metadataChanges) {
+            Map<String, ApplicationMetadata> directOldMD = getMapMD(oldMD);
+            Map<String, ApplicationMetadata> directNewMD = getMapMD(newMD);
 
-		return Response.ok(app).build();
-	}
+            // Remove deleted MD
+            for (ApplicationMetadata currentMd : oldMD) {
+                if (newMD == null || !directNewMD.containsKey(currentMd.getKey())) {
+                    em.remove(currentMd);
+                }
+            }
+            // Merge or persist
+            if (newMD != null) {
+                for (ApplicationMetadata md : newMD) {
+                    if (directOldMD.containsKey(md.getKey())) {
+                        em.merge(md);
+                    } else {
+                        md.setApplication(currentapp);
+                        if (md.getCreationTimestamp() == null) {
+                            md.setCreationTimestamp(app.getCreationTimestamp());
+                        }
+                        em.persist(md);
+                    }
+                }
+            }
+            currentapp.setApplicationMetadata(app.getApplicationMetadata());
+        }
 
-	@POST
-	@Path("/")
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces({ MediaType.APPLICATION_JSON })
-	@EnsureTransaction
-	@Securable(roles = Rol.ADMIN)
-	@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
-	public Response create(Application app, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
-		LOG.info("Creating new application");
-		// EntityManager em = emProvider.get();
-		app.setCreationTimestamp(new Date());
-		em.persist(app);
+        em.merge(currentapp);
+        if (metadataChanges) {
+            metadataHelper.propagateMetadata(em, currentapp);
+        }
+        return Response.ok(currentapp).build();
+    }
 
-		if (app.getApplicationMetadata() != null) {
-			for (ApplicationMetadata md : app.getApplicationMetadata()) {
-				md.setApplication(app);
-				md.setCreationTimestamp(new Date());
-				em.persist(md);
-			}
-		}
-		LOG.info("Creating application ({}) with date: {}", app.getId(), app.getCreationTimestamp());
+    /**
+     * getMapMD<p> 
+     * Build a map from metadata key → entity for fast reconciliation. 
+     * 
+     * @param applicationMetadata
+     * @return mapMD
+     */
+    private Map<String, ApplicationMetadata> getMapMD(Set<ApplicationMetadata> amd) {
+        Map<String, ApplicationMetadata> map = new HashMap<>();
+        if (amd != null) {
+            for (ApplicationMetadata m : amd) {
+                map.put(m.getKey(), m);
+            }
+        }
+        return map;
+    }
 
-		return Response.ok(app).build();
-	}
-
-	@PUT
-	@POST
-	@Path("/{appid}")
-	@EnsureTransaction
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces({ MediaType.APPLICATION_JSON })
-	@Securable(roles = Rol.ADMIN)
-	@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
-	public Response modify(Application app, @PathParam("appid") String appid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
-		LOG.info("Modifying application with id: {}", appid);
-		// EntityManager em = emProvider.get();
-		Application currentapp = em.find(Application.class, Integer.parseInt(appid));
-		if (currentapp == null) {
-			LOG.error("Application with id {} not found in DB", appid);
-			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Application not found with ID: " + appid).build();
-		}
-		currentapp.setCode(app.getCode());
-		currentapp.setName(app.getName());
-		currentapp.setLicenseFilename(app.getLicenseFilename());
-		currentapp.setDescription(app.getDescription());
-
-		Set<ApplicationMetadata> newMD = app.getApplicationMetadata();
-		Set<ApplicationMetadata> oldMD = currentapp.getApplicationMetadata();
-		boolean metadataChanges = !metadataHelper.match(newMD, oldMD);
-		if (metadataChanges) {
-			Map<String, ApplicationMetadata> directOldMD = getMapMD(oldMD);
-			Map<String, ApplicationMetadata> directNewMD = getMapMD(newMD);
-			for (ApplicationMetadata currentMd : oldMD) {
-				if (newMD == null || !directNewMD.containsKey(currentMd.getKey())) {
-					em.remove(currentMd);
-				}
-			}
-
-			if (newMD != null) {
-				for (ApplicationMetadata md : newMD) {
-					if (directOldMD.containsKey(md.getKey())) {
-						em.merge(md);
-					} else {
-						md.setApplication(currentapp);
-						if (md.getCreationTimestamp() == null) {
-							md.setCreationTimestamp(app.getCreationTimestamp());
-						}
-						em.persist(md);
-					}
-				}
-			}
-			currentapp.setApplicationMetadata(app.getApplicationMetadata());
-		}
-		em.merge(currentapp);
-		if (metadataChanges) {
-			metadataHelper.propagateMetadata(em, currentapp);
-		}
-		return Response.ok(currentapp).build();
-	}
-
-	private Map<String, ApplicationMetadata> getMapMD(Set<ApplicationMetadata> amd) {
-		Map<String, ApplicationMetadata> map = new HashMap<String, ApplicationMetadata>();
-		if (amd != null) {
-			for (ApplicationMetadata applicationMetadata : amd) {
-				map.put(applicationMetadata.getKey(), applicationMetadata);
-			}
-		}
-		return map;
-	}
-
-	@DELETE
-	@Path("/{appid}")
-	@EnsureTransaction
-	@Produces({ MediaType.APPLICATION_JSON })
-	@Securable(roles = Rol.ADMIN)
-	@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
-	public Response delete(@PathParam("appid") String appid, @Context HttpServletRequest request) {
-		LOG.info("Deleting app with id: {}", appid);
-		// EntityManager em = emProvider.get();
-		Application app = em.find(Application.class, Integer.parseInt(appid));
-		if (app == null) {
-			LOG.error("Application with id {} can not be deleted, It was not found in DB", appid);
-			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Application not found with ID: " + appid).build();
-		}
-		/*
-		 * if (app.getLicenseTypes() != null &&
-		 * !app.getLicenseTypes().isEmpty()) { throw new
-		 * SeCurisServiceException(ErrorCodes.NOT_FOUND,
-		 * "Application can not be deleted becasue has assigned one or more License types, ID: "
-		 * + appid); }
-		 */
-		em.remove(app);
-		return Response.ok(Utils.createMap("success", true, "id", appid)).build();
-	}
-
+    /**
+     * delete<p>
+     * Delete an application by ID.
+     * <p>Note: deletion is not allowed if there are dependent entities (enforced by DB/cascade).</p>
+     * 
+     * @param appId
+     * @param request
+     */
+    @DELETE
+    @Path("/{appid}")
+    @EnsureTransaction
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Securable(roles = Rol.ADMIN)
+    @RolesAllowed(BasicSecurityContext.ROL_ADMIN)
+    public Response delete(@PathParam("appid") String appid, @Context HttpServletRequest request) {
+        LOG.info("Deleting app with id: {}", appid);
+        Application app = em.find(Application.class, Integer.parseInt(appid));
+        if (app == null) {
+            LOG.error("Application with id {} can not be deleted, It was not found in DB", appid);
+            return Response.status(Status.NOT_FOUND)
+                    .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Application not found with ID: " + appid)
+                    .build();
+        }
+        em.remove(app);
+        return Response.ok(Utils.createMap("success", true, "id", appid)).build();
+    }
 }
+

--
Gitblit v1.3.2