/* * JBoss, Home of Professional Open Source * Copyright 2009 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.util; import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import static java.util.Collections.singletonMap; import static java.util.Collections.unmodifiableMap; /** * Static helpers for Infinispan-specific collections * * @author Manik Surtani * @since 4.0 */ public class InfinispanCollections { private static final ReversibleOrderedSet<Object> EMPTY_ROS = new EmptyReversibleOrderedSet<Object>(); private static final class EmptyReversibleOrderedSet<E> extends AbstractSet<E> implements ReversibleOrderedSet<E> { Iterator<E> it = new Iterator() { @Override public boolean hasNext() { return false; } @Override public E next() { throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; @Override public Iterator<E> iterator() { return it; } @Override public int size() { return 0; } @Override public Iterator<E> reverseIterator() { return it; } } /** * A function that converts a type into another one. * * @param <E> Input type. * @param <T> Output type. */ public static interface Function<E, T> { /** * Transforms an instance of the given input into an instace of the * type to be returned. * * @param input Instance of the input type. * @return Instance of the output type. */ T transform(E input); } /** * A function that converts an entry into a key/value pair for use in a map. * @param <K> generated key * @param <V> generated value * @param <E> entry input */ public static interface MapMakerFunction<K, V, E> { /** * Transforms the given input into a key/value pair for use in a map * @param input instance of the input type * @return a Map.Entry parameterized with K and V */ Map.Entry<K, V> transform(E input); } /** * Given a map of well known key/value types, it makes a shallow copy of it * while at the same time transforming it's value type to a desired output * type. The transformation of the value type is done using a given a * function. * * @param input contains the input key/value pair map * @param f function instance to use to transform the value part of the map * @param <K> input map's key type * @param <V> desired output type of the map's value * @param <E> input map's value type * @return a shallow copy of the input Map with all its values transformed. */ public static <K, V, E> Map<K, V> transformMapValue(Map<K, E> input, Function<E, V> f) { // This screams for a map function! Gimme functional programming pleasee... if (input.isEmpty()) return Collections.emptyMap(); if (input.size() == 1) { Map.Entry<K, E> single = input.entrySet().iterator().next(); return singletonMap(single.getKey(), f.transform(single.getValue())); } else { Map<K, V> copy = new HashMap<K, V>(input.size()); for (Map.Entry<K, E> entry : input.entrySet()) copy.put(entry.getKey(), f.transform(entry.getValue())); return unmodifiableMap(copy); } } /** * Given a collection, transforms the collection to a map given a {@link MapMakerFunction} * * @param input contains a collection of type E * @param f MapMakerFunction instance to use to transform the collection to a key/value pair * @param <K> output map's key type * @param <V> output type of the map's value * @param <E> input collection's entry type * @return a Map with keys and values generated from the input collection */ public static <K, V, E> Map<K, V> transformCollectionToMap(Collection<E> input, MapMakerFunction<K, V, E> f) { // This screams for a map function! Gimme functional programming pleasee... if (input.isEmpty()) return Collections.emptyMap(); if (input.size() == 1) { E single = input.iterator().next(); Map.Entry<K, V> entry = f.transform(single); return singletonMap(entry.getKey(), entry.getValue()); } else { Map<K, V> map = new HashMap<K, V>(input.size()); for (E e : input) { Map.Entry<K, V> entry = f.transform(e); map.put(entry.getKey(), entry.getValue()); } return unmodifiableMap(map); } } }