/* * Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved. */ package net.curisit.securis.services; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.persistence.EntityManager; import jakarta.persistence.TypedQuery; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.POST; import jakarta.ws.rs.PUT; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import net.curisit.integrity.commons.Utils; import net.curisit.securis.DefaultExceptionHandler; import net.curisit.securis.SeCurisException; import net.curisit.securis.db.Application; import net.curisit.securis.db.LicenseType; import net.curisit.securis.db.LicenseTypeMetadata; import net.curisit.securis.db.User.Rol; import net.curisit.securis.ioc.EnsureTransaction; import net.curisit.securis.security.BasicSecurityContext; import net.curisit.securis.security.Securable; import net.curisit.securis.services.exception.SeCurisServiceException; import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes; import net.curisit.securis.services.helpers.MetadataHelper; import net.curisit.securis.utils.TokenHelper; /** * LicenseTypeResource *
* CRUD for license types. Non-admin queries are scoped to the applications * accessible by the caller. Metadata changes are reconciled and, when keys * change, can be propagated to dependent entities via {@link MetadataHelper}. * * @author JRA * Last reviewed by JRA on Oct 5, 2025. */ @Path("/licensetype") public class LicenseTypeResource { private static final Logger LOG = LogManager.getLogger(LicenseTypeResource.class); @Inject TokenHelper tokenHelper; @Inject MetadataHelper metadataHelper; @Context EntityManager em; public LicenseTypeResource() { } /** * index *
* List license types. Non-admin users get only types for their allowed apps.
*
* @param bsc security context.
* @return 200 OK with list (possibly empty).
*/
@GET
@Path("/")
@Produces({ MediaType.APPLICATION_JSON })
@Securable
public Response index(@Context BasicSecurityContext bsc) {
LOG.info("Getting license types list ");
em.clear();
TypedQuery
* Fetch a license type by id.
*
* @param ltid LicenseType id (string form).
* @param token (unused) header token.
* @return 200 OK with the entity.
* @throws SeCurisServiceException 404 if not found.
*/
@GET
@Path("/{ltid}")
@Produces({ MediaType.APPLICATION_JSON })
@Securable
public Response get(@PathParam("ltid") String ltid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) throws SeCurisServiceException {
LOG.info("Getting license type data for id: {}: ", ltid);
if (ltid == null || "".equals(ltid)) {
LOG.error("LicenseType ID is mandatory");
return Response.status(Status.NOT_FOUND).build();
}
em.clear();
LicenseType lt = em.find(LicenseType.class, Integer.parseInt(ltid));
if (lt == null) {
LOG.error("LicenseType with id {} not found in DB", ltid);
throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "LicenseType was not found in DB");
}
return Response.ok(lt).build();
}
/**
* create
*
* Create a new license type. Requires ADMIN. Sets application reference,
* persists metadata entries and stamps creation time.
*
* @param lt Payload.
* @param token (unused) token header.
* @return 200 OK with created entity, or 404 if app missing.
*/
@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
@Produces({ MediaType.APPLICATION_JSON })
@EnsureTransaction
@Securable(roles = Rol.ADMIN)
@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
public Response create(LicenseType lt, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
LOG.info("Creating new license type");
try {
setApplication(lt, lt.getApplicationId(), em);
} catch (SeCurisException e) {
return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, e.getMessage()).build();
}
if (lt.getApplicationId() == null) {
LOG.error("Application is missing for current license type data");
return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Application is missing for current license type data").build();
}
lt.setCreationTimestamp(new Date());
em.persist(lt);
Set
* Update an existing license type. Reconciles metadata:
* removes keys not present in the new set; merges existing; persists new ones.
* If keys changed, {@link MetadataHelper#propagateMetadata} is invoked.
*
* @param lt New values.
* @param ltid LicenseType id.
* @param token (unused) token.
* @return 200 OK with updated entity; 404 if not found or app missing.
*/
@PUT
@POST
@Path("/{ltid}")
@EnsureTransaction
@Consumes(MediaType.APPLICATION_JSON)
@Produces({ MediaType.APPLICATION_JSON })
@Securable(roles = Rol.ADMIN)
@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
public Response modify(LicenseType lt, @PathParam("ltid") String ltid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
LOG.info("Modifying license type with id: {}", ltid);
LicenseType currentlt = em.find(LicenseType.class, Integer.parseInt(ltid));
if (currentlt == null) {
LOG.error("LicenseType with id {} not found in DB", ltid);
return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License type not found with ID: " + ltid).build();
}
try {
setApplication(currentlt, lt.getApplicationId(), em);
} catch (SeCurisException e) {
return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, e.getMessage()).build();
}
currentlt.setCode(lt.getCode());
currentlt.setName(lt.getName());
currentlt.setDescription(lt.getDescription());
Set
* Delete a license type by id. Requires ADMIN.
*
* @param ltid LicenseType id.
* @param req request (unused).
* @return 200 OK on success; 404 if not found.
*/
@DELETE
@Path("/{ltid}")
@EnsureTransaction
@Produces({ MediaType.APPLICATION_JSON })
@Securable(roles = Rol.ADMIN)
@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
public Response delete(@PathParam("ltid") String ltid, @Context HttpServletRequest req) {
LOG.info("Deleting app with id: {}", ltid);
LicenseType app = em.find(LicenseType.class, Integer.parseInt(ltid));
if (app == null) {
LOG.error("LicenseType with id {} can not be deleted, It was not found in DB", ltid);
return Response.status(Status.NOT_FOUND).build();
}
em.remove(app);
return Response.ok(Utils.createMap("success", true, "id", ltid)).build();
}
// ---------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------
private Set
* Resolve and set the application of a license type.
*
* @param licType target LicenseType.
* @param applicationId id of the application (nullable).
* @param em entity manager.
* @throws SeCurisException if id provided but not found.
*/
private void setApplication(LicenseType licType, Integer applicationId, EntityManager em) throws SeCurisException {
Application app = null;
if (applicationId != null) {
app = em.find(Application.class, applicationId);
if (app == null) {
LOG.error("LicenseType application with id {} not found in DB", applicationId);
throw new SecurityException("License type's app not found with ID: " + applicationId);
}
}
licType.setApplication(app);
}
}