From 347803bd8d8349baa0577156896a1ec924a69e6d Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Mon, 03 Apr 2017 16:41:28 +0000
Subject: [PATCH] #3535 fix - Marked obsolete metadata field on licenses

---
 securis/src/main/java/net/curisit/securis/db/License.java                      |  705 +++++++++++++++++++++++++------------------------
 securis/src/main/webapp/src/app/resources/licenses.ts                          |    6 
 securis/src/main/java/net/curisit/securis/services/ApiResource.java            |    4 
 securis/src/main/java/net/curisit/securis/services/helpers/MetadataHelper.java |   21 +
 securis/src/main/webapp/src/app/listing/license.list.component.ts              |    3 
 securis/src/main/webapp/src/app/forms/pack.form.component.ts                   |    2 
 securis/src/main/webapp/src/app/forms/license.form.component.ts                |    2 
 securis/src/main/webapp/sql_update.sql                                         |    2 
 securis/src/main/java/net/curisit/securis/db/Pack.java                         |   10 
 securis/src/main/resources/db/schema.sql                                       |    2 
 securis/src/main/webapp/src/app/listing/license.list.component.html            |    3 
 securis/src/main/java/net/curisit/securis/services/PackResource.java           |   43 +-
 12 files changed, 426 insertions(+), 377 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/db/License.java b/securis/src/main/java/net/curisit/securis/db/License.java
index ba3c11f..1d721da 100644
--- a/securis/src/main/java/net/curisit/securis/db/License.java
+++ b/securis/src/main/java/net/curisit/securis/db/License.java
@@ -22,13 +22,6 @@
 import javax.persistence.Table;
 import javax.persistence.TypedQuery;
 
-import net.curisit.integrity.commons.Utils;
-import net.curisit.securis.db.common.CreationTimestampEntity;
-import net.curisit.securis.db.common.ModificationTimestampEntity;
-import net.curisit.securis.db.listeners.CreationTimestampListener;
-import net.curisit.securis.db.listeners.ModificationTimestampListener;
-import net.curisit.securis.services.exception.SeCurisServiceException;
-
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.hibernate.annotations.Type;
@@ -40,6 +33,13 @@
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+import net.curisit.integrity.commons.Utils;
+import net.curisit.securis.db.common.CreationTimestampEntity;
+import net.curisit.securis.db.common.ModificationTimestampEntity;
+import net.curisit.securis.db.listeners.CreationTimestampListener;
+import net.curisit.securis.db.listeners.ModificationTimestampListener;
+import net.curisit.securis.services.exception.SeCurisServiceException;
+
 /**
  * Entity implementation class for Entity: license
  * 
@@ -47,425 +47,432 @@
 @JsonAutoDetect
 @JsonInclude(Include.NON_NULL)
 @Entity
-@EntityListeners({
-        CreationTimestampListener.class, ModificationTimestampListener.class
-})
+@EntityListeners({ CreationTimestampListener.class, ModificationTimestampListener.class })
 @Table(name = "license")
 @JsonIgnoreProperties(ignoreUnknown = true)
-@NamedQueries({
-        @NamedQuery(name = "license-by-code", query = "SELECT l FROM License l where l.code = :code"),
-        @NamedQuery(name = "license-by-activation-code", query = "SELECT l FROM License l where l.activationCode = :activationCode"),
-        @NamedQuery(name = "last-code-suffix-used-in-pack", query = "SELECT max(l.codeSuffix) FROM License l where l.pack.id = :packId"),
-        @NamedQuery(name = "list-licenses-by-pack", query = "SELECT l FROM License l where l.pack.id = :packId"),
-        @NamedQuery(name = "list-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash"),
-        @NamedQuery(name = "list-active-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash and l.status in ('AC', 'PA')"),
-        @NamedQuery(name = "list-valid-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash and l.status in ('RE', 'AC', 'PA')")
+@NamedQueries({ @NamedQuery(name = "license-by-code", query = "SELECT l FROM License l where l.code = :code"),
+		@NamedQuery(name = "license-by-activation-code", query = "SELECT l FROM License l where l.activationCode = :activationCode"),
+		@NamedQuery(name = "last-code-suffix-used-in-pack", query = "SELECT max(l.codeSuffix) FROM License l where l.pack.id = :packId"),
+		@NamedQuery(name = "list-licenses-by-pack", query = "SELECT l FROM License l where l.pack.id = :packId"),
+		@NamedQuery(name = "list-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash"),
+		@NamedQuery(name = "list-active-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash and l.status in ('AC', 'PA')"),
+		@NamedQuery(name = "list-valid-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash and l.status in ('RE', 'AC', 'PA')")
 
 })
 public class License implements CreationTimestampEntity, ModificationTimestampEntity, Serializable {
 
-    private static final long serialVersionUID = 2700310404904877227L;
+	private static final long serialVersionUID = 2700310404904877227L;
 
-    private static final Logger LOG = LogManager.getLogger(License.class);
+	private static final Logger LOG = LogManager.getLogger(License.class);
 
-    @Id
-    @GeneratedValue
-    private Integer id;
+	@Id
+	@GeneratedValue
+	private Integer id;
 
-    private String code;
+	private String code;
 
-    @Column(name = "activation_code")
-    @JsonProperty("activation_code")
-    private String activationCode;
+	@Column(name = "metadata_obsolete")
+	@JsonProperty("metadata_obsolete")
+	private Boolean metadataObsolete;
 
-    @Column(name = "code_suffix")
-    @JsonProperty("code_suffix")
-    private Integer codeSuffix;
+	@Column(name = "activation_code")
+	@JsonProperty("activation_code")
+	private String activationCode;
 
-    @JsonIgnore
-    @ManyToOne
-    @JoinColumn(name = "pack_id")
-    private Pack pack;
+	@Column(name = "code_suffix")
+	@JsonProperty("code_suffix")
+	private Integer codeSuffix;
 
-    @JsonIgnore
-    @ManyToOne
-    @JoinColumn(name = "created_by")
-    private User createdBy;
+	@JsonIgnore
+	@ManyToOne
+	@JoinColumn(name = "pack_id")
+	private Pack pack;
 
-    @JsonIgnore
-    @ManyToOne
-    @JoinColumn(name = "cancelled_by")
-    private User cancelledBy;
+	@JsonIgnore
+	@ManyToOne
+	@JoinColumn(name = "created_by")
+	private User createdBy;
 
-    @Type(type = "net.curisit.securis.db.common.LicenseStatusType")
-    private LicenseStatus status;
+	@JsonIgnore
+	@ManyToOne
+	@JoinColumn(name = "cancelled_by")
+	private User cancelledBy;
 
-    @Column(name = "full_name")
-    @JsonProperty("full_name")
-    private String fullName;
+	@Type(type = "net.curisit.securis.db.common.LicenseStatusType")
+	private LicenseStatus status;
 
-    private String email;
+	@Column(name = "full_name")
+	@JsonProperty("full_name")
+	private String fullName;
 
-    @Column(name = "request_data")
-    @JsonProperty("request_data")
-    private String requestData;
+	private String email;
 
-    /**
-     * request data hash is automatically set when we use
-     * {@link License#setRequestData(String)} method
-     */
-    @Column(name = "request_data_hash")
-    @JsonIgnore
-    private String reqDataHash;
+	@Column(name = "request_data")
+	@JsonProperty("request_data")
+	private String requestData;
 
