org.eclipse.sw360.datahandler.common.CommonUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sw360.datahandler.common.CommonUtils.java

Source

/*
 * Copyright Siemens AG, 2014-2016.
 * With modifications by Bosch Software Innovations GmbH, 2016
 * Part of the SW360 Portal Project.
 *
 * SPDX-License-Identifier: EPL-1.0
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.eclipse.sw360.datahandler.common;

import com.google.common.base.*;
import com.google.common.collect.*;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.QuoteMode;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.thrift.TBase;
import org.apache.thrift.TException;
import org.apache.thrift.TFieldIdEnum;
import org.eclipse.sw360.datahandler.thrift.DocumentState;
import org.eclipse.sw360.datahandler.thrift.ModerationState;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.RequestSummary;
import org.eclipse.sw360.datahandler.thrift.attachments.Attachment;
import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentContent;
import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentType;
import org.eclipse.sw360.datahandler.thrift.attachments.CheckStatus;
import org.eclipse.sw360.datahandler.thrift.components.Release;
import org.eclipse.sw360.datahandler.thrift.licenses.Todo;
import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest;
import org.eclipse.sw360.datahandler.thrift.users.User;
import org.eclipse.sw360.datahandler.thrift.users.UserService;
import org.ektorp.DocumentOperationResult;
import org.jetbrains.annotations.NotNull;

import java.io.*;
import java.lang.reflect.Array;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.google.common.base.Strings.isNullOrEmpty;
import static org.apache.log4j.LogManager.getLogger;

/**
 * @author Cedric.Bodet@tngtech.com
 * @author Johannes.Najjar@tngtech.com
 */
public class CommonUtils {

    private static String SYSTEM_CONFIGURATION_PATH = "/etc/sw360";

    private CommonUtils() {
        // Utility class with only static functions
    }

    private static final Ordering<String> CASE_INSENSITIVE_ORDERING = Ordering.from(String.CASE_INSENSITIVE_ORDER);

    public static final CSVFormat sw360CsvFormat = CSVFormat.RFC4180.withQuote('\'').withEscape('\\')
            .withIgnoreSurroundingSpaces(true).withQuoteMode(QuoteMode.ALL);

    private static final Splitter COMMA_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();

    public static final Joiner COMMA_JOINER = Joiner.on(", ");

    private static final Comparator<CheckStatus> CHECK_STATUS_COMPARATOR = Comparator.comparingInt(cs -> {
        switch (cs) {
        case ACCEPTED:
            return 2;
        case NOTCHECKED:
            return 1;
        case REJECTED:
            return 0;
        }
        throw new IllegalArgumentException("CheckStatus is unknown to this Comparator: " + cs.name());
    });

    public static final String TMP_TODO_ID_PREFIX = "tmp";

    private static final Predicate<String> NOT_EMPTY_OR_NULL = new Predicate<String>() {
        @Override
        public boolean apply(String input) {
            return !Strings.isNullOrEmpty(input);
        }
    };

    /**
     * Returns a sorted list containing the elements of the given collection.
     * The list is sorted alphabetically, ignoring case.
     */
    public static List<String> getSortedList(Collection<String> collection) {
        return collection != null ? CASE_INSENSITIVE_ORDERING.immutableSortedCopy(collection)
                : ImmutableList.<String>of();
    }

    public static String joinStrings(Iterable<String> strings) {
        return strings != null ? COMMA_JOINER.join(strings) : "";
    }

    public static Predicate<String> notEmptyOrNull() {
        return NOT_EMPTY_OR_NULL;
    }

    /**
     * Return true if and item is contained in a collection, false otherwise. Null objects make the function returns false
     */
    public static <T> boolean contains(T item, Collection<T> collection) {
        return item != null && collection != null && collection.contains(item);
    }

    public static <T> boolean contains(T item, T[] array) {
        return array != null && contains(item, ImmutableList.copyOf(array));
    }

    /**
     * Add a String to a set, if the string is not null
     */
    public static <T> void add(Collection<T> collection, T item) {
        if (collection != null && item != null) {
            collection.add(item);
        }
    }

