/** * 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; } } }