@@ -, +, @@ 
---
 .../domain/product/SUSEProductFactory.java    |  49 +-----
 .../product/SUSEProductSCCRepository.java     |  45 ++++-
 .../redhat/rhn/domain/scc/SCCRepository.java  |  15 +-
 .../rhn/domain/scc/SCCRepositoryAuth.java     |  14 +-
 .../manager/content/ContentSyncManager.java   | 162 +++++++++---------
 ....mc.Manager-4.3.14-improve-content-syncing |   2 +
 6 files changed, 149 insertions(+), 138 deletions(-)
 create mode 100644 java/spacewalk-java.changes.mc.Manager-4.3.14-improve-content-syncing
--- a/java/code/src/com/redhat/rhn/domain/product/SUSEProductFactory.java	
+++ a/java/code/src/com/redhat/rhn/domain/product/SUSEProductFactory.java	
@@ -137,31 +137,14 @@ public class SUSEProductFactory extends HibernateFactory {
      * @return list of {@link SUSEProductSCCRepository}
      */
     public static List<SUSEProductSCCRepository> lookupPSRByChannelLabel(String channelLabel) {
-        Session session = getSession();
-        Criteria c = session.createCriteria(SUSEProductSCCRepository.class);
-        c.add(Restrictions.eq("channelLabel", channelLabel));
-        return ((List<SUSEProductSCCRepository>) c.list()).stream()
+        return getSession().createNamedQuery("SUSEProductSCCRepository.lookupByLabel", SUSEProductSCCRepository.class)
+                .setParameter("label", channelLabel)
+                .stream()
                 .sorted((a, b) ->
                         RPM_VERSION_COMPARATOR.compare(b.getProduct().getVersion(), a.getProduct().getVersion()))
                 .collect(Collectors.toList());
     }
 
-    /**
-     * lookup {@link SUSEProductSCCRepository} by given ID triple
-     * @param rootId root product id
-     * @param productId product id
-     * @param repoId repository id
-     * @return the product/repository item
-     */
-    public static Optional<SUSEProductSCCRepository> lookupProductRepoByIds(long rootId, long productId, long repoId) {
-        Session session = getSession();
-        Criteria c = session.createCriteria(SUSEProductSCCRepository.class);
-        c.add(Restrictions.eq("rootProduct.productId", rootId));
-        c.add(Restrictions.eq("product.productId", productId));
-        c.add(Restrictions.eq("repository.sccId", repoId));
-        return Optional.ofNullable((SUSEProductSCCRepository) c.uniqueResult());
-    }
-
     /**
      * Insert or update a {@link SUSEProductExtension}.
      * @param productExtension migration target to be inserted.
@@ -208,17 +191,6 @@ public class SUSEProductFactory extends HibernateFactory {
                 .orElseGet(Stream::empty).collect(Collectors.toList());
     }
 
-    /**
-     * Lookup SUSEProductChannels by channel label
-     * @param channelLabel the label
-     * @return list of SUSEProductChannels
-     */
-    public static List<SUSEProductSCCRepository> lookupByChannelLabel(String channelLabel) {
-        Session session = HibernateFactory.getSession();
-        return session.getNamedQuery("SUSEProductSCCRepository.lookupByLabel")
-                .setParameter("label", channelLabel).list();
-    }
-
     /**
      * Lookup SUSE Product Channels by channel name
      * @param name the channel name
@@ -239,21 +211,15 @@ public class SUSEProductFactory extends HibernateFactory {
      * @return SUSEProductSCCRepository entry with the newest product
      */
     public static Optional<SUSEProductSCCRepository> lookupByChannelLabelFirst(String channelLabel) {
-        return  lookupByChannelLabel(channelLabel)
-                .stream()
-                // sort so we always choose the latest version
-                .sorted((a, b) ->  RPM_VERSION_COMPARATOR.compare(b.getProduct().getVersion(),
-                        a.getProduct().getVersion()))
-
-                // We take the first item since there can be more than one entry.
-                // This only happens for sles11 sp1/2  and rolling release attempts like caasp 1/2
-                .findFirst();
+        // We take the first item since there can be more than one entry.
+        // This only happens for sles11 sp1/2  and rolling release attempts like caasp 1/2
+        return  lookupPSRByChannelLabel(channelLabel).stream().findFirst();
     }
 
 
     private static Stream<SUSEProductChannel> findSyncedMandatoryChannels(SUSEProduct product, SUSEProduct base,
                                                                       String baseChannelLabel) {
-        Stream<SUSEProductChannel> concat = Stream.concat(
+        return Stream.concat(
                 product.getSuseProductChannels().stream().filter(
                         pc -> Optional.ofNullable(pc.getChannel().getParentChannel())
                                 .map(c -> c.getLabel().equals(baseChannelLabel))
@@ -263,7 +229,6 @@ public class SUSEProductFactory extends HibernateFactory {
                         p -> findSyncedMandatoryChannels(p, base, baseChannelLabel)
                 )
         );
-        return concat;
     }
 
     private static Optional<SUSEProductChannel> findSyncProductChannelByLabel(String channelLabel) {
--- a/java/code/src/com/redhat/rhn/domain/product/SUSEProductSCCRepository.java	
+++ a/java/code/src/com/redhat/rhn/domain/product/SUSEProductSCCRepository.java	
@@ -17,6 +17,8 @@ package com.redhat.rhn.domain.product;
 import com.redhat.rhn.domain.BaseDomainHelper;
 import com.redhat.rhn.domain.scc.SCCRepository;
 
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.hibernate.annotations.Type;
 
 import javax.persistence.Column;
@@ -27,7 +29,6 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
-import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.SequenceGenerator;
 import javax.persistence.Table;
@@ -40,11 +41,9 @@ import javax.persistence.UniqueConstraint;
 @Entity
 @Table(name = "suseProductSCCRepository", uniqueConstraints =
 @UniqueConstraint(columnNames = {"product_id", "root_product_id", "repo_id"}))
-@NamedQueries({
-        @NamedQuery(
-                name = "SUSEProductSCCRepository.lookupByLabel",
-                query = "select pr from SUSEProductSCCRepository pr where pr.channelLabel = :label")
-})
+@NamedQuery(
+        name = "SUSEProductSCCRepository.lookupByLabel",
+        query = "FROM SUSEProductSCCRepository pr WHERE pr.channelLabel = :label")
 public class SUSEProductSCCRepository extends BaseDomainHelper {
 
     private Long id;
@@ -255,6 +254,40 @@ public class SUSEProductSCCRepository extends BaseDomainHelper {
         gpgKeyFingerprint = gpgKeyFingerprintIn;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof SUSEProductSCCRepository)) {
+            return false;
+        }
+        SUSEProductSCCRepository otherCast = (SUSEProductSCCRepository) other;
+        return new EqualsBuilder()
+                .append(getChannelLabel(), otherCast.getChannelLabel())
+                .append(getProduct(), otherCast.getProduct())
+                .append(getRootProduct(), otherCast.getRootProduct())
+                .append(getRepository(), otherCast.getRepository())
+                .append(getChannelName(), otherCast.getChannelName())
+                .append(isMandatory(), otherCast.isMandatory())
+                .append(getUpdateTag(), otherCast.getUpdateTag())
+                .append(getGpgKeyUrl(), otherCast.getGpgKeyUrl())
+                .isEquals();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder()
+                .append(getChannelLabel())
+                .append(getProduct())
+                .append(getRootProduct())
+                .append(getRepository())
+                .toHashCode();
+    }
+
     @Override
     public String toString() {
         return "(ProductId: " + getProduct().getProductId() +
--- a/java/code/src/com/redhat/rhn/domain/scc/SCCRepository.java	
+++ a/java/code/src/com/redhat/rhn/domain/scc/SCCRepository.java	
@@ -249,7 +249,7 @@ public class SCCRepository extends BaseDomainHelper {
     /**
      * @return Returns the auth.
      */
-    @OneToMany(mappedBy = "repo")
+    @OneToMany(mappedBy = "repo", orphanRemoval = true)
     public Set<SCCRepositoryAuth> getRepositoryAuth() {
         return auth;
     }
@@ -319,7 +319,13 @@ public class SCCRepository extends BaseDomainHelper {
         }
         SCCRepository otherSCCRepository = (SCCRepository) other;
         return new EqualsBuilder()
-            .append(getUrl(), otherSCCRepository.getUrl())
+                .append(getUrl(), otherSCCRepository.getUrl())
+                .append(getSccId(), otherSCCRepository.getSccId())
+                .append(getName(), otherSCCRepository.getName())
+                .append(getDescription(), otherSCCRepository.getDescription())
+                .append(isAutorefresh(), otherSCCRepository.isAutorefresh())
+                .append(isSigned(), otherSCCRepository.isSigned())
+                .append(isInstallerUpdates(), otherSCCRepository.isInstallerUpdates())
             .isEquals();
     }
 
@@ -329,8 +335,9 @@ public class SCCRepository extends BaseDomainHelper {
     @Override
     public int hashCode() {
         return new HashCodeBuilder()
-            .append(getUrl())
-            .toHashCode();
+                .append(getUrl())
+                .append(getSccId())
+                .toHashCode();
     }
 
     /**
--- a/java/code/src/com/redhat/rhn/domain/scc/SCCRepositoryAuth.java	
+++ a/java/code/src/com/redhat/rhn/domain/scc/SCCRepositoryAuth.java	
@@ -31,6 +31,7 @@ import java.util.function.Function;
 import javax.persistence.Column;
 import javax.persistence.DiscriminatorColumn;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
@@ -38,7 +39,6 @@ import javax.persistence.Inheritance;
 import javax.persistence.InheritanceType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
-import javax.persistence.NamedNativeQueries;
 import javax.persistence.NamedNativeQuery;
 import javax.persistence.OneToOne;
 import javax.persistence.SequenceGenerator;
@@ -52,10 +52,8 @@ import javax.persistence.Transient;
 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
 @DiscriminatorColumn(name = "auth_type")
 @Table(name = "suseSCCRepositoryAuth")
-@NamedNativeQueries({
-        @NamedNativeQuery(name = "SCCRepositoryAuth.lookupRepoIdWithAuth",
-                query = "select distinct ra.repo_id from suseSCCRepositoryAuth ra")
-})
+@NamedNativeQuery(name = "SCCRepositoryAuth.lookupRepoIdWithAuth",
+        query = "select distinct ra.repo_id from suseSCCRepositoryAuth ra")
 public abstract class SCCRepositoryAuth extends BaseDomainHelper {
 
     private Long id;
@@ -115,7 +113,7 @@ public abstract class SCCRepositoryAuth extends BaseDomainHelper {
     /**
      * @return the contentSource
      */
-    @OneToOne
+    @OneToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "source_id")
     public ContentSource getContentSource() {
         return contentSource;
@@ -131,8 +129,8 @@ public abstract class SCCRepositoryAuth extends BaseDomainHelper {
     /**
      * @return Returns the products.
      */
-    @ManyToOne
-    @JoinColumn(name = "repo_id")
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "repo_id", nullable = false)
     public SCCRepository getRepo() {
         return repo;
     }
--- a/java/code/src/com/redhat/rhn/manager/content/ContentSyncManager.java	
+++ a/java/code/src/com/redhat/rhn/manager/content/ContentSyncManager.java	
@@ -408,7 +408,7 @@ public class ContentSyncManager {
         for (Channel sc : syncedChannels) {
             List<SUSEProductChannel> spcList = SUSEProductFactory.lookupSyncedProductChannelsByLabel(sc.getLabel());
             if (spcList.isEmpty()) {
-                List<SUSEProductSCCRepository> missingData = SUSEProductFactory.lookupByChannelLabel(sc.getLabel());
+                List<SUSEProductSCCRepository> missingData = SUSEProductFactory.lookupPSRByChannelLabel(sc.getLabel());
                 missingData.forEach(md -> {
                     SUSEProductChannel correctedData = new SUSEProductChannel();
                     correctedData.setProduct(md.getProduct());
@@ -428,7 +428,7 @@ public class ContentSyncManager {
         List<String> installedChannelLabels = getInstalledChannelLabels();
 
         List<Tuple2<SUSEProductSCCRepository, MgrSyncStatus>> availableChannels =
-                TimeUtils.logTime(LOG, "getAvailableCHannels", this::getAvailableChannels).stream().map(e -> {
+                TimeUtils.logTime(LOG, "getAvailableChannels", this::getAvailableChannels).stream().map(e -> {
                     MgrSyncStatus status = installedChannelLabels.contains(e.getChannelLabel()) ?
                             MgrSyncStatus.INSTALLED : MgrSyncStatus.AVAILABLE;
                     return new Tuple2<>(e, status);
@@ -661,6 +661,30 @@ public class ContentSyncManager {
         auth.setContentSource(source);
     }
 
+    private void linkOrphanContentSource(ContentSource cs) {
+        for (Channel c : cs.getChannels()) {
+            ChannelFactory.findVendorRepositoryByChannel(c).ifPresentOrElse(
+                    repo -> repo.getBestAuth().ifPresentOrElse(
+                            auth -> {
+                                LOG.debug("Has new auth: {}", cs.getLabel());
+                                auth.setContentSource(cs);
+                                SCCCachingFactory.saveRepositoryAuth(auth);
+                            },
+                            () -> {
+                                LOG.debug("No auth anymore - remove content source: {}", cs.getLabel());
+                                c.getSources().remove(cs);
+                                ChannelFactory.remove(cs);
+                            }
+                    ),
+                    () -> {
+                        LOG.debug("No repository found for channel: '{}' - remove content source", cs.getLabel());
+                        c.getSources().remove(cs);
+                        ChannelFactory.remove(cs);
+                    }
+            );
+        }
+    }
+
     /**
      * Search for orphan contentsource or channels and try to find
      * available repositories. In case they are found they get linked.
@@ -673,34 +697,17 @@ public class ContentSyncManager {
         HibernateFactory.getSession().flush();
         // find all CountentSource with org id == NULL which do not have a sccrepositoryauth
         List<ContentSource> orphan = ChannelFactory.lookupOrphanVendorContentSources();
-        if (orphan != null) {
+        if (!orphan.isEmpty()) {
             LOG.debug("found orphan vendor content sources: {}", orphan.size());
             // find sccrepositoryauth and link
-            orphan.forEach(cs ->
-                cs.getChannels().forEach(c ->
-                    ChannelFactory.findVendorRepositoryByChannel(c).ifPresentOrElse(
-                        repo -> repo.getBestAuth().ifPresentOrElse(
-                            auth -> {
-                                LOG.debug("Has new auth: {}", cs.getLabel());
-                                auth.setContentSource(cs);
-                                SCCCachingFactory.saveRepositoryAuth(auth);
-                            },
-                            () -> {
-                                LOG.debug("No auth anymore - remove content source: {}", cs.getLabel());
-                                ChannelFactory.remove(cs);
-                            }
-                        ),
-                        () -> {
-                            LOG.debug("No repository found for channel: '{}' - remove content source", cs.getLabel());
-                            ChannelFactory.remove(cs);
-                        }
-                    )
-                )
-            );
+            for (ContentSource cs : orphan) {
+                linkOrphanContentSource(cs);
+            }
+            HibernateFactory.getSession().flush();
         }
         // find all rhnChannel with org id == null and no content source
         List<Channel> orphanChannels = ChannelFactory.lookupOrphanVendorChannels();
-        if (orphanChannels != null) {
+        if (!orphanChannels.isEmpty()) {
             LOG.debug("found orphan vendor channels: {}", orphanChannels.size());
             // find sccrepository auth and create content source and link
             orphanChannels.forEach(c -> Opt.consume(ChannelFactory.findVendorRepositoryByChannel(c),
@@ -721,11 +728,12 @@ public class ContentSyncManager {
 
             // check if this auth item is the "best" available auth for this repo
             // if not, switch it over to the best
-            if (auth.getRepo().getBestAuth().isEmpty()) {
+            Optional<SCCRepositoryAuth> bestAuthOpt = auth.getRepo().getBestAuth();
+            if (bestAuthOpt.isEmpty()) {
                 LOG.warn("no best auth available for repo {}", auth.getRepo());
                 continue;
             }
-            SCCRepositoryAuth bestAuth = auth.getRepo().getBestAuth().get();
+            SCCRepositoryAuth bestAuth = bestAuthOpt.get();
             if (!bestAuth.equals(auth)) {
                 // we are not the "best" available repository auth item.
                 // remove the content source link and set it to the "best"
@@ -939,6 +947,7 @@ public class ContentSyncManager {
             SCCRepository repo = availableReposById.get(jsonRepo.getSCCId());
             if (repo == null) {
                 LOG.error("No repository with ID '{}' found", jsonRepo.getSCCId());
+                // This happens when no ChannelTemplate reference this repository
                 continue;
             }
             Set<SCCRepositoryAuth> allRepoAuths = repo.getRepositoryAuth();
@@ -1017,7 +1026,10 @@ public class ContentSyncManager {
         authList.stream()
                 .filter(repoAuth -> repoAuth.cloudRmtAuth().isEmpty()) // rmtAuth is handled elsewhere (where?)
                 .filter(repoAuth -> !repoIdsFromCredential.contains(repoAuth.getRepo().getSccId()))
-                .forEach(SCCCachingFactory::deleteRepositoryAuth);
+                .forEach(a -> {
+                    a.getRepo().getRepositoryAuth().remove(a);
+                    SCCCachingFactory.deleteRepositoryAuth(a);
+                });
     }
 
     private void generatePtfChannels(List<SCCRepositoryJson> repositories) {
@@ -1381,17 +1393,15 @@ public class ContentSyncManager {
      * @throws ContentSyncException in case of an error
      */
     public Collection<SCCSubscriptionJson> updateSubscriptions() throws ContentSyncException {
-        LOG.info("ContentSyncManager.getSubscriptions called");
-        List<ContentSyncSource> sources = filterCredentials();
-        List<SCCSubscriptionJson> subscriptions = sources.stream()
-            .flatMap(source -> updateSubscriptions(source).stream())
-            .collect(Collectors.toList());
+        return TimeUtils.logTime(LOG, "updateSubscriptions", () -> {
+            List<ContentSyncSource> sources = filterCredentials();
+            List<SCCSubscriptionJson> subscriptions = sources.stream()
+                    .flatMap(source -> updateSubscriptions(source).stream())
+                    .collect(Collectors.toList());
 
-        if (LOG.isDebugEnabled()) {
             LOG.debug("Found {} available subscriptions.", subscriptions.size());
-        }
-        LOG.info("ContentSyncManager.getSubscriptions finished");
-        return subscriptions;
+            return subscriptions;
+        });
     }
 
     /**
@@ -1503,9 +1513,9 @@ public class ContentSyncManager {
      * @throws ContentSyncException in case of an error
      */
     public void updateRepositories(String mirrorUrl) throws ContentSyncException {
-        LOG.info("ContentSyncManager.updateRepository called");
-        refreshRepositoriesAuthentication(mirrorUrl, false);
-        LOG.info("ContentSyncManager.updateRepository finished");
+        TimeUtils.logTime(LOG, "updateRepositories", () ->
+                refreshRepositoriesAuthentication(mirrorUrl, false)
+        );
     }
 
     /**
@@ -1514,9 +1524,9 @@ public class ContentSyncManager {
      * @throws ContentSyncException in case of an error
      */
     public void updateRepositoriesPayg() throws ContentSyncException {
-        LOG.info("ContentSyncManager.updateRepository payg called");
-        refreshRepositoriesAuthentication(null, true);
-        LOG.info("ContentSyncManager.updateRepository payg finished");
+        TimeUtils.logTime(LOG, "updateRepositoriesPayg", () ->
+                refreshRepositoriesAuthentication(null, true)
+        );
     }
 
     /**
@@ -1525,7 +1535,7 @@ public class ContentSyncManager {
      * @throws ContentSyncException in case of an error
      */
     public void updateChannelFamilies(Collection<ChannelFamilyJson> channelFamilies) throws ContentSyncException {
-        LOG.info("ContentSyncManager.updateChannelFamilies called");
+        LOG.info("Sync started with updateChannelFamilies");
         List<String> suffixes = Arrays.asList("", "ALPHA", "BETA");
 
         for (ChannelFamilyJson channelFamily : channelFamilies) {
@@ -1533,7 +1543,7 @@ public class ContentSyncManager {
                 ChannelFamily family = createOrUpdateChannelFamily(
                         channelFamily.getLabel(), channelFamily.getName(), suffix);
                 // Create rhnPublicChannelFamily entry if it doesn't exist
-                if (family.getPublicChannelFamily() == null) {
+                if (family != null && family.getPublicChannelFamily() == null) {
                     PublicChannelFamily pcf = new PublicChannelFamily();
 
                     // save the public channel family
@@ -1543,7 +1553,6 @@ public class ContentSyncManager {
                 }
             }
         }
-        LOG.info("ContentSyncManager.updateChannelFamilies finished");
     }
 
     /**
@@ -2027,13 +2036,14 @@ public class ContentSyncManager {
      * @throws ContentSyncException in case of an error
      */
     public void updateSUSEProducts(List<SCCProductJson> products) throws ContentSyncException {
-        updateSUSEProducts(
-                Stream.concat(
-                        products.stream(),
-                        getAdditionalProducts().stream()
-                ).collect(Collectors.toList()),
-                readUpgradePaths(), loadStaticTree(),
-                getAdditionalRepositories());
+        TimeUtils.logTime(LOG, "updateSUSEProducts", () ->
+                updateSUSEProducts(
+                        Stream.concat(
+                                products.stream(),
+                                getAdditionalProducts().stream()
+                        ).collect(Collectors.toList()),
+                        readUpgradePaths(), loadStaticTree(), getAdditionalRepositories())
+        );
     }
 
     /**
@@ -2047,7 +2057,6 @@ public class ContentSyncManager {
      */
     public void updateSUSEProducts(List<SCCProductJson> products, List<UpgradePathJson> upgradePathJsons,
                                    List<ProductTreeEntry> staticTree, List<SCCRepositoryJson> additionalRepos) {
-        LOG.info("ContentSyncManager.updateSUSEProducts called");
         Map<Long, SUSEProduct> processed = new HashMap<>();
 
         List<SCCProductJson> allProducts = overrideProductAttributes(
@@ -2076,7 +2085,6 @@ public class ContentSyncManager {
 
         updateUpgradePaths(products, upgradePathJsons);
         HibernateFactory.getSession().flush();
-        LOG.info("ContentSyncManager.updateSUSEProducts finished");
     }
 
     /**
@@ -2122,10 +2130,13 @@ public class ContentSyncManager {
     private Stream<SUSEProductSCCRepository> getAvailableRepositories(SUSEProduct root, SUSEProduct product) {
         List<SUSEProductSCCRepository> allEntries = SUSEProductFactory.allProductRepos();
         List<Long> repoIdsWithAuth = SCCCachingFactory.lookupRepositoryIdsWithAuth();
+        Map<Tuple2<SUSEProduct, SUSEProduct>, List<SUSEProductExtension>> allSUSEProdExt =
+                SUSEProductFactory.findAllSUSEProductExtensions().stream()
+                        .collect(Collectors.groupingBy(e -> new Tuple2<>(e.getRootProduct(), e.getBaseProduct())));
 
         Map<Tuple2<SUSEProduct, SUSEProduct>, List<SUSEProductSCCRepository>> entriesByProducts = allEntries.stream()
                 .collect(Collectors.groupingBy(e -> new Tuple2<>(e.getRootProduct(), e.getProduct())));
-        return getAvailableRepositories(root, product, entriesByProducts, repoIdsWithAuth);
+        return getAvailableRepositories(root, product, entriesByProducts, repoIdsWithAuth, allSUSEProdExt);
     }
 
     /**
@@ -2134,18 +2145,19 @@ public class ContentSyncManager {
      * @param product product to get available repositories from
      * @param allEntries lookup map for repositories by product and root product
      * @param repoIdsWithAuth lookup list for all authenticated repositories by id
+     * @param allSUSEProdExt lookup map for all extensions
      * @return stream of available repositories of product
      */
     private Stream<SUSEProductSCCRepository> getAvailableRepositories(
         SUSEProduct root,
         SUSEProduct product,
         Map<Tuple2<SUSEProduct, SUSEProduct>, List<SUSEProductSCCRepository>> allEntries,
-        List<Long> repoIdsWithAuth
+        List<Long> repoIdsWithAuth,
+        Map<Tuple2<SUSEProduct, SUSEProduct>, List<SUSEProductExtension>> allSUSEProdExt
     ) {
-
+        Tuple2<SUSEProduct, SUSEProduct> rootProductTuple = new Tuple2<>(root, product);
         List<SUSEProductSCCRepository> entries =
-                Optional.ofNullable(allEntries.get(new Tuple2<>(root, product)))
-                        .orElseGet(Collections::emptyList);
+                allEntries.getOrDefault(rootProductTuple, Collections.emptyList());
         boolean isAccessible = entries.stream()
                 .filter(SUSEProductSCCRepository::isMandatory)
                 .allMatch(entry -> {
@@ -2167,9 +2179,12 @@ public class ContentSyncManager {
                     entries.stream().filter(e ->
                             e.isMandatory() || repoIdsWithAuth.contains(e.getRepository().getId())
                     ),
-                    SUSEProductFactory.findAllExtensionProductsForRootOf(product, root).stream()
-                            .flatMap(nextProduct ->
-                                    getAvailableRepositories(root, nextProduct, allEntries, repoIdsWithAuth))
+                    // We iterate recursively to not evaluate extensions when the parent is not accessible
+                    allSUSEProdExt.getOrDefault(rootProductTuple, new ArrayList<>())
+                            .stream()
+                            .map(SUSEProductExtension::getExtensionProduct)
+                            .flatMap(nextProduct -> getAvailableRepositories(root, nextProduct, allEntries,
+                                    repoIdsWithAuth, allSUSEProdExt))
             );
         }
         else {
@@ -2185,6 +2200,9 @@ public class ContentSyncManager {
     public List<SUSEProductSCCRepository> getAvailableChannels() {
         List<SUSEProductSCCRepository> allEntries = SUSEProductFactory.allProductRepos();
         List<Long> repoIdsWithAuth = SCCCachingFactory.lookupRepositoryIdsWithAuth();
+        Map<Tuple2<SUSEProduct, SUSEProduct>, List<SUSEProductExtension>> allSUSEProdExt =
+                SUSEProductFactory.findAllSUSEProductExtensions().stream()
+                        .collect(Collectors.groupingBy(e -> new Tuple2<>(e.getRootProduct(), e.getBaseProduct())));
 
         Map<Tuple2<SUSEProduct, SUSEProduct>, List<SUSEProductSCCRepository>> entriesByProducts = allEntries.stream()
                 .collect(Collectors.groupingBy(e -> new Tuple2<>(e.getRootProduct(), e.getProduct())));
@@ -2193,7 +2211,7 @@ public class ContentSyncManager {
                 .filter(SUSEProductSCCRepository::isRoot)
                 .map(SUSEProductSCCRepository::getProduct)
                 .distinct()
-                .flatMap(p -> getAvailableRepositories(p, p, entriesByProducts, repoIdsWithAuth))
+                .flatMap(p -> getAvailableRepositories(p, p, entriesByProducts, repoIdsWithAuth, allSUSEProdExt))
                 .collect(Collectors.toList());
     }
 
@@ -2490,9 +2508,7 @@ public class ContentSyncManager {
      */
     public static String getUUID() {
         if (uuid == null) {
-            BufferedReader reader = null;
-            try {
-                reader = new BufferedReader(new FileReader(UUID_FILE));
+            try (BufferedReader reader = new BufferedReader(new FileReader(UUID_FILE))) {
                 String line;
                 while ((line = reader.readLine()) != null) {
                     if (line.startsWith("username")) {
@@ -2501,21 +2517,11 @@ public class ContentSyncManager {
                 }
             }
             catch (FileNotFoundException e) {
-                LOG.info("Server not registered at SCC: {}", e.getMessage());
+                LOG.debug("Server not registered at SCC: {}", e.getMessage());
             }
             catch (IOException e) {
                 LOG.warn("Unable to read SCC credentials file: {}", e.getMessage());
             }
-            finally {
-                if (reader != null) {
-                    try {
-                        reader.close();
-                    }
-                    catch (IOException e) {
-                        LOG.warn("IO exception on SCC credentials file: {}", e.getMessage());
-                    }
-                }
-            }
             if (uuid == null) {
                 uuid = Config.get().getString(ConfigDefaults.SCC_BACKUP_SRV_USR);
                 if (uuid == null) {