    /**
     * Add all from right to left collection
     */
    public static <T> void addAll(Collection<T> left, Collection<T> right) {
        if (left != null && right != null) {
            left.addAll(right);
        }
    }

    public static <T> void removeAll(Collection<T> left, Collection<T> right) {
        if (left != null && right != null) {
            left.removeAll(right);
        }
    }

    public static <T> List<T> nullToEmptyList(List<T> in) {
        return in != null ? in : ImmutableList.<T>of();
    }

    public static <T> Collection<T> nullToEmptyCollection(Collection<T> in) {
        return in != null ? in : ImmutableList.<T>of();
    }

    public static <T> Set<T> nullToEmptySet(Set<T> in) {
        return in != null ? in : ImmutableSet.<T>of();
    }

    public static <K, V> Map<K, V> nullToEmptyMap(Map<K, V> in) {
        return in != null ? in : ImmutableMap.<K, V>of();
    }

    public static <T> Set<T> toSingletonSet(T in) {
        return in != null ? ImmutableSet.of(in) : ImmutableSet.<T>of();
    }

    public static String nullToEmptyString(Object in) {
        return in != null ? in.toString() : "";
    }

    public static Set<String> splitToSet(String value) {
        return ImmutableSet.copyOf(COMMA_SPLITTER.split(value));
    }

    /**
     * @param string string to convert to int
     * @return int value if input positive, negative on error
     */
    public static int toUnsignedInt(String string) {
        int integer = -1;
        try {
            integer = Integer.valueOf(string);
        } catch (NullPointerException | NumberFormatException ignored) { // sic.
        }
        return integer;
    }

    public static boolean oneIsNull(Object... objects) {
        for (Object object : objects) {
            if (object == null)
                return true;
        }
        return false;
    }

    public static boolean allAreEmptyOrNull(Collection... collections) {
        return !atLeastOneIsNotEmpty(collections);
    }

    public static boolean allAreEmptyOrNull(Map... maps) {
        return !atLeastOneIsNotEmpty(maps);
    }

    public static boolean allAreEmptyOrNull(String... strings) {
        return !atLeastOneIsNotEmpty(strings);
    }

    public static boolean atLeastOneIsNotEmpty(Collection... collections) {
        for (Collection collection : collections) {
            if (collection != null && !collection.isEmpty())
                return true;
        }
        return false;
    }

    public static boolean atLeastOneIsNotEmpty(Map... maps) {
        for (Map map : maps) {
            if (map != null && !map.isEmpty())
                return true;
        }
        return false;
    }

    public static boolean atLeastOneIsNotEmpty(String... strings) {
        for (String string : strings) {
            if (!Strings.isNullOrEmpty(string))
                return true;
        }
        return false;
    }

    public static boolean allAreEmpty(Object... objects) {
        return !atLeastOneIsNotEmpty(objects);
    }

    public static boolean atLeastOneIsNotEmpty(Object... objects) {

        for (Object object : objects) {
            if (object instanceof Collection)
                if (!((Collection) object).isEmpty())
                    return true;
        }

        return false;
    }

    public static int compareAsNullsAreSmaller(Object o1, Object o2) {
        if (o1 == null) {
            return o2 == null ? 0 : -1;
        }
        if (o2 == null)
            return 1;

        return 0;
    }

    public static boolean allHaveSameLength(Object... arrays) {
        if (arrays.length < 1) {
            return true;
        }

        int length = Array.getLength(arrays[0]);
        for (Object array : arrays) {
            if (Array.getLength(array) != length) {
                return false;
            }
        }

        return true;
    }

    public static Optional<Attachment> getAttachmentOptional(final String attachmentId,
            Set<Attachment> attachments) {
        return attachments.stream().filter(attachment -> attachmentId.equals(attachment.getAttachmentContentId()))
                .findFirst();
    }

