| .. | .. |
|---|
| 1 | +/* |
|---|
| 2 | + * Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved. |
|---|
| 3 | + */ |
|---|
| 1 | 4 | package net.curisit.securis.services.helpers; |
|---|
| 2 | 5 | |
|---|
| 3 | 6 | import java.util.Collection; |
|---|
| .. | .. |
|---|
| 24 | 27 | import net.curisit.securis.db.PackMetadata; |
|---|
| 25 | 28 | import net.curisit.securis.db.common.Metadata; |
|---|
| 26 | 29 | |
|---|
| 30 | +/** |
|---|
| 31 | + * MetadataHelper |
|---|
| 32 | + * <p> |
|---|
| 33 | + * Utilities to compare, merge and propagate metadata across the hierarchy: |
|---|
| 34 | + * Application -> LicenseType -> Pack -> (marks License as metadata-obsolete) |
|---|
| 35 | + * <p> |
|---|
| 36 | + * Provides: |
|---|
| 37 | + * - Equality checks on metadata sets. |
|---|
| 38 | + * - Merge semantics: remove keys not present, update changed values/mandatory flags. |
|---|
| 39 | + * - Propagation from Application down to LicenseType and from LicenseType down to Packs. |
|---|
| 40 | + * - Marking existing licenses as "metadataObsolete" when pack metadata changes and |
|---|
| 41 | + * the license is in a state where consumers could depend on metadata snapshot. |
|---|
| 42 | + * |
|---|
| 43 | + * Thread-safety: ApplicationScoped, stateless. |
|---|
| 44 | + * |
|---|
| 45 | + * @author JRA |
|---|
| 46 | + * Last reviewed by JRA on Oct 5, 2025. |
|---|
| 47 | + */ |
|---|
| 27 | 48 | @ApplicationScoped |
|---|
| 28 | 49 | public class MetadataHelper { |
|---|
| 29 | 50 | |
|---|
| 30 | | - private static final Logger log = LogManager.getLogger(MetadataHelper.class); |
|---|
| 51 | + private static final Logger log = LogManager.getLogger(MetadataHelper.class); |
|---|
| 31 | 52 | |
|---|
| 32 | | - public <T extends Metadata> boolean match(T m1, T m2) { |
|---|
| 33 | | - if (m1 == null || m2 == null) { |
|---|
| 34 | | - return false; |
|---|
| 35 | | - } |
|---|
| 36 | | - return Objects.equals(m1.getKey(), m2.getKey()) && Objects.equals(m1.getValue(), m2.getValue()) && m1.isMandatory() == m2.isMandatory(); |
|---|
| 37 | | - } |
|---|
| 53 | + /** |
|---|
| 54 | + * match |
|---|
| 55 | + * <p> |
|---|
| 56 | + * Compare two metadata entries (key, value, mandatory). |
|---|
| 57 | + * |
|---|
| 58 | + * @param m1 First metadata. |
|---|
| 59 | + * @param m2 Second metadata. |
|---|
| 60 | + * @param <T> Metadata subtype. |
|---|
| 61 | + * @return true if equal in key/value/mandatory, false otherwise or if any is null. |
|---|
| 62 | + */ |
|---|
| 63 | + public <T extends Metadata> boolean match(T m1, T m2) { |
|---|
| 64 | + if (m1 == null || m2 == null) { |
|---|
| 65 | + return false; |
|---|
| 66 | + } |
|---|
| 67 | + return Objects.equals(m1.getKey(), m2.getKey()) && Objects.equals(m1.getValue(), m2.getValue()) && m1.isMandatory() == m2.isMandatory(); |
|---|
| 68 | + } |
|---|
| 38 | 69 | |
|---|
| 39 | | - public <T extends Metadata> Metadata findByKey(String key, Collection<T> listMd) { |
|---|
| 40 | | - return listMd.parallelStream().filter(m -> Objects.equals(key, m.getKey())).findAny().orElse(null); |
|---|
| 41 | | - } |
|---|
| 70 | + /** |
|---|
| 71 | + * findByKey |
|---|
| 72 | + * <p> |
|---|
| 73 | + * Find a metadata by key in a collection. |
|---|
| 74 | + * |
|---|
| 75 | + * @param key Metadata key to search. |
|---|
| 76 | + * @param listMd Collection of metadata. |
|---|
| 77 | + * @param <T> Metadata subtype. |
|---|
| 78 | + * @return The first matching metadata or null. |
|---|
| 79 | + */ |
|---|
| 80 | + public <T extends Metadata> Metadata findByKey(String key, Collection<T> listMd) { |
|---|
| 81 | + return listMd.parallelStream().filter(m -> Objects.equals(key, m.getKey())).findAny().orElse(null); |
|---|
| 82 | + } |
|---|
| 42 | 83 | |
|---|
| 43 | | - public <T extends Metadata> boolean match(Set<T> listMd1, Set<T> listMd2) { |
|---|
| 44 | | - if (listMd1.size() != listMd2.size()) { |
|---|
| 45 | | - return false; |
|---|
| 46 | | - } |
|---|
| 47 | | - return listMd1.parallelStream().allMatch(m -> this.match(m, findByKey(m.getKey(), listMd2))); |
|---|
| 48 | | - } |
|---|
| 84 | + /** |
|---|
| 85 | + * match |
|---|
| 86 | + * <p> |
|---|
| 87 | + * Compare two sets of metadata for equality (size + all entries match). |
|---|
| 88 | + * |
|---|
| 89 | + * @param listMd1 First set. |
|---|
| 90 | + * @param listMd2 Second set. |
|---|
| 91 | + * @param <T> Metadata subtype. |
|---|
| 92 | + * @return true if both sets match element-wise, false otherwise. |
|---|
| 93 | + */ |
|---|
| 94 | + public <T extends Metadata> boolean match(Set<T> listMd1, Set<T> listMd2) { |
|---|
| 95 | + if (listMd1.size() != listMd2.size()) { |
|---|
| 96 | + return false; |
|---|
| 97 | + } |
|---|
| 98 | + return listMd1.parallelStream().allMatch(m -> this.match(m, findByKey(m.getKey(), listMd2))); |
|---|
| 99 | + } |
|---|
| 49 | 100 | |
|---|
| 50 | | - public <T extends Metadata, K extends Metadata> void mergeMetadata(EntityManager em, Set<T> srcListMd, Set<K> tgtListMd, Set<String> keys) { |
|---|
| 101 | + /** |
|---|
| 102 | + * mergeMetadata |
|---|
| 103 | + * <p> |
|---|
| 104 | + * Merge metadata from a source set (truth) into a target set. |
|---|
| 105 | + * - Removes entries in target whose keys are not in {@code keys}. |
|---|
| 106 | + * - Updates entries in target whose value/mandatory differ from source. |
|---|
| 107 | + * - Does NOT create new entries; caller is expected to persist new ones separately. |
|---|
| 108 | + * |
|---|
| 109 | + * @param em EntityManager to remove/merge. |
|---|
| 110 | + * @param srcListMd Source metadata set (truth). |
|---|
| 111 | + * @param tgtListMd Target metadata set to update. |
|---|
| 112 | + * @param keys Keys present in source. |
|---|
| 113 | + * @param <T> Source metadata type. |
|---|
| 114 | + * @param <K> Target metadata type. |
|---|
| 115 | + */ |
|---|
| 116 | + public <T extends Metadata, K extends Metadata> void mergeMetadata(EntityManager em, Set<T> srcListMd, Set<K> tgtListMd, Set<String> keys) { |
|---|
| 51 | 117 | |
|---|
| 52 | | - Set<K> mdToRemove = tgtListMd.parallelStream() // |
|---|
| 53 | | - .filter(md -> !keys.contains(md.getKey())) // |
|---|
| 54 | | - .collect(Collectors.toSet()); |
|---|
| 55 | | - for (K tgtMd : mdToRemove) { |
|---|
| 56 | | - log.info("MD key to remove: {} - {}", tgtMd.getKey(), tgtMd); |
|---|
| 57 | | - if (tgtMd instanceof LicenseTypeMetadata) { |
|---|
| 58 | | - log.info("LT: {}, tx: {}, contans: {}", LicenseTypeMetadata.class.cast(tgtMd).getLicenseType(), em.isJoinedToTransaction(), em.contains(tgtMd)); |
|---|
| 59 | | - } |
|---|
| 60 | | - em.remove(tgtMd); |
|---|
| 61 | | - } |
|---|
| 62 | | - Set<K> keysToUpdate = tgtListMd.parallelStream() // |
|---|
| 63 | | - .filter(md -> keys.contains(md.getKey())) // |
|---|
| 64 | | - .collect(Collectors.toSet()); |
|---|
| 65 | | - for (K tgtMd : keysToUpdate) { |
|---|
| 66 | | - Metadata md = this.findByKey(tgtMd.getKey(), srcListMd); |
|---|
| 67 | | - if (md.isMandatory() != tgtMd.isMandatory() || !Objects.equals(md.getValue(), tgtMd.getValue())) { |
|---|
| 68 | | - tgtMd.setMandatory(md.isMandatory()); |
|---|
| 69 | | - tgtMd.setValue(md.getValue()); |
|---|
| 70 | | - log.info("MD key to update: {}", tgtMd.getKey()); |
|---|
| 71 | | - em.merge(tgtMd); |
|---|
| 72 | | - } |
|---|
| 73 | | - } |
|---|
| 74 | | - } |
|---|
| 118 | + // Remove missing keys |
|---|
| 119 | + Set<K> mdToRemove = tgtListMd.parallelStream() |
|---|
| 120 | + .filter(md -> !keys.contains(md.getKey())) |
|---|
| 121 | + .collect(Collectors.toSet()); |
|---|
| 122 | + for (K tgtMd : mdToRemove) { |
|---|
| 123 | + log.info("MD key to remove: {} - {}", tgtMd.getKey(), tgtMd); |
|---|
| 124 | + if (tgtMd instanceof LicenseTypeMetadata) { |
|---|
| 125 | + log.info("LT: {}, tx: {}, contans: {}", LicenseTypeMetadata.class.cast(tgtMd).getLicenseType(), em.isJoinedToTransaction(), em.contains(tgtMd)); |
|---|
| 126 | + } |
|---|
| 127 | + em.remove(tgtMd); |
|---|
| 128 | + } |
|---|
| 75 | 129 | |
|---|
| 76 | | - private Set<LicenseTypeMetadata> createNewMetadata(Set<ApplicationMetadata> appMd, Set<LicenseTypeMetadata> existingMd, LicenseType licenseType) { |
|---|
| 77 | | - Set<String> oldKeys = existingMd.stream().map(md -> md.getKey()).collect(Collectors.toSet()); |
|---|
| 78 | | - return appMd.parallelStream() // |
|---|
| 79 | | - .filter(md -> !oldKeys.contains(md.getKey())) // |
|---|
| 80 | | - .map(appmd -> { |
|---|
| 81 | | - LicenseTypeMetadata ltmd = new LicenseTypeMetadata(); |
|---|
| 82 | | - ltmd.setLicenseType(licenseType); |
|---|
| 83 | | - ltmd.setKey(appmd.getKey()); |
|---|
| 84 | | - ltmd.setValue(appmd.getValue()); |
|---|
| 85 | | - ltmd.setMandatory(appmd.isMandatory()); |
|---|
| 86 | | - return ltmd; |
|---|
| 87 | | - }).collect(Collectors.toSet()); |
|---|
| 88 | | - } |
|---|
| 130 | + // Update changed keys |
|---|
| 131 | + Set<K> keysToUpdate = tgtListMd.parallelStream() |
|---|
| 132 | + .filter(md -> keys.contains(md.getKey())) |
|---|
| 133 | + .collect(Collectors.toSet()); |
|---|
| 134 | + for (K tgtMd : keysToUpdate) { |
|---|
| 135 | + Metadata md = this.findByKey(tgtMd.getKey(), srcListMd); |
|---|
| 136 | + if (md.isMandatory() != tgtMd.isMandatory() || !Objects.equals(md.getValue(), tgtMd.getValue())) { |
|---|
| 137 | + tgtMd.setMandatory(md.isMandatory()); |
|---|
| 138 | + tgtMd.setValue(md.getValue()); |
|---|
| 139 | + log.info("MD key to update: {}", tgtMd.getKey()); |
|---|
| 140 | + em.merge(tgtMd); |
|---|
| 141 | + } |
|---|
| 142 | + } |
|---|
| 143 | + } |
|---|
| 89 | 144 | |
|---|
| 90 | | - private Set<PackMetadata> createNewMetadata(Set<LicenseTypeMetadata> ltMd, Set<PackMetadata> existingMd, Pack pack) { |
|---|
| 91 | | - Set<String> oldKeys = existingMd.stream().map(md -> md.getKey()).collect(Collectors.toSet()); |
|---|
| 92 | | - return ltMd.parallelStream() // |
|---|
| 93 | | - .filter(md -> !oldKeys.contains(md.getKey())) // |
|---|
| 94 | | - .map(md -> { |
|---|
| 95 | | - PackMetadata pmd = new PackMetadata(); |
|---|
| 96 | | - pmd.setPack(pack); |
|---|
| 97 | | - pmd.setKey(md.getKey()); |
|---|
| 98 | | - pmd.setValue(md.getValue()); |
|---|
| 99 | | - pmd.setMandatory(md.isMandatory()); |
|---|
| 100 | | - return pmd; |
|---|
| 101 | | - }).collect(Collectors.toSet()); |
|---|
| 102 | | - } |
|---|
| 145 | + // -- Internal helpers to create new metadata rows when propagating |
|---|
| 103 | 146 | |
|---|
| 104 | | - /** |
|---|
| 105 | | - * Copy the modified app metadata to LicenseTypes and Packs |
|---|
| 106 | | - * |
|---|
| 107 | | - * @param em |
|---|
| 108 | | - * @param app |
|---|
| 109 | | - */ |
|---|
| 110 | | - public void propagateMetadata(EntityManager em, Application app) { |
|---|
| 111 | | - Set<ApplicationMetadata> appMd = app.getApplicationMetadata(); |
|---|
| 112 | | - Set<String> keys = appMd.parallelStream().map(md -> md.getKey()).collect(Collectors.toSet()); |
|---|
| 113 | | - for (LicenseType lt : app.getLicenseTypes()) { |
|---|
| 114 | | - log.info("Lic type to update: {}", lt.getCode()); |
|---|
| 115 | | - this.mergeMetadata(em, appMd, lt.getMetadata(), keys); |
|---|
| 116 | | - Set<LicenseTypeMetadata> newMdList = createNewMetadata(appMd, lt.getMetadata(), lt); |
|---|
| 117 | | - for (LicenseTypeMetadata newMetadata : newMdList) { |
|---|
| 118 | | - em.persist(newMetadata); |
|---|
| 119 | | - } |
|---|
| 120 | | - em.detach(lt); |
|---|
| 121 | | - // Probably there is a better way to get the final metadata from JPA... |
|---|
| 122 | | - TypedQuery<LicenseTypeMetadata> updatedMdQuery = em.createNamedQuery("list-licensetype-metadata", LicenseTypeMetadata.class); |
|---|
| 123 | | - updatedMdQuery.setParameter("licenseTypeId", lt.getId()); |
|---|
| 124 | | - Set<LicenseTypeMetadata> updatedMd = new HashSet<>(updatedMdQuery.getResultList()); |
|---|
| 147 | + /** |
|---|
| 148 | + * createNewMetadata<p> |
|---|
| 149 | + * Create new metadata |
|---|
| 150 | + * |
|---|
| 151 | + * @param appMd |
|---|
| 152 | + * @param existingMd |
|---|
| 153 | + * @param licenseType |
|---|
| 154 | + * @return newMetadata |
|---|
| 155 | + */ |
|---|
| 156 | + private Set<LicenseTypeMetadata> createNewMetadata(Set<ApplicationMetadata> appMd, Set<LicenseTypeMetadata> existingMd, LicenseType licenseType) { |
|---|
| 157 | + Set<String> oldKeys = existingMd.stream().map(md -> md.getKey()).collect(Collectors.toSet()); |
|---|
| 158 | + return appMd.parallelStream() |
|---|
| 159 | + .filter(md -> !oldKeys.contains(md.getKey())) |
|---|
| 160 | + .map(appmd -> { |
|---|
| 161 | + LicenseTypeMetadata ltmd = new LicenseTypeMetadata(); |
|---|
| 162 | + ltmd.setLicenseType(licenseType); |
|---|
| 163 | + ltmd.setKey(appmd.getKey()); |
|---|
| 164 | + ltmd.setValue(appmd.getValue()); |
|---|
| 165 | + ltmd.setMandatory(appmd.isMandatory()); |
|---|
| 166 | + return ltmd; |
|---|
| 167 | + }).collect(Collectors.toSet()); |
|---|
| 168 | + } |
|---|
| 125 | 169 | |
|---|
| 126 | | - lt.setMetadata(updatedMd); |
|---|
| 127 | | - propagateMetadata(em, lt, keys); |
|---|
| 128 | | - } |
|---|
| 129 | | - } |
|---|
| 170 | + /** |
|---|
| 171 | + * createNewMetadata<p> |
|---|
| 172 | + * Create the new metadata |
|---|
| 173 | + * |
|---|
| 174 | + * @param ltMd |
|---|
| 175 | + * @param existingMd |
|---|
| 176 | + * @param pack |
|---|
| 177 | + * @return newMetadata |
|---|
| 178 | + */ |
|---|
| 179 | + private Set<PackMetadata> createNewMetadata(Set<LicenseTypeMetadata> ltMd, Set<PackMetadata> existingMd, Pack pack) { |
|---|
| 180 | + Set<String> oldKeys = existingMd.stream().map(md -> md.getKey()).collect(Collectors.toSet()); |
|---|
| 181 | + return ltMd.parallelStream() |
|---|
| 182 | + .filter(md -> !oldKeys.contains(md.getKey())) |
|---|
| 183 | + .map(md -> { |
|---|
| 184 | + PackMetadata pmd = new PackMetadata(); |
|---|
| 185 | + pmd.setPack(pack); |
|---|
| 186 | + pmd.setKey(md.getKey()); |
|---|
| 187 | + pmd.setValue(md.getValue()); |
|---|
| 188 | + pmd.setMandatory(md.isMandatory()); |
|---|
| 189 | + return pmd; |
|---|
| 190 | + }).collect(Collectors.toSet()); |
|---|
| 191 | + } |
|---|
| 130 | 192 | |
|---|
| 131 | | - /** |
|---|
| 132 | | - * Copy the modified licenseType metadata to Packs |
|---|
| 133 | | - * |
|---|
| 134 | | - * @param em |
|---|
| 135 | | - * @param lt |
|---|
| 136 | | - * @param keys |
|---|
| 137 | | - */ |
|---|
| 138 | | - public void propagateMetadata(EntityManager em, LicenseType lt, Set<String> keys) { |
|---|
| 139 | | - Set<LicenseTypeMetadata> ltMd = lt.getMetadata(); |
|---|
| 140 | | - TypedQuery<Pack> packsQuery = em.createNamedQuery("list-packs-by-lic-type", Pack.class); |
|---|
| 141 | | - packsQuery.setParameter("lt_id", lt.getId()); |
|---|
| 142 | | - List<Pack> packs = packsQuery.getResultList(); |
|---|
| 143 | | - log.info("Packs to update the metadata: {}", packs.size()); |
|---|
| 144 | | - for (Pack pack : packs) { |
|---|
| 145 | | - if (pack.isFrozen()) { |
|---|
| 146 | | - log.warn("Metadata in LicenseType {} has changed but the Pack {} is frozen and won't be updated.", lt.getCode(), pack.getCode()); |
|---|
| 147 | | - continue; |
|---|
| 148 | | - } |
|---|
| 149 | | - this.mergeMetadata(em, ltMd, pack.getMetadata(), keys); |
|---|
| 150 | | - Set<PackMetadata> newMdList = createNewMetadata(ltMd, pack.getMetadata(), pack); |
|---|
| 151 | | - for (PackMetadata newMetadata : newMdList) { |
|---|
| 152 | | - em.persist(newMetadata); |
|---|
| 153 | | - } |
|---|
| 154 | | - markObsoleteMetadata(em, pack); |
|---|
| 155 | | - em.detach(pack); |
|---|
| 156 | | - } |
|---|
| 157 | | - } |
|---|
| 193 | + /** |
|---|
| 194 | + * propagateMetadata (Application -> LicenseTypes -> Packs) |
|---|
| 195 | + * <p> |
|---|
| 196 | + * Propagates application metadata changes down to all its license types and packs: |
|---|
| 197 | + * - mergeMetadata on LicenseType |
|---|
| 198 | + * - create new LicenseTypeMetadata for new keys |
|---|
| 199 | + * - re-fetch LT metadata (detached/merged semantics) |
|---|
| 200 | + * - propagateMetadata(LicenseType) to packs |
|---|
| 201 | + * |
|---|
| 202 | + * @param em EntityManager. |
|---|
| 203 | + * @param app Application with updated metadata loaded. |
|---|
| 204 | + */ |
|---|
| 205 | + public void propagateMetadata(EntityManager em, Application app) { |
|---|
| 206 | + Set<ApplicationMetadata> appMd = app.getApplicationMetadata(); |
|---|
| 207 | + Set<String> keys = appMd.parallelStream().map(md -> md.getKey()).collect(Collectors.toSet()); |
|---|
| 208 | + for (LicenseType lt : app.getLicenseTypes()) { |
|---|
| 209 | + log.info("Lic type to update: {}", lt.getCode()); |
|---|
| 210 | + this.mergeMetadata(em, appMd, lt.getMetadata(), keys); |
|---|
| 211 | + Set<LicenseTypeMetadata> newMdList = createNewMetadata(appMd, lt.getMetadata(), lt); |
|---|
| 212 | + for (LicenseTypeMetadata newMetadata : newMdList) { |
|---|
| 213 | + em.persist(newMetadata); |
|---|
| 214 | + } |
|---|
| 215 | + em.detach(lt); |
|---|
| 158 | 216 | |
|---|
| 159 | | - public void markObsoleteMetadata(EntityManager em, Pack pack) { |
|---|
| 160 | | - TypedQuery<License> existingPackLicenses = em.createNamedQuery("list-licenses-by-pack", License.class); |
|---|
| 161 | | - existingPackLicenses.setParameter("packId", pack.getId()); |
|---|
| 162 | | - for (License lic : existingPackLicenses.getResultList()) { |
|---|
| 163 | | - log.info("License from pack: {}, status: {}", lic.getCode(), lic.getStatus()); |
|---|
| 164 | | - if (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE || lic.getStatus() == LicenseStatus.CANCELLED) { |
|---|
| 165 | | - lic.setMetadataObsolete(true); |
|---|
| 166 | | - em.merge(lic); |
|---|
| 167 | | - } |
|---|
| 168 | | - } |
|---|
| 169 | | - } |
|---|
| 217 | + // Re-read updated metadata |
|---|
| 218 | + TypedQuery<LicenseTypeMetadata> updatedMdQuery = em.createNamedQuery("list-licensetype-metadata", LicenseTypeMetadata.class); |
|---|
| 219 | + updatedMdQuery.setParameter("licenseTypeId", lt.getId()); |
|---|
| 220 | + Set<LicenseTypeMetadata> updatedMd = new HashSet<>(updatedMdQuery.getResultList()); |
|---|
| 221 | + |
|---|
| 222 | + lt.setMetadata(updatedMd); |
|---|
| 223 | + propagateMetadata(em, lt, keys); |
|---|
| 224 | + } |
|---|
| 225 | + } |
|---|
| 226 | + |
|---|
| 227 | + /** |
|---|
| 228 | + * propagateMetadata (LicenseType -> Packs) |
|---|
| 229 | + * <p> |
|---|
| 230 | + * Propagates license type metadata changes to all its packs: |
|---|
| 231 | + * - mergeMetadata on Pack |
|---|
| 232 | + * - create new PackMetadata for new keys |
|---|
| 233 | + * - markObsoleteMetadata on packs to flag their licenses |
|---|
| 234 | + * |
|---|
| 235 | + * Frozen packs are skipped. |
|---|
| 236 | + * |
|---|
| 237 | + * @param em EntityManager. |
|---|
| 238 | + * @param lt LicenseType with updated metadata set. |
|---|
| 239 | + * @param keys Set of keys present in the source. |
|---|
| 240 | + */ |
|---|
| 241 | + public void propagateMetadata(EntityManager em, LicenseType lt, Set<String> keys) { |
|---|
| 242 | + Set<LicenseTypeMetadata> ltMd = lt.getMetadata(); |
|---|
| 243 | + TypedQuery<Pack> packsQuery = em.createNamedQuery("list-packs-by-lic-type", Pack.class); |
|---|
| 244 | + packsQuery.setParameter("lt_id", lt.getId()); |
|---|
| 245 | + List<Pack> packs = packsQuery.getResultList(); |
|---|
| 246 | + log.info("Packs to update the metadata: {}", packs.size()); |
|---|
| 247 | + for (Pack pack : packs) { |
|---|
| 248 | + if (pack.isFrozen()) { |
|---|
| 249 | + log.warn("Metadata in LicenseType {} has changed but the Pack {} is frozen and won't be updated.", lt.getCode(), pack.getCode()); |
|---|
| 250 | + continue; |
|---|
| 251 | + } |
|---|
| 252 | + this.mergeMetadata(em, ltMd, pack.getMetadata(), keys); |
|---|
| 253 | + Set<PackMetadata> newMdList = createNewMetadata(ltMd, pack.getMetadata(), pack); |
|---|
| 254 | + for (PackMetadata newMetadata : newMdList) { |
|---|
| 255 | + em.persist(newMetadata); |
|---|
| 256 | + } |
|---|
| 257 | + markObsoleteMetadata(em, pack); |
|---|
| 258 | + em.detach(pack); |
|---|
| 259 | + } |
|---|
| 260 | + } |
|---|
| 261 | + |
|---|
| 262 | + /** |
|---|
| 263 | + * markObsoleteMetadata |
|---|
| 264 | + * <p> |
|---|
| 265 | + * For all licenses within the given pack, mark {@code metadataObsolete = true} |
|---|
| 266 | + * if the license is in a relevant state (ACTIVE, PRE_ACTIVE, CANCELLED). |
|---|
| 267 | + * This lets clients know that metadata-dependent artifacts might need refresh. |
|---|
| 268 | + * |
|---|
| 269 | + * @param em EntityManager. |
|---|
| 270 | + * @param pack Pack whose licenses to mark. |
|---|
| 271 | + */ |
|---|
| 272 | + public void markObsoleteMetadata(EntityManager em, Pack pack) { |
|---|
| 273 | + TypedQuery<License> existingPackLicenses = em.createNamedQuery("list-licenses-by-pack", License.class); |
|---|
| 274 | + existingPackLicenses.setParameter("packId", pack.getId()); |
|---|
| 275 | + for (License lic : existingPackLicenses.getResultList()) { |
|---|
| 276 | + log.info("License from pack: {}, status: {}", lic.getCode(), lic.getStatus()); |
|---|
| 277 | + if (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE || lic.getStatus() == LicenseStatus.CANCELLED) { |
|---|
| 278 | + lic.setMetadataObsolete(true); |
|---|
| 279 | + em.merge(lic); |
|---|
| 280 | + } |
|---|
| 281 | + } |
|---|
| 282 | + } |
|---|
| 170 | 283 | } |
|---|
| 284 | + |
|---|