/* * Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved. */ package net.curisit.securis.db; import java.io.Serializable; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.NamedQueries; import jakarta.persistence.NamedQuery; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import org.hibernate.annotations.Type; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import net.curisit.integrity.commons.Utils; /** * Pack *

* Group/bundle of licenses for an organization and application (via LicenseType). * Tracks capacity, availability, status, and validity windows. * * Mapping details: * - Table: pack * - ManyToOne to Organization, LicenseType, User (createdBy) * - OneToMany licenses (lazy) * - Custom type: net.curisit.securis.db.common.PackStatusType * - Named queries for listing and filtering by org/app. * * @author JRA * Last reviewed by JRA on Oct 5, 2025. */ @JsonAutoDetect @JsonInclude(Include.NON_NULL) @Entity @Table(name = "pack") @JsonIgnoreProperties(ignoreUnknown = true) @NamedQueries({ @NamedQuery(name = "list-packs", query = "SELECT pa FROM Pack pa"), @NamedQuery(name = "pack-by-code", query = "SELECT pa FROM Pack pa where pa.code = :code"), @NamedQuery(name = "list-packs-by-lic-type", query = "SELECT pa FROM Pack pa where pa.licenseType.id = :lt_id"), @NamedQuery(name = "list-packs-by-orgs-apps", query = "SELECT pa FROM Pack pa where pa.organization.id in :list_ids_org and pa.licenseType.application.id in :list_ids_app "), @NamedQuery(name = "list-packs-by-apps", query = "SELECT pa FROM Pack pa where pa.licenseType.application.id in :list_ids_app ") }) public class Pack implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue private Integer id; private String code; private String comments; private Boolean frozen; @Column(name = "creation_timestamp") @JsonProperty("creation_timestamp") private Date creationTimestamp; @JsonIgnore @ManyToOne @JoinColumn(name = "organization_id") private Organization organization; @JsonIgnore @ManyToOne @JoinColumn(name = "license_type_id") private LicenseType licenseType; @JsonIgnore @ManyToOne @JoinColumn(name = "created_by") private User createdBy; @JsonIgnore @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH }, mappedBy = "pack") private Set licenses; @Column(name = "num_licenses") @JsonProperty("num_licenses") private int numLicenses; @Column(name = "init_valid_date") @JsonProperty("init_valid_date") private Date initValidDate; @Column(name = "end_valid_date") @JsonProperty("end_valid_date") private Date endValidDate; @Type(type = "net.curisit.securis.db.common.PackStatusType") private PackStatus status; @Column(name = "license_preactivation") @JsonProperty("license_preactivation") private boolean licensePreactivation; @Column(name = "preactivation_valid_period") @JsonProperty("preactivation_valid_period") private Integer preactivationValidPeriod; @Column(name = "renew_valid_period") @JsonProperty("renew_valid_period") private Integer renewValidPeriod; @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH }, mappedBy = "pack") private Set metadata; // ---------------- Getters & setters ---------------- /** * getId