    @NotNull
    public static Attachment getNewAttachment(User user, String attachmentContentId, String fileName) {
        Attachment attachment = new Attachment();
        attachment.setCreatedBy(user.getEmail());
        attachment.setCreatedOn(SW360Utils.getCreatedOn());
        attachment.setCreatedComment("");
        attachment.setCreatedTeam(user.getDepartment());
        attachment.setFilename(fileName);
        attachment.setAttachmentContentId(attachmentContentId);
        attachment.setAttachmentType(AttachmentType.DOCUMENT);
        attachment.setCheckStatus(CheckStatus.NOTCHECKED);
        attachment.setCheckedComment("");
        attachment.setSha1("");
        return attachment;
    }

    @NotNull
    public static Comparator<ModerationRequest> compareByTimeStampDescending() {
        return new Comparator<ModerationRequest>() {
            @Override
            public int compare(ModerationRequest o1, ModerationRequest o2) {
                return Long.compare(o2.getTimestamp(), o1.getTimestamp());
            }
        };
    }

    public static boolean isInProgressOrPending(ModerationRequest moderationRequest) {
        return moderationRequest.getModerationState().equals(ModerationState.INPROGRESS)
                || moderationRequest.getModerationState().equals(ModerationState.PENDING);
    }

    @NotNull
    public static DocumentState getOriginalDocumentState() {
        DocumentState documentState = new DocumentState().setIsOriginalDocument(true);
        documentState.unsetModerationState();
        return documentState;
    }

    public static Optional<ModerationRequest> getFirstModerationRequestOfUser(
            List<ModerationRequest> moderationRequestsForDocumentId, final String email) {
        return moderationRequestsForDocumentId.stream()
                .filter(moderationRequest -> moderationRequest.getRequestingUser().equals(email)).findFirst();
    }

    @NotNull
    public static DocumentState getModeratedDocumentState(ModerationRequest moderationRequest) {
        DocumentState documentState = new DocumentState().setIsOriginalDocument(false);
        documentState.setModerationState(moderationRequest.getModerationState());
        return documentState;
    }

    public static boolean isStillRelevant(ModerationRequest request) {
        return request.getModerationState().equals(ModerationState.PENDING)
                || request.getModerationState().equals(ModerationState.INPROGRESS);
    }

    public static <T, V> AfterFunction<T, V> afterFunction(Function<V, T> function) {
        return new AfterFunction<>(function);
    }

    public static void closeQuietly(Closeable closeable, Logger logger) {
        if (closeable == null) {
            return;
        }
        try {
            closeable.close();
        } catch (IOException e) {
            logger.warn("cannot close closeable", e);
        }
    }

    public static boolean isValidUrl(String url) {
        try {
            return !isNullOrEmpty(new URL(url).getHost());
        } catch (MalformedURLException e) {
            return false;
        }
    }

    public static String getTargetNameOfUrl(String url) {
        try {
            String path = new URL(url).getPath();
            String fileName = FilenameUtils.getName(path);
            return !isNullOrEmpty(fileName) ? fileName : path;
        } catch (MalformedURLException e) {
            return "";
        }
    }

    public static Boolean getBoolOrNull(String in) {
        if (!isNullOrEmpty(in)) {
            //elegance in redundancy :)
            if (in.equalsIgnoreCase("true"))
                return true;
            else if (in.equalsIgnoreCase("false"))
                return false;
        }
        return null;
    }

    public static Integer getIntegerOrNull(String in) {
        Integer out = null;
        if (!isNullOrEmpty(in)) {
            try {
                out = Integer.parseInt(in);
            } catch (NumberFormatException ignored) {
            }
        }
        return out;
    }

    public static <T extends Enum<T>> String getEnumStringOrNull(T val) {
        if (val != null)
            return val.name();
        return null;
    }

    public static Map<String, User> getStringUserMap(UserService.Iface userClient) throws TException {
        Map<String, User> userMap;
        userMap = Maps.uniqueIndex(userClient.getAllUsers(), new Function<User, String>() {
            @Override
            public String apply(User input) {
                return input.getEmail();
            }
        });
        return userMap;
    }

