package org.sigmah.shared.util;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Utility class for <code>Collection</code> types.
*
* @author Raphaƫl Calabro (raphael.calabro@netapsys.fr)
*/
public final class Collections {
/**
* Private constructor.
*/
private Collections() {
// Nothing.
}
/**
* Find if the given <code>haystack</code> of elements contains one the given <code>needles</code>.
*
* @param <T>
* Type of the elements contained in the collection.
* @param haystack
* Set of elements to search in.
* @param needles
* Collection of elements to find.
* @return <code>true</code> if one of the <code>needles</code> is found in <code>haystack</code>,
* <code>false</code> if none are found.
*/
public static <T> boolean containsOneOf(final Collection<T> haystack, final Collection<T> needles) {
for (final T needle : needles) {
if (haystack.contains(needle)) {
return true;
}
}
return false;
}
/**
* Join the elements of the collection with the given separator.
*
* @param <T>
* Type of the elements contained in the collection.
* @param collection
* Collection of elements.
* @param separator
* Separator to insert between each element.
* @return A new string joining every elements in the collection with the given separator.
*/
public static <T> String join(final Collection<T> collection, final String separator) {
return join(collection, new Mapper<T, String>() {
@Override
public String forEntry(T s) {
return String.valueOf(s);
}
}, separator);
}
/**
* Join the elements of the collection with the given separator.
*
* @param <T>
* Type of the elements contained in the collection.
* @param collection
* Collection of elements.
* @param mapper
* Transform the content of the collection to <code>String</code>.
* @param separator
* Separator to insert between each element.
* @return A new string joining every elements in the collection with the given separator.
*/
public static <T> String join(final Collection<T> collection, final Mapper<T, String> mapper, final String separator) {
final StringBuilder builder = new StringBuilder();
for (final T entry : collection) {
builder.append(mapper.forEntry(entry)).append(separator);
}
removeLastSeparator(builder, separator);
return builder.toString();
}
/**
* Join the elements of the collection with the given separator.
*
* @param <T>
* Type of the elements contained in the collection.
* @param collection
* Collection of elements.
* @param mapper
* Transform the content of the collection to <code>String</code>.
* @param separator
* Separator to insert between each element.
* @return A new string joining every elements in the collection with the given separator.
*/
public static <T> String join(final Collection<T> collection, final OptionnalMapper<T, String> mapper, final String separator) {
final StringBuilder builder = new StringBuilder();
for (final T entry : collection) {
if (!mapper.skipEntry(entry)) {
builder.append(mapper.forEntry(entry)).append(separator);
}
}
removeLastSeparator(builder, separator);
return builder.toString();
}
/**
* Merge the given collections in a new <code>Set</code>.
*
* @param <T>
* Type of the objects inside the collections.
* @param collections
* Collections to merge.
* @return A new <code>Set</code> with the content of the given collections.
*/
@SafeVarargs
public static <T> Set<T> merge(final Collection<T>... collections) {
final Set<T> merged = new HashSet<T>();
for (final Collection<T> collection : collections) {
if (collection != null) {
merged.addAll(collection);
}
}
return merged;
}
/**
* Creates a list by mapping the elements from the given collection.
*
* @param <S>
* Source type.
* @param <D>
* Destination type.
* @param collection
* Collection to map.
* @param mapper
* Mapper from S to D.
* @return A new list.
*/
public static <S, D> List<D> map(final Collection<S> collection, final Mapper<S, D> mapper) {
final ArrayList<D> list = new ArrayList<D>();
for (final S entry : collection) {
list.add(mapper.forEntry(entry));
}
return list;
}
/**
* Creates a list by mapping the elements from the given collection.
* <p>
* The elements identified as skippable from the given mapper will not be
* included in the returned list.
*
* @param <S>
* Source type.
* @param <D>
* Destination type.
* @param collection
* Collection to map.
* @param mapper
* Mapper from S to D.
* @return A new list.
*/
public static <S, D> List<D> map(final Collection<S> collection, final OptionnalMapper<S, D> mapper) {
final ArrayList<D> list = new ArrayList<D>();
for (final S entry : collection) {
if (!mapper.skipEntry(entry)) {
list.add(mapper.forEntry(entry));
}
}
return list;
}
/**
* Removes the last separator in the given <code>StringBuilder</code>.
*
* @param builder
* StringBuilder to modify.
* @param separator
* Separator to remove.
*/
private static void removeLastSeparator(final StringBuilder builder, final String separator) {
final int builderLength = builder.length();
if (builderLength > 0) {
builder.setLength(builderLength - separator.length());
}
}
/**
* Simple mapper interface.
*
* @param <S>
* Source type.
* @param <D>
* Destination type.
*/
public interface Mapper<S, D> {
/**
* Map the given element to the required type.
*
* @param entry
* Element to map.
* @return The element converted.
*/
D forEntry(S entry);
}
/**
* Mapper interface for collections with optional elements.
*
* @param <S>
* Source type.
* @param <D>
* Destination type.
*/
public interface OptionnalMapper<S, D> extends Mapper<S, D> {
/**
* Decide if the given entry should be mapped or not.
*
* @param entry
* Entry to verify.
* @return <code>true</code> to skip the given entry,
* <code>false</code> otherwise.
*/
boolean skipEntry(S entry);
}
}