io.reinert.requestor.uri.UriParser.java Source code

Java tutorial

Introduction

Here is the source code for io.reinert.requestor.uri.UriParser.java

Source

/*
 * Copyright 2015 Danilo Reinert
 *
 * 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.
 */
package io.reinert.requestor.uri;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.URL;

import io.reinert.requestor.LightMap;

/**
 * Parses a URI.
 */
public class UriParser {

    private String scheme;
    private String user;
    private String password;
    private String host;
    private int port = -1;
    private String[] segments;
    private Map<String, Buckets> matrixParams;
    private Buckets queryParams;
    private String fragment;

    public static UriParser newInstance() {
        return new UriParser();
    }

    private UriParser() {
    }

    public Uri getUri() {
        return new Uri(scheme, user, password, host, port, segments, matrixParams, queryParams, fragment);
    }

    public UriParser parse(String uri) {
        if (uri == null || uri.isEmpty())
            throw new UriParseException("The uri argument cannot be null or empty");

        resetParser();

        String parsedUri = uri;
        String query;
        int pos;

        // Extract fragment
        pos = parsedUri.indexOf('#');
        if (pos > -1) {
            // Check last char
            fragment = parsedUri.length() - pos == 1 ? null : URL.decode(parsedUri.substring(pos + 1));
            // Remove parsed part from parsing uri
            parsedUri = parsedUri.substring(0, pos);
        }

        // Extract query
        pos = parsedUri.indexOf('?');
        if (pos > -1) {
            // Check last char
            query = parsedUri.length() - pos == 1 ? null : parsedUri.substring(pos + 1);
            parseQuery(query);
            // Remove parsed part from parsing uri
            parsedUri = parsedUri.substring(0, pos);
        }

        // Extract protocol
        if (parsedUri.length() > 2 && parsedUri.substring(0, 2).equals("//")) {
            // Relative-Scheme
            scheme = null;
            parsedUri = parsedUri.substring(2);
            // Extract "user:pass@host:port"
            parsedUri = parseAuthority(parsedUri);
        } else {
            pos = parsedUri.indexOf("://");
            if (pos > -1) {
                scheme = pos > 0 ? parsedUri.substring(0, pos) : null;
                parsedUri = parsedUri.substring(pos + 3);

                // Extract "user:pass@host:port"
                parsedUri = parseAuthority(parsedUri);
            }
        }

        // The left part must be the path
        final List<String> parsedSegments = new ArrayList<String>();
        final String[] rawSegments = parsedUri.split("/");
        for (String segment : rawSegments) {
            if (!segment.isEmpty()) {
                String[] matrixParts = segment.split(";");
                final String parsedSegment = URL.decode(matrixParts[0]);
                parsedSegments.add(parsedSegment);
                if (matrixParts.length > 1) {
                    if (matrixParams == null) {
                        matrixParams = GWT.create(LightMap.class);
                    }
                    final Buckets buckets = GWT.create(Buckets.class);
                    matrixParams.put(parsedSegment, buckets);
                    for (int i = 1; i < matrixParts.length; i++) {
                        String[] matrixElements = matrixParts[i].split("=");
                        if (matrixElements.length == 1) {
                            buckets.add(URL.decode(matrixElements[0]), null);
                        } else {
                            buckets.add(URL.decode(matrixElements[0]), URL.decode(matrixElements[1]));
                        }
                    }
                }
            }
        }
        this.segments = parsedSegments.toArray(new String[parsedSegments.size()]);

        return this;
    }

    private String parseAuthority(String uri) {
        uri = parseUserInfo(uri);
        return parseHost(uri);
    }

    private String parseUserInfo(String uri) {
        // Extract username:password
        int pathDivider = uri.indexOf('/');
        int pos = uri.lastIndexOf('@', pathDivider > -1 ? pathDivider : uri.length() - 1);

        // authority@ must come before /path
        if (pos > -1 && (pathDivider == -1 || pos < pathDivider)) {
            String[] t = uri.substring(0, pos).split(":");
            user = !t[0].isEmpty() ? URL.decode(t[0]) : null;
            password = t.length > 1 && !t[1].isEmpty() ? URL.decode(t[1]) : null;
            uri = uri.substring(pos + 1);
        } else {
            user = null;
            password = null;
        }

        return uri;
    }

    private String parseHost(String uri) {
        // Extract host:port
        int pos = uri.indexOf('/');

        if (pos == -1)
            pos = uri.length();

        String[] authority = uri.substring(0, pos).split(":");
        host = !authority[0].isEmpty() ? authority[0] : null;
        port = authority.length > 1 && !authority[1].isEmpty() ? Integer.parseInt(authority[1]) : -1;

        return pos == uri.length() ? "/" : uri.substring(pos);
    }

    private void parseQuery(String query) {
        // throw out the funky business - "?"[name"="value"&"]+
        query = query.replaceAll("/&+/g", "&").replaceAll("/^\\?*&*|&+$/g", "");

        if (query.isEmpty())
            return;

        queryParams = GWT.create(Buckets.class);
        String[] p, pairs = query.split("&");
        String name, value;
        for (final String pair : pairs) {
            p = pair.split("=");
            name = URL.decodeQueryString(p[0]);
            // no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters
            value = p.length > 1 && !p[1].isEmpty() ? URL.decodeQueryString(p[1]) : null;
            queryParams.add(name, value);
        }
    }

    private void resetParser() {
        scheme = null;
        user = null;
        password = null;
        host = null;
        port = -1;
        segments = null;
        matrixParams = null;
        queryParams = null;
        fragment = null;
    }
}