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/helpers/LicenseHelper.java |  287 +++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 177 insertions(+), 110 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/services/helpers/LicenseHelper.java b/securis/src/main/java/net/curisit/securis/services/helpers/LicenseHelper.java
index 7159ddc..a2115d6 100644
--- a/securis/src/main/java/net/curisit/securis/services/helpers/LicenseHelper.java
+++ b/securis/src/main/java/net/curisit/securis/services/helpers/LicenseHelper.java
@@ -1,3 +1,6 @@
+/*
+ * Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved.
+ */
 package net.curisit.securis.services.helpers;
 
 import java.io.File;
@@ -30,128 +33,192 @@
 import net.curisit.securis.services.exception.SeCurisServiceException;
 import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
 
+/**
+ * LicenseHelper
+ * <p>
+ * Stateless utility component for license lifecycle operations and helpers:
+ * - cancelation with history auditing
+ * - license resolution and validity checks
+ * - license file generation in a temp directory
+ * - metadata extraction and expiration date computation from packs
+ * - sequential code suffix allocation per pack
+ *
+ * Thread-safety: ApplicationScoped, stateless.
+ * 
+ * @author JRA
+ * Last reviewed by JRA on Oct 5, 2025.
+ */
 @ApplicationScoped
 public class LicenseHelper {
 
-	@SuppressWarnings("unused")
-	private static final Logger LOG = LogManager.getLogger(LicenseHelper.class);
-	private static final long MS_PER_DAY = 24L * 3600L * 1000L;
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LogManager.getLogger(LicenseHelper.class);
 
-	@Inject
-	private UserHelper userHelper;
+    /** Milliseconds per day (used to derive expiration dates). */
+    private static final long MS_PER_DAY = 24L * 3600L * 1000L;
 
-	/**
-	 * Cancel the license
-	 * 
-	 * @param lic
-	 * @param em
-	 */
-	public void cancelLicense(License lic, String reason, BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
-		lic.setStatus(LicenseStatus.CANCELLED);
-		lic.setCancelledById(bsc.getUserPrincipal().getName());
-		lic.setModificationTimestamp(new Date());
-		em.persist(lic);
+    @Inject private UserHelper userHelper;
 
-		em.persist(createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancellation reason: " + reason));
-	}
+    /**
+     * cancelLicense
+     * <p>
+     * Transitions a license to CANCELLED, records who canceled it and why,
+     * and appends a {@link LicenseHistory} entry.
+     *
+     * @param lic  Target license (managed).
+     * @param reason Human-readable cancellation reason (auditable).
+     * @param bsc Current security context (used to identify the user).
+     * @param em  Entity manager to persist changes.
+     * @throws SeCurisServiceException never thrown here, declared for symmetry with callers.
+     */
+    public void cancelLicense(License lic, String reason, BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
+        lic.setStatus(LicenseStatus.CANCELLED);
+        lic.setCancelledById(bsc.getUserPrincipal().getName());
+        lic.setModificationTimestamp(new Date());
+        em.persist(lic);
 
-	/**
-	 * Validates that the passed license exists and is still valid
-	 * 
-	 * @param licBean
-	 * @param em
-	 * @return The License instance in DB
-	 * @throws SeCurisServiceException
-	 */
-	public License getActiveLicenseFromDB(LicenseBean licBean, EntityManager em) throws SeCurisServiceException {
-		License lic = License.findLicenseByCode(licBean.getLicenseCode(), em);
-		if (lic == null) {
-			throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "Current license code doesn't exist");
-		}
-		if (lic.getStatus() != LicenseStatus.ACTIVE && lic.getStatus() != LicenseStatus.PRE_ACTIVE) {
-			throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "Current license in not active");
-		}
-		return lic;
-	}
+        em.persist(createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancellation reason: " + reason));
+    }
 
-	public LicenseHistory createLicenseHistoryAction(License lic, User user, String action, String comments) {
-		LicenseHistory lh = new LicenseHistory();
-		lh.setLicense(lic);
-		lh.setUser(user);
-		lh.setCreationTimestamp(new Date());
-		lh.setAction(action);
-		lh.setComments(comments);
-		return lh;
-	}
+    /**
+     * getActiveLicenseFromDB
+     * <p>
+     * Resolve license by code and verify that it's ACTIVE or PRE_ACTIVE.
+     *
+     * @param licBean License bean containing the code to check.
+     * @param em      EntityManager for DB access.
+     * @return The managed {@link License} instance.
+     * @throws SeCurisServiceException if code not found or license not in an active-ish state.
+     */
+    public License getActiveLicenseFromDB(LicenseBean licBean, EntityManager em) throws SeCurisServiceException {
+        License lic = License.findLicenseByCode(licBean.getLicenseCode(), em);
+        if (lic == null) {
+            throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "Current license code doesn't exist");
+        }
+        if (lic.getStatus() != LicenseStatus.ACTIVE && lic.getStatus() != LicenseStatus.PRE_ACTIVE) {
+            throw new SeCurisServiceException(ErrorCodes.LICENSE_DATA_IS_NOT_VALID, "Current license in not active");
+        }
+        return lic;
+    }
 
