org.ldp4j.http.AlternativeEvaluation.java Source code

Java tutorial

Introduction

Here is the source code for org.ldp4j.http.AlternativeEvaluation.java

Source

/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *             http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.commons:ldp4j-commons-http:0.2.1
 *   Bundle      : ldp4j-commons-http-0.2.1.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.http;

import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;

import com.google.common.base.MoreObjects;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

final class AlternativeEvaluation {

    private static final class AttributeQuality<T extends Negotiable> {

        private final Quality quality;
        private final Weighted<T> value;

        private AttributeQuality(final Quality quality, final Weighted<T> value) {
            this.quality = quality;
            this.value = value;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(getClass()).omitNullValues().add("quality", this.quality)
                    .add("value", this.value).toString();
        }

        static <T extends Negotiable> AttributeQuality<T> create(double weight) {
            return new AttributeQuality<>(Qualities.definite(weight), null);
        }

        static <T extends Negotiable> AttributeQuality<T> create(Weighted<T> value) {
            final Quality quality = value.entity().isWildcard() ? Qualities.speculative(value.weight())
                    : Qualities.definite(value.weight());
            return new AttributeQuality<>(quality, value);
        }

        static <T extends Negotiable> AttributeQuality<T> create(double weight, Weighted<T> value) {
            return new AttributeQuality<>(Qualities.definite(weight), value);
        }

    }

    private interface Matcher<T> {
        boolean includes(T t1, T t2);
    }

    private static final class MediaTypeMatcher implements Matcher<MediaType> {
        private static final MediaTypeMatcher INSTANCE = new MediaTypeMatcher();

        @Override
        public boolean includes(MediaType t1, MediaType t2) {
            return MediaTypes.includes(t1, t2);
        }
    }

    private static final class CharacterEncodingMatcher implements Matcher<CharacterEncoding> {
        private static final CharacterEncodingMatcher INSTANCE = new CharacterEncodingMatcher();

        @Override
        public boolean includes(CharacterEncoding t1, CharacterEncoding t2) {
            return CharacterEncodings.includes(t1, t2);
        }
    }

    private static final class LanguageMatcher implements Matcher<Language> {
        private static final LanguageMatcher INSTANCE = new LanguageMatcher();

        @Override
        public boolean includes(Language t1, Language t2) {
            return Languages.includes(t1, t2);
        }
    }

    static final Comparator<AlternativeEvaluation> COMPARATOR = new Comparator<AlternativeEvaluation>() {
        @Override
        public int compare(AlternativeEvaluation o1, AlternativeEvaluation o2) {
            int comparison = o2.quality.compareTo(o1.quality);
            if (comparison != 0) {
                return comparison;
            }
            return AlternativeComparator.INSTANCE.compare(o2.alternative, o1.alternative);
        }
    };

    private final ImmutableAlternative alternative;
    private final boolean predefined;

    private AttributeQuality<MediaType> qt;
    private AttributeQuality<CharacterEncoding> qc;
    private AttributeQuality<Language> ql;
    private ImmutableQuality quality;

    private AlternativeEvaluation(boolean predefined, ImmutableAlternative alternative) {
        this.predefined = predefined;
        this.alternative = alternative;
    }

    ImmutableAlternative alternative() {
        return this.alternative;
    }

    ImmutableQuality quality() {
        return this.quality;
    }

    ImmutableVariant variant() {
        ImmutableVariant selection = null;
        if (this.predefined) {
            selection = ImmutableVariant.copyOf(this.alternative);
        } else {
            final MediaType mediaType = normalize(this.alternative.type(), ContentNegotiator.DEFAULT_MEDIA_TYPE);
            final CharacterEncoding charset = normalize(this.alternative.charset(),
                    ContentNegotiator.DEFAULT_CHARACTER_ENCODING);
            final Language language = normalize(this.alternative.language(), ContentNegotiator.DEFAULT_LANGUAGE);
            selection = ImmutableVariant.newInstance().type(mediaType).charset(charset).language(language);
        }
        return selection;
    }