-    @Column(name = "license_data")
-    @JsonProperty("license_data")
-    @JsonIgnore
-    // The license data is sent to user as a separate file, It doesn't need to
-    // be included as License attribute on browser
-    private String licenseData;
+	/**
+	 * request data hash is automatically set when we use
+	 * {@link License#setRequestData(String)} method
+	 */
+	@Column(name = "request_data_hash")
+	@JsonIgnore
+	private String reqDataHash;
 
-    @Column(name = "creation_timestamp")
-    @JsonProperty("creation_timestamp")
-    private Date creationTimestamp;
+	@Column(name = "license_data")
+	@JsonProperty("license_data")
+	@JsonIgnore
+	// The license data is sent to user as a separate file, It doesn't need to
+	// be included as License attribute on browser
+	private String licenseData;
 
-    @Column(name = "modification_timestamp")
-    @JsonProperty("modification_timestamp")
-    private Date modificationTimestamp;
+	@Column(name = "creation_timestamp")
+	@JsonProperty("creation_timestamp")
+	private Date creationTimestamp;
 
-    @Column(name = "last_access_timestamp")
-    @JsonProperty("last_access_timestamp")
-    private Date lastAccessTimestamp;
+	@Column(name = "modification_timestamp")
+	@JsonProperty("modification_timestamp")
+	private Date modificationTimestamp;
 
-    @Column(name = "expiration_date")
-    @JsonProperty("expiration_date")
-    private Date expirationDate;
+	@Column(name = "last_access_timestamp")
+	@JsonProperty("last_access_timestamp")
+	private Date lastAccessTimestamp;
 
-    private String comments;
+	@Column(name = "expiration_date")
+	@JsonProperty("expiration_date")
+	private Date expirationDate;
 
-    @OneToMany(fetch = FetchType.LAZY, mappedBy = "license")
-    @JsonIgnore
-    private List<LicenseHistory> history;
+	private String comments;
 
-    public Integer getId() {
-        return id;
-    }
+	@OneToMany(fetch = FetchType.LAZY, mappedBy = "license")
+	@JsonIgnore
+	private List<LicenseHistory> history;
 
-    public String getCode() {
-        return code;
-    }
+	public Integer getId() {
+		return id;
+	}
 
-    public void setCode(String code) {
-        this.code = code;
-    }
+	public String getCode() {
+		return code;
+	}
 
-    @Override
-    public Date getCreationTimestamp() {
-        return creationTimestamp;
-    }
+	public void setCode(String code) {
+		this.code = code;
+	}
 
-    @Override
-    public void setCreationTimestamp(Date creationTimestamp) {
-        this.creationTimestamp = creationTimestamp;
-    }
+	@Override
+	public Date getCreationTimestamp() {
+		return creationTimestamp;
+	}
 
-    public User getCreatedBy() {
-        return createdBy;
-    }
+	@Override
+	public void setCreationTimestamp(Date creationTimestamp) {
+		this.creationTimestamp = creationTimestamp;
+	}
 
-    public void setCreatedBy(User createdBy) {
-        this.createdBy = createdBy;
-    }
+	public User getCreatedBy() {
+		return createdBy;
+	}
 
-    public Pack getPack() {
-        return pack;
-    }
+	public void setCreatedBy(User createdBy) {
+		this.createdBy = createdBy;
+	}
 