* Return primary key. * * @return id */ public Integer getId() { return id; } /** * setId

* Set primary key. * * @param id */ public void setId(Integer id) { this.id = id; } /** * getCode

* Return pack code. * * @return packCode */ public String getCode() { return code; } /** * setCode

* Set pack code. * * @param packCode */ public void setCode(String code) { this.code = code; } /** * getCreationTimestamp

* Return creation timestamp. * * @return creationTimestamp */ public Date getCreationTimestamp() { return creationTimestamp; } /** * setCreationTimestamp

* Set creation timestamp. * * @param creationTimestamp */ public void setCreationTimestamp(Date creationTimestamp) { this.creationTimestamp = creationTimestamp; } /** * getOrganization

* Return owning organization (entity). * * @return organization */ public Organization getOrganization() { return organization; } /** * setOrganization

* Set owning organization (entity). * * @param organization */ public void setOrganization(Organization organization) { this.organization = organization; } /** * getLicenseType

* Return license type (entity). * * @return licenseType */ public LicenseType getLicenseType() { return licenseType; } /** * setLicenseType

* Set license type (entity). * * @param licenseType */ public void setLicenseType(LicenseType licenseType) { this.licenseType = licenseType; } /** * getCreatedBy

* Return creator (entity). * * @return user */ public User getCreatedBy() { return createdBy; } /** * setCreatedBy

* Set creator (entity). * * @param user */ public void setCreatedBy(User createdBy) { this.createdBy = createdBy; } /** * getNumLicenses

* Return capacity (licenses). * * @return numLicenses * Number of licenses */ public int getNumLicenses() { return numLicenses; } /** * setNumLicenses

* Set capacity (licenses). * * @param numLicenses * Number of licenses */ public void setNumLicenses(int numLicenses) { this.numLicenses = numLicenses; } /** * getNumActivations

* Count ACTIVE/PRE_ACTIVE licenses in this pack. * * @return numActivations * number of activated licenses */ @JsonProperty("num_activations") public int getNumActivations() { if (licenses == null) return 0; int num = 0; for (License lic : licenses) { if (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE) num++; } return num; } /** * getNumCreations

* Count all created licenses (including waiting for activation). Ignores CANCELLED. * * @return numCreations * number of created licenses */ @JsonProperty("num_creations") public int getNumCreations() { if (licenses == null) return 0; int num = 0; for (License lic : licenses) { if (lic.getStatus() != LicenseStatus.CANCELLED) num++; } return num; } /** * getNumAvailables

* Number of available licenses in this pack: capacity - activations. * * @return numAvailable * Number of available licenses */ @JsonProperty("num_available") public int getNumAvailables() { return numLicenses - getNumActivations(); } /** * getOrgName

* Expose organization name. * * @return orgName */ @JsonProperty("organization_name") public String getOrgName() { return organization == null ? null : organization.getName(); } /** * getAppName

* Expose application name via license type. * * @return appName */ @JsonProperty("application_name") public String getAppName() { if (licenseType == null) return null; Application app = licenseType.getApplication(); return app == null ? null : app.getName(); } /** * getOrgId

* Expose organization id. * * @return orgId */ @JsonProperty("organization_id") public Integer getOrgId() { return organization == null ? null : organization.getId(); } /** * setOrgId

* Setter by id for JSON binding (creates shallow Organization). * * @param orgId */ @JsonProperty("organization_id") public void setOrgId(Integer idOrg) { if (idOrg == null) { organization = null; } else { organization = new Organization(); organization.setId(idOrg); } } /** * setLicTypeId

* Setter by id for JSON binding (creates shallow LicenseType). * * @param licTypeId */ @JsonProperty("license_type_id") public void setLicTypeId(Integer idLT) { if (idLT == null) { licenseType = null; } else { licenseType = new LicenseType(); licenseType.setId(idLT); } } /** * getLicTypeId

* Expose license type id. * * @return licTypeId */ @JsonProperty("license_type_id") public Integer getLicTypeId() { return licenseType == null ? null : licenseType.getId(); } /** * getCreatedById

* Expose creator username. * * @return username */ @JsonProperty("created_by_id") public String getCreatedById() { return createdBy == null ? null : createdBy.getUsername(); } /** * setCreatedById

* Setter by username (creates shallow User). * * @param username */ @JsonProperty("created_by_id") public void setCreatedById(String username) { createdBy = new User(); createdBy.setUsername(username); } /** * getCreatedByname

* Expose creator full display name. * * @return userName */ @JsonProperty("created_by_name") public String getCreatedByname() { return createdBy == null ? null : String.format("%s %s (%s)", createdBy.getFirstName(), createdBy.getLastName() != null ? createdBy.getLastName() : "", createdBy.getUsername()); } /** * getLicenseTypeCode

* Expose license type code. * * @return licenseTypeCode */ @JsonProperty("licensetype_code") public String getLicenseTypeCode() { return licenseType == null ? null : licenseType.getCode(); } /** * getComments

* Return comments. * * @return comments */ public String getComments() { return comments; } /** * setComments

* Set comments. * * @param comments */ public void setComments(String comments) { this.comments = comments; } /** * isLicensePreactivation

* Whether licenses are pre-activated. * * @return isLicensePreactivation */ public boolean isLicensePreactivation() { return licensePreactivation; } /** * setLicensePreactivation

* Set pre-activation flag. * * @param licensePreactivation */ public void setLicensePreactivation(boolean licensePreactivation) { this.licensePreactivation = licensePreactivation; } /** * getMetadata

* Return pack metadata entries. * * @return metadata */ public Set getMetadata() { return metadata; } /** * setMetadata

* Set pack metadata entries. * * @param metadata */ public void setMetadata(Set metadata) { this.metadata = metadata; } /** * getStatus

* Return pack status. * * @return packStatus */ public PackStatus getStatus() { return status; } /** * setStatus

* Set pack status. * * @param packStatus */ public void setStatus(PackStatus status) { this.status = status; } /** * getInitValidDate

* Return start of validity window. * * @return initValidDate */ public Date getInitValidDate() { return initValidDate; } /** * setInitValidDate

* Set start of validity window. * * @param initValidDate */ public void setInitValidDate(Date initValidDate) { this.initValidDate = initValidDate; } /** * getEndValidDate

* Return end of validity window. * * @return endValidDate */ public Date getEndValidDate() { return endValidDate; } /** * setEndValidDate

* Set end of validity window. * * @param endValidDate */ public void setEndValidDate(Date endValidDate) { this.endValidDate = endValidDate; } /** * getLicenses

* Return contained licenses (entity set). * * @return licenses */ public Set getLicenses() { return licenses; } /** * setLicenses

* Set contained licenses (entity set). * * @param licenses */ public void setLicenses(Set licenses) { this.licenses = licenses; } /** * getPreactivationValidPeriod

* Return preactivation validity (days). * * @return preactivationValidPeriod */ public Integer getPreactivationValidPeriod() { return preactivationValidPeriod; } /** * setPreactivationValidPeriod

* Set preactivation validity (days). * * @param preactivationValidPeriod */ public void setPreactivationValidPeriod(Integer preactivationValidPeriod) { this.preactivationValidPeriod = preactivationValidPeriod; } /** * getRenewValidPeriod

* Return renewal validity (days). * * @return renewValidPeriod */ public Integer getRenewValidPeriod() { return renewValidPeriod; } /** * setRenewValidPeriod

* Set renewal validity (days). * * @param renewValidPeriod */ public void setRenewValidPeriod(Integer renewValidPeriod) { this.renewValidPeriod = renewValidPeriod; } // ---------------- Object methods ---------------- /** * equals

