package net.curisit.securis.services.helpers; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import javax.enterprise.context.ApplicationScoped; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import net.curisit.securis.db.Application; import net.curisit.securis.db.ApplicationMetadata; import net.curisit.securis.db.LicenseType; import net.curisit.securis.db.LicenseTypeMetadata; import net.curisit.securis.db.Pack; import net.curisit.securis.db.PackMetadata; import net.curisit.securis.db.common.Metadata; @ApplicationScoped public class MetadataHelper { private static final Logger log = LogManager.getLogger(MetadataHelper.class); public boolean match(T m1, T m2) { if (m1 == null || m2 == null) { return false; } return Objects.equals(m1.getKey(), m2.getKey()) && Objects.equals(m1.getValue(), m2.getValue()) && m1.isMandatory() == m2.isMandatory(); } public Metadata findByKey(String key, Collection listMd) { return listMd.parallelStream().filter(m -> Objects.equals(key, m.getKey())).findAny().orElse(null); } public boolean match(Set listMd1, Set listMd2) { if (listMd1.size() != listMd2.size()) { return false; } return listMd1.parallelStream().allMatch(m -> this.match(m, findByKey(m.getKey(), listMd2))); } public void mergeMetadata(EntityManager em, Set srcListMd, Set tgtListMd, Set keys) { Set mdToRemove = tgtListMd.parallelStream() // .filter(md -> !keys.contains(md.getKey())) // .collect(Collectors.toSet()); for (K tgtMd : mdToRemove) { log.info("MD key to remove: {} - {}", tgtMd.getKey(), tgtMd); if (tgtMd instanceof LicenseTypeMetadata) { log.info("LT: {}, tx: {}, contans: {}", LicenseTypeMetadata.class.cast(tgtMd).getLicenseType(), em.isJoinedToTransaction(), em.contains(tgtMd)); } em.remove(tgtMd); } Set keysToUpdate = tgtListMd.parallelStream() // .filter(md -> keys.contains(md.getKey())) // .collect(Collectors.toSet()); for (K tgtMd : keysToUpdate) { Metadata md = this.findByKey(tgtMd.getKey(), srcListMd); if (md.isMandatory() != tgtMd.isMandatory() || !Objects.equals(md.getValue(), tgtMd.getValue())) { tgtMd.setMandatory(md.isMandatory()); tgtMd.setValue(md.getValue()); log.info("MD key to update: {}", tgtMd.getKey()); em.merge(tgtMd); } } } private Set createNewMetadata(Set appMd, Set existingMd, LicenseType licenseType) { Set oldKeys = existingMd.stream().map(md -> md.getKey()).collect(Collectors.toSet()); return appMd.parallelStream() // .filter(md -> !oldKeys.contains(md.getKey())) // .map(appmd -> { LicenseTypeMetadata ltmd = new LicenseTypeMetadata(); ltmd.setLicenseType(licenseType); ltmd.setKey(appmd.getKey()); ltmd.setValue(appmd.getValue()); ltmd.setMandatory(appmd.isMandatory()); return ltmd; }).collect(Collectors.toSet()); } private Set createNewMetadata(Set ltMd, Set existingMd, Pack pack) { Set oldKeys = existingMd.stream().map(md -> md.getKey()).collect(Collectors.toSet()); return ltMd.parallelStream() // .filter(md -> !oldKeys.contains(md.getKey())) // .map(md -> { PackMetadata pmd = new PackMetadata(); pmd.setPack(pack); pmd.setKey(md.getKey()); pmd.setValue(md.getValue()); pmd.setMandatory(md.isMandatory()); return pmd; }).collect(Collectors.toSet()); } /** * Copy the modified app metadata to LicenseTypes and Packs * * @param em * @param app */ public void propagateMetadata(EntityManager em, Application app) { Set appMd = app.getApplicationMetadata(); Set 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 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); // Probably there is a better way to get the final metadata from JPA... TypedQuery updatedMdQuery = em.createNamedQuery("list-licensetype-metadata", LicenseTypeMetadata.class); updatedMdQuery.setParameter("licenseTypeId", lt.getId()); Set updatedMd = new HashSet<>(updatedMdQuery.getResultList()); lt.setMetadata(updatedMd); propagateMetadata(em, lt, keys); } } /** * Copy the modified licenseType metadata to Packs * * @param em * @param lt * @param keys */ public void propagateMetadata(EntityManager em, LicenseType lt, Set keys) { Set ltMd = lt.getMetadata(); TypedQuery packsQuery = em.createNamedQuery("list-packs-by-lic-type", Pack.class); packsQuery.setParameter("lt_id", lt.getId()); List packs = packsQuery.getResultList(); log.info("Packs to update the metadata: {}", packs.size()); for (Pack pack : packs) { this.mergeMetadata(em, ltMd, pack.getMetadata(), keys); Set newMdList = createNewMetadata(ltMd, pack.getMetadata(), pack); for (PackMetadata newMetadata : newMdList) { log.info("MD key to add to pack: {}", newMetadata.getKey()); em.persist(newMetadata); } em.detach(pack); } } }