-    public void setPack(Pack pack) {
-        this.pack = pack;
-    }
+	public Pack getPack() {
+		return pack;
+	}
 
-    @JsonProperty("created_by_id")
-    public String getCreatedById() {
-        return createdBy == null ? null : createdBy.getUsername();
-    }
+	public void setPack(Pack pack) {
+		this.pack = pack;
+	}
 
-    @JsonProperty("created_by_id")
-    public void setCreatedById(String username) {
-        if (username == null) {
-            createdBy = null;
-        } else {
-            createdBy = new User();
-            createdBy.setUsername(username);
-        }
-    }
+	@JsonProperty("created_by_id")
+	public String getCreatedById() {
+		return createdBy == null ? null : createdBy.getUsername();
+	}
 
-    @JsonProperty("cancelled_by_id")
-    public String getCancelledById() {
-        return cancelledBy == null ? null : cancelledBy.getUsername();
-    }
+	@JsonProperty("created_by_id")
+	public void setCreatedById(String username) {
+		if (username == null) {
+			createdBy = null;
+		} else {
+			createdBy = new User();
+			createdBy.setUsername(username);
+		}
+	}
 
-    @JsonProperty("cancelled_by_id")
-    public void setCancelledById(String username) {
-        if (username == null) {
-            cancelledBy = null;
-        } else {
-            cancelledBy = new User();
-            cancelledBy.setUsername(username);
-        }
-    }
+	@JsonProperty("cancelled_by_id")
+	public String getCancelledById() {
+		return cancelledBy == null ? null : cancelledBy.getUsername();
+	}
 
-    @JsonProperty("pack_code")
-    public String getPackCode() {
-        return pack == null ? null : pack.getCode();
-    }
+	@JsonProperty("cancelled_by_id")
+	public void setCancelledById(String username) {
+		if (username == null) {
+			cancelledBy = null;
+		} else {
+			cancelledBy = new User();
+			cancelledBy.setUsername(username);
+		}
+	}
 
-    @JsonProperty("pack_id")
-    public Integer getPackId() {
-        return pack == null ? null : pack.getId();
-    }
+	@JsonProperty("pack_code")
+	public String getPackCode() {
+		return pack == null ? null : pack.getCode();
+	}
 
-    @JsonProperty("pack_id")
-    public void setPackId(Integer idPack) {
-        if (idPack == null) {
-            pack = null;
-        } else {
-            pack = new Pack();
-            pack.setId(idPack);
-        }
-    }
+	@JsonProperty("pack_id")
+	public Integer getPackId() {
+		return pack == null ? null : pack.getId();
+	}
 
-    public LicenseStatus getStatus() {
-        return status;
-    }
+	@JsonProperty("pack_id")
+	public void setPackId(Integer idPack) {
+		if (idPack == null) {
+			pack = null;
+		} else {
+			pack = new Pack();
+			pack.setId(idPack);
+		}
+	}
 
-    public void setStatus(LicenseStatus status) {
-        this.status = status;
-    }
+	public LicenseStatus getStatus() {
+		return status;
+	}
 
-    @Override
-    public Date getModificationTimestamp() {
-        return modificationTimestamp;
-    }
+	public void setStatus(LicenseStatus status) {
+		this.status = status;
+	}
 
-    @Override
-    public void setModificationTimestamp(Date modificationTimestamp) {
-        this.modificationTimestamp = modificationTimestamp;
-    }
+	@Override
+	public Date getModificationTimestamp() {
+		return modificationTimestamp;
+	}
 
-    public String getFullName() {
-        return fullName;
-    }
+	@Override
+	public void setModificationTimestamp(Date modificationTimestamp) {
+		this.modificationTimestamp = modificationTimestamp;
+	}
 
-    public void setFullName(String fullName) {
-        this.fullName = fullName;
-    }
+	public String getFullName() {
+		return fullName;
+	}
 
-    public String getEmail() {
-        return email;
-    }
+	public void setFullName(String fullName) {
+		this.fullName = fullName;
+	}
 
-    public void setEmail(String email) {
-        this.email = email;
-    }
+	public String getEmail() {
+		return email;
+	}
 