    void evaluate(List<Weighted<MediaType>> accepts, List<Weighted<CharacterEncoding>> acceptCharsets,
            List<Weighted<Language>> acceptLanguages) {
        final Quality qs = Qualities.definite(this.alternative.quality());
        this.qt = computeMediaTypeQuality(accepts);
        this.qc = computeCharsetQuality(acceptCharsets);
        this.ql = computeLanguageQuality(acceptLanguages);
        this.quality = combine(qs, this.qt.quality, this.qc.quality, this.ql.quality);
    }

    private AttributeQuality<MediaType> computeMediaTypeQuality(List<Weighted<MediaType>> acceptable) {
        return computeAttributeQuality(this.alternative.type(), acceptable, MediaTypeMatcher.INSTANCE,
                MediaTypeComparator.INSTANCE);
    }

    private AttributeQuality<CharacterEncoding> computeCharsetQuality(
            List<Weighted<CharacterEncoding>> acceptable) {
        return computeAttributeQuality(this.alternative.charset(), acceptable, CharacterEncodingMatcher.INSTANCE,
                CharacterEncodingComparator.INSTANCE);
    }

    private AttributeQuality<Language> computeLanguageQuality(List<Weighted<Language>> acceptable) {
        return computeAttributeQuality(this.alternative.language(), acceptable, LanguageMatcher.INSTANCE,
                LanguageComparator.INSTANCE);
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(getClass()).omitNullValues().add("predefined", this.predefined)
                .add("alternative", this.alternative).add("qt", this.qt).add("qc", this.qc).add("ql", this.ql)
                .add("quality", this.quality).toString();
    }

    static AlternativeEvaluation predefined(Alternative alternative) {
        return new AlternativeEvaluation(true, ImmutableAlternative.copyOf(alternative));
    }

    static AlternativeEvaluation generated(ImmutableAlternative alternative) {
        return new AlternativeEvaluation(false, alternative);
    }

    private static <T extends Negotiable> T normalize(T original, T defaultValue) {
        T result = original;
        if (result == null) {
            result = defaultValue;
        }
        return result;
    }

    private static <T extends Negotiable> AttributeQuality<T> computeAttributeQuality(T attribute,
            List<Weighted<T>> acceptable, Matcher<T> matcher, Comparator<T> comparator) {
        if (attribute == null) {
            return AttributeQuality.create(1.0D, getPreferredValue(acceptable, comparator));
        }
        if (acceptable.isEmpty()) {
            return AttributeQuality.create(1.0D);
        }
        final SortedSet<Weighted<T>> compatible = Sets.newTreeSet(WeightedComparator.create(comparator));
        for (Weighted<T> accept : acceptable) {
            if (matcher.includes(accept.entity(), attribute)) {
                compatible.add(accept);
            }
        }
        if (compatible.isEmpty()) {
            return AttributeQuality.create(0.0D);
        }
        return AttributeQuality.create(Iterables.get(compatible, 0));
    }

    private static <T extends Negotiable> Weighted<T> getPreferredValue(List<Weighted<T>> accepts,
            Comparator<T> comparator) {
        final SortedSet<Weighted<T>> sortedAccepts = Sets.newTreeSet(WeightedComparator.create(comparator));
        sortedAccepts.addAll(accepts);
        Weighted<T> first = Iterables.getFirst(sortedAccepts, null);
        if (first != null && first.entity().isWildcard()) {
            first = null;
        }
        return first;
    }

    private static ImmutableQuality combine(Quality... qualities) {
        Quality.Type type = Quality.Type.DEFINITE;
        double weight = 1.0D;
        for (Quality quality : qualities) {
            if (Quality.Type.DEFINITE.equals(type)) {
                type = quality.type();
            }
            weight *= quality.weight();
        }
        return ImmutableQuality.create(type, weight);
    }

}