* Compare the current object with the given object * * @param object * @return isEquals */ @Override public boolean equals(Object obj) { if (!(obj instanceof Application)) return false; return id != null && id.equals(Pack.class.cast(obj).id); } /** * hashCode

* Get the object hashCode * * @return hashCode */ @Override public int hashCode() { return (id == null ? 0 : id.hashCode()); } /** * toString

* Get the string describing the current object * * @return object string */ @Override public String toString() { return String.format("Pack: ID: %d, code: %s", id, code); } /** * isFrozen

* Null-safe boolean getter. * * @return isFrozen */ public boolean isFrozen() { return frozen != null && frozen; } /** * setFrozen

* Set frozen flag (nullable wrapper). * * @param frozen */ public void setFrozen(Boolean frozen) { this.frozen = frozen; } // ---------------- Status transitions ---------------- /** * Action

* Available actions for the Pack */ public static class Action { public static final int CREATE = 1; public static final int ACTIVATION = 2; public static final int PUT_ONHOLD = 3; public static final int CANCEL = 4; public static final int DELETE = 5; } /** * Status

* Pack status */ public static class Status { private static final Map> transitions = Utils.createMap( Action.ACTIVATION, Arrays.asList(PackStatus.CREATED, PackStatus.ON_HOLD, PackStatus.EXPIRED), Action.PUT_ONHOLD, Arrays.asList(PackStatus.ACTIVE), Action.CANCEL, Arrays.asList(PackStatus.ACTIVE, PackStatus.ON_HOLD, PackStatus.EXPIRED), Action.DELETE, Arrays.asList(PackStatus.CANCELLED, PackStatus.CREATED) ); /** * isActionValid

* Validate whether an action is allowed given the current pack status. * * @param action action constant * @param currentStatus current pack status * @return true if allowed */ public static boolean isActionValid(Integer action, PackStatus currentStatus) { List validStatuses = transitions.get(action); return validStatuses != null && validStatuses.contains(currentStatus); } } }