-    public void setId(Integer id) {
-        this.id = id;
-    }
+	public void setEmail(String email) {
+		this.email = email;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public User getCancelledBy() {
+		return cancelledBy;
+	}
+
+	public void setCancelledBy(User cancelledBy) {
+		this.cancelledBy = cancelledBy;
+	}
 
-    public User getCancelledBy() {
-        return cancelledBy;
-    }
+	public Date getLastAccessTimestamp() {
+		return lastAccessTimestamp;
+	}
 
-    public void setCancelledBy(User cancelledBy) {
-        this.cancelledBy = cancelledBy;
-    }
+	public void setLastAccessTimestamp(Date lastAccessTimestamp) {
+		this.lastAccessTimestamp = lastAccessTimestamp;
+	}
 
-    public Date getLastAccessTimestamp() {
-        return lastAccessTimestamp;
-    }
+	public String getRequestData() {
+		return requestData;
+	}
 
-    public void setLastAccessTimestamp(Date lastAccessTimestamp) {
-        this.lastAccessTimestamp = lastAccessTimestamp;
-    }
+	public void setRequestData(String requestData) {
+		this.requestData = requestData;
+		this.reqDataHash = BlockedRequest.generateHash(this.requestData);
+	}
 
-    public String getRequestData() {
-        return requestData;
-    }
+	public String getLicenseData() {
+		return licenseData;
+	}
 
-    public void setRequestData(String requestData) {
-        this.requestData = requestData;
-        this.reqDataHash = BlockedRequest.generateHash(this.requestData);
-    }
+	public void setLicenseData(String licenseData) {
+		this.licenseData = licenseData;
+	}
 
-    public String getLicenseData() {
-        return licenseData;
-    }
+	public String getComments() {
+		return comments;
+	}
 
-    public void setLicenseData(String licenseData) {
-        this.licenseData = licenseData;
-    }
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
 
-    public String getComments() {
-        return comments;
-    }
+	public List<LicenseHistory> getHistory() {
+		return history;
+	}
 
-    public void setComments(String comments) {
-        this.comments = comments;
-    }
+	public void setHistory(List<LicenseHistory> history) {
+		this.history = history;
+	}
 
-    public List<LicenseHistory> getHistory() {
-        return history;
-    }
+	public Date getExpirationDate() {
+		return expirationDate;
+	}
 
-    public void setHistory(List<LicenseHistory> history) {
-        this.history = history;
-    }
+	public void setExpirationDate(Date expirationDate) {
+		this.expirationDate = expirationDate;
+	}
 
-    public Date getExpirationDate() {
-        return expirationDate;
-    }
+	public String getReqDataHash() {
+		return reqDataHash;
+	}
 
-    public void setExpirationDate(Date expirationDate) {
-        this.expirationDate = expirationDate;
-    }
+	public static class Action {
+		public static final int CREATE = 1;
+		public static final int REQUEST = 2;
+		public static final int ACTIVATION = 3;
+		public static final int SEND = 4;
+		public static final int DOWNLOAD = 5;
+		public static final int CANCEL = 6;
+		public static final int DELETE = 7;
+		public static final int BLOCK = 8;
+		public static final int UNBLOCK = 9;
+	}
 
-    public String getReqDataHash() {
-        return reqDataHash;
-    }
+	public static class Status {
 
-    public static class Action {
-        public static final int CREATE = 1;
-        public static final int REQUEST = 2;
-        public static final int ACTIVATION = 3;
-        public static final int SEND = 4;
-        public static final int DOWNLOAD = 5;
-        public static final int CANCEL = 6;
-        public static final int DELETE = 7;
-        public static final int BLOCK = 8;
-        public static final int UNBLOCK = 9;
-    }
+		private static final Map<Integer, List<LicenseStatus>> transitions = Utils.createMap( //
+				Action.REQUEST, Arrays.asList(LicenseStatus.CREATED, LicenseStatus.REQUESTED), //
+				Action.ACTIVATION, Arrays.asList(LicenseStatus.CREATED, LicenseStatus.REQUESTED, LicenseStatus.PRE_ACTIVE, LicenseStatus.EXPIRED), //
+				Action.SEND, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
+				Action.DOWNLOAD, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
+				Action.CANCEL, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE, LicenseStatus.REQUESTED, LicenseStatus.EXPIRED), //
+				Action.DELETE, Arrays.asList(LicenseStatus.CANCELLED, LicenseStatus.CREATED, LicenseStatus.BLOCKED), //
+				Action.UNBLOCK, Arrays.asList(LicenseStatus.BLOCKED), //
+				Action.BLOCK, Arrays.asList(LicenseStatus.CANCELLED) //
+		);
 
-    public static class Status {
+		/**
+		 * It checks if a given action is valid for the License, passing the
+		 * action and the current license status
+		 * 
+		 * @param oldStatus
+		 * @param newStatus
+		 * @return
+		 */
+		public static boolean isActionValid(Integer action, LicenseStatus currentStatus) {
+			List<LicenseStatus> validStatuses = transitions.get(action);
+			LOG.info("Action {} is valid ? => {} current: {} OK? {}", action, validStatuses, currentStatus, validStatuses.contains(currentStatus));
+			return validStatuses != null && validStatuses.contains(currentStatus);
+		}
+	}
 
-        private static final Map<Integer, List<LicenseStatus>> transitions = Utils.createMap( //
-                Action.REQUEST, Arrays.asList(LicenseStatus.CREATED, LicenseStatus.REQUESTED), //
-                Action.ACTIVATION, Arrays.asList(LicenseStatus.CREATED, LicenseStatus.REQUESTED, LicenseStatus.PRE_ACTIVE, LicenseStatus.EXPIRED), //
-                Action.SEND, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
-                Action.DOWNLOAD, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
-                Action.CANCEL, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE, LicenseStatus.REQUESTED, LicenseStatus.EXPIRED), //
-                Action.DELETE, Arrays.asList(LicenseStatus.CANCELLED, LicenseStatus.CREATED, LicenseStatus.BLOCKED), //
-                Action.UNBLOCK, Arrays.asList(LicenseStatus.BLOCKED), //
-                Action.BLOCK, Arrays.asList(LicenseStatus.CANCELLED) //
-                );
+	/**
+	 * Return licenses with status: REquested, ACtive, Pre-Active for a given
+	 * request data
+	 * 
+	 * @param requestData
+	 * @param em
+	 * @return
+	 * @throws SeCurisServiceException
+	 */
+	public static License findValidLicenseByRequestData(String requestData, EntityManager em) throws SeCurisServiceException {
+		TypedQuery<License> query = em.createNamedQuery("list-valid-licenses-by-req-data", License.class);
+		query.setParameter("hash", BlockedRequest.generateHash(requestData));
+		try {
+			List<License> list = query.getResultList();
+			if (list.size() == 0) {
+				return null;
+			}
+			if (list.size() > 1) {
+				LOG.error("There are more than 1 active or requested license for request data: {}\nHash: {}", requestData, BlockedRequest.generateHash(requestData));
+			}
+			return list.get(0);
+		} catch (NoResultException e) {
+			// There is no license for request data
+			return null;
+		}
+	}
 
