Java tutorial
/** * 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.paging.Page; import org.candlepin.paging.PageRequest; import org.candlepin.service.ProductServiceAdapter; import com.google.inject.Inject; import com.google.inject.persist.Transactional; import org.hibernate.Criteria; import org.hibernate.ReplicationMode; import org.hibernate.criterion.CriteriaSpecification; import org.hibernate.criterion.Order; import org.hibernate.criterion.Restrictions; import org.hibernate.sql.JoinType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * EntitlementCurator */ public class EntitlementCurator extends AbstractHibernateCurator<Entitlement> { private static Logger log = LoggerFactory.getLogger(EntitlementCurator.class); private ProductServiceAdapter productAdapter; /** * default ctor */ @Inject public EntitlementCurator(ProductServiceAdapter productAdapter) { super(Entitlement.class); this.productAdapter = productAdapter; } // TODO: handles addition of new entitlements only atm! /** * @param entitlements entitlements to update * @return updated entitlements. */ @Transactional public Set<Entitlement> bulkUpdate(Set<Entitlement> entitlements) { Set<Entitlement> toReturn = new HashSet<Entitlement>(); for (Entitlement toUpdate : entitlements) { Entitlement found = find(toUpdate.getId()); if (found != null) { toReturn.add(found); continue; } toReturn.add(create(toUpdate)); } return toReturn; } public Page<List<Entitlement>> listByConsumer(Consumer consumer, PageRequest pageRequest) { Criteria query = createSecureCriteria().createAlias("pool", "p").add(Restrictions.eq("consumer", consumer)) // Never show a consumer expired entitlements .add(Restrictions.ge("p.endDate", new Date())); return listByCriteria(query, pageRequest); } /** * This must return a sorted list in order to avoid deadlocks * * @param consumer * @return list of entitlements belonging to the consumer, ordered by pool id */ @SuppressWarnings("unchecked") public List<Entitlement> listByConsumer(Consumer consumer) { return createSecureCriteria().createAlias("pool", "p").add(Restrictions.eq("consumer", consumer)) // Never show a consumer expired entitlements .add(Restrictions.ge("p.endDate", new Date())).addOrder(Order.asc("p.id")).list(); } public List<Entitlement> listByEnvironment(Environment environment) { Criteria criteria = currentSession().createCriteria(Entitlement.class).createCriteria("consumer") .add(Restrictions.eq("environment", environment)); return criteria.list(); } /** * List entitlements for a consumer which are valid for a specific date. * * @param consumer Consumer to list entitlements for. * @param activeOn The date we want to see entitlements which are active on. * @return List of entitlements. */ public List<Entitlement> listByConsumerAndDate(Consumer consumer, Date activeOn) { /* * Essentially the opposite of the above query which searches for entitlement * overlap with a "modifying" entitlement being granted. This query is used to * search for modifying entitlements which overlap with a regular entitlement * being granted. As such the logic is basically reversed. * */ Criteria criteria = currentSession().createCriteria(Entitlement.class) .add(Restrictions.eq("consumer", consumer)).createCriteria("pool") .add(Restrictions.le("startDate", activeOn)).add(Restrictions.ge("endDate", activeOn)); List<Entitlement> entitlements = criteria.list(); return entitlements; } public List<Entitlement> listByOwner(Owner owner) { Criteria query = currentSession().createCriteria(Entitlement.class).add(Restrictions.eq("owner", owner)); return listByCriteria(query); } /* * Creates date filtering criteria to for checking if an entitlement has any overlap * with a "modifying" entitlement that has just been granted. */ private Criteria createModifiesDateFilteringCriteria(Consumer consumer, Date startDate, Date endDate) { Criteria criteria = currentSession().createCriteria(Entitlement.class) .add(Restrictions.eq("consumer", consumer)).createCriteria("pool").add(Restrictions.or( // Dates overlap if the start or end date is in our range Restrictions.or(Restrictions.between("startDate", startDate, endDate), Restrictions.between("endDate", startDate, endDate)), Restrictions.and( // The dates overlap if our range is completely encapsulated Restrictions.le("startDate", startDate), Restrictions.ge("endDate", endDate)))); return criteria; } /** * List all entitlements for the given consumer which provide the given product ID, * and overlap at least partially with the given start and end dates. * * i.e. given start date must be within the entitlements start/end dates, or * the given end date must be within the entitlements start/end dates, * or the given start date must be before the entitlement *and* the given end date * must be after entitlement. (i.e. we are looking for *any* overlap) * * @param consumer Consumer whose entitlements we're checking. * @param productId Find entitlements providing this productId. * @param startDate Find entitlements * @param endDate * @return list of entitlements providing the given product */ public Set<Entitlement> listProviding(Consumer consumer, String productId, Date startDate, Date endDate) { // Will re-use this criteria for both queries we need to do: // Find direct matches on the pool's product ID: Criteria parentProductCrit = createModifiesDateFilteringCriteria(consumer, startDate, endDate) .add(Restrictions.eq("productId", productId)); // Using a set to prevent duplicate matches, if somehow Set<Entitlement> finalResults = new HashSet<Entitlement>(); finalResults.addAll(parentProductCrit.list()); Criteria providedCrit = createModifiesDateFilteringCriteria(consumer, startDate, endDate) .createCriteria("providedProducts").add(Restrictions.eq("productId", productId)); finalResults.addAll(providedCrit.list()); return finalResults; } public Set<Entitlement> listModifying(Entitlement entitlement) { Set<Entitlement> modifying = new HashSet<Entitlement>(); // Get the map of product Ids to the set of // overlapping entitlements that provide them Map<String, Set<Entitlement>> pidEnts = getOverlappingForModifying(entitlement); if (pidEnts.isEmpty()) { // Empty collections break hibernate queries return modifying; } // Retrieve all products at once from the adapter List<Product> products = productAdapter.getProductsByIds(pidEnts.keySet()); for (Product p : products) { boolean modifies = p.modifies(entitlement.getProductId()); Iterator<ProvidedProduct> ppit = entitlement.getPool().getProvidedProducts().iterator(); // No need to continue checking once we have found a modified product while (!modifies && ppit.hasNext()) { modifies = modifies || p.modifies(ppit.next().getProductId()); } if (modifies) { // Return all entitlements for the modified product modifying.addAll(pidEnts.get(p.getId())); } } return modifying; } /* * Add a productId to entitlement mapping, creating the collection if necessary */ private void addProductIdToMap(Map<String, Set<Entitlement>> map, String pid, Entitlement e) { if (!map.containsKey(pid)) { map.put(pid, new HashSet<Entitlement>()); } map.get(pid).add(e); } /* * Add an entitlement to the productId Entitlement map, using the entitlements * productId as well as those if its provided products. */ private void addToMap(Map<String, Set<Entitlement>> map, Entitlement e) { addProductIdToMap(map, e.getProductId(), e); for (ProvidedProduct pp : e.getPool().getProvidedProducts()) { addProductIdToMap(map, pp.getProductId(), e); } } @SuppressWarnings("unchecked") public Map<String, Set<Entitlement>> getOverlappingForModifying(Entitlement e) { List<Entitlement> overlapEnts = createModifiesDateFilteringCriteria(e.getConsumer(), e.getStartDate(), e.getEndDate()).list(); Map<String, Set<Entitlement>> pidEnts = new HashMap<String, Set<Entitlement>>(); for (Entitlement ent : overlapEnts) { addToMap(pidEnts, ent); } return pidEnts; } @Transactional public Page<List<Entitlement>> listByConsumerAndProduct(Consumer consumer, String productId, PageRequest pageRequest) { Criteria query = createSecureCriteria().add(Restrictions.eq("consumer", consumer)).createAlias("pool", "p") .createAlias("p.providedProducts", "pp", CriteriaSpecification.LEFT_JOIN) // Never show a consumer expired entitlements .add(Restrictions.ge("p.endDate", new Date())).add(Restrictions .or(Restrictions.eq("p.productId", productId), Restrictions.eq("pp.productId", productId))); Page<List<Entitlement>> page = listByCriteria(query, pageRequest); return page; } @Transactional public void delete(Entitlement entity) { Entitlement toDelete = find(entity.getId()); log.debug("Deleting entitlement: " + toDelete); log.debug("certs.size = " + toDelete.getCertificates().size()); for (EntitlementCertificate cert : toDelete.getCertificates()) { currentSession().delete(cert); } currentSession().delete(toDelete); } @Transactional public Entitlement findByCertificateSerial(Long serial) { return (Entitlement) currentSession().createCriteria(Entitlement.class).createCriteria("certificates") .add(Restrictions.eq("serial.id", serial)).uniqueResult(); } @Transactional public Entitlement replicate(Entitlement ent) { for (EntitlementCertificate ec : ent.getCertificates()) { ec.setEntitlement(ent); CertificateSerial cs = ec.getSerial(); if (cs != null) { this.currentSession().replicate(cs, ReplicationMode.EXCEPTION); } } this.currentSession().replicate(ent, ReplicationMode.EXCEPTION); return ent; } /** * Find the entitlements for the given consumer that are part of the specified stack. * * @param consumer the consumer * @param stackId the ID of the stack * @return the list of entitlements for the consumer that are in the stack. */ @SuppressWarnings("unchecked") public List<Entitlement> findByStackId(Consumer consumer, String stackId) { Criteria activeNowQuery = currentSession().createCriteria(Entitlement.class) .add(Restrictions.eq("consumer", consumer)).createAlias("pool", "ent_pool") .createAlias("ent_pool.productAttributes", "attrs") .add(Restrictions.eq("attrs.name", "stacking_id")).add(Restrictions.eq("attrs.value", stackId)) .add(Restrictions.isNull("ent_pool.sourceEntitlement")) .createAlias("ent_pool.sourceStack", "ss", JoinType.LEFT_OUTER_JOIN) .add(Restrictions.isNull("ss.id")); return activeNowQuery.list(); } /** * For a given stack, find the eldest active entitlement with a subscription ID. * This is used to look up the upstream subscription certificate to use to talk to * the CDN. * * @param consumer the consumer * @param stackId the ID of the stack * @return the eldest active entitlement with a subscription ID, or null if none can * be found. */ public Entitlement findUpstreamEntitlementForStack(Consumer consumer, String stackId) { Date currentDate = new Date(); Criteria activeNowQuery = currentSession().createCriteria(Entitlement.class) .add(Restrictions.eq("consumer", consumer)).createAlias("pool", "ent_pool") .createAlias("ent_pool.productAttributes", "attrs") .add(Restrictions.le("ent_pool.startDate", currentDate)) .add(Restrictions.ge("ent_pool.endDate", currentDate)) .add(Restrictions.eq("attrs.name", "stacking_id")).add(Restrictions.eq("attrs.value", stackId)) .add(Restrictions.isNull("ent_pool.sourceEntitlement")) .createAlias("ent_pool.sourceSubscription", "sourceSub").add(Restrictions.isNotNull("sourceSub.id")) .addOrder(Order.asc("created")) // eldest entitlement .setMaxResults(1); return (Entitlement) activeNowQuery.uniqueResult(); } }