/** * Copyright (c) 2009 - 2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package org.candlepin.controller; import org.candlepin.model.Owner; import org.candlepin.model.Pool; import org.candlepin.model.Product; import org.candlepin.model.dto.Subscription; import org.candlepin.service.SubscriptionServiceAdapter; import org.candlepin.util.Util; import com.google.inject.persist.UnitOfWork; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; /** * Refresher */ public class Refresher { private CandlepinPoolManager poolManager; private SubscriptionServiceAdapter subAdapter; private OwnerManager ownerManager; private boolean lazy; private UnitOfWork uow; private static Logger log = LoggerFactory.getLogger(Refresher.class); private Map<String, Owner> owners = Util.newMap(); private Set<Product> products = Util.newSet(); Refresher(CandlepinPoolManager poolManager, SubscriptionServiceAdapter subAdapter, OwnerManager ownerManager, boolean lazy) { this.poolManager = poolManager; this.subAdapter = subAdapter; this.ownerManager = ownerManager; this.lazy = lazy; } public Refresher setUnitOfWork(UnitOfWork uow) { this.uow = uow; return this; } public Refresher add(Owner owner) { if (owner == null || owner.getKey() == null) { throw new IllegalArgumentException("Owner is null or lacks identifying information"); } this.owners.put(owner.getKey(), owner); return this; } /** * Add a product that has been changed to be refreshed globally. * * Will be used to lookup any subscription using the product, either as a SKU or a * provided product, and trigger a refresh for that specific subscription. * * WARNING: Should only be used in upstream production environments, downstream should * always be driven by manifest import, which should never trigger a global refresh * for other orgs. * * @param product * @return this Refresher instance */ public Refresher add(Product product) { products.add(product); return this; } public void run() { // If products were specified on the refresher, lookup any subscriptions // using them, regardless of organization, and trigger a refresh for those // specific subscriptions. Set<Subscription> subscriptions = Util.newSet(); for (Product product : products) { // TODO: This adapter call is not implemented in prod, and cannot be. We plan // to fix this whole code path in near future by looking for pools using the // given products to be refreshed. List<Subscription> subs = subAdapter.getSubscriptions(product.toDTO()); log.debug("Will refresh {} subscriptions in all orgs using product: ", subs.size(), product.getId()); if (log.isDebugEnabled()) { for (Subscription s : subs) { Owner so = s.getOwner(); if (so == null || so.getKey() == null) { log.debug(" Received a subscription without a well-defined owner: {}", s.getId()); continue; } if (!this.owners.containsKey(so.getKey())) { log.debug(" {}", s); } } } subscriptions.addAll(subs); } for (Subscription subscription : subscriptions) { // drop any subs for owners in our owners list. we'll get them with the full // refreshPools call. Owner so = subscription.getOwner(); // This probably shouldn't ever happen, but let's make sure it doesn't anyway. if (so == null || so.getKey() == null) { log.error("Received a subscription without a well-defined owner: {}", subscription.getId()); continue; } if (this.owners.containsKey(so.getKey())) { log.debug("Skipping subscription \"{}\" for owner: {}", subscription.getId(), so); continue; } /* * on the off chance that this is actually a new subscription, make * the required pools. this shouldn't happen; we should really get a * refresh pools by owner call for it, but why not handle it, just * in case! * * Regenerate certificates here, that way if it fails, the whole * thing rolls back. We don't want to refresh without marking ents * dirty, they will never get regenerated */ Pool masterPool = poolManager.convertToMasterPool(subscription); poolManager.refreshPoolsForMasterPool(masterPool, true, lazy, Collections.<String, Product>emptyMap()); } for (Owner owner : this.owners.values()) { poolManager.refreshPoolsWithRegeneration(subAdapter, owner, lazy); poolManager.recalculatePoolQuantitiesForOwner(owner); ownerManager.refreshOwnerForContentAccess(owner); } } }