-        /**
-         * It checks if a given action is valid for the License, passing the
-         * action and the current license status
-         * 
-         * @param oldStatus
-         * @param newStatus
-         * @return
-         */
-        public static boolean isActionValid(Integer action, LicenseStatus currentStatus) {
-            List<LicenseStatus> validStatuses = transitions.get(action);
-            LOG.info("Action {} is valid ? => {} current: {} OK? {}", action, validStatuses, currentStatus, validStatuses.contains(currentStatus));
-            return validStatuses != null && validStatuses.contains(currentStatus);
-        }
-    }
+	/**
+	 * Return licenses with status: REquested, ACtive, Pre-Active for a given
+	 * request data
+	 * 
+	 * @param requestData
+	 * @param em
+	 * @return
+	 * @throws SeCurisServiceException
+	 */
+	public static License findLicenseByActivationCode(String activationCode, EntityManager em) throws SeCurisServiceException {
+		TypedQuery<License> query = em.createNamedQuery("license-by-activation-code", License.class);
+		query.setParameter("activationCode", activationCode);
+		try {
+			return query.getSingleResult();
+		} catch (NoResultException e) {
+			// There is no license for request data
+			return null;
+		}
+	}
 
-    /**
-     * Return licenses with status: REquested, ACtive, Pre-Active for a given
-     * request data
-     * 
-     * @param requestData
-     * @param em
-     * @return
-     * @throws SeCurisServiceException
-     */
-    public static License findValidLicenseByRequestData(String requestData, EntityManager em) throws SeCurisServiceException {
-        TypedQuery<License> query = em.createNamedQuery("list-valid-licenses-by-req-data", License.class);
-        query.setParameter("hash", BlockedRequest.generateHash(requestData));
-        try {
-            List<License> list = query.getResultList();
-            if (list.size() == 0) {
-                return null;
-            }
-            if (list.size() > 1) {
-                LOG.error("There are more than 1 active or requested license for request data: {}\nHash: {}", requestData,
-                        BlockedRequest.generateHash(requestData));
-            }
-            return list.get(0);
-        } catch (NoResultException e) {
-            // There is no license for request data
-            return null;
-        }
-    }
+	public static License findActiveLicenseByRequestData(String requestData, EntityManager em) throws SeCurisServiceException {
+		TypedQuery<License> query = em.createNamedQuery("list-active-licenses-by-req-data", License.class);
+		query.setParameter("hash", BlockedRequest.generateHash(requestData));
+		try {
+			List<License> list = query.getResultList();
+			if (list.size() == 0) {
+				return null;
+			}
+			if (list.size() > 1) {
+				LOG.error("There are more than 1 active license for request data: {}\nHash: {}", requestData, BlockedRequest.generateHash(requestData));
+			}
+			return list.get(0);
+		} catch (NoResultException e) {
+			// There is no license for request data
+			return null;
+		}
+	}
 
-    /**
-     * Return licenses with status: REquested, ACtive, Pre-Active for a given
-     * request data
-     * 
-     * @param requestData
-     * @param em
-     * @return
-     * @throws SeCurisServiceException
-     */
-    public static License findLicenseByActivationCode(String activationCode, EntityManager em) throws SeCurisServiceException {
-        TypedQuery<License> query = em.createNamedQuery("license-by-activation-code", License.class);
-        query.setParameter("activationCode", activationCode);
-        try {
-            return query.getSingleResult();
-        } catch (NoResultException e) {
-            // There is no license for request data
-            return null;
-        }
-    }
+	public static License findLicenseByCode(String code, EntityManager em) throws SeCurisServiceException {
+		TypedQuery<License> query = em.createNamedQuery("license-by-code", License.class);
+		query.setParameter("code", code);
+		try {
+			return query.getSingleResult();
+		} catch (NoResultException e) {
+			// There is no license for request data
+			return null;
+		}
+	}
 
-    public static License findActiveLicenseByRequestData(String requestData, EntityManager em) throws SeCurisServiceException {
-        TypedQuery<License> query = em.createNamedQuery("list-active-licenses-by-req-data", License.class);
-        query.setParameter("hash", BlockedRequest.generateHash(requestData));
-        try {
-            List<License> list = query.getResultList();
-            if (list.size() == 0) {
-                return null;
-            }
-            if (list.size() > 1) {
-                LOG.error("There are more than 1 active license for request data: {}\nHash: {}", requestData,
-                        BlockedRequest.generateHash(requestData));
-            }
-            return list.get(0);
-        } catch (NoResultException e) {
-            // There is no license for request data
-            return null;
-        }
-    }
+	public Integer getCodeSuffix() {
+		return codeSuffix;
+	}
 