    public static void getMessageForRequestSummary(RequestSummary releaseRequestSummary, String typeInfo,
            StringBuilder stringBuilder) {
        if (releaseRequestSummary.isSetTotalAffectedElements() && releaseRequestSummary.isSetTotalElements()) {
            stringBuilder.append("Affected ").append(typeInfo).append(" elements: ")
                    .append(releaseRequestSummary.getTotalAffectedElements()).append(" of ")
                    .append(releaseRequestSummary.getTotalElements()).append(". ");
        }
    }

    public static RequestSummary prepareMessage(RequestSummary input, String info) {
        StringBuilder stringBuilder = new StringBuilder();
        if (input.isSetMessage()) {
            stringBuilder.append(input.message);
        }

        getMessageForRequestSummary(input, info, stringBuilder);
        input.setMessage(stringBuilder.toString());

        return input;
    }

    public static RequestStatus reduceRequestStatus(RequestStatus r1, RequestStatus r2) {
        if (RequestStatus.SUCCESS.equals(r1) && RequestStatus.SUCCESS.equals(r2)) {
            return RequestStatus.SUCCESS;
        }
        return RequestStatus.FAILURE;
    }

    public static RequestSummary addToMessage(RequestSummary left, RequestSummary right, String info) {
        left.setRequestStatus(reduceRequestStatus(left.requestStatus, right.requestStatus));

        StringBuilder stringBuilder = new StringBuilder();
        if (left.isSetMessage()) {
            stringBuilder.append(left.message);
        }

        getMessageForRequestSummary(right, info, stringBuilder);
        left.setMessage(stringBuilder.toString());

        return left;
    }

    @NotNull
    public static RequestSummary addRequestSummaries(RequestSummary left, String typeInfoLeft, RequestSummary right,
            String typeInfoRight) {
        final RequestSummary requestSummary = prepareMessage(left, typeInfoLeft);
        return addToMessage(requestSummary, right, typeInfoRight);
    }

    public static ImmutableList<String> getAttachmentURLsFromAttachmentContents(
            List<AttachmentContent> attachmentContents) {
        return FluentIterable.from(attachmentContents).transform(new Function<AttachmentContent, String>() {
            @Override
            public String apply(AttachmentContent input) {
                return input.getRemoteUrl();
            }
        }).toList();
    }

    public static RequestSummary addRequestSummaries(RequestSummary left, RequestSummary right) {
        RequestSummary result = new RequestSummary();
        result.requestStatus = left.isSetRequestStatus() && left.requestStatus.equals(RequestStatus.SUCCESS)
                && right.isSetRequestStatus() && right.requestStatus.equals(RequestStatus.SUCCESS)
                        ? RequestStatus.SUCCESS
                        : RequestStatus.FAILURE;
        result.setTotalElements(left.getTotalElements() + right.getTotalElements());
        result.setTotalAffectedElements(left.getTotalAffectedElements() + right.getTotalAffectedElements());
        return result;
    }

    @NotNull
    public static Map<String, List<String>> getIdentifierToListOfDuplicates(
            ListMultimap<String, String> identifierToIds) {
        Map<String, List<String>> output = new HashMap<>();

        for (String identifier : identifierToIds.keySet()) {
            List<String> ids = identifierToIds.get(identifier);
            if (ids.size() > 1) {
                output.put(identifier, ids);
            }
        }

        return output;
    }

    @NotNull
    public static RequestSummary getRequestSummary(List<String> ids,
            List<DocumentOperationResult> documentOperationResults) {
        final RequestSummary requestSummary = new RequestSummary();
        requestSummary.requestStatus = documentOperationResults.isEmpty() ? RequestStatus.SUCCESS
                : RequestStatus.FAILURE;
        requestSummary.setTotalElements(ids.size());
        requestSummary.setTotalAffectedElements(ids.size() - documentOperationResults.size());
        return requestSummary;
    }

    public static RequestSummary getRequestSummary(int total, int failures) {
        final RequestSummary requestSummary = new RequestSummary();
        requestSummary.requestStatus = failures == 0 ? RequestStatus.SUCCESS : RequestStatus.FAILURE;
        requestSummary.setTotalElements(total);
        requestSummary.setTotalAffectedElements(total - failures);
        return requestSummary;
    }

