All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.fge.uritemplate.vars.specs.VariableSpec Maven / Gradle / Ivy

There is a newer version: 0.9
Show newest version
package com.github.fge.uritemplate.vars.specs;

import com.github.fge.uritemplate.URITemplateException;
import com.github.fge.uritemplate.expression.ExpressionType;
import com.github.fge.uritemplate.vars.values.VariableValue;
import com.google.common.base.CharMatcher;
import com.google.common.primitives.UnsignedBytes;

import java.nio.charset.Charset;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;

import static com.github.fge.uritemplate.expression.ExpressionType.*;

/*
 * TODO: intelligence here
 *
 * A varspec has all the necessary elements to render according to the needs. It
 * needs two elements to operate:
 *
 * - the type of the value;
 * - the type of the expression.
 *
 * According to its own, internal information, its rendering method (name to be
 * decided) should be able to return a String to the caller with the appropriate
 * contents.
 */
public abstract class VariableSpec
{
    protected static final EnumSet PARAM_STYLE_EXPRESSIONS
        = EnumSet.of(PATH_PARAMETERS, QUERY_STRING, QUERY_CONT);
    private static final CharMatcher UNRESERVED;
    private static final CharMatcher RESERVED_PLUS_UNRESERVED;

    static {
        /*
         * Charsets defined by RFC 6570, section 1.5
         */
        // reserved
        final CharMatcher reserved = CharMatcher.inRange('a', 'z')
            .or(CharMatcher.inRange('A', 'Z'))
            .or(CharMatcher.inRange('0', '9'))
            .or(CharMatcher.anyOf("-._~"));
        // gen-delims
        final CharMatcher genDelims = CharMatcher.anyOf(":/?#[]@");
        // sub-delims
        final CharMatcher subDelims = CharMatcher.anyOf("!$&'()*+,;=");
        UNRESERVED = reserved.precomputed();
        // "reserved" is gen-delims or sub-delims
        RESERVED_PLUS_UNRESERVED = reserved.or(genDelims).or(subDelims)
            .precomputed();
    }

    protected final VariableSpecType type;
    protected final String name;

    protected VariableSpec(final VariableSpecType type, final String name)
    {
        this.type = type;
        this.name = name;
    }

    public final VariableSpecType getType()
    {
        return type;
    }

    public final String getName()
    {
        return name;
    }

    public final String render(final ExpressionType type,
        final VariableValue value)
        throws URITemplateException
    {
        switch (value.getType()) {
            case SCALAR:
                return renderScalar(type, value.getScalarValue());
            case ARRAY:
                return renderList(type, value.getListValue());
            case MAP:
                return renderMap(type, value.getMapValue());
        }

        throw new RuntimeException("How did I get there?");
    }

    protected abstract String renderScalar(final ExpressionType type,
        final String value)
        throws URITemplateException;

    protected abstract String renderList(final ExpressionType type,
        final List value)
        throws URITemplateException;

    protected abstract String renderMap(final ExpressionType type,
        final Map map)
        throws URITemplateException;

    @Override
    public abstract int hashCode();

    @Override
    public abstract boolean equals(final Object obj);

    @Override
    public abstract String toString();

    protected static String expandString(final ExpressionType type,
        final String s)
    {
        final CharMatcher matcher = type.isRawExpand()
            ? RESERVED_PLUS_UNRESERVED : UNRESERVED;
        final StringBuilder sb = new StringBuilder(s.length());
        for (final char c: s.toCharArray())
            sb.append(matcher.matches(c) ? c : pctEncode(c));
        return sb.toString();
    }

    private static String pctEncode(final char c)
    {
        final String tmp = new String(new char[] { c });
        final byte[] bytes = tmp.getBytes(Charset.forName("UTF-8"));
        final StringBuilder sb = new StringBuilder();
        for (final byte b: bytes)
            sb.append('%').append(UnsignedBytes.toString(b, 16));
        return sb.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy