org.ldp4j.server.utils.CharsetPreference.java Source code

Java tutorial

Introduction

Here is the source code for org.ldp4j.server.utils.CharsetPreference.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.framework:ldp4j-server-core:0.2.1
 *   Bundle      : ldp4j-server-core-0.2.1.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.server.utils;

import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.CharMatcher;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.math.DoubleMath;

public final class CharsetPreference implements Comparable<CharsetPreference> {

    private static final int MAX_WEIGHT = 1000;
    private static final double MAX_WEIGHT_DOUBLE = 1000D;

    private static final char[] CTRL = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
            21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127 };

    private static final char[] SEPARATORS = { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '\"', '/', '[', ']',
            '?', '=', '{', '}', ' ', '\t' };

    private static final CharMatcher TOKEN_MATCHER = CharMatcher.ASCII.and(CharMatcher.noneOf(new String(CTRL)))
            .and(CharMatcher.noneOf(new String(SEPARATORS)));

    private static final Pattern QUALITY_PATTERN = Pattern.compile("(q|Q)=((1\\.0{0,3})|(0\\.\\d{0,3}))");
    private static final DecimalFormat FORMAT;

    static {
        DecimalFormat format = new DecimalFormat("0", new DecimalFormatSymbols(Locale.ENGLISH));
        format.setMaximumFractionDigits(3);
        FORMAT = format;
    }

    private final String charset;
    private final int weight;

    public CharsetPreference(String charset, int weight) {
        this.charset = charset;
        this.weight = weight;
    }

    public String charset() {
        return this.charset;
    }

    public double weight() {
        return this.weight / MAX_WEIGHT_DOUBLE;
    }

    public boolean isWildcard() {
        return "*".equals(this.charset);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return Objects.hash(this.charset, this.weight);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object obj) {
        boolean result = false;
        if (obj instanceof CharsetPreference) {
            final CharsetPreference that = (CharsetPreference) obj;
            result = Objects.equals(this.charset, that.charset) && Objects.equals(this.weight, that.weight);
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return this.charset + (this.weight == MAX_WEIGHT ? ""
                : " ; q=" + FORMAT.format((float) this.weight / (float) MAX_WEIGHT));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int compareTo(CharsetPreference o) {
        return this.weight - o.weight;
    }

    /** Create a charset preference that matches the following grammar:
     *  <pre>       {@code
        CHAR           = <any US-ASCII character (octets 0 - 127)>
        DIGIT          = <any US-ASCII digit "0".."9">
        CTL            = <any US-ASCII control character
                    (octets 0 - 31) and DEL (127)>
        SP             = <US-ASCII SP, space (32)>
        HT             = <US-ASCII HT, horizontal-tab (9)>
        <">            = <US-ASCII double-quote mark (34)>
        token          = 1*<any CHAR except CTLs or separators>
        separators     = "(" | ")" | "<" | ">" | "@"
                  | "," | ";" | ":" | "\" | <">
                  | "/" | "[" | "]" | "?" | "="
                  | "{" | "}" | SP | HT
        charset        = token
        qvalue         = ( "0" [ "." 0*3DIGIT ] )
                  | ( "1" [ "." 0*3("0") ] )
        preference     = ( charset | "*" )[ ";" "q" "=" qvalue ]}</pre>
     */
    public static CharsetPreference valueOf(String str) {
        String[] parts = str.split(";");
        if (parts.length <= 2) {
            String charsetName = parts[0].trim();
            if ("*".equals(charsetName) || TOKEN_MATCHER.matchesAllOf(charsetName)) {
                int weight = MAX_WEIGHT;
                if (parts.length == 2) {
                    String weightValue = parts[1].trim();
                    Matcher matcher = QUALITY_PATTERN.matcher(weightValue);
                    if (!matcher.matches()) {
                        return null;
                    }
                    if (weightValue.charAt(2) == '0') {
                        weight = Integer.parseInt(Strings.padEnd(weightValue.substring(4), 3, '0'));
                    }
                }
                return new CharsetPreference(charsetName, weight);
            }
        }
        return null;
    }

    public static CharsetPreference wildcard() {
        return new CharsetPreference("*", MAX_WEIGHT);
    }

    public static CharsetPreference wildcard(double weight) {
        return new CharsetPreference("*", round(weight));
    }

    public static CharsetPreference create(Charset charset) {
        Objects.requireNonNull(charset, "Charset cannot be null");
        return new CharsetPreference(charset.name(), MAX_WEIGHT);
    }

    public static CharsetPreference create(Charset charset, double weight) {
        Objects.requireNonNull(charset, "Charset cannot be null");
        return new CharsetPreference(charset.name(), round(weight));
    }

    static int round(double weight) {
        Preconditions.checkArgument(weight >= 0D, "Weight must be greater than or equal to 0 (%s)", weight);
        Preconditions.checkArgument(weight <= 1D, "Weight must be lower than or equal to 1 (%s)", weight);
        return DoubleMath.roundToInt(weight * MAX_WEIGHT_DOUBLE, RoundingMode.DOWN);
    }

}