001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.client;
019
020import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
021import static java.util.Optional.ofNullable;
022
023import java.time.ZoneId;
024import java.time.format.DateTimeFormatter;
025import java.util.List;
026import java.util.Map;
027import java.util.Map.Entry;
028import java.util.Optional;
029import java.util.stream.Collectors;
030
031/**
032 * Helpers for constructing headers.
033 *
034 * @author bbpennel
035 */
036public class HeaderHelpers {
037
038    // Formatter for converting instants to RFC1123 timestamps in UTC
039    public static DateTimeFormatter UTC_RFC_1123_FORMATTER = RFC_1123_DATE_TIME.withZone(ZoneId.of("UTC"));
040
041    /**
042     * Format a map of values to q values into a quality value formatted header, as per:
043     *  https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
044     *
045     * For example, "md5;q=1.0, sha256,sha512;q=0.3"
046     *
047     * @param qualityMap mapping of values to their quality values.
048     * @return Formatted quality value header representation of the provided map.
049     */
050    public static String formatQualityValues(final Map<String, ? extends Object> qualityMap) {
051        // Group header values by common q values
052        final Map<Optional<Object>, List<Entry<String, ? extends Object>>> qualityToVal =
053                qualityMap.entrySet().stream()
054                .collect(Collectors.groupingBy(e -> ofNullable(e.getValue())));
055
056        // Join together all the groupings of q values to header values to produce final header
057        return qualityToVal.entrySet().stream()
058                .map(e -> {
059                    // Join together all the header values with the same q value
060                    final String joinedValues = e.getValue().stream()
061                            .map(Entry::getKey)
062                            .collect(Collectors.joining(","));
063                    // Add the q value if one was specified
064                    if (e.getKey().isPresent()) {
065                        return joinedValues + ";q=" + e.getKey().get();
066                    } else {
067                        return joinedValues;
068                    }
069                }) // join together the groupings
070                .collect(Collectors.joining(", "));
071    }
072
073    private HeaderHelpers() {
074    }
075}