Package org.candlepin.model

Source Code of org.candlepin.model.PoolCurator

/**
* 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.model;

import org.candlepin.model.activationkeys.ActivationKey;
import org.candlepin.model.activationkeys.ActivationKeyPool;
import org.candlepin.paging.Page;
import org.candlepin.paging.PageRequest;
import org.candlepin.policy.criteria.CriteriaRules;
import org.candlepin.policy.js.ProductCache;

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.persist.Transactional;

import org.hibernate.Criteria;
import org.hibernate.Filter;
import org.hibernate.LockOptions;
import org.hibernate.Query;
import org.hibernate.ReplicationMode;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.internal.FilterImpl;
import org.hibernate.sql.JoinType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

/**
* EntitlementPoolCurator
*/
public class PoolCurator extends AbstractHibernateCurator<Pool> {

    private static Logger log = LoggerFactory.getLogger(PoolCurator.class);
    private CriteriaRules poolCriteria;
    @Inject
    protected Injector injector;

    @Inject
    protected ProductCache productCache;

    @Inject
    protected PoolCurator(CriteriaRules poolCriteria) {
        super(Pool.class);
        this.poolCriteria = poolCriteria;
    }

    @Override
    @Transactional
    public Pool find(Serializable id) {
        Pool pool = super.find(id);
        return pool;
    }

    @Override
    @Transactional
    public List<Pool> listAll() {
        List<Pool> pools = super.listAll();
        return pools;
    }

    /**
     * Returns list of pools owned by the given Owner.
     * @param o Owner to filter
     * @return pools owned by the given Owner.
     */
    @Transactional
    public List<Pool> listByOwner(Owner o) {
        return listByOwner(o, null);
    }

    /**
     * Returns list of pools owned by the given Owner.
     * @param o Owner to filter
     * @param activeOn only include pools active on the given date.
     * @return pools owned by the given Owner.
     */
    @Transactional
    public List<Pool> listByOwner(Owner o, Date activeOn) {
        return listAvailableEntitlementPools(null, o, null, activeOn, true);
    }

    /**
     * Return all pools referencing the given entitlement as their source entitlement.
     *
     * @param e Entitlement
     * @return Pools created as a result of this entitlement.
     */
    public List<Pool> listBySourceEntitlement(Entitlement e) {
        List<Pool> results = createSecureCriteria()
            .add(Restrictions.eq("sourceEntitlement", e)).list();
        if (results == null) {
            results = new LinkedList<Pool>();
        }
        return results;
    }

    /**
     * Returns list of pools available to the consumer.
     *
     * @param c Consumer to filter
     * @return pools available to the consumer.
     */
    @Transactional
    public List<Pool> listByConsumer(Consumer c) {
        return listAvailableEntitlementPools(c, c.getOwner(), (String) null, null,
            true);
    }

    /**
     * List all entitlement pools for the given owner and product.
     *
     * @param owner owner of the entitlement pool
     * @param productId product filter.
     * @return list of EntitlementPools
     */
    @Transactional
    public List<Pool> listByOwnerAndProduct(Owner owner,
            String productId) {
        return listAvailableEntitlementPools(null, owner, productId, null, false);
    }

    @SuppressWarnings("unchecked")
    public List<Pool> listExpiredPools() {
        Date today = new Date();
        Criteria crit = createSecureCriteria().add(
            Restrictions.lt("endDate", today));
        List<Pool> results = crit.list();
        if (results == null) {
            results = new LinkedList<Pool>();
        }
        return results;
    }

    @SuppressWarnings("unchecked")
    @Transactional
    public List<Pool> listAvailableEntitlementPools(Consumer c, Owner o,
            String productId, Date activeOn, boolean activeOnly) {
        return listAvailableEntitlementPools(c, o, productId, activeOn, activeOnly,
            new PoolFilterBuilder(), null, false).getPageData();
    }

