All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.faktorips.util.ClassToInstancesMap Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) Faktor Zehn GmbH - faktorzehn.org
 * 
 * This source code is available under the terms of the AGPL Affero General Public License version
 * 3.
 * 
 * Please see LICENSE.txt for full license terms, including the additional permissions and
 * restrictions as well as the possibility of alternative license terms.
 *******************************************************************************/

package org.faktorips.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * This class is a map with a class as key and a collection of instances of this class as value. The
 * class does NOT implements the {@link Map} interface because this interface does not set the
 * correct generics. But this class does implements the same methods like {@link Map} except of the
 * generics.
 * 

* The generic Type T represents the base class used in this map. All keys have to be a subclass or * the same class. *

* Remember that this map does only handles a bunch of list with the same superclass. Changing any * of these lists does also change the list in the map. Only the method {@link #values()} does * create a new List containing every object of the values. All other methods never create list * copies. * * @author dirmeier */ public class ClassToInstancesMap { private final ConcurrentHashMap, List> internalMap = new ConcurrentHashMap<>(); /** * Getting the list of instances stored of the type given by the key. If there is no element for * this key this method would return an empty list. Never return null. * * @param key The class of the instances you want to get * @return A list of instances of the given class */ public List get(Class key) { return getInstanceList(key); } /** * Putting the value to the classes of its type. Use this method only if you want to put the * instance to exactly its implementation class used as key. Use {@link #put(Class, Object)} if * you want to store the instance for example with its interface used as the key. Calling this * method multiple times with the same key value pair would add a new value every time. That * means you could have the same instance multiple time. * * @param value the value you want to add * @return the list of all values already added to the map for the given key including the new * one. */ public List put(K value) { @SuppressWarnings("unchecked") // this is exactly this class Class implClass = (Class)value.getClass(); return put(implClass, value); } /** * Putting the value to the classes of key. Calling this method multiple times with the same key * value pair would add a new value every time. That means you could have the same instance * multiple time. * * @param key The key specifying the class of the value * @param value the value you want to add * @return the list of all values already added to the map for the given key including the new * one. */ public List put(Class key, K value) { List list = getInstanceList(key); list.add(value); return list; } /** * This method puts the value into the list specified by the key class. Use this method only if * you do not know the concrete class at compile time, use {@link #put(Class, Object)} instead. * If you do not have the information about key and value you could use this put method. The * type check is done at runtime, this method would throw a {@link RuntimeException} in case of * type mismatch. * * @param key The class that identifies the list of values * @param value the value you want to add to this map * @return the list of values of type key after adding the value */ public List putWithRuntimeCheck(Class key, T value) { if (key.isAssignableFrom(value.getClass())) { @SuppressWarnings("unchecked") List list = (List)getInstanceList(key); list.add(value); return list; } else { throw new RuntimeException("The value " + value + " is not of type " + key); } } /** * The whole size of the map that means how many instances are stored in this map. If you want * to know how many objects are stored of one type use {@link #size(Class)}. * * @return The number of discrete values stored in this map. */ public int size() { return valuesInternal().size(); } /** * Getting the number of objects stored for the specified key. * * @param key The class you want to get the number of instances for * @return the number of values stored for the specified class. */ public int size(Class key) { return getInstanceList(key).size(); } /** * Return true if this map is empty * * @return true if the map is empty or false if there is at least one element. */ public boolean isEmpty() { return valuesInternal().isEmpty(); } /** * Check if the map contains the value. This method running over all value lists searching for * the specified value. * * @param value The value you want to know if it is contained * @return true if the value is in the list or false if not */ public boolean containsValue(Object value) { for (List list : internalMap.values()) { if (list.contains(value)) { return true; } } return false; } /** * Check if the map contains a list of values for the specified type. * * @param type The type for which we check if there is a list of values for * @return true if there is a list of values of the specified type */ public boolean containsValuesOf(Class type) { return internalMap.get(type) != null; } /** * Remove a single element from the list and returns true if it was removed successfully. If the * list containing the object multiple times only the fist one will be removed! * * @param key The key of the list that should contain the object * @param object the object you want to remove * @return true if the object was found in the list. */ public boolean remove(Class key, T object) { List instanceList = getInstanceList(key); return instanceList.remove(object); } /** * Remove all objects for a given key and returns the list of removed objects. The returned list * is a copy of the original included list, changing this list does not matter fot this map. * * @param key The class of the objects you want to remove * @return the list of removed objects */ public synchronized List removeAll(Class key) { List list = getInstanceList(key); List result = new ArrayList<>(list); list.clear(); return result; } /** * Remove every object in the map. */ public void clear() { internalMap.clear(); } /** * This method returns all values in one collection but does not guaranty any order of the * values. * * @return All values stored in this map in one collection. */ private List valuesInternal() { ArrayList result = new ArrayList<>(); for (List list : internalMap.values()) { result.addAll(list); } return result; } /** * This method returns all values in one collection. The order of the lists of different classes * is always the same. * * @return All values stored in this map in one collection. */ public List values() { ArrayList result = new ArrayList<>(); Set> keySet = internalMap.keySet(); ArrayList> sortedKeySet = new ArrayList<>(keySet); Collections.sort(sortedKeySet, Comparator.comparing(Class::getName)); for (Class key : sortedKeySet) { result.addAll(internalMap.get(key)); } return result; } /** * Gets the set of list of instances stored for the given key. Creates a new list if absent. *

* Returns the very list instance that is stored in the map for the given key (not a defensive * copy). Thus adding values to that list changes this map. *

* This method is thread safe. Ensures that only a single list instance is created for each key, * and that multiple threads will share these instances (and not overwrite each other's values). * * @param key The class to return a list of instances for. * * @type K a sub class of the key */ @SuppressWarnings("unchecked") private List getInstanceList(Class key) { return (List)internalMap.computeIfAbsent(key, $ -> new ArrayList()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy