package sk.stuba.fiit.perconik.activity.serializers; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.google.common.base.Equivalence; import com.google.common.base.Predicate; import com.google.common.collect.TreeTraverser; import sk.stuba.fiit.perconik.data.content.AnyContent; import static java.lang.Integer.toHexString; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Predicates.instanceOf; import static com.google.common.base.Strings.padStart; import static com.google.common.collect.Maps.immutableEntry; import static com.google.common.collect.Maps.newLinkedHashMap; import static sk.stuba.fiit.perconik.data.content.StructuredContents.key; import static sk.stuba.fiit.perconik.utilities.MoreLists.newArrayListSuitableFor; public final class References { private References() {} public static Map<String, Object> extractObjects(final AnyContent content, final String prefix, final Iterable<String> keys, final Predicate<Object> filter) { return extractObjects(content, prefix, keys, filter, Equivalence.equals()); } public static Map<String, Object> extractObjects(final AnyContent content, final String prefix, final Iterable<String> keys, final Predicate<Object> filter, final Equivalence<Object> equivalence) { checkNotNull(prefix); checkNotNull(keys); checkNotNull(filter); checkNotNull(equivalence); Map<String, Object> objects = newLinkedHashMap(); for (Entry<Object, Object> entry: new AnyContentTraverser().preOrderTraversal(immutableEntry((Object) null, (Object) content))) { Object value = entry.getValue(); if (value instanceof AnyContent) { value = ((AnyContent) value).any(); } if (!(value instanceof Map)) { continue; } @SuppressWarnings("unchecked") Map<String, String> container = (Map<String, String>) value; for (String key: keys) { Object object = container.get(key); if (filter.apply(object)) { String hash = padStart(toHexString(equivalence.hash(object)), 8, '0'); objects.put(hash, object); container.put(key, prefix + "@" + hash); } } } return objects; } private static final class AnyContentTraverser extends TreeTraverser<Entry<Object, Object>> { AnyContentTraverser() {} @Override @SuppressWarnings("unchecked") public Iterable<Entry<Object, Object>> children(final Entry<Object, Object> entry) { Object value = entry.getValue(); if (value instanceof AnyContent) { value = ((AnyContent) value).any(); } if (value instanceof Map) { return ((Map<Object, Object>) value).entrySet(); } if (value instanceof Collection) { List<Entry<Object, Object>> children = newArrayListSuitableFor((Collection<?>) value); for (Object element: (Collection<?>) value) { children.add(immutableEntry((Object) null, element)); } return children; } return emptyList(); } } public static void referenceObjects(final AnyContent content, final String field, final Iterable<String> keys, final Predicate<Object> filter) { referenceObjects(content, field, keys, filter, Equivalence.equals()); } public static void referenceObjects(final AnyContent content, final String field, final Iterable<String> keys, final Predicate<Object> filter, final Equivalence<Object> equivalence) { String key = key("internals", field); content.put(key, extractObjects(content, key, keys, filter, equivalence)); } public static void referenceStrings(final AnyContent content) { referenceObjects(content, "strings", asList("description", "string", "text"), instanceOf(String.class)); } }