    /**
     * List entitlement pools.
     *
     * Pools will be refreshed from the underlying subscription service.
     *
     * @param c Consumer being entitled.
     * @param o Owner whose subscriptions should be inspected.
     * @param productId only entitlements which provide this product are included.
     * @param activeOn Indicates to return only pools valid on this date.
     *        Set to null for no date filtering.
     * @param activeOnly if true, only active entitlements are included.
     * @param filters filter builder with set filters to apply to the criteria.
     * @param pageRequest used to specify paging criteria.
     * @param postFilter if you plan on filtering the list in java
     * @return List of entitlement pools.
     */
    @SuppressWarnings("unchecked")
    @Transactional
    public Page<List<Pool>> listAvailableEntitlementPools(Consumer c, Owner o,
            String productId, Date activeOn, boolean activeOnly, PoolFilterBuilder filters,
            PageRequest pageRequest, boolean postFilter) {
        if (o == null && c != null) {
            o = c.getOwner();
        }

        if (log.isDebugEnabled()) {
            log.debug("Listing available pools for:");
            log.debug("   consumer: " + c);
            log.debug("   owner: " + o);
            log.debug("   product: " + productId);
        }

        Criteria crit = createSecureCriteria();
        if (activeOnly) {
            crit.add(Restrictions.eq("activeSubscription", Boolean.TRUE));
        }
        if (c != null) {
            crit.add(Restrictions.eq("owner", c.getOwner()));

            // Ask the rules for any business logic criteria to filter with for
            // this consumer
            List<Criterion> filterCriteria = poolCriteria.availableEntitlementCriteria(
                c);

            if (log.isDebugEnabled()) {
                log.debug("Got " + filterCriteria.size() +
                    "  query filters from database.");
            }

            for (Criterion rulesCriteria : filterCriteria) {
                crit.add(rulesCriteria);
            }
        }
        if (o != null) {
            crit.add(Restrictions.eq("owner", o));
            crit.add(Restrictions.ne("productName", Product.ueberProductNameForOwner(o)));
        }
        if (activeOn != null) {
            crit.add(Restrictions.le("startDate", activeOn));
            crit.add(Restrictions.ge("endDate", activeOn));
        }

        if (productId != null) {
            crit.createAlias("providedProducts", "providedProduct",
                CriteriaSpecification.LEFT_JOIN);

            crit.add(Restrictions.or(Restrictions.eq("productId", productId),
                Restrictions.eq("providedProduct.productId", productId)));
        }

        // Append any specified filters
        if (filters != null) {
            filters.applyTo(crit);
        }

        return listByCriteria(crit, pageRequest, postFilter);
    }

    @Transactional
    public List<Pool> listPoolsRestrictedToUser(String username) {
        return listByCriteria(
            currentSession().createCriteria(Pool.class)
                .add(Restrictions.eq("restrictedToUsername", username)));
    }

    @Transactional
    public Pool findUeberPool(Owner o) {
        return (Pool) createSecureCriteria()
            .add(Restrictions.eq("owner", o))
            .add(Restrictions.eq("productName", Product.ueberProductNameForOwner(o)))
            .uniqueResult();
    }

    @SuppressWarnings("unchecked")
    public List<Entitlement> retrieveFreeEntitlementsOfPool(Pool existingPool,
        boolean lifo) {
        return criteriaToSelectEntitlementForPool(existingPool)
            .addOrder(lifo ? Order.desc("created") : Order.asc("created"))
            .list();
    }

    @SuppressWarnings("unchecked")
    public List<String> retrieveFreeEntitlementIdsOfPool(Pool existingPool,
        boolean lifo) {
        return criteriaToSelectEntitlementForPool(existingPool)
            .addOrder(lifo ? Order.desc("created") : Order.asc("created"))
            .setProjection(Projections.id())
            .list();
    }

    public void deactivatePool(Pool pool) {
        if (log.isDebugEnabled()) {
            log.info("Subscription disappeared for pool: " + pool);
        }
        pool.setActiveSubscription(Boolean.FALSE);
        merge(pool);
    }

    private Criteria criteriaToSelectEntitlementForPool(Pool entitlementPool) {
        return this.currentSession().createCriteria(Entitlement.class)
            .add(Restrictions.eq("pool", entitlementPool));
    }

    /**
     * @param entitlementPool entitlement pool to search.
     * @return entitlements in the given pool.
     */
    @Transactional
    @SuppressWarnings("unchecked")
    public List<Entitlement> entitlementsIn(Pool entitlementPool) {
        return criteriaToSelectEntitlementForPool(entitlementPool).list();
    }

    /**
     * @param subId Subscription to look up pools by
     * @return pools from the given subscription, sorted by pool.id to avoid deadlocks
     */
    @SuppressWarnings("unchecked")
    public List<Pool> lookupBySubscriptionId(String subId) {
        return createSecureCriteria()
            .createAlias("sourceSubscription", "sourceSub")
            .add(Restrictions.eq("sourceSub.subscriptionId", subId))
            .addOrder(Order.asc("id")).list();
    }

    /**
     * Attempts to find pools which are over subscribed after the creation or modification
     * of the given entitlement.
     *
     * To do this we search for only the pools related to the subscription ID which
     * could have changed, the two cases where this can happen are:
     *
     * 1. Bonus pool (not derived from any entitlement) after a bind. (in cases such as
     * exporting to downstream)
     * 2. A derived pool whose source entitlement just had it's quantity reduced.
     *
     * This has to be done carefully to avoid potential performance problems with
     * virt_bonus on-site subscriptions where one pool is created per physical
     * entitlement.
     *
     * @param subId Subscription ID of the pool.
     * @param ent Entitlement just created or modified.
     * @return Pools with too many entitlements for their new quantity.
     */
    @SuppressWarnings("unchecked")
    public List<Pool> lookupOversubscribedBySubscriptionId(String subId, Entitlement ent) {
        return currentSession().createCriteria(Pool.class)
            .createAlias("sourceSubscription", "sourceSub")
            .add(Restrictions.eq("sourceSub.subscriptionId", subId))
            .add(Restrictions.ge("quantity", 0L))
            .add(Restrictions.gtProperty("consumed", "quantity"))
            .add(Restrictions.or(
                Restrictions.isNull("sourceEntitlement"),
                Restrictions.eqOrIsNull("sourceEntitlement", ent)))
            .list();
    }