    public static Properties loadProperties(Class<?> clazz, String propertiesFilePath) {
        return loadProperties(clazz, propertiesFilePath, true);
    }

    public static Properties loadProperties(Class<?> clazz, String propertiesFilePath, boolean useSystemConfig) {
        Properties props = new Properties();

        try (InputStream resourceAsStream = clazz.getResourceAsStream(propertiesFilePath)) {
            if (resourceAsStream == null)
                throw new IOException("cannot open " + propertiesFilePath);

            props.load(resourceAsStream);
        } catch (IOException e) {
            getLogger(clazz).error("Error opening resources " + propertiesFilePath + ".", e);
        }

        if (useSystemConfig) {
            File systemPropertiesFile = new File(SYSTEM_CONFIGURATION_PATH, propertiesFilePath);
            if (systemPropertiesFile.exists()) {
                try (InputStream resourceAsStream = new FileInputStream(systemPropertiesFile.getPath())) {
                    if (resourceAsStream == null)
                        throw new IOException("cannot open " + systemPropertiesFile.getPath());

                    props.load(resourceAsStream);
                } catch (IOException e) {
                    getLogger(clazz).error("Error opening resources " + systemPropertiesFile.getPath() + ".", e);
                }
            }
        }
        return props;
    }

    public static Optional<byte[]> loadResource(Class<?> clazz, String resourceFilePath) {
        return loadResource(clazz, resourceFilePath, true);
    }

    public static Optional<byte[]> loadResource(Class<?> clazz, String resourceFilePath,
            boolean useSystemResourses) {
        if (isNullOrEmpty(resourceFilePath)) {
            return Optional.empty();
        }
        if (useSystemResourses) {
            File systemResourceFile = new File(SYSTEM_CONFIGURATION_PATH, resourceFilePath);
            if (systemResourceFile.exists()) {
                try (InputStream resourceAsStream = new FileInputStream(systemResourceFile.getPath())) {
                    if (resourceAsStream == null) {
                        throw new IOException("cannot open " + systemResourceFile.getPath());
                    }
                    return Optional.of(IOUtils.toByteArray(resourceAsStream));
                } catch (IOException e) {
                    getLogger(clazz).error("Error opening resources " + systemResourceFile.getPath() + ".", e);
                }
            }
        }

        try (InputStream resourceAsStream = clazz.getResourceAsStream(resourceFilePath)) {
            if (resourceAsStream == null)
                throw new IOException("cannot open " + resourceFilePath);
            return Optional.of(IOUtils.toByteArray(resourceAsStream));
        } catch (IOException e) {
            getLogger(clazz).error("Error opening resources " + resourceFilePath + ".", e);
        }
        return Optional.empty();
    }

    public static <T> T getFirst(Iterable<T> iterable) {
        final Iterator<T> iterator = iterable.iterator();
        if (iterator.hasNext()) {
            return iterator.next();
        } else {
            throw new NoSuchElementException();
        }
    }

    public static Optional<Attachment> getBestClearingReport(Release release) {
        return nullToEmptyCollection(release.getAttachments()).stream()
                .filter(att -> att.getAttachmentType() == AttachmentType.CLEARING_REPORT)
                .max(Comparator.comparing(Attachment::getCheckStatus, CHECK_STATUS_COMPARATOR));
    }

    public static boolean isTemporaryTodo(Todo todo) {
        return todo.isSetId() && todo.getId().startsWith(TMP_TODO_ID_PREFIX);
    }

    public static class AfterFunction<T, V> {
        private Function<V, T> transformer;

        private AfterFunction(Function<V, T> transformer) {
            this.transformer = transformer;
        }

        public Predicate<V> is(Predicate<T> predicate) {
            return Predicates.compose(predicate, transformer);
        }
    }

    public static <T> Optional<T> wrapThriftOptionalReplacement(List<T> thriftOutput) {
        if (thriftOutput == null || thriftOutput.size() == 0) {
            return Optional.empty();
        }
        if (thriftOutput.size() > 1) {
            getLogger(CommonUtils.class)
                    .error("List contained more then one item but was treated as \"Optional\".");
        }
        return Optional.of(thriftOutput.get(0));
    }

