/* * Copyright Terracotta, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ehcache.core; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.ehcache.core.spi.store.Store; import org.ehcache.spi.loaderwriter.CacheLoaderWriter; /** * Utility methods and common data for {@link EhcacheWithLoaderWriter Ehcache} * bulk method unit tests. * * @author Clifford W. Johnson */ final class EhcacheBasicBulkUtil { /** Private, niladic constructor to prevent instantiation. */ private EhcacheBasicBulkUtil() { } /** * Entries for populating {@link Store Store} and * {@link CacheLoaderWriter} instances in the * unit tests. The entries used are generally subset using the key sets * {@link #KEY_SET_A}, {@link #KEY_SET_B}, {@link #KEY_SET_C}, and/or * {@link #KEY_SET_F}. * <p> * Some tests are dependent on the order of the keys/entries. In general, * for each key set ('xxxXn'), the keys/entries must be ordered by 'n'. */ static final Map<String, String> TEST_ENTRIES; static { final Map<String, String> testEntries = new LinkedHashMap<String, String>(); testEntries.put("keyA1", "valueA1"); // keySet A testEntries.put("keyB1", "valueB1"); // keySet B testEntries.put("keyC1", "valueC1"); // keySet C testEntries.put("keyD1", "valueD1"); // KeySet D testEntries.put("keyE1", "valueE1"); // KeySet E testEntries.put("keyF1", "valueF1"); // KeySet F testEntries.put("keyC2", "valueC2"); // keySet C testEntries.put("keyD2", "valueD2"); // KeySet D testEntries.put("keyA2", "valueA2"); // keySet A testEntries.put("keyB2", "valueB2"); // ketSet B testEntries.put("keyF2", "valueF2"); // keySet F testEntries.put("keyE2", "valueE2"); // KeySet E testEntries.put("keyD3", "valueD3"); // KeySet D testEntries.put("keyC3", "valueC3"); // keySet C testEntries.put("keyF3", "valueF3"); // keySet F testEntries.put("keyE3", "valueE3"); // KeySet E testEntries.put("keyA3", "valueA3"); // keySet A testEntries.put("keyB3", "valueB3"); // ketSet B testEntries.put("keyF4", "valueF4"); // KeySet F testEntries.put("keyE4", "valueE4"); // KeySet E testEntries.put("keyD4", "valueD4"); // KeySet D testEntries.put("keyC4", "valueC4"); // keySet C testEntries.put("keyB4", "valueB4"); // keySet B testEntries.put("keyA4", "valueA4"); // keySet A testEntries.put("keyE5", "valueE5"); // KeySet E testEntries.put("keyF5", "valueF5"); // KeySet F testEntries.put("keyB5", "valueB5"); // keySet B testEntries.put("keyA5", "valueA5"); // keySet A testEntries.put("keyD5", "valueD5"); // KeySet D testEntries.put("keyC5", "valueC5"); // keySet C testEntries.put("keyB6", "valueB6"); // keySet B testEntries.put("keyA6", "valueA6"); // keySet A testEntries.put("keyE6", "valueE6"); // KeySet E testEntries.put("keyF6", "valueF6"); // KeySet F testEntries.put("keyC6", "valueC6"); // keySet C testEntries.put("keyD6", "valueD6"); // KeySet D testEntries.put("keyB7", "valueB7"); // keySet B testEntries.put("keyE7", "valueE7"); // KeySet E testEntries.put("keyF7", "valueF7"); // KeySet F testEntries.put("keyC7", "valueC7"); // keySet C testEntries.put("keyD7", "valueD7"); // KeySet D testEntries.put("keyE8", "valueE8"); // KeySet E testEntries.put("keyF8", "valueF8"); // KeySet F testEntries.put("keyC8", "valueC8"); // keySet C testEntries.put("keyD8", "valueD8"); // KeySet D testEntries.put("keyF9", "valueF9"); // KeySet F testEntries.put("keyC9", "valueC9"); // keySet C testEntries.put("keyD9", "valueD9"); // KeySet D testEntries.put("keyC10", "valueC10"); // keySet C testEntries.put("keyD10", "valueD10"); // KeySet D testEntries.put("keyD11", "valueD11"); // KeySet D TEST_ENTRIES = Collections.unmodifiableMap(testEntries); } /** The {@link #TEST_ENTRIES} key subset matching {@code xxxAx}. */ static final Set<String> KEY_SET_A; /** The {@link #TEST_ENTRIES} key subset matching {@code xxxBx}. */ static final Set<String> KEY_SET_B; /** The {@link #TEST_ENTRIES} key subset matching {@code xxxCx}. */ static final Set<String> KEY_SET_C; /** The {@link #TEST_ENTRIES} key subset matching {@code xxxDx}. */ static final Set<String> KEY_SET_D; /** The {@link #TEST_ENTRIES} key subset matching {@code xxxEx}. */ static final Set<String> KEY_SET_E; /** The {@link #TEST_ENTRIES} key subset matching {@code xxxFx}. */ static final Set<String> KEY_SET_F; static { final Set<String> keySetA = new LinkedHashSet<String>(); final Set<String> keySetB = new LinkedHashSet<String>(); final Set<String> keySetC = new LinkedHashSet<String>(); final Set<String> keySetD = new LinkedHashSet<String>(); final Set<String> keySetE = new LinkedHashSet<String>(); final Set<String> keySetF = new LinkedHashSet<String>(); for (final String key : TEST_ENTRIES.keySet()) { final char set = key.charAt(3); switch (set) { case 'A': keySetA.add(key); break; case 'B': keySetB.add(key); break; case 'C': keySetC.add(key); break; case 'D': keySetD.add(key); break; case 'E': keySetE.add(key); break; case 'F': keySetF.add(key); break; default: throw new AssertionError(); } } KEY_SET_A = Collections.unmodifiableSet(keySetA); KEY_SET_B = Collections.unmodifiableSet(keySetB); KEY_SET_C = Collections.unmodifiableSet(keySetC); KEY_SET_D = Collections.unmodifiableSet(keySetD); KEY_SET_E = Collections.unmodifiableSet(keySetE); KEY_SET_F = Collections.unmodifiableSet(keySetF); } /** * Gets a {@code Map} holding entries corresponding to the key {@code Iterable} provided. * * @param subset the {@code Iterable} over the keys for entries to copy into the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding the designated entries */ static Map<String, String> getEntryMap(final Iterable<String> subset) { return getEntryMap(Collections.singletonList(subset), null); } /** * Gets a {@code Map} holding entries corresponding to the key {@code Iterable}s provided. * * @param subset1 the first {@code Iterable} over the keys for entries to copy into the result {@code Map} * @param subset2 the second {@code Iterable}s over the keys for entries to copy into the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding the designated entries */ static Map<String, String> getEntryMap(final Iterable<String> subset1, final Iterable<String> subset2) { final List<Iterable<String>> subsets = new ArrayList<Iterable<String>>(2); subsets.add(subset1); subsets.add(subset2); return getEntryMap(subsets, null); } /** * Gets a {@code Map} holding entries corresponding to the key {@code Iterable}s provided. * * @param subset1 the first {@code Iterable} over the keys for entries to copy into the result {@code Map} * @param subset2 the second {@code Iterable}s over the keys for entries to copy into the result {@code Map} * @param subset3 the third {@code Iterable}s over the keys for entries to copy into the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding the designated entries */ static Map<String, String> getEntryMap( final Iterable<String> subset1, final Iterable<String> subset2, final Iterable<String> subset3) { final List<Iterable<String>> subsets = new ArrayList<Iterable<String>>(3); subsets.add(subset1); subsets.add(subset2); subsets.add(subset3); return getEntryMap(subsets, null); } /** * Gets a {@code Map} holding entries corresponding to the key {@code Iterable}s provided. * * @param subset1 the first {@code Iterable} over the keys for entries to copy into the result {@code Map} * @param subset2 the second {@code Iterable}s over the keys for entries to copy into the result {@code Map} * @param subset3 the third {@code Iterable}s over the keys for entries to copy into the result {@code Map} * @param subset4 the fourth {@code Iterable}s over the keys for entries to copy into the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding the designated entries */ static Map<String, String> getEntryMap( final Iterable<String> subset1, final Iterable<String> subset2, final Iterable<String> subset3, final Iterable<String> subset4) { final List<Iterable<String>> subsets = new ArrayList<Iterable<String>>(4); subsets.add(subset1); subsets.add(subset2); subsets.add(subset3); subsets.add(subset4); return getEntryMap(subsets, null); } /** * Gets a {@code Map} holding entries corresponding to the key {@code Iterable} provided. Each entry * value is prepended with the prefix value provided. * * @param prefix the non-{@code null} prefix used to alter each entry's value * @param subset the {@code Iterable} over the keys for entries to copy into the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding the designated entries */ static Map<String, String> getAltEntryMap(final String prefix, final Iterable<String> subset) { assert prefix != null; return getEntryMap(Collections.singletonList(subset), prefix); } /** * Gets a {@code Map} holding entries corresponding to the key {@code Iterable}s provided. * * @param subsets the {@code Iterable}s over the keys for entries to copy into the result {@code Map} * @param prefix the value to prepend to each entry value; if {@code null}, the values are not altered * * @return a new, insert-ordered, modifiable {@code Map} holding the designated entries */ private static Map<String, String> getEntryMap(final List<Iterable<String>> subsets, final String prefix) { final StringBuilder sb = (prefix == null ? null : new StringBuilder(prefix)); final Map<String, String> entryMap = new LinkedHashMap<String, String>(); for (final Iterable<String> subset : subsets) { for (final String key : subset) { String value = TEST_ENTRIES.get(key); if (prefix != null) { sb.setLength(prefix.length()); value = sb.append(value).toString(); } entryMap.put(key, value); } } return entryMap; } /** * Gets a {@code Map} having a {@code null} value for each of the keys provided in {@code keySet}. * * @param keySet the {@code Iterable} over the keys for the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding {@code null} values for each key provided */ static Map<String, String> getNullEntryMap(final Iterable<String> keySet) { return getNullEntryMap(Collections.singletonList(keySet)); } /** * Gets a {@code Map} having a {@code null} value for each of the keys provided all identified keySets. * * @param keySet1 the first {@code Iterable} over the keys for the result {@code Map} * @param keySet2 the second {@code Iterable} over the keys for the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding {@code null} values for each key provided */ static Map<String, String> getNullEntryMap(final Iterable<String> keySet1, final Iterable<String> keySet2) { final List<Iterable<String>> keySets = new ArrayList<Iterable<String>>(2); keySets.add(keySet1); keySets.add(keySet2); return getNullEntryMap(keySets); } /** * Gets a {@code Map} having a {@code null} value for each of the keys provided in {@code keySets}. * * @param keySets the {@code Iterable}s over the keys for the result {@code Map} * * @return a new, insert-ordered, modifiable {@code Map} holding {@code null} values for each key provided */ private static Map<String, String> getNullEntryMap(final List<Iterable<String>> keySets) { final Map<String, String> entryMap = new LinkedHashMap<String, String>(); for (final Iterable<String> keySet : keySets) { for (final String key : keySet) { entryMap.put(key, null); } } return entryMap; } /** * Gets a {@code Map} containing all of the entries from the maps provided. * * @param map1 the first {@code Map} instance to combine * @param map2 the second {@code Map} instance to combine * * @return a new {@code Map} containing all of the entries */ static Map<String, String> union(final Map<String, String> map1, final Map<String, String> map2) { final List<Map<String, String>> maps = new ArrayList<Map<String, String>>(); maps.add(map1); maps.add(map2); return unionMaps(maps); } /** * Gets a {@code Map} containing all of the entries from the maps provided. * * @param map1 the first {@code Map} instance to combine * @param map2 the second {@code Map} instance to combine * @param map3 the third {@code Map} instance to combine * * @return a new {@code Map} containing all of the entries */ static Map<String, String> union( final Map<String, String> map1, final Map<String, String> map2, final Map<String, String> map3) { final List<Map<String, String>> maps = new ArrayList<Map<String, String>>(); maps.add(map1); maps.add(map2); maps.add(map3); return unionMaps(maps); } /** * Gets a {@code Map} containing all of the entries from the maps provided. * * @param maps the {@code Map} instances to combine * * @return a new {@code Map} containing all of the entries */ private static Map<String, String> unionMaps(final List<Map<String, String>> maps) { final Map<String, String> union = new HashMap<String, String>(); for (Map<String, String> map : maps) { union.putAll(map); } return union; } /** * Gets a {@code Set} containing all of the elements from the sets provided * * @param set1 the first {@code Set} instance to combine * @param set2 the second {@code Set} instance to combine * * @return a new {@code Set} containing all of the elements */ static Set<String> union(final Set<String> set1, final Set<String> set2) { final List<Set<String>> sets = new ArrayList<Set<String>>(); sets.add(set1); sets.add(set2); return unionSets(sets); } /** * Gets a {@code Set} containing all of the entries from the sets provided. * * @param sets the {@code Set} instances to combine * * @return a new {@code Set} containing all of the elements */ private static Set<String> unionSets(final List<Set<String>> sets) { final Set<String> union = new HashSet<String>(); for (final Set<String> set : sets) { union.addAll(set); } return union; } /** * Gets a new {@code Set} that is the interleaved union of the {@code Set}s provided. * * @param keySet1 the first {@code Set} of keys to appear in the result {@code Set} * @param keySet2 the second {@code Set} of keys to appear in the result {@code Set} * * @return a new, modifiable {@code Set} holding the designated keys * * @see #fanIn(java.util.List) */ static Set<String> fanIn(final Set<String> keySet1, final Set<String> keySet2) { final List<Set<String>> keySets = new ArrayList<Set<String>>(); keySets.add(keySet1); keySets.add(keySet2); return fanIn(keySets); } /** * Gets a new {@code Set} that is the interleaved union of the {@code Set}s provided. * * @param keySet1 the first {@code Set} of keys to appear in the result {@code Set} * @param keySet2 the second {@code Set} of keys to appear in the result {@code Set} * @param keySet3 the third {@code Set} of keys to appear in the result {@code Set} * * @return a new, modifiable {@code Set} holding the designated keys * * @see #fanIn(java.util.List) */ static Set<String> fanIn(final Set<String> keySet1, final Set<String> keySet2, final Set<String> keySet3) { final List<Set<String>> keySets = new ArrayList<Set<String>>(); keySets.add(keySet1); keySets.add(keySet2); keySets.add(keySet3); return fanIn(keySets); } /** * Gets a new {@code Set} that is the interleaved union of the {@code Set}s provided. * * @param keySet1 the first {@code Set} of keys to appear in the result {@code Set} * @param keySet2 the second {@code Set} of keys to appear in the result {@code Set} * @param keySet3 the third {@code Set} of keys to appear in the result {@code Set} * @param keySet4 the fourth {@code Set} of keys to appear in the result {@code Set} * * @return a new, modifiable {@code Set} holding the designated keys * * @see #fanIn(java.util.List) */ static Set<String> fanIn( final Set<String> keySet1, final Set<String> keySet2, final Set<String> keySet3, final Set<String> keySet4) { final List<Set<String>> keySets = new ArrayList<Set<String>>(); keySets.add(keySet1); keySets.add(keySet2); keySets.add(keySet3); keySets.add(keySet4); return fanIn(keySets); } /** * Gets a new {@code Set} that is the interleaved union of the {@code Set}s provided. The * set returned from this operation is in the following order: * <ul> * <li>keySet[0][0]</li> * <li>keySet[1][0]</li> * <li>...</li> * <li>keySet[N][0]</li> * <li>keySet[0][1]</li> * <li>keySet[1][1]</li> * <li>...</li> * <li>keySet[N][1]</li> * <li>keySet[0][2]</li> * <li>keySet[1][2]</li> * <li>...</li> * <li>keySet[N][2]</li> * <li>...</li> * </ul> * where {@code keySet[0][0]} is the first item returned from the {@code Iterator} obtained from * {@code {@code keySets.get(0).iterator()}, {@code keySet[1][0]} is the first item obtained from * {@code {@code keySets.get(1).iterator()}, etc. * * @param keySets the {@code Set}s of keys to appear in the result {@code Set} * * @return a new, modifiable {@code Set} holding the designated keys */ private static Set<String> fanIn(final List<Set<String>> keySets) { final Set<String> union = new LinkedHashSet<String>(); /* * Collect the keys from the sets provided in the iteration order of the main * test entry map. */ for (final String key : TEST_ENTRIES.keySet()) { for (final Set<String> keySet : keySets) { if (keySet.contains(key)) { union.add(key); break; } } } return union; } /** * Copies entries from the {@code Set} provided until reaching a barrier item. * The items are copied in iterator order and the result does not include the barrier. * * @param source the {@code Set} from which the items are copied * @param barrier the barrier indicating the end of the copy * * @return a new, entry-ordered {@code Set} containing the subset of {@code source} */ static Set<String> copyUntil(final Set<String> source, final String barrier) { final Set<String> subset = new LinkedHashSet<String>(); for (final String sourceItem : source) { if (barrier.equals(sourceItem)) { break; } subset.add(sourceItem); } return subset; } /** * Makes a shallow copy of the {@code Set} provided retaining only those elements identified * by in the {@code Collection} {@code retained}. * * @param source the {@code Set} from which the copy is made * @param retained the elements to keep in the copy * * @return a new, entry-ordered {@code Set} containing the just the retained elements */ static Set<String> copyOnly(final Set<String> source, final Collection<String> retained) { final Set<String> copy = new LinkedHashSet<String>(source); copy.retainAll(retained); return copy; } /** * Makes a shallow copy of the {@code Set} provided omitting those elements identified by the * {@code Collection} {@code removed}. * * @param source the {@code Set} from which the copy is made * @param removed the elements to omit from the copy * * @return a new, entry-ordered {@code Set} containing the elements from {@code source} less those * specified in {@code removed} */ static Set<String> copyWithout(final Set<String> source, final Collection<String> removed) { final Set<String> copy = new LinkedHashSet<String>(source); copy.removeAll(removed); return copy; } /** * Makes a shallow copy of the {@code Map} provided retaining only those entries identified * by the keys in the {@code Collection} {@code retained}. * * @param source the {@code Map} from which the copy is made * @param retained the keys of the entries to keep in the copy * * @return a new, entry-ordered {@code Map} containing the just the retained entries */ static Map<String, String> copyOnly(final Map<String, String> source, final Collection<String> retained) { final Map<String, String> copy = new LinkedHashMap<String, String>(source); copy.keySet().retainAll(retained); return copy; } /** * Makes a shallow copy of the {@code Map} provided omitting those entries identified by the * keys in the {@code Collection} {@code removed}. * * @param source the {@code Map} from which the copy is made * @param removed the keys of the entries to omit from the copy * * @return a new, entry-ordered {@code Map} containing the entries from {@code source} less those * specified in {@code removed} */ static Map<String, String> copyWithout(final Map<String, String> source, final Collection<String> removed) { final Map<String, String> copy = new LinkedHashMap<String, String>(source); copy.keySet().removeAll(removed); return copy; } }