    @Transactional
    public Pool replicate(Pool pool) {
        for (ProvidedProduct pp : pool.getProvidedProducts()) {
            pp.setPool(pool);
        }

        for (DerivedProvidedProduct dpp : pool.getDerivedProvidedProducts()) {
            dpp.setPool(pool);
        }

        for (PoolAttribute pa : pool.getAttributes()) {
            pa.setPool(pool);
        }

        for (ProductPoolAttribute ppa : pool.getProductAttributes()) {
            ppa.setPool(pool);
        }

        for (DerivedProductPoolAttribute dppa : pool.getDerivedProductAttributes()) {
            dppa.setPool(pool);
        }

        // Looks like this is restored in MigrateOwnerJob.replicateEntitlements:
        pool.setSourceEntitlement(null);

        this.currentSession().replicate(pool, ReplicationMode.EXCEPTION);

        return pool;
    }

    @Transactional
    public Pool create(Pool entity) {

        /* Ensure all referenced PoolAttributes are correctly pointing to
         * this pool. This is useful for pools being created from
         * incoming json.
         */
        for (PoolAttribute attr : entity.getAttributes()) {
            attr.setPool(entity);
        }

        return super.create(entity);
    }

    private static final String CONSUMER_FILTER = "Entitlement_CONSUMER_FILTER";

    public int getNoOfDependentEntitlements(String entitlementId) {
        Filter consumerFilter = disableConsumerFilter();
        Integer result = (Integer)
            currentSession().createCriteria(Entitlement.class)
                .setProjection(Projections.rowCount())
                .createCriteria("pool")
                    .createCriteria("sourceEntitlement")
                        .add(Restrictions.idEq(entitlementId))
                .list().get(0);
        enableIfPrevEnabled(consumerFilter);
        return result;
    }

    // TODO: watch out for performance. Should we limit the certificates
    // retrieved?
    @SuppressWarnings("unchecked")
    public List<EntitlementCertificate> retrieveEntCertsOfPoolsWithSourceEntitlement(
        String entId) {
        return
            currentSession().createCriteria(EntitlementCertificate.class)
            .createCriteria("entitlement")
                .createCriteria("pool")
                    .createCriteria("sourceEntitlement").add(Restrictions.idEq(entId))
            .list();
    }


    /**
     * @param session
     * @param consumerFilter
     */
    private void enableIfPrevEnabled(Filter consumerFilter) {
        // if filter was previously enabled, restore it.
        if (consumerFilter != null) {
            FilterImpl filterImpl = (FilterImpl) consumerFilter;
            Filter filter = currentSession().enableFilter(CONSUMER_FILTER);
            filter.setParameter("consumer_id", filterImpl.getParameter("consumer_id"));
        }
    }

    public Filter disableConsumerFilter() {
        Filter consumerFilter = currentSession().getEnabledFilter(CONSUMER_FILTER);
        currentSession().disableFilter(CONSUMER_FILTER);
        return consumerFilter;
    }

    public Pool lockAndLoad(Pool pool) {
        currentSession().refresh(pool, LockOptions.UPGRADE);
        getEntityManager().refresh(pool);
        return pool;
    }

    public List<ActivationKey> getActivationKeysForPool(Pool p) {
        List<ActivationKey> activationKeys = new ArrayList<ActivationKey>();
        List<ActivationKeyPool> activationKeyPools = currentSession().createCriteria(
            ActivationKeyPool.class).add(Restrictions.eq("pool", p)).list();

        for (ActivationKeyPool akp : activationKeyPools) {
            activationKeys.add(akp.getKey());
        }

        return activationKeys;
    }

