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 <roberto.sanchez@curisit.net><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