-	public LicenseHistory createLicenseHistoryAction(License lic, User user, String action) {
-		return createLicenseHistoryAction(lic, user, action, null);
-	}
+    /**
+     * createLicenseHistoryAction
+     * <p>
+     * Helper to build a {@link LicenseHistory} entry.
+     *
+     * @param lic      License affected.
+     * @param user     User performing the action.
+     * @param action   Action code (see {@link LicenseHistory.Actions}).
+     * @param comments Optional comments, can be null.
+     * @return transient {@link LicenseHistory} ready to persist.
+     */
+    public LicenseHistory createLicenseHistoryAction(License lic, User user, String action, String comments) {
+        LicenseHistory lh = new LicenseHistory();
+        lh.setLicense(lic);
+        lh.setUser(user);
+        lh.setCreationTimestamp(new Date());
+        lh.setAction(action);
+        lh.setComments(comments);
+        return lh;
+    }
 
-	/**
-	 * Create a license file in a temporary directory
-	 * 
-	 * @param lic
-	 * @param licFileName
-	 * @return
-	 * @throws IOException
-	 */
-	public File createTemporaryLicenseFile(License lic, String licFileName) throws IOException {
-		File f = Files.createTempDirectory("securis-server").toFile();
-		f = new File(f, licFileName);
-		FileUtils.writeStringToFile(f, lic.getLicenseData(), StandardCharsets.UTF_8);
-		return f;
-	}
+    /**
+     * createLicenseHistoryAction
+     * <p>
+     * Overload without comments.
+     *
+     * @param lic    License affected.
+     * @param user   User performing the action.
+     * @param action Action code.
+     * @return transient {@link LicenseHistory}.
+     */
+    public LicenseHistory createLicenseHistoryAction(License lic, User user, String action) {
+        return createLicenseHistoryAction(lic, user, action, null);
+    }
 
-	public Map<String, Object> extractPackMetadata(Set<PackMetadata> packMetadata) {
-		Map<String, Object> metadata = new HashMap<>();
-		for (PackMetadata md : packMetadata) {
-			metadata.put(md.getKey(), md.getValue());
-		}
+    /**
+     * createTemporaryLicenseFile
+     * <p>
+     * Materializes the license payload into a temporary file for emailing/download.
+     * The file is created under a unique temporary directory.
+     *
+     * Caller is responsible for deleting the file and its parent directory.
+     *
+     * @param lic         License whose JSON/XML/text payload is in {@code getLicenseData()}.
+     * @param licFileName Desired file name (e.g. "license.lic").
+     * @return A {@link File} pointing to the newly created file.
+     * @throws IOException If the temporary directory or file cannot be created/written.
+     */
+    public File createTemporaryLicenseFile(License lic, String licFileName) throws IOException {
+        File f = Files.createTempDirectory("securis-server").toFile();
+        f = new File(f, licFileName);
+        FileUtils.writeStringToFile(f, lic.getLicenseData(), StandardCharsets.UTF_8);
+        return f;
+    }
 
-		return metadata;
-	}
+    /**
+     * extractPackMetadata
+     * <p>
+     * Converts pack metadata set to a map for license generation.
+     *
+     * @param packMetadata Set of {@link PackMetadata}.
+     * @return Map with keys/values copied from metadata entries.
+     */
+    public Map<String, Object> extractPackMetadata(Set<PackMetadata> packMetadata) {
+        Map<String, Object> metadata = new HashMap<>();
+        for (PackMetadata md : packMetadata) {
+            metadata.put(md.getKey(), md.getValue());
+        }
+        return metadata;
+    }
 