-    public static License findLicenseByCode(String code, EntityManager em) throws SeCurisServiceException {
-        TypedQuery<License> query = em.createNamedQuery("license-by-code", License.class);
-        query.setParameter("code", code);
-        try {
-            return query.getSingleResult();
-        } catch (NoResultException e) {
-            // There is no license for request data
-            return null;
-        }
-    }
+	public void setCodeSuffix(Integer codeSuffix) {
+		this.codeSuffix = codeSuffix;
+	}
 
-    public Integer getCodeSuffix() {
-        return codeSuffix;
-    }
+	public String getActivationCode() {
+		return activationCode;
+	}
 
-    public void setCodeSuffix(Integer codeSuffix) {
-        this.codeSuffix = codeSuffix;
-    }
+	public void setActivationCode(String activationCode) {
+		this.activationCode = activationCode;
+	}
 
-    public String getActivationCode() {
-        return activationCode;
-    }
+	public boolean isMetadataObsolete() {
+		return metadataObsolete != null && metadataObsolete;
+	}
 
-    public void setActivationCode(String activationCode) {
-        this.activationCode = activationCode;
-    }
+	public void setMetadataObsolete(Boolean obsolete) {
+		this.metadataObsolete = obsolete;
+	}
 
 }
diff --git a/securis/src/main/java/net/curisit/securis/db/Pack.java b/securis/src/main/java/net/curisit/securis/db/Pack.java
index 3885630..eb11298 100644
--- a/securis/src/main/java/net/curisit/securis/db/Pack.java
+++ b/securis/src/main/java/net/curisit/securis/db/Pack.java
@@ -56,6 +56,8 @@
 
 	private String comments;
 
+	private Boolean frozen;
+
 	@Column(name = "creation_timestamp")
 	@JsonProperty("creation_timestamp")
 	private Date creationTimestamp;
@@ -365,6 +367,14 @@
 		return String.format("Pack: ID: %d, code: %s", id, code);
 	}
 
+	public boolean isFrozen() {
+		return frozen != null && frozen;
+	}
+
+	public void setFrozen(Boolean frozen) {
+		this.frozen = frozen;
+	}
+
 	public static class Action {
 		public static final int CREATE = 1;
 		public static final int ACTIVATION = 2;
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 26eea8a..de78528 100644
--- a/securis/src/main/java/net/curisit/securis/services/ApiResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/ApiResource.java
@@ -268,10 +268,6 @@
 		return renewFromPreviousLicense(lic, bsc);
 	}
 
