| /*
|
| * 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
|
| * <p>
|
| * 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<License> 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<PackMetadata> metadata;
|
|
|
| // ---------------- Getters & setters ----------------
|
|
|
| /**
|
| * getId<p>
|
| * Return primary key.
|
| *
|
| * @return id
|
| */
|
| public Integer getId() { return id; }
|
|
|
| /**
|
| * setId<p>
|
| * Set primary key.
|
| *
|
| * @param id
|
| */
|
| public void setId(Integer id) { this.id = id; }
|
|
|
| /**
|
| * getCode<p>
|
| * Return pack code.
|
| *
|
| * @return packCode
|
| */
|
| public String getCode() { return code; }
|
|
|
| /**
|
| * setCode<p>
|
| * Set pack code.
|
| *
|
| * @param packCode
|
| */
|
| public void setCode(String code) { this.code = code; }
|
|
|
| /**
|
| * getCreationTimestamp<p>
|
| * Return creation timestamp.
|
| *
|
| * @return creationTimestamp
|
| */
|
| public Date getCreationTimestamp() { return creationTimestamp; }
|
|
|
| /**
|
| * setCreationTimestamp<p>
|
| * Set creation timestamp.
|
| *
|
| * @param creationTimestamp
|
| */
|
| public void setCreationTimestamp(Date creationTimestamp) { this.creationTimestamp = creationTimestamp; }
|
|
|
| /**
|
| * getOrganization<p>
|
| * Return owning organization (entity).
|
| *
|
| * @return organization
|
| */
|
| public Organization getOrganization() { return organization; }
|
|
|
| /**
|
| * setOrganization<p>
|
| * Set owning organization (entity).
|
| *
|
| * @param organization
|
| */
|
| public void setOrganization(Organization organization) { this.organization = organization; }
|
|
|
| /**
|
| * getLicenseType<p>
|
| * Return license type (entity).
|
| *
|
| * @return licenseType
|
| */
|
| public LicenseType getLicenseType() { return licenseType; }
|
|
|
| /**
|
| * setLicenseType<p>
|
| * Set license type (entity).
|
| *
|
| * @param licenseType
|
| */
|
| public void setLicenseType(LicenseType licenseType) { this.licenseType = licenseType; }
|
|
|
| /**
|
| * getCreatedBy<p>
|
| * Return creator (entity).
|
| *
|
| * @return user
|
| */
|
| public User getCreatedBy() { return createdBy; }
|
|
|
| /**
|
| * setCreatedBy<p>
|
| * Set creator (entity).
|
| *
|
| * @param user
|
| */
|
| public void setCreatedBy(User createdBy) { this.createdBy = createdBy; }
|
|
|
| /**
|
| * getNumLicenses<p>
|
| * Return capacity (licenses).
|
| *
|
| * @return numLicenses
|
| * Number of licenses
|
| */
|
| public int getNumLicenses() { return numLicenses; }
|
|
|
| /**
|
| * setNumLicenses<p>
|
| * Set capacity (licenses).
|
| *
|
| * @param numLicenses
|
| * Number of licenses
|
| */
|
| public void setNumLicenses(int numLicenses) { this.numLicenses = numLicenses; }
|
|
|
| /**
|
| * getNumActivations<p>
|
| * 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<p>
|
| * 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<p>
|
| * 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<p>
|
| * Expose organization name.
|
| *
|
| * @return orgName
|
| */
|
| @JsonProperty("organization_name")
|
| public String getOrgName() { return organization == null ? null : organization.getName(); }
|
|
|
| /**
|
| * getAppName<p>
|
| * 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<p>
|
| * Expose organization id.
|
| *
|
| * @return orgId
|
| */
|
| @JsonProperty("organization_id")
|
| public Integer getOrgId() { return organization == null ? null : organization.getId(); }
|
|
|
| /**
|
| * setOrgId<p>
|
| * 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<p>
|
| * 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<p>
|
| * Expose license type id.
|
| *
|
| * @return licTypeId
|
| */
|
| @JsonProperty("license_type_id")
|
| public Integer getLicTypeId() { return licenseType == null ? null : licenseType.getId(); }
|
|
|
| /**
|
| * getCreatedById<p>
|
| * Expose creator username.
|
| *
|
| * @return username
|
| */
|
| @JsonProperty("created_by_id")
|
| public String getCreatedById() { return createdBy == null ? null : createdBy.getUsername(); }
|
|
|
| /**
|
| * setCreatedById<p>
|
| * Setter by username (creates shallow User).
|
| *
|
| * @param username
|
| */
|
| @JsonProperty("created_by_id")
|
| public void setCreatedById(String username) {
|
| createdBy = new User();
|
| createdBy.setUsername(username);
|
| }
|
|
|
| /**
|
| * getCreatedByname<p>
|
| * 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<p>
|
| * Expose license type code.
|
| *
|
| * @return licenseTypeCode
|
| */
|
| @JsonProperty("licensetype_code")
|
| public String getLicenseTypeCode() { return licenseType == null ? null : licenseType.getCode(); }
|
|
|
| /**
|
| * getComments<p>
|
| * Return comments.
|
| *
|
| * @return comments
|
| */
|
| public String getComments() { return comments; }
|
|
|
| /**
|
| * setComments<p>
|
| * Set comments.
|
| *
|
| * @param comments
|
| */
|
| public void setComments(String comments) { this.comments = comments; }
|
|
|
| /**
|
| * isLicensePreactivation<p>
|
| * Whether licenses are pre-activated.
|
| *
|
| * @return isLicensePreactivation
|
| */
|
| public boolean isLicensePreactivation() { return licensePreactivation; }
|
|
|
| /**
|
| * setLicensePreactivation<p>
|
| * Set pre-activation flag.
|
| *
|
| * @param licensePreactivation
|
| */
|
| public void setLicensePreactivation(boolean licensePreactivation) { this.licensePreactivation = licensePreactivation; }
|
|
|
| /**
|
| * getMetadata<p>
|
| * Return pack metadata entries.
|
| *
|
| * @return metadata
|
| */
|
| public Set<PackMetadata> getMetadata() { return metadata; }
|
|
|
| /**
|
| * setMetadata<p>
|
| * Set pack metadata entries.
|
| *
|
| * @param metadata
|
| */
|
| public void setMetadata(Set<PackMetadata> metadata) { this.metadata = metadata; }
|
|
|
| /**
|
| * getStatus<p>
|
| * Return pack status.
|
| *
|
| * @return packStatus
|
| */
|
| public PackStatus getStatus() { return status; }
|
|
|
| /**
|
| * setStatus<p>
|
| * Set pack status.
|
| *
|
| * @param packStatus
|
| */
|
| public void setStatus(PackStatus status) { this.status = status; }
|
|
|
| /**
|
| * getInitValidDate<p>
|
| * Return start of validity window.
|
| *
|
| * @return initValidDate
|
| */
|
| public Date getInitValidDate() { return initValidDate; }
|
|
|
| /**
|
| * setInitValidDate<p>
|
| * Set start of validity window.
|
| *
|
| * @param initValidDate
|
| */
|
| public void setInitValidDate(Date initValidDate) { this.initValidDate = initValidDate; }
|
|
|
| /**
|
| * getEndValidDate<p>
|
| * Return end of validity window.
|
| *
|
| * @return endValidDate
|
| */
|
| public Date getEndValidDate() { return endValidDate; }
|
|
|
| /**
|
| * setEndValidDate<p>
|
| * Set end of validity window.
|
| *
|
| * @param endValidDate
|
| */
|
| public void setEndValidDate(Date endValidDate) { this.endValidDate = endValidDate; }
|
|
|
| /**
|
| * getLicenses<p>
|
| * Return contained licenses (entity set).
|
| *
|
| * @return licenses
|
| */
|
| public Set<License> getLicenses() { return licenses; }
|
|
|
| /**
|
| * setLicenses<p>
|
| * Set contained licenses (entity set).
|
| *
|
| * @param licenses
|
| */
|
| public void setLicenses(Set<License> licenses) { this.licenses = licenses; }
|
|
|
| /**
|
| * getPreactivationValidPeriod<p>
|
| * Return preactivation validity (days).
|
| *
|
| * @return preactivationValidPeriod
|
| */
|
| public Integer getPreactivationValidPeriod() { return preactivationValidPeriod; }
|
|
|
| /**
|
| * setPreactivationValidPeriod<p>
|
| * Set preactivation validity (days).
|
| *
|
| * @param preactivationValidPeriod
|
| */
|
| public void setPreactivationValidPeriod(Integer preactivationValidPeriod) { this.preactivationValidPeriod = preactivationValidPeriod; }
|
|
|
| /**
|
| * getRenewValidPeriod<p>
|
| * Return renewal validity (days).
|
| *
|
| * @return renewValidPeriod
|
| */
|
| public Integer getRenewValidPeriod() { return renewValidPeriod; }
|
|
|
| /**
|
| * setRenewValidPeriod<p>
|
| * Set renewal validity (days).
|
| *
|
| * @param renewValidPeriod
|
| */
|
| public void setRenewValidPeriod(Integer renewValidPeriod) { this.renewValidPeriod = renewValidPeriod; }
|
|
|
| // ---------------- Object methods ----------------
|
|
|
| /**
|
| * equals<p>
|
| * 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<p>
|
| * Get the object hashCode
|
| *
|
| * @return hashCode
|
| */
|
| @Override
|
| public int hashCode() { return (id == null ? 0 : id.hashCode()); }
|
|
|
| /**
|
| * toString<p>
|
| * 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<p>
|
| * Null-safe boolean getter.
|
| *
|
| * @return isFrozen
|
| */
|
| public boolean isFrozen() { return frozen != null && frozen; }
|
|
|
| /**
|
| * setFrozen<p>
|
| * Set frozen flag (nullable wrapper).
|
| *
|
| * @param frozen
|
| */
|
| public void setFrozen(Boolean frozen) { this.frozen = frozen; }
|
|
|
| // ---------------- Status transitions ----------------
|
|
|
| /**
|
| * Action<p>
|
| * 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<p>
|
| * Pack status
|
| */
|
| public static class Status {
|
|
|
| private static final Map<Integer, List<PackStatus>> 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<p>
|
| * 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<PackStatus> validStatuses = transitions.get(action);
|
| return validStatuses != null && validStatuses.contains(currentStatus);
|
| }
|
| }
|
| }
|