/**
* 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.policy.js.compliance.hash;
import org.candlepin.model.Consumer;
import org.candlepin.model.ConsumerInstalledProduct;
import org.candlepin.model.Entitlement;
import org.candlepin.model.Pool;
import org.candlepin.policy.js.compliance.ComplianceReason;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
/**
* A collection of classes and methods that can be used to generate a
* hashable {@link String} from an object.
*/
public class HashableStringGenerators {
public static final StringGenerator STRING = new StringGenerator();
public static final StringEntryGenerator STRING_ENTRY = new StringEntryGenerator();
public static final EntitlementSetEntryGenerator ENTITLEMENT_SET_ENTRY =
new EntitlementSetEntryGenerator();
public static final EntitlementGenerator ENTITLEMENT = new EntitlementGenerator();
public static final PoolGenerator POOL = new PoolGenerator();
public static final ComplianceReasonGenerator COMPLIANCE_REASON = new ComplianceReasonGenerator();
public static final ConsumerGenerator CONSUMER = new ConsumerGenerator();
public static final ConsumerInstalledProductGenerator INSTALLED_PRODUCT =
new ConsumerInstalledProductGenerator();
private HashableStringGenerators() {
}
/**
* Generates a string from a collection of type T to be included in a hash.
* Once each object's string has been generated by the specified generator,
* the results are sorted so that we are guaranteed the same order when
* the hash is created.
*
* @param target the collection to generate the string for.
* @param generator a generator capable of generating a string from T
* @return the generated string
*/
public static <T extends Object> String generateFromCollection(
Collection<T> target, HashableStringGenerator<T> generator) {
// Just append null if the collection was null.
if (target == null) {
return null;
}
StringBuilder builder = new StringBuilder();
// TODO Is there a better way to do this without having to iterate twice?
List<String> generated = new LinkedList<String>();
for (T item : target) {
generated.add(generator.generate(item));
}
// Must sort our strings so that they are in the same order when hashed.
Collections.sort(generated);
for (String toAdd : generated) {
builder.append(toAdd);
}
return builder.toString();
}
/**
* Generate a string for a given object that is intended to be used in a hash.
* @param target the target object
* @param generator a generator capable of generating a string from the target object
* @return the generated string
*/
public static <T extends Object> String generateFromObject(T target,
HashableStringGenerator<T> generator) {
return generator.generate(target);
}
/**
* String generator will generate a {@link String} from a {@link String}.
* This generator just returns the string as is, and is intended for use
* when generating a collection of strings.
*/
private static class StringGenerator implements HashableStringGenerator<String> {
@Override
public String generate(String target) {
return target;
}
}
/**
* Generates a string from an {@link Entry} of String to collection of {@link Entitlement}s into
* intended for use in a hash.
*
*/
private static class EntitlementSetEntryGenerator implements
HashableStringGenerator<Entry<String, Set<Entitlement>>> {
@Override
public String generate(Entry<String, Set<Entitlement>> target) {
if (target == null) {
return null;
}
String allEnts = generateFromCollection(target.getValue(), ENTITLEMENT);
return target.getKey() + allEnts;
}
}
/**
* Generates a string from an {@link Entitlement} intended for use in a hash.
*/
private static class EntitlementGenerator implements HashableStringGenerator<Entitlement> {
@Override
public String generate(Entitlement target) {
if (target == null) {
return null;
}
String generated = target.getId() + target.getQuantity();
generated += generateFromObject(target.getPool(), POOL);
return generated;
}
}
private static class PoolGenerator implements HashableStringGenerator<Pool> {
@Override
public String generate(Pool target) {
if (target == null) {
return null;
}
return target.getId() + getTime(target.getUpdated());
}
/**
* Safely get time from a date. If the specified date is null, return null;
*
* @param date the target date
* @return time as long, or null if the specified date is null;
*/
private Long getTime(Date date) {
return date == null ? null : date.getTime();
}
}
/**
* Generates a string from a {@link ComplianceReason} intended for use in a hash.
*/
private static class ComplianceReasonGenerator implements HashableStringGenerator<ComplianceReason> {
@Override
public String generate(ComplianceReason target) {
if (target == null) {
return null;
}
String generated = target.getKey();
generated += generateFromCollection(target.getAttributes().entrySet(), STRING_ENTRY);
return generated;
}
}
/**
* Generates a string from an {@link Entry} of String key and String intended for use in a hash.
*/
static class StringEntryGenerator implements HashableStringGenerator<Entry<String, String>> {
@Override
public String generate(Entry<String, String> target) {
return target == null ? null : target.getKey() + target.getValue();
}
}
/**
* Generates a String from a {@link Consumer} intended for use in a hash.
*/
private static class ConsumerGenerator implements HashableStringGenerator<Consumer> {
@Override
public String generate(Consumer target) {
if (target == null) {
return null;
}
String generated = target.getUuid();
generated += generateFromCollection(target.getFacts().entrySet(), STRING_ENTRY);
generated += generateFromCollection(target.getInstalledProducts(), INSTALLED_PRODUCT);
generated += generateFromCollection(target.getEntitlements(), ENTITLEMENT);
return generated;
}
}
/**
* Generates a string from an {@link ConsumerInstalledProduct} intended for use in a hash.
*/
private static class ConsumerInstalledProductGenerator
implements HashableStringGenerator<ConsumerInstalledProduct> {
@Override
public String generate(ConsumerInstalledProduct target) {
if (target == null) {
return null;
}
String generated = target.getProductId();
generated += target.getArch();
generated += target.getVersion();
return generated;
}
}
}