-	/**
-	 * If the action is a renew the expiration date is got form pack end valid
-	 * date, if the action is a pre-activation the expiration date is calculated
-	 * using the pack default valid period
-	 * 
-	 * @param pack
-	 * @param isPreActivation
-	 * @return
-	 */
-	public Date getExpirationDateFromPack(Pack pack, boolean isPreActivation) {
-		Long validPeriod;
-		if (pack.getEndValidDate().before(new Date())) {
-			throw new CurisRuntimeException("Pack end valid period is reached, no new licenses can be activated.");
-		}
-		if (isPreActivation) {
-			validPeriod = pack.getPreactivationValidPeriod() * MS_PER_DAY;
-		} else {
-			if (pack.getRenewValidPeriod() <= 0) {
-				return pack.getEndValidDate();
-			}
-			long renewPeriod = pack.getRenewValidPeriod() * MS_PER_DAY;
-			long expirationPeriod = pack.getEndValidDate().getTime() - new Date().getTime();
-			validPeriod = renewPeriod < expirationPeriod ? renewPeriod : expirationPeriod;
-		}
-		Date expirationDate = new Date(new Date().getTime() + validPeriod);
-		return expirationDate;
-	}
+    /**
+     * getExpirationDateFromPack
+     * <p>
+     * Computes license expiration date depending on action type:
+     * - Pre-activation: {@code preactivationValidPeriod} days from now.
+     * - Renew/Activation: min(renewValidPeriod days, pack end date - now).
+     * Fails fast if pack end date is already in the past.
+     *
+     * @param pack            Pack with policy data.
+     * @param isPreActivation Whether the operation is a pre-activation.
+     * @return Calculated expiration {@link Date}.
+     * @throws CurisRuntimeException if the pack's end date is in the past.
+     */
+    public Date getExpirationDateFromPack(Pack pack, boolean isPreActivation) {
+        Long validPeriod;
+        if (pack.getEndValidDate().before(new Date())) {
+            throw new CurisRuntimeException("Pack end valid period is reached, no new licenses can be activated.");
+        }
+        if (isPreActivation) {
+            validPeriod = pack.getPreactivationValidPeriod() * MS_PER_DAY;
+        } else {
+            if (pack.getRenewValidPeriod() <= 0) {
+                return pack.getEndValidDate();
+            }
+            long renewPeriod = pack.getRenewValidPeriod() * MS_PER_DAY;
+            long expirationPeriod = pack.getEndValidDate().getTime() - new Date().getTime();
+            validPeriod = renewPeriod < expirationPeriod ? renewPeriod : expirationPeriod;
+        }
+        Date expirationDate = new Date(new Date().getTime() + validPeriod);
+        return expirationDate;
+    }
 
-	/**
-	 * Get the next free code suffis for a given Pack
-	 * 
-	 * @param packId
-	 * @param em
-	 * @return
-	 */
-	public int getNextCodeSuffix(int packId, EntityManager em) {
-		TypedQuery<Integer> query = em.createNamedQuery("last-code-suffix-used-in-pack", Integer.class);
-		query.setParameter("packId", packId);
-		Integer lastCodeSuffix = query.getSingleResult();
-		return lastCodeSuffix == null ? 1 : lastCodeSuffix + 1;
-	}
-
+    /**
+     * getNextCodeSuffix
+     * <p>
+     * Retrieves the last used code suffix for a given pack and returns the next one.
+     * If none found, returns 1.
+     *
+     * @param packId Pack identifier.
+     * @param em     EntityManager to query the DB.
+     * @return Next sequential suffix (>= 1).
+     */
+    public int getNextCodeSuffix(int packId, EntityManager em) {
+        TypedQuery<Integer> query = em.createNamedQuery("last-code-suffix-used-in-pack", Integer.class);
+        query.setParameter("packId", packId);
+        Integer lastCodeSuffix = query.getSingleResult();
+        return lastCodeSuffix == null ? 1 : lastCodeSuffix + 1;
+    }
 }
+

--
Gitblit v1.3.2