/**
* 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 com.google.common.collect.Iterables;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import org.hibernate.Session;
import org.hibernate.SQLQuery;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/**
* ContentCurator
*/
public class ContentCurator extends AbstractHibernateCurator<Content> {
private static Logger log = LoggerFactory.getLogger(ContentCurator.class);
private ProductCurator productCurator;
@Inject
public ContentCurator(ProductCurator productCurator) {
super(Content.class);
this.productCurator = productCurator;
}
// Needs an override due to the use of UUID as db identifier.
@Override
@Transactional
public void delete(Content entity) {
Content toDelete = find(entity.getUuid());
currentSession().delete(toDelete);
}
/**
* Retrieves a Content instance for the specified content UUID. If no matching content could be
* be found, this method returns null.
*
* @param uuid
* The UUID of the content to retrieve
*
* @return
* the Content instance for the content with the specified UUID or null if no matching content
* was found.
*/
@Transactional
public Content lookupByUuid(String uuid) {
return (Content) currentSession().createCriteria(Content.class).setCacheable(true)
.add(Restrictions.eq("uuid", uuid)).uniqueResult();
}
/**
* Fetches a collection of content used by the given products
*
* @param products
* The products for which to fetch content
*
* @return
* A collection of content used by the specified products
*/
@SuppressWarnings("unchecked")
public CandlepinQuery<Content> getContentByProducts(Collection<Product> products) {
Collection<String> uuids = new HashSet<String>();
for (Product product : products) {
uuids.add(product.getUuid());
}
return this.getContentByProductUuids(uuids);
}
/**
* Fetches a collection of content used by the given products
*
* @param productUuids
* A collection of UUIDs representing the products for which to fetch content
*
* @return
* A collection of content used by the specified products
*/
@SuppressWarnings("unchecked")
public CandlepinQuery<Content> getContentByProductUuids(Collection<String> productUuids) {
if (productUuids != null && !productUuids.isEmpty()) {
// We're doing this in two queries because (a) that's what Hibernate's doing already due
// to the projection and (b) DISTINCT_ROOT_ENTITY only works when listing, not when
// scrolling.
Session session = this.currentSession();
// For reasons I can only speculate, Hibernate literally refuses* to run this query
// when built with HQL or Criteria, so we're doing it in straight SQL.
// * By refuses, I mean silently returns an empty list without ever actually hitting
// the database.
Collection<String> uuids = new HashSet<String>();
// Make sure we don't hit the parameter limit when building queries...
Iterable<List<String>> uuidBlocks = Iterables.partition(productUuids, getQueryParameterLimit());
for (List<String> uuidBlock : uuidBlocks) {
StringBuilder builder = new StringBuilder("SELECT DISTINCT content_uuid FROM ")
.append(ProductContent.DB_TABLE)
.append(" WHERE (");
int blockCount = (int) Math.ceil(uuidBlock.size() / (float) getInBlockSize());
for (int i = 0; i < blockCount;) {
if (i != 0) {
builder.append(" OR ");
}
builder.append("product_uuid IN (?").append(++i).append(')');
}
builder.append(')');
log.debug("getContentByProductUuids query: {}", builder);
SQLQuery query = session.createSQLQuery(builder.toString());
int param = 0;
Iterable<List<String>> blocks = Iterables.partition(uuidBlock, getInBlockSize());
for (List<String> block : blocks) {
query.setParameterList(String.valueOf(++param), block);
}
// Add the uuids to our ever-growing collection
uuids.addAll(query.list());
}
if (uuids != null && !uuids.isEmpty()) {
DetachedCriteria criteria = this.createSecureDetachedCriteria()
.add(CPRestrictions.in("uuid", uuids));
return this.cpQueryFactory.<Content>buildQuery(session, criteria);
}
}
return this.cpQueryFactory.<Content>buildQuery();
}
}