-	private SignedLicenseBean renewLicense(RequestBean req, EntityManager em) throws SeCurisServiceException {
-		return renewLicense(req, em);
-	}
-
 	/**
 	 * Creates a new signed license from request data or from previous license
 	 * if It's a renew
diff --git a/securis/src/main/java/net/curisit/securis/services/PackResource.java b/securis/src/main/java/net/curisit/securis/services/PackResource.java
index 89bc311..a417a98 100644
--- a/securis/src/main/java/net/curisit/securis/services/PackResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/PackResource.java
@@ -44,6 +44,7 @@
 import net.curisit.securis.services.exception.SeCurisServiceException;
 import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
 import net.curisit.securis.services.helpers.LicenseHelper;
+import net.curisit.securis.services.helpers.MetadataHelper;
 import net.curisit.securis.utils.LicUtils;
 import net.curisit.securis.utils.TokenHelper;
 
@@ -60,6 +61,9 @@
 
 	@Inject
 	TokenHelper tokenHelper;
+
+	@Inject
+	MetadataHelper metadataHelper;
 
 	@Context
 	EntityManager em;
@@ -273,27 +277,34 @@
 		currentPack.setEndValidDate(pack.getEndValidDate());
 
 		Set<PackMetadata> newMD = pack.getMetadata();
-		Set<String> newMdKeys = getMdKeys(newMD);
-		for (PackMetadata currentMd : currentPack.getMetadata()) {
-			if (!newMdKeys.contains(currentMd.getKey())) {
-				em.remove(currentMd);
-			}
-		}
-
-		if (newMD != null) {
-			Set<String> oldMdKeys = getMdKeys(newMD);
-			for (PackMetadata md : newMD) {
-				if (oldMdKeys.contains(md.getKey())) {
-					em.merge(md);
-				} else {
-					md.setPack(currentPack);
-					em.persist(md);
+		boolean metadataChanges = !metadataHelper.match(newMD, currentPack.getMetadata());
+		if (metadataChanges) {
+			Set<String> newMdKeys = getMdKeys(newMD);
+			for (PackMetadata currentMd : currentPack.getMetadata()) {
+				if (!newMdKeys.contains(currentMd.getKey())) {
+					em.remove(currentMd);
 				}
 			}
+
+			if (newMD != null) {
+				Set<String> oldMdKeys = getMdKeys(newMD);
+				for (PackMetadata md : newMD) {
+					if (oldMdKeys.contains(md.getKey())) {
+						em.merge(md);
+					} else {
+						md.setPack(currentPack);
+						em.persist(md);
+					}
+				}
+			}
+			currentPack.setMetadata(newMD);
 		}
-		currentPack.setMetadata(newMD);
 		em.merge(currentPack);
 
+		if (metadataChanges) {
+			metadataHelper.markObsoleteMetadata(em, currentPack);
+		}
+
 		return Response.ok(currentPack).build();
 	}
 
diff --git a/securis/src/main/java/net/curisit/securis/services/helpers/MetadataHelper.java b/securis/src/main/java/net/curisit/securis/services/helpers/MetadataHelper.java
index 6934095..ce6fb45 100644
--- a/securis/src/main/java/net/curisit/securis/services/helpers/MetadataHelper.java
+++ b/securis/src/main/java/net/curisit/securis/services/helpers/MetadataHelper.java
@@ -16,6 +16,8 @@
 
 import net.curisit.securis.db.Application;
 import net.curisit.securis.db.ApplicationMetadata;
+import net.curisit.securis.db.License;
+import net.curisit.securis.db.LicenseStatus;
 import net.curisit.securis.db.LicenseType;
 import net.curisit.securis.db.LicenseTypeMetadata;
 import net.curisit.securis.db.Pack;
@@ -108,13 +110,11 @@
 	public void propagateMetadata(EntityManager em, Application app) {
 		Set<ApplicationMetadata> appMd = app.getApplicationMetadata();
 		Set<String> keys = appMd.parallelStream().map(md -> md.getKey()).collect(Collectors.toSet());
-		log.info("App metadata keys: {}", keys);
 		for (LicenseType lt : app.getLicenseTypes()) {
 			log.info("Lic type to update: {}", lt.getCode());
 			this.mergeMetadata(em, appMd, lt.getMetadata(), keys);
 			Set<LicenseTypeMetadata> newMdList = createNewMetadata(appMd, lt.getMetadata(), lt);
 			for (LicenseTypeMetadata newMetadata : newMdList) {
-				log.info("MD key to add to lt: {}", newMetadata.getKey());
 				em.persist(newMetadata);
 			}
 			em.detach(lt);
@@ -142,14 +142,29 @@
 		List<Pack> packs = packsQuery.getResultList();
 		log.info("Packs to update the metadata: {}", packs.size());
 		for (Pack pack : packs) {
+			if (pack.isFrozen()) {
+				log.warn("Metadata in LicenseType {} has changed but the Pack {} is frozen and won't be updated.", lt.getCode(), pack.getCode());
+				continue;
+			}
 			this.mergeMetadata(em, ltMd, pack.getMetadata(), keys);
 			Set<PackMetadata> newMdList = createNewMetadata(ltMd, pack.getMetadata(), pack);
 			for (PackMetadata newMetadata : newMdList) {
-				log.info("MD key to add to pack: {}", newMetadata.getKey());
 				em.persist(newMetadata);
 			}
+			markObsoleteMetadata(em, pack);
 			em.detach(pack);
 		}
 	}
 
+	public void markObsoleteMetadata(EntityManager em, Pack pack) {
+		TypedQuery<License> existingPackLicenses = em.createNamedQuery("list-licenses-by-pack", License.class);
+		existingPackLicenses.setParameter("packId", pack.getId());
+		for (License lic : existingPackLicenses.getResultList()) {
+			log.info("License from pack: {}, status: {}", lic.getCode(), lic.getStatus());
+			if (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE || lic.getStatus() == LicenseStatus.CANCELLED) {
+				lic.setMetadataObsolete(true);
+				em.merge(lic);
+			}
+		}
+	}
 }
diff --git a/securis/src/main/resources/db/schema.sql b/securis/src/main/resources/db/schema.sql
index 8dd55f3..cbe5721 100644
--- a/securis/src/main/resources/db/schema.sql
+++ b/securis/src/main/resources/db/schema.sql
@@ -90,6 +90,7 @@
   renew_valid_period INT NOT NULL DEFAULT 30,  
   created_by varchar(45) NULL ,  
   creation_timestamp TIMESTAMP NOT NULL default now(),
+  frozen BOOLEAN NOT NULL default false,
   PRIMARY KEY (id));
   
 drop table IF EXISTS pack_metadata;
@@ -122,6 +123,7 @@
   cancelled_by varchar(45) NULL ,  
   created_by varchar(45) NULL ,  
   status VARCHAR(2) NOT NULL default 'CR',  
+  metadata_obsolete BOOLEAN NOT NULL default false,
   PRIMARY KEY (id),
   index(request_data_hash, pack_id));
   
diff --git a/securis/src/main/webapp/sql_update.sql b/securis/src/main/webapp/sql_update.sql
new file mode 100644
index 0000000..08c0847
--- /dev/null
+++ b/securis/src/main/webapp/sql_update.sql
@@ -0,0 +1,2 @@
+alter table pack add column frozen BOOLEAN NOT NULL default false;
+alter table license add column metadata_obsolete BOOLEAN NOT NULL default false;
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/forms/license.form.component.ts b/securis/src/main/webapp/src/app/forms/license.form.component.ts
index 6414714..2f3c71b 100644
--- a/securis/src/main/webapp/src/app/forms/license.form.component.ts
+++ b/securis/src/main/webapp/src/app/forms/license.form.component.ts
@@ -56,7 +56,7 @@
     return this.licenses[action](this.data.id).subscribe(
       (actionResponse : any) => {
         this.toaster.success(this.$L.get('Action "{}" executed successfully', action));
-        this.reload();
+        this.init();
       },
       (err : any) => this.toaster.error(this.$L.get('Action "{}" failed', action))
     );
diff --git a/securis/src/main/webapp/src/app/forms/pack.form.component.ts b/securis/src/main/webapp/src/app/forms/pack.form.component.ts
index 9b7c195..de8295c 100644
--- a/securis/src/main/webapp/src/app/forms/pack.form.component.ts
+++ b/securis/src/main/webapp/src/app/forms/pack.form.component.ts
@@ -69,7 +69,7 @@
     return this.packs[action](this.data.id).subscribe(
       (actionResponse : any) => {
         this.toaster.success(this.$L.get('Action "{}" executed successfully', action));
-        this.reload();
+        this.init();
       },
       (err : any) => this.toaster.error(this.$L.get('Action "{}" failed', action))
     );
diff --git a/securis/src/main/webapp/src/app/listing/license.list.component.html b/securis/src/main/webapp/src/app/listing/license.list.component.html
index e2b0c30..0271bfc 100644
--- a/securis/src/main/webapp/src/app/listing/license.list.component.html
+++ b/securis/src/main/webapp/src/app/listing/license.list.component.html
@@ -50,6 +50,9 @@
           <a md-button color="primary" [href]="'mailto:' + value + '?subject=SeCuris'">{{value}}</a>
         </div>
       </template>
+      <template tdDataTableTemplate="metadata_obsolete" let-row="row" let-value="value">
+          <md-icon *ngIf="value" color="warn" [mdTooltip]="$L.get('License metadata is obsolete')">warning</md-icon>
+      </template>
       <template tdDataTableTemplate="expiration_date" let-row="row">
         <div layout="row">
           <span [class.expired]="isLicenseExpired(row)" >{{row.expiration_date | date: 'mediumDate'}}</span>
diff --git a/securis/src/main/webapp/src/app/listing/license.list.component.ts b/securis/src/main/webapp/src/app/listing/license.list.component.ts
index 843f985..14a6050 100644
--- a/securis/src/main/webapp/src/app/listing/license.list.component.ts
+++ b/securis/src/main/webapp/src/app/listing/license.list.component.ts
@@ -19,7 +19,7 @@
   created_by_id: '_client',
   creation_timestamp: 1447848747000,
   email: 'ccalvo@curisit.net',
-  expiration_date: 1450440747000,
+  expiration_date: 1450440747000, 
   full_name: 'César SA',
   id: 110,
   licenseData: '{"appCode":"CISA","appName":"CurisIntegrity SA","licenseCode":"CISA02-494-1","activationCode":"19fa8d30-29cb-4b59-81b5-3837af8204b6","expirationDate":1450440746790,"arch":"x86_64","osName":"Mac OS X","macAddresses":["60-03-08-95-AE-D0","B6-2B-33-E9-64-2D"],"crcLogo":"10f6379e0e1c00ebc403160307e3c5d0aba0727c9cae0bf1ac7cd19d84fdc80f","metadata":{"maxWellLifeLines":"50","simulationModes":"A1,A2,N1,QL"},"signature":"Tejun4bNbknxOyEmPaO/fGfGhv4URhVON/7bESxbODFWMJYKQqOPHrDiSUMlf6RbfWSVg2Dry8bY1WX881QGjTkBaHeDJKCy1EaJBwJ2nv9TYSMOiRj0eqMNYWE9/oLpvufHylAkPUpZwXVkSzTxmN+RvWa2Xt4Fu7xN+4PDHV4t7PSq7QwsFlD9ArgYC6Vx+zuL9WZANBtJ2gU/gKOE0CU0KjsB49RGQSFS/G27+H/YuDkCiQq7PC7VdVwYONQ2HO91fyPvInIrzDC5+sWHcUAqSCop//8klMy03hWl6VvAlaSP7kNM3KadyqXIJ3tx4Jwm1W+gBb3tngHzVCpYmw=="}',
@@ -37,6 +37,7 @@
   pack: any = null;
   columns: ITdDataTableColumn[] = [
     { name: 'code', label: 'Code', tooltip: 'License code' },
+    { name: 'metadata_obsolete', label: 'Obsolete', tooltip: 'Metadata obsolete' },
     { name: 'full_name', label: 'User name' },
     { name: 'email', label: 'User email' },
     { name: 'expiration_date', label: 'Expiration date' },
diff --git a/securis/src/main/webapp/src/app/resources/licenses.ts b/securis/src/main/webapp/src/app/resources/licenses.ts
index 87de7bd..c15580d 100644
--- a/securis/src/main/webapp/src/app/resources/licenses.ts
+++ b/securis/src/main/webapp/src/app/resources/licenses.ts
@@ -3,7 +3,9 @@
 import { Injectable } from '@angular/core';
 import { Http, RequestOptions, ResponseContentType, Response } from '@angular/http';
 import { SeCurisResourceServices } from './base';
-import * as saveAsFile from "file-saver";
+import "file-saver";
+
+declare var saveAs: FileSaver;
 
 export const LIC_STATUS = {
 	CREATED: 'CR',
@@ -109,7 +111,7 @@
         return this.http.get(url).map((response : Response) => {
 			let filename =  JSON.parse(response.headers.get('Content-Disposition').match(/".*"$/g)[0]);
 			let content = JSON.stringify(response.json(), null, 2);
-			saveAsFile( new Blob([ content ], { type : 'application/octet-stream' }), filename);
+			saveAs( new Blob([ content ], { type : 'application/octet-stream' }), filename);
 			return Observable.of(true);
 		}).catch(err => super.processErrorResponse(err));
 	}

--
Gitblit v1.3.2