    public static String formatTime(int seconds) {
        if (seconds < 0) {
            return "not set";
        }
        int hours = seconds / 3600;
        int remainder = seconds % 3600;
        int minutes = remainder / 60;
        seconds = remainder % 60;
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    public static Map<String, Set<String>> mergeMapIntoMap(Map<String, Set<String>> source,
            Map<String, Set<String>> destination) {
        if (destination == null) {
            return source;
        }
        if (source == null) {
            return destination;
        }
        source.keySet().stream().forEach(k -> {
            if (destination.containsKey(k)) {
                destination.get(k).addAll(source.get(k));
            } else {
                destination.put(k, source.get(k));
            }
        });
        return destination;
    }

    public static boolean isNullEmptyOrWhitespace(String string) {
        return string == null || string.trim().length() == 0;
    }

    public static <T> java.util.function.Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Set<Object> visitedKeys = new HashSet<>();
        return t -> visitedKeys.add(keyExtractor.apply(t));
    }

    public static Set<String> getNullToEmptyKeyset(Map<String, ?> map) {
        return nullToEmptyMap(map).keySet();
    }

    public static Set<String> getNullToEmptyValue(Map<String, Set<String>> map, String key) {
        return nullToEmptySet(nullToEmptyMap(map).get(key));
    }

    public static Set<String> unifiedKeyset(Map<String, ?>... maps) {
        Set<String> keys = new HashSet<>();
        for (Map<String, ?> map : maps) {
            keys.addAll(getNullToEmptyKeyset(map));
        }
        return keys;
    }

    public static <U extends TFieldIdEnum, T extends TBase<T, U>> boolean isMapFieldMapOfStringSets(U field,
            T document, T documentAdditions, T documentDeletions, Logger logger) {
        List<Map<String, Object>> maps = Arrays.asList((Map<String, Object>) document.getFieldValue(field),
                (Map<String, Object>) documentAdditions.getFieldValue(field),
                (Map<String, Object>) documentDeletions.getFieldValue(field));
        List<Map<String, ?>> nonEmptyMaps = maps.stream().filter(m -> m != null && !m.isEmpty())
                .collect(Collectors.toList());
        if (nonEmptyMaps.isEmpty()) {
            logger.info("Field was empty in document, documentAdditions and documentDeletions: "
                    + field.getFieldName());
            return false;
        }

        Object value = nonEmptyMaps.stream().findAny().get().entrySet().stream()
                .map(e -> ((Map.Entry<String, Object>) e).getValue()).findAny().get();
        if (!(value instanceof Set)) {
            return false;
        }
        List<Map<String, ?>> nonEmptyMapsContainingNonEmptySet = nonEmptyMaps.stream()
                .filter(m -> nonEmptyMapOfSetsContainsNonEmptySet((Map<String, Set<Object>>) m))
                .collect(Collectors.toList());

        if (nonEmptyMapsContainingNonEmptySet.isEmpty()) {
            logger.warn("Field contained only maps of only empty sets: " + field.getFieldName());
            return false;
        }

        Map<String, Set<Object>> mapWithNonEmptySet = (Map<String, Set<Object>>) nonEmptyMapsContainingNonEmptySet
                .stream().findAny().get();
        Object element = getNonEmptySetFromMapOfSets(mapWithNonEmptySet).get().stream().findAny().get();
        return (element instanceof String);
    }

    private static boolean nonEmptyMapOfSetsContainsNonEmptySet(Map<String, Set<Object>> map) {
        Optional<Set<Object>> nonEmptySet = getNonEmptySetFromMapOfSets(map);
        return nonEmptySet.isPresent();
    }

    private static Optional<Set<Object>> getNonEmptySetFromMapOfSets(Map<String, Set<Object>> map) {
        return map.entrySet().stream().map(e -> ((Map.Entry<String, Set<Object>>) e).getValue())
                .filter(s -> !s.isEmpty()).findAny();
    }

}