    /**
     * Method to compile service/support level lists. One is the available levels for
     *  consumers for this owner. The second is the level names that are exempt. Exempt
     *  means that a product pool with this level can be used with a consumer of any
     *  service level.
     *
     * @param owner The owner that has the list of available service levels for
     *              its consumers
     * @param exempt boolean to show if the desired list is the levels that are
     *               explicitly marked with the support_level_exempt attribute.
     * @return Set of levels based on exempt flag.
     */
    public Set<String> retrieveServiceLevelsForOwner(Owner owner, boolean exempt) {
        String stmt = "select distinct a.name, a.value, a.productId " +
                        "from ProductPoolAttribute as a " +
                        "inner join a.pool as p " +
                        "where p.owner.id = :owner_id and " +
                        "(a.name = 'support_level' or a.name='support_level_exempt') " +
                        "order by a.name DESC";

        Query q = currentSession().createQuery(stmt);
        q.setParameter("owner_id", owner.getId());
        List<Object[]> results = q.list();

        // Use case insensitive comparison here, since we treat
        // Premium the same as PREMIUM or premium, to make it easier for users to specify
        // a level on the CLI. However, use the original case, since Premium is more
        // attractive than PREMIUM.
        Set<String> slaSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
        Set<String> exemptSlaSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);

        Set<String> exemptProductIds = new HashSet<String>();

        for (Object[] result : results) {
            String name = (String) result[0];
            String value = (String) result[1];
            String productId = (String) result[2];

            if ("support_level_exempt".equals(name) && "true".equalsIgnoreCase(value)) {
                exemptProductIds.add(productId);
            }
            else if ("support_level".equalsIgnoreCase(name) &&
                (value != null && !value.trim().equals("")) &&
                exemptProductIds.contains(productId)) {

                exemptSlaSet.add(value);
            }
        }

        for (Object[] result : results) {
            String name = (String) result[0];
            String value = (String) result[1];

            if (!"support_level_exempt".equals(name) && !exemptSlaSet.contains(value)) {
                slaSet.add(value);
            }
        }

        if (exempt) {
            return exemptSlaSet;
        }
        return slaSet;
    }

    /**
     * There is an issue with attributes in the database. Duplicate attribute
     *  name/value pairs were showing up from outside the Candlepin code.
     *  Only one was getting pulled into the HashSet and the other ignored.
     *  Uses explicit lookup and deletion instead of the Hibernate cascade which
     *  relies on the data structure in memory.
     *
     * @param entity pool to be deleted.
     */
    @Transactional
    public void delete(Pool entity) {
        Pool toDelete = find(entity.getId());
        if (toDelete != null) {
            currentSession().delete(toDelete);
            this.flush();
        }
        else {
            log.info("Pool " + entity.getId() + " not found. Skipping deletion. noop");
        }
    }

    /**
     * @param consumer
     * @param stackId
     * @return Number of derived pools which exist for the given consumer and stack
     */
    public Pool getSubPoolForStackId(Consumer consumer, String stackId) {
        Criteria getCount = createSecureCriteria()
            .createAlias("sourceStack", "ss")
            .add(Restrictions.eq("ss.sourceConsumer", consumer))
            .add(Restrictions.and(Restrictions.isNotNull("ss.sourceStackId"),
                                  Restrictions.eq("ss.sourceStackId", stackId)));
        return (Pool) getCount.uniqueResult();
    }

    @SuppressWarnings("unchecked")
    public List<Pool> getOwnerSubPoolsForStackId(Owner owner, String stackId) {
        return createSecureCriteria()
            .createAlias("sourceStack", "ss")
            .add(Restrictions.eq("ss.sourceStackId", stackId))
            .add(Restrictions.eq("owner", owner))
            .list();
    }

    // Get rid of pools from subs that don't exist
    @SuppressWarnings("unchecked")
    public List<Pool> getPoolsFromBadSubs(Owner owner, Collection<String> subIds) {
        Criteria crit = currentSession().createCriteria(Pool.class)
                .add(Restrictions.eq("owner", owner));
        if (!subIds.isEmpty()) {
            crit.createAlias("sourceSubscription", "sourceSub");
            crit.add(Restrictions.and(Restrictions.not(Restrictions.in("sourceSub.subscriptionId", subIds)),
                    Restrictions.isNotNull("sourceSub.subscriptionId")));
        }
        crit.addOrder(Order.asc("id"));
        return crit.list();
    }

    @SuppressWarnings("unchecked")
    public List<Pool> getPoolsBySubscriptionId(String subId) {
        return currentSession().createCriteria(Pool.class)
            .createAlias("sourceSubscription", "sourceSub",
                    JoinType.LEFT_OUTER_JOIN)
            .add(Restrictions.eq("sourceSub.subscriptionId", subId))
            .addOrder(Order.asc("id"))
            .list();
    }

    @SuppressWarnings("unchecked")
    public List<Pool> getOwnersFloatingPools(Owner owner) {
        return currentSession().createCriteria(Pool.class)
                .add(Restrictions.eq("owner", owner))
                .createAlias("sourceSubscription", "sourceSub",
                    JoinType.LEFT_OUTER_JOIN)
                .add(Restrictions.isNull("sourceSub.subscriptionId"))
                .addOrder(Order.asc("id"))
                .list();
    }
}
TOP

Related Classes of org.candlepin.model.PoolCurator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.