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/ApiResource.java | 840 +++++++++++++++++++++++++++++++----------------------------
1 files changed, 444 insertions(+), 396 deletions(-)
diff --git a/securis/src/main/java/net/curisit/securis/services/ApiResource.java b/securis/src/main/java/net/curisit/securis/services/ApiResource.java
index 2718e51..07da3d2 100644
--- a/securis/src/main/java/net/curisit/securis/services/ApiResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/ApiResource.java
@@ -1,3 +1,6 @@
+/*
+* Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved.
+*/
package net.curisit.securis.services;
import java.io.IOException;
@@ -49,446 +52,491 @@
import net.curisit.securis.utils.TokenHelper;
/**
- * External API to be accessed by third parties
- *
- * @author roberto <roberto.sanchez@curisit.net>
- */
+* ApiResource
+* <p>
+* External API for license operations, intended for third-party clients.
+*
+* Endpoints:
+* - GET /api/ -> Plain-text status with date (health check).
+* - GET /api/ping -> JSON status (message + date).
+* - POST /api/request -> Create license from RequestBean (JSON).
+* - POST /api/request -> Create license from request file (multipart).
+* - POST /api/renew -> Renew from previous LicenseBean (JSON).
+* - POST /api/renew -> Renew from previous license file (multipart).
+* - POST /api/validate -> Server-side validation of a license.
+*
+* Security:
+* - Methods that mutate/inspect licenses require {@link Securable} with role {@link Rol#API_CLIENT}.
+* - {@link EnsureTransaction} ensures transaction handling at the filter/interceptor layer.
+*
+* Errors:
+* - Business errors are mapped to {@link SeCurisServiceException} with {@link ErrorCodes}.
+*
+* @author JRA
+* Last reviewed by JRA on Oct 5, 2025.
+*/
@Path("/api")
public class ApiResource {
- private static final Logger LOG = LogManager.getLogger(ApiResource.class);
+ private static final Logger LOG = LogManager.getLogger(ApiResource.class);
- @Inject
- TokenHelper tokenHelper;
+ @Inject TokenHelper tokenHelper;
+ @Inject private LicenseHelper licenseHelper;
+ @Context EntityManager em;
+ @Inject LicenseGenerator licenseGenerator;
- @Inject
- private LicenseHelper licenseHelper;
+ /** Fixed username representing API client actor for audit trails. */
+ public static final String API_CLIENT_USERNAME = "_client";
- @Context
- EntityManager em;
+ /** Default constructor (required by JAX-RS). */
+ public ApiResource() { }
- @Inject
- LicenseGenerator licenseGenerator;
+ // -------------------- Health checks --------------------
- public static final String API_CLIENT_USERNAME = "_client";
+ /**
+ * index<p>
+ * Plain text endpoint to verify API is reachable.
+ *
+ * @return 200 OK with simple message
+ */
+ @GET
+ @Path("/")
+ @Produces({ MediaType.TEXT_PLAIN })
+ public Response index() {
+ return Response.ok("SeCuris API. Date: " + new Date()).build();
+ }
- public ApiResource() {
- }
+ /**
+ * ping<p>
+ * JSON endpoint for health checks.
+ *
+ * @return 200 OK with {@link StatusBean}
+ */
+ @GET
+ @Path("/ping")
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response ping() {
+ StatusBean status = new StatusBean();
+ status.setDate(new Date());
+ status.setMessage(LicenseManager.PING_MESSAGE);
+ return Response.ok(status).build();
+ }
- /**
- *
- * @return Simple text message to check API status
- */
- @GET
- @Path("/")
- @Produces({ MediaType.TEXT_PLAIN })
- public Response index() {
- return Response.ok("SeCuris API. Date: " + new Date()).build();
- }
+ // -------------------- License creation --------------------
- /**
- *
- * @return Simple text message to check API status
- */
- @GET
- @Path("/ping")
- @Produces({ MediaType.APPLICATION_JSON })
- public Response ping() {
- StatusBean status = new StatusBean();
- status.setDate(new Date());
- status.setMessage(LicenseManager.PING_MESSAGE);
- return Response.ok(status).build();
- }
+ /**
+ * createFromRequest<p>
+ * Create a new license from JSON request data.
+ *
+ * @param request RequestBean payload
+ * @param nameOrReference Holder name or external reference (header)
+ * @param userEmail Email (header)
+ * @return {@link SignedLicenseBean} JSON
+ */
+ @POST
+ @Path("/request")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Securable(roles = Rol.API_CLIENT)
+ @Produces({ MediaType.APPLICATION_JSON })
+ @EnsureTransaction
+ public Response createFromRequest(RequestBean request,
+ @HeaderParam(LicenseManager.HEADER_LICENSE_NAME_OR_REFERENCE) String nameOrReference,
+ @HeaderParam(LicenseManager.HEADER_LICENSE_EMAIL) String userEmail)
+ throws IOException, SeCurisServiceException, SeCurisException {
+ LOG.info("Request to get license: {}", request);
+ SignedLicenseBean lic = createLicense(request, em, nameOrReference, userEmail);
+ return Response.ok(lic).build();
+ }
- /**
- * Request a new license file based in a RequestBean object sent as
- * parameter
- *
- * @param mpfdi
- * @param bsc
- * @return
- * @throws IOException
- * @throws SeCurisServiceException
- */
- @POST
- @Path("/request")
- @Consumes(MediaType.APPLICATION_JSON)
- @Securable(roles = Rol.API_CLIENT)
- @Produces({ MediaType.APPLICATION_JSON })
- @EnsureTransaction
- public Response createFromRequest(RequestBean request, @HeaderParam(LicenseManager.HEADER_LICENSE_NAME_OR_REFERENCE) String nameOrReference,
- @HeaderParam(LicenseManager.HEADER_LICENSE_EMAIL) String userEmail) throws IOException, SeCurisServiceException, SeCurisException {
- LOG.info("Request to get license: {}", request);
- SignedLicenseBean lic = createLicense(request, em, nameOrReference, userEmail);
+ /**
+ * createFromRequestFile<p>
+ * Create a new license from a multipart form (uploaded request fields).
+ *
+ * @param mpfdi multipart input
+ * @param nameOrReference holder name/reference (header)
+ * @param userEmail email (header)
+ * @return {@link SignedLicenseBean} JSON
+ */
+ @POST
+ @Path("/request")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Securable(roles = Rol.API_CLIENT)
+ @Produces({ MediaType.APPLICATION_JSON })
+ @EnsureTransaction
+ @SuppressWarnings("unchecked")
+ public Response createFromRequestFile(MultipartFormDataInput mpfdi,
+ @HeaderParam(LicenseManager.HEADER_LICENSE_NAME_OR_REFERENCE) String nameOrReference,
+ @HeaderParam(LicenseManager.HEADER_LICENSE_EMAIL) String userEmail)
+ throws IOException, SeCurisServiceException, SeCurisException {
+ RequestBean req = new RequestBean();
+ req.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null));
+ req.setActivationCode(mpfdi.getFormDataPart("activationCode", String.class, null));
+ req.setPackCode(mpfdi.getFormDataPart("packCode", String.class, null));
+ req.setLicenseTypeCode(mpfdi.getFormDataPart("licenseTypeCode", String.class, null));
+ req.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null));
+ req.setArch(mpfdi.getFormDataPart("arch", String.class, null));
+ req.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null));
+ req.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null));
+ req.setOsName(mpfdi.getFormDataPart("osName", String.class, null));
- return Response.ok(lic).build();
- }
+ return createFromRequest(req, nameOrReference, userEmail);
+ }
- /**
- * Returns a License file in JSON format from an uploaded Request file
- *
- * @param mpfdi
- * @param bsc
- * @return
- * @throws IOException
- * @throws SeCurisServiceException
- * @throws SeCurisException
- */
- @POST
- @Path("/request")
- @Consumes(MediaType.MULTIPART_FORM_DATA)
- @Securable(roles = Rol.API_CLIENT)
- @Produces({ MediaType.APPLICATION_JSON })
- @EnsureTransaction
- @SuppressWarnings("unchecked")
- public Response createFromRequestFile(MultipartFormDataInput mpfdi, @HeaderParam(LicenseManager.HEADER_LICENSE_NAME_OR_REFERENCE) String nameOrReference,
- @HeaderParam(LicenseManager.HEADER_LICENSE_EMAIL) String userEmail) throws IOException, SeCurisServiceException, SeCurisException {
- RequestBean req = new RequestBean();
- req.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null));
- req.setActivationCode(mpfdi.getFormDataPart("activationCode", String.class, null));
- req.setPackCode(mpfdi.getFormDataPart("packCode", String.class, null));
- req.setLicenseTypeCode(mpfdi.getFormDataPart("licenseTypeCode", String.class, null));
- req.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null));
- req.setArch(mpfdi.getFormDataPart("arch", String.class, null));
- req.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null));
- req.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null));
- req.setOsName(mpfdi.getFormDataPart("osName", String.class, null));
+ // -------------------- License renew --------------------
- return createFromRequest(req, nameOrReference, userEmail);
- }
+ /**
+ * renewFromPreviousLicense<p>
+ * Renew a license from an existing {@link LicenseBean} JSON payload.
+ * Only <b>Active</b> licenses within one month of expiration are eligible.
+ *
+ * @param previousLic current license bean
+ * @param bsc security context
+ * @return new {@link SignedLicenseBean}
+ */
+ @POST
+ @Path("/renew")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Securable(roles = Rol.API_CLIENT)
+ @Produces({ MediaType.APPLICATION_JSON })
+ @EnsureTransaction
+ public Response renewFromPreviousLicense(LicenseBean previousLic, @Context BasicSecurityContext bsc)
+ throws IOException, SeCurisServiceException, SeCurisException {
+ LOG.info("Renew license: {}", previousLic);
- /**
- * Create a new License file based in a previous one
- *
- * @param request
- * @param bsc
- * @return
- * @throws IOException
- * @throws SeCurisServiceException
- * @throws SeCurisException
- */
- @POST
- @Path("/renew")
- @Consumes(MediaType.APPLICATION_JSON)
- @Securable(roles = Rol.API_CLIENT)
- @Produces({ MediaType.APPLICATION_JSON })
- @EnsureTransaction
- public Response renewFromPreviousLicense(LicenseBean previousLic, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException {
- LOG.info("Renew license: {}", previousLic);
+ if (previousLic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) {
+ throw new SeCurisServiceException(ErrorCodes.UNNECESSARY_RENEW, "The license is still valid, not ready for renew");
+ }
- if (previousLic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) {
- throw new SeCurisServiceException(ErrorCodes.UNNECESSARY_RENEW, "The license is still valid, not ready for renew");
- }
+ License lic = License.findLicenseByCode(previousLic.getLicenseCode(), em);
+ if (lic == null) {
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "Current license is missing in DB");
+ }
+ if (lic.getStatus() != LicenseStatus.ACTIVE) {
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "Only licenses with status 'Active' can be renew");
+ }
- // EntityManager em = emProvider.get();
- License lic = License.findLicenseByCode(previousLic.getLicenseCode(), em);
- if (lic == null) {
- throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "Current license is missing in DB");
- }
+ SignedLicenseBean signedLic = renewLicense(previousLic, em);
+ LOG.info("Renewed license code: {}, until: {}", signedLic.getLicenseCode(), signedLic.getExpirationDate());
- if (lic.getStatus() != LicenseStatus.ACTIVE) {
- throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "Only licenses with status 'Active' can be renew");
- }
+ return Response.ok(signedLic).build();
+ }
- SignedLicenseBean signedLic = renewLicense(previousLic, em);
- LOG.info("Renewed license code: {}, until: {}", signedLic.getLicenseCode(), signedLic.getExpirationDate());
+ /**
+ * renewFromLicenseFile<p>
+ * Renew a license from multipart (uploaded prior license fields).
+ *
+ * @param mpfdi multipart input
+ * @param bsc security context
+ * @return new {@link SignedLicenseBean}
+ */
+ @POST
+ @Path("/renew")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Securable(roles = Rol.API_CLIENT)
+ @Produces({ MediaType.APPLICATION_JSON })
+ @EnsureTransaction
+ @SuppressWarnings("unchecked")
+ public Response renewFromLicenseFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc)
+ throws IOException, SeCurisServiceException, SeCurisException {
+ LicenseBean lic = new LicenseBean();
- return Response.ok(signedLic).build();
- }
+ lic.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null));
+ lic.setActivationCode(mpfdi.getFormDataPart("activationName", String.class, null));
+ lic.setAppName(mpfdi.getFormDataPart("appName", String.class, null));
+ lic.setArch(mpfdi.getFormDataPart("arch", String.class, null));
+ lic.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null));
+ lic.setPackCode(mpfdi.getFormDataPart("packCode", String.class, null));
+ lic.setLicenseTypeCode(mpfdi.getFormDataPart("licenseCode", String.class, null));
+ lic.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null));
+ lic.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null));
+ lic.setOsName(mpfdi.getFormDataPart("osName", String.class, null));
+ lic.setExpirationDate(mpfdi.getFormDataPart("expirationDate", Date.class, null));
- /**
- * License validation on server side, in this case we validate that the
- * current licenses has not been cancelled and they are still in valid
- * period. If the pack has reached the end valid period, the license is no
- * longer valid.
- *
- * @param currentLic
- * @param bsc
- * @return
- * @throws IOException
- * @throws SeCurisServiceException
- * @throws SeCurisException
- */
- @POST
- @Path("/validate")
- @Consumes(MediaType.APPLICATION_JSON)
- @Securable(roles = Rol.API_CLIENT)
- @Produces({ MediaType.APPLICATION_JSON })
- @EnsureTransaction
- public Response validate(LicenseBean currentLic, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException {
- LOG.info("Validate license: {}", currentLic);
+ LOG.info("Lic expires at: {}", lic.getExpirationDate());
+ if (lic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) {
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "The license is still valid, not ready for renew");
+ }
- if (currentLic.getExpirationDate().before(new Date())) {
- throw new SeCurisServiceException(ErrorCodes.LICENSE_IS_EXPIRED, "The license is expired");
- }
+ return renewFromPreviousLicense(lic, bsc);
+ }
- License existingLic = licenseHelper.getActiveLicenseFromDB(currentLic, em);
+ // -------------------- Validation --------------------
- Pack pack = existingLic.getPack();
- if (pack.getEndValidDate().before(new Date())) {
- throw new SeCurisServiceException(ErrorCodes.LICENSE_PACK_IS_NOT_VALID, "The pack end valid date has been reached");
- }
- if (pack.getStatus() != PackStatus.ACTIVE) {
- LOG.error("The Pack {} status is not active, is: {}", pack.getCode(), pack.getStatus());
- throw new SeCurisServiceException(ErrorCodes.LICENSE_PACK_IS_NOT_VALID, "The pack status is not Active");
- }
+ /**
+ * validate<p>
+ * Server-side validation of a license:
+ * - Not expired
+ * - Pack still valid and active
+ * - Signature valid
+ *
+ * @param currentLic license to validate
+ * @param bsc security context
+ * @return same license if valid
+ */
+ @POST
+ @Path("/validate")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Securable(roles = Rol.API_CLIENT)
+ @Produces({ MediaType.APPLICATION_JSON })
+ @EnsureTransaction
+ public Response validate(LicenseBean currentLic, @Context BasicSecurityContext bsc)
+ throws IOException, SeCurisServiceException, SeCurisException {
+ LOG.info("Validate license: {}", currentLic);
- try {
- SignatureHelper.getInstance().validateSignature(currentLic);
- } catch (SeCurisException ex) {
- throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "The license signature is not valid");
- }
+ if (currentLic.getExpirationDate().before(new Date())) {
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_IS_EXPIRED, "The license is expired");
+ }
- return Response.ok(currentLic).build();
- }
+ License existingLic = licenseHelper.getActiveLicenseFromDB(currentLic, em);
- /**
- * Returns a new License file in JSON format based in a previous license
- * There is 2 /renew services with json input and with upload file
- *
- * @param mpfdi
- * @param bsc
- * @return
- * @throws IOException
- * @throws SeCurisServiceException
- * @throws SeCurisException
- */
- @POST
- @Path("/renew")
- @Consumes(MediaType.MULTIPART_FORM_DATA)
- @Securable(roles = Rol.API_CLIENT)
- @Produces({ MediaType.APPLICATION_JSON })
- @EnsureTransaction
- @SuppressWarnings("unchecked")
- public Response renewFromLicenseFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException {
- LicenseBean lic = new LicenseBean();
+ Pack pack = existingLic.getPack();
+ if (pack.getEndValidDate().before(new Date())) {
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_PACK_IS_NOT_VALID, "The pack end valid date has been reached");
+ }
+ if (pack.getStatus() != PackStatus.ACTIVE) {
+ LOG.error("The Pack {} status is not active, is: {}", pack.getCode(), pack.getStatus());
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_PACK_IS_NOT_VALID, "The pack status is not Active");
+ }
- lic.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null));
- lic.setActivationCode(mpfdi.getFormDataPart("activationName", String.class, null));
- lic.setAppName(mpfdi.getFormDataPart("appName", String.class, null));
- lic.setArch(mpfdi.getFormDataPart("arch", String.class, null));
- lic.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null));
- lic.setPackCode(mpfdi.getFormDataPart("packCode", String.class, null));
- lic.setLicenseTypeCode(mpfdi.getFormDataPart("licenseCode", String.class, null));
- lic.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null));
- lic.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null));
- lic.setOsName(mpfdi.getFormDataPart("osName", String.class, null));
- lic.setExpirationDate(mpfdi.getFormDataPart("expirationDate", Date.class, null));
- LOG.info("Lic expires at: {}", lic.getExpirationDate());
- if (lic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) {
- throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "The license is still valid, not ready for renew");
- }
+ try {
+ SignatureHelper.getInstance().validateSignature(currentLic);
+ } catch (SeCurisException ex) {
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "The license signature is not valid");
+ }
- return renewFromPreviousLicense(lic, bsc);
- }
+ return Response.ok(currentLic).build();
+ }
- /**
- * Creates a new signed license from request data or from previous license
- * if It's a renew
- *
- * @param req
- * @param em
- * @param renew
- * @return
- * @throws SeCurisServiceException
- */
- private SignedLicenseBean createLicense(RequestBean req, EntityManager em, String nameOrReference, String email) throws SeCurisServiceException {
- License lic = null;
+ // -------------------- Internal helpers --------------------
- if (req.getActivationCode() != null) {
- lic = License.findLicenseByActivationCode(req.getActivationCode(), em);
- if (lic == null) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The given activation code is invalid: " + req.getActivationCode());
- }
- if (lic.getStatus() == LicenseStatus.ACTIVE) {
- RequestBean initialRequest;
- try {
- initialRequest = JsonUtils.json2object(lic.getRequestData(), RequestBean.class);
- if (!req.match(initialRequest)) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "There is already an active license for given activation code: " + req.getActivationCode());
- } else {
- return JsonUtils.json2object(lic.getLicenseData(), SignedLicenseBean.class);
- }
- } catch (SeCurisException e) {
- LOG.error("Error getting existing license", e);
- throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Original request is wrong");
- }
- } else {
- if (req.getAppCode() != null && !req.getAppCode().equals(lic.getPack().getLicenseType().getApplication().getCode())) {
- LOG.error("Activation code {} belongs to app: {} but was sent by: {}", req.getActivationCode(), lic.getPack().getLicenseType().getApplication().getCode(),
- req.getAppCode());
- throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The given activation code belongs to a different application: " + req.getActivationCode());
- }
- }
- // We validate if the HW is the same, otherwise an error is
- // thrown
- } else {
- try {
- lic = License.findValidLicenseByRequestData(JsonUtils.toJSON(req), em);
- } catch (SeCurisException e1) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Request sent is not valid");
- }
- if (lic != null) {
- try {
- if (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE) {
- return JsonUtils.json2object(lic.getLicenseData(), SignedLicenseBean.class);
- }
- } catch (SeCurisException e) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error trying to get the license bean from license code: " + lic.getCode());
- }
- } else {
- lic = new License();
- }
- }
+ /**
+ * createLicense<p>
+ * Creates a new signed license from request data or reuses an existing
+ * pre-active/active one when allowed by business rules.
+ *
+ * @param req request bean
+ * @param em entity manager
+ * @param nameOrReference license holder name/reference (header)
+ * @param email email (header)
+ * @return signed license bean
+ */
+ private SignedLicenseBean createLicense(RequestBean req, EntityManager em, String nameOrReference, String email)
+ throws SeCurisServiceException {
- Pack pack;
- if (lic.getActivationCode() == null) {
- try {
- pack = em.createNamedQuery("pack-by-code", Pack.class).setParameter("code", req.getPackCode()).getSingleResult();
- } catch (NoResultException e) {
- throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "No pack found for code: " + req.getPackCode());
- }
+ License lic = null;
- if (pack.getNumAvailables() <= 0) {
- throw new SeCurisServiceException(ErrorCodes.NO_AVAILABLE_LICENSES, "The current pack has no licenses availables");
- }
- if (lic.getStatus() == LicenseStatus.REQUESTED && !pack.isLicensePreactivation()) {
- throw new SeCurisServiceException(ErrorCodes.NO_AVAILABLE_LICENSES, "Current pack doesn't allow license preactivation");
- }
+ // (1) Activation-code flow
+ if (req.getActivationCode() != null) {
+ lic = License.findLicenseByActivationCode(req.getActivationCode(), em);
+ if (lic == null) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The given activation code is invalid: " + req.getActivationCode());
+ }
+ if (lic.getStatus() == LicenseStatus.ACTIVE) {
+ try {
+ RequestBean initialRequest = JsonUtils.json2object(lic.getRequestData(), RequestBean.class);
+ if (!req.match(initialRequest)) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_DATA,
+ "There is already an active license for given activation code: " + req.getActivationCode());
+ } else {
+ return JsonUtils.json2object(lic.getLicenseData(), SignedLicenseBean.class);
+ }
+ } catch (SeCurisException e) {
+ LOG.error("Error getting existing license", e);
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Original request is wrong");
+ }
+ } else {
+ if (req.getAppCode() != null &&
+ !req.getAppCode().equals(lic.getPack().getLicenseType().getApplication().getCode())) {
+ LOG.error("Activation code {} belongs to app: {} but was sent by: {}",
+ req.getActivationCode(), lic.getPack().getLicenseType().getApplication().getCode(), req.getAppCode());
+ throw new SeCurisServiceException(ErrorCodes.INVALID_DATA,
+ "The given activation code belongs to a different application: " + req.getActivationCode());
+ }
+ }
+ } else {
+ // (2) Request-data flow (idempotent check)
+ try {
+ lic = License.findValidLicenseByRequestData(JsonUtils.toJSON(req), em);
+ } catch (SeCurisException e1) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Request sent is not valid");
+ }
+ if (lic != null) {
+ try {
+ if (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE) {
+ return JsonUtils.json2object(lic.getLicenseData(), SignedLicenseBean.class);
+ }
+ } catch (SeCurisException e) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT,
+ "Error trying to get the license bean from license code: " + lic.getCode());
+ }
+ } else {
+ lic = new License();
+ }
+ }
- if (!req.getCustomerCode().equals(pack.getOrganization().getCode())) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Customer code is not valid: " + req.getCustomerCode());
- }
+ // (3) Pack validation & constraints
+ Pack pack;
+ if (lic.getActivationCode() == null) {
+ try {
+ pack = em.createNamedQuery("pack-by-code", Pack.class)
+ .setParameter("code", req.getPackCode())
+ .getSingleResult();
+ } catch (NoResultException e) {
+ throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "No pack found for code: " + req.getPackCode());
+ }
- if (!req.getLicenseTypeCode().equals(pack.getLicenseTypeCode())) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "License type code is not valid: " + req.getLicenseTypeCode());
- }
- } else {
- pack = lic.getPack();
- }
- if (pack.getStatus() != PackStatus.ACTIVE) {
- LOG.error("The Pack {} status is not active, is: {}", pack.getCode(), pack.getStatus());
- throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "The pack status is not Active");
- }
- SignedLicenseBean signedLicense;
- try {
- String licCode;
- if (lic.getCode() == null) {
- licCode = LicUtils.getLicenseCode(pack.getCode(), licenseHelper.getNextCodeSuffix(pack.getId(), em));
- } else {
- licCode = lic.getCode();
- }
- Date expirationDate = licenseHelper.getExpirationDateFromPack(pack, lic.getActivationCode() == null);
+ if (pack.getNumAvailables() <= 0) {
+ throw new SeCurisServiceException(ErrorCodes.NO_AVAILABLE_LICENSES, "The current pack has no licenses availables");
+ }
+ if (lic.getStatus() == LicenseStatus.REQUESTED && !pack.isLicensePreactivation()) {
+ throw new SeCurisServiceException(ErrorCodes.NO_AVAILABLE_LICENSES, "Current pack doesn't allow license preactivation");
+ }
+ if (!req.getCustomerCode().equals(pack.getOrganization().getCode())) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Customer code is not valid: " + req.getCustomerCode());
+ }
+ if (!req.getLicenseTypeCode().equals(pack.getLicenseTypeCode())) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "License type code is not valid: " + req.getLicenseTypeCode());
+ }
+ } else {
+ pack = lic.getPack();
+ }
- LicenseBean lb = licenseGenerator.generateLicense(req, licenseHelper.extractPackMetadata(pack.getMetadata()), expirationDate, licCode, pack.getAppName());
- signedLicense = new SignedLicenseBean(lb);
- } catch (SeCurisException e) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Error generating license: " + e.toString());
- }
- try {
- lic.setRequestData(JsonUtils.toJSON(req));
- if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
- throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be activated");
- }
- lic.setLicenseData(JsonUtils.toJSON(signedLicense));
- } catch (SeCurisException e) {
- LOG.error("Error generating license JSON", e);
- throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generating license JSON");
- }
+ if (pack.getStatus() != PackStatus.ACTIVE) {
+ LOG.error("The Pack {} status is not active, is: {}", pack.getCode(), pack.getStatus());
+ throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "The pack status is not Active");
+ }
- lic.setModificationTimestamp(new Date());
- lic.setExpirationDate(signedLicense.getExpirationDate());
- User user = em.find(User.class, API_CLIENT_USERNAME);
- if (lic.getStatus() != LicenseStatus.REQUESTED) {
- lic.setPack(pack);
- lic.setCreatedBy(user);
- lic.setCreationTimestamp(new Date());
- if (lic.getActivationCode() != null) {
- lic.setStatus(LicenseStatus.ACTIVE);
- } else {
- lic.setStatus(pack.isLicensePreactivation() ? LicenseStatus.PRE_ACTIVE : LicenseStatus.REQUESTED);
- }
- lic.setCode(signedLicense.getLicenseCode());
- lic.setCodeSuffix(LicUtils.getLicenseCodeSuffix(signedLicense.getLicenseCode()));
- if (lic.getEmail() == null || "".equals(lic.getEmail())) {
- lic.setEmail(email);
- }
- if (lic.getFullName() == null || "".equals(lic.getFullName())) {
- lic.setFullName(nameOrReference);
- }
- if (lic.getId() != null) {
- em.merge(lic);
- } else {
- em.persist(lic);
- }
- em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.CREATE));
- if (lic.getActivationCode() != null) {
- em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.ACTIVATE, "Activated by code on creation"));
- } else {
- if (pack.isLicensePreactivation()) {
- em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.PRE_ACTIVATE, "Pre-activated on creation"));
- } else {
- LOG.warn("License ({}) created, but the pack doesn't allow preactivation", lic.getCode());
- throw new SeCurisServiceException(ErrorCodes.NO_AVAILABLE_LICENSES, "Current pack doesn't allow license preactivation");
- }
- }
- } else {
- lic.setStatus(LicenseStatus.PRE_ACTIVE);
- em.merge(lic);
- em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.PRE_ACTIVATE, "Pre-activated after request"));
- }
+ // (4) License generation
+ SignedLicenseBean signedLicense;
+ try {
+ String licCode = (lic.getCode() == null)
+ ? LicUtils.getLicenseCode(pack.getCode(), licenseHelper.getNextCodeSuffix(pack.getId(), em))
+ : lic.getCode();
- return signedLicense;
- }
+ Date expirationDate = licenseHelper.getExpirationDateFromPack(pack, lic.getActivationCode() == null);
+ LicenseBean lb = licenseGenerator.generateLicense(
+ req,
+ licenseHelper.extractPackMetadata(pack.getMetadata()),
+ expirationDate,
+ licCode,
+ pack.getAppName()
+ );
+ signedLicense = new SignedLicenseBean(lb);
+ } catch (SeCurisException e) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Error generating license: " + e.toString());
+ }
- /**
- * Creates a new signed license from request data or from previous license
- * if It's a renew
- *
- * @param req
- * @param em
- * @param renew
- * @return
- * @throws SeCurisServiceException
- */
- private SignedLicenseBean renewLicense(LicenseBean previousLicenseBean, EntityManager em) throws SeCurisServiceException {
+ // (5) Persist/merge license + history
+ try {
+ lic.setRequestData(JsonUtils.toJSON(req));
+ if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
+ throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be activated");
+ }
+ lic.setLicenseData(JsonUtils.toJSON(signedLicense));
+ } catch (SeCurisException e) {
+ LOG.error("Error generating license JSON", e);
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generating license JSON");
+ }
- License lic = License.findLicenseByCode(previousLicenseBean.getLicenseCode(), em);
- if (lic.getStatus() != LicenseStatus.ACTIVE && lic.getStatus() != LicenseStatus.PRE_ACTIVE) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The current license has been cancelled");
- }
+ lic.setModificationTimestamp(new Date());
+ lic.setExpirationDate(signedLicense.getExpirationDate());
+ User user = em.find(User.class, API_CLIENT_USERNAME);
- Pack pack = lic.getPack();
- SignedLicenseBean signedLicense;
- try {
- String licCode = lic.getCode();
- Date expirationDate = licenseHelper.getExpirationDateFromPack(pack, false);
+ if (lic.getStatus() != LicenseStatus.REQUESTED) {
+ lic.setPack(pack);
+ lic.setCreatedBy(user);
+ lic.setCreationTimestamp(new Date());
+ if (lic.getActivationCode() != null) {
+ lic.setStatus(LicenseStatus.ACTIVE);
+ } else {
+ lic.setStatus(pack.isLicensePreactivation() ? LicenseStatus.PRE_ACTIVE : LicenseStatus.REQUESTED);
+ }
+ lic.setCode(signedLicense.getLicenseCode());
+ lic.setCodeSuffix(LicUtils.getLicenseCodeSuffix(signedLicense.getLicenseCode()));
+ if (lic.getEmail() == null || "".equals(lic.getEmail())) {
+ lic.setEmail(email);
+ }
+ if (lic.getFullName() == null || "".equals(lic.getFullName())) {
+ lic.setFullName(nameOrReference);
+ }
+ if (lic.getId() != null) {
+ em.merge(lic);
+ } else {
+ em.persist(lic);
+ }
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.CREATE));
+ if (lic.getActivationCode() != null) {
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.ACTIVATE, "Activated by code on creation"));
+ } else {
+ if (pack.isLicensePreactivation()) {
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.PRE_ACTIVATE, "Pre-activated on creation"));
+ } else {
+ LOG.warn("License ({}) created, but the pack doesn't allow preactivation", lic.getCode());
+ throw new SeCurisServiceException(ErrorCodes.NO_AVAILABLE_LICENSES, "Current pack doesn't allow license preactivation");
+ }
+ }
+ } else {
+ lic.setStatus(LicenseStatus.PRE_ACTIVE);
+ em.merge(lic);
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.PRE_ACTIVATE, "Pre-activated after request"));
+ }
- LicenseBean lb = licenseGenerator.generateLicense(previousLicenseBean, licenseHelper.extractPackMetadata(pack.getMetadata()), expirationDate, licCode,
- pack.getAppName());
- signedLicense = new SignedLicenseBean(lb);
- } catch (SeCurisException e) {
- throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Error generating license: " + e.toString());
- }
- try {
- lic.setRequestData(JsonUtils.toJSON(signedLicense, RequestBean.class));
- if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
- throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be activated");
- }
- lic.setLicenseData(JsonUtils.toJSON(signedLicense));
- } catch (SeCurisException e) {
- LOG.error("Error generating license JSON", e);
- throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generating license JSON");
- }
+ return signedLicense;
+ }
- lic.setModificationTimestamp(new Date());
- lic.setExpirationDate(signedLicense.getExpirationDate());
- User user = em.find(User.class, API_CLIENT_USERNAME);
+ /**
+ * renewLicense<p>
+ * Internal renew logic used by JSON and multipart variants.
+ *
+ * @param previousLicenseBean previous license data
+ * @param em entity manager
+ * @return new signed license bean
+ */
+ private SignedLicenseBean renewLicense(LicenseBean previousLicenseBean, EntityManager em)
+ throws SeCurisServiceException {
- lic.setStatus(LicenseStatus.ACTIVE);
- em.merge(lic);
- em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.RENEW));
+ License lic = License.findLicenseByCode(previousLicenseBean.getLicenseCode(), em);
+ if (lic.getStatus() != LicenseStatus.ACTIVE && lic.getStatus() != LicenseStatus.PRE_ACTIVE) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The current license has been cancelled");
+ }
- return signedLicense;
- }
+ Pack pack = lic.getPack();
+ SignedLicenseBean signedLicense;
+ try {
+ String licCode = lic.getCode();
+ Date expirationDate = licenseHelper.getExpirationDateFromPack(pack, false);
+
+ LicenseBean lb = licenseGenerator.generateLicense(
+ previousLicenseBean,
+ licenseHelper.extractPackMetadata(pack.getMetadata()),
+ expirationDate,
+ licCode,
+ pack.getAppName()
+ );
+ signedLicense = new SignedLicenseBean(lb);
+ } catch (SeCurisException e) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Error generating license: " + e.toString());
+ }
+ try {
+ lic.setRequestData(JsonUtils.toJSON(signedLicense, RequestBean.class));
+ if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
+ throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be activated");
+ }
+ lic.setLicenseData(JsonUtils.toJSON(signedLicense));
+ } catch (SeCurisException e) {
+ LOG.error("Error generating license JSON", e);
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generating license JSON");
+ }
+
+ lic.setModificationTimestamp(new Date());
+ lic.setExpirationDate(signedLicense.getExpirationDate());
+ User user = em.find(User.class, API_CLIENT_USERNAME);
+
+ lic.setStatus(LicenseStatus.ACTIVE);
+ em.merge(lic);
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.RENEW));
+
+ return signedLicense;
+ }
}
+
--
Gitblit v1.3.2