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

com.github.jsonldjava.utils.JsonLdUrl Maven / Gradle / Ivy

There is a newer version: 0.10.4
Show newest version
/*
 * Copyright (c) 2012, Deutsche Forschungszentrum für Künstliche Intelligenz GmbH
 * Copyright (c) 2012-2017, JSONLD-Java contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the  nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.github.jsonldjava.utils;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * JsonLdUrl.
 *
 * @author @tristan
 * @author Peter Ansell [email protected]
 */
public class JsonLdUrl {

    private String href = "";
    private String protocol = "";
    private String host = "";
    private String auth = "";
    private String user = "";
    private String password = "";
    private String hostname = "";
    private String port = "";
    public String relative = "";
    String path = "";
    private String directory = "";
    public String file = "";
    public String query = "";
    private String hash = "";

    // things not populated by the regex (NOTE: i don't think it matters if
    // these are null or "" to start with)
    private String pathname = null;
    private String normalizedPath = null;
    private String authority = null;

    private static Pattern parser = Pattern.compile(
            "^(?:([^:\\/?#]+):)?(?:\\/\\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\\/?#]*)(?::(\\d*))"
                    + "?))?((("
                    + "(?:[^?#\\/]*\\/)*)([^?#]*))(?:\\?([^#]*))?(?:#(.*))?)");

    public static JsonLdUrl parse(String url) {
        final JsonLdUrl rval = new JsonLdUrl();
        rval.href = url;

        final Matcher matcher = parser.matcher(url);
        if (matcher.matches()) {
            if (matcher.group(1) != null) {
                rval.protocol = matcher.group(1);
            }
            if (matcher.group(2) != null) {
                rval.host = matcher.group(2);
            }
            if (matcher.group(3) != null) {
                rval.auth = matcher.group(3);
            }
            if (matcher.group(4) != null) {
                rval.user = matcher.group(4);
            }
            if (matcher.group(5) != null) {
                rval.password = matcher.group(5);
            }
            if (matcher.group(6) != null) {
                rval.hostname = matcher.group(6);
            }
            if (matcher.group(7) != null) {
                rval.port = matcher.group(7);
            }
            if (matcher.group(8) != null) {
                rval.relative = matcher.group(8);
            }
            if (matcher.group(9) != null) {
                rval.path = matcher.group(9);
            }
            if (matcher.group(10) != null) {
                rval.directory = matcher.group(10);
            }
            if (matcher.group(11) != null) {
                rval.file = matcher.group(11);
            }
            if (matcher.group(12) != null) {
                rval.query = matcher.group(12);
            }
            if (matcher.group(13) != null) {
                rval.hash = matcher.group(13);
            }

            // normalize to node.js API
            if (!"".equals(rval.host) && "".equals(rval.path)) {
                rval.path = "/";
            }
            rval.pathname = rval.path;
            parseAuthority(rval);
            rval.normalizedPath = removeDotSegments(rval.pathname, !"".equals(rval.authority));
            if (!"".equals(rval.query)) {
                rval.path += "?" + rval.query;
            }
            if (!"".equals(rval.protocol)) {
                rval.protocol += ":";
            }
            if (!"".equals(rval.hash)) {
                rval.hash = "#" + rval.hash;
            }
            return rval;
        }

        return rval;
    }

    /**
     * Removes dot segments from a JsonLdUrl path.
     *
     * @param path         the path to remove dot segments from.
     * @param hasAuthority true if the JsonLdUrl has an authority, false if not.
     * @return The URL without the dot segments
     */
    private static String removeDotSegments(String path, boolean hasAuthority) {
        StringBuilder rval = new StringBuilder();

        if (path.indexOf("/") == 0) {
            rval = new StringBuilder("/");
        }

        // RFC 3986 5.2.4 (reworked)
        final List input = new ArrayList<>(Arrays.asList(path.split("/")));
        if (path.endsWith("/")) {
            // javascript .split includes a blank entry if the string ends with
            // the delimiter, java .split does not so we need to add it manually
            input.add("");
        }
        final List output = new ArrayList<>();
        for (int i = 0; i < input.size(); i++) {
            if (".".equals(input.get(i)) || ("".equals(input.get(i)) && input.size() - i > 1)) {
                // input.remove(0);
                continue;
            }
            if ("..".equals(input.get(i))) {
                // input.remove(0);
                if (hasAuthority
                        || (output.size() > 0 && !"..".equals(output.get(output.size() - 1)))) {
                    // [].pop() doesn't fail, to replicate this we need to check
                    // that there is something to remove
                    if (output.size() > 0) {
                        output.remove(output.size() - 1);
                    }
                } else {
                    output.add("..");
                }
                continue;
            }
            output.add(input.get(i));
            // input.remove(0);
        }

        if (output.size() > 0) {
            rval.append(output.get(0));
            for (int i = 1; i < output.size(); i++) {
                rval.append("/").append(output.get(i));
            }
        }
        return rval.toString();
    }

    public static String removeBase(Object baseobj, String iri) {
        if (baseobj == null) {
            return iri;
        }

        JsonLdUrl base;
        if (baseobj instanceof String) {
            base = JsonLdUrl.parse((String) baseobj);
        } else {
            base = (JsonLdUrl) baseobj;
        }

        // establish base root
        String root = "";
        if (!"".equals(base.href)) {
            root += (base.protocol) + "//" + base.authority;
        }
        // support network-path reference with empty base
        else if (iri.indexOf("//") != 0) {
            root += "//";
        }

        // IRI not relative to base
        if (iri.indexOf(root) != 0) {
            return iri;
        }

        // remove root from IRI and parse remainder
        final JsonLdUrl rel = JsonLdUrl.parse(iri.substring(root.length()));

        // remove path segments that match
        final List baseSegments = new ArrayList<>(
                Arrays.asList(base.normalizedPath.split("/")));
        if (base.normalizedPath.endsWith("/")) {
            baseSegments.add("");
        }
        final List iriSegments = new ArrayList<>(
                Arrays.asList(rel.normalizedPath.split("/")));
        if (rel.normalizedPath.endsWith("/")) {
            iriSegments.add("");
        }

        while (baseSegments.size() > 0 && iriSegments.size() > 0) {
            if (!baseSegments.get(0).equals(iriSegments.get(0))) {
                break;
            }
            if (baseSegments.size() > 0) {
                baseSegments.remove(0);
            }
            if (iriSegments.size() > 0) {
                iriSegments.remove(0);
            }
        }

        // use '../' for each non-matching base segment
        StringBuilder rval = new StringBuilder();
        if (baseSegments.size() > 0) {
            // don't count the last segment if it isn't a path (doesn't end in
            // '/')
            // don't count empty first segment, it means base began with '/'
            if (!base.normalizedPath.endsWith("/") || "".equals(baseSegments.get(0))) {
                baseSegments.remove(baseSegments.size() - 1);
            }
            for (int i = 0; i < baseSegments.size(); ++i) {
                rval.append("../");
            }
        }

        // prepend remaining segments
        if (iriSegments.size() > 0) {
            rval.append(iriSegments.get(0));
        }
        for (int i = 1; i < iriSegments.size(); i++) {
            rval.append("/").append(iriSegments.get(i));
        }

        // add query and hash
        if (!"".equals(rel.query)) {
            rval.append("?").append(rel.query);
        }
        if (!"".equals(rel.hash)) {
            rval.append(rel.hash);
        }

        if ("".equals(rval.toString())) {
            rval = new StringBuilder("./");
        }

        return rval.toString();
    }

    public static String resolve(String baseUri, String pathToResolve) {
        // TODO: some input will need to be normalized to perform the expected
        // result with java
        // TODO: we can do this without using java URI!
        if (baseUri == null) {
            return pathToResolve;
        }
        if (pathToResolve == null || "".equals(pathToResolve.trim())) {
            return baseUri;
        }
        try {
            URI uri = new URI(baseUri);
            // query string parsing
            if (pathToResolve.startsWith("?")) {
                // drop fragment from uri if it has one
                if (uri.getFragment() != null) {
                    uri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), null, null);
                }
                // add query to the end manually (as URI.resolve does it wrong)
                return uri.toString() + pathToResolve;
            }

            uri = uri.resolve(pathToResolve);
            // java doesn't discard unnecessary dot segments
            String path = uri.getPath();
            if (path != null) {
                path = JsonLdUrl.removeDotSegments(uri.getPath(), true);
            }
            return new URI(uri.getScheme(), uri.getAuthority(), path, uri.getQuery(),
                    uri.getFragment()).toString();
        } catch (final URISyntaxException e) {
            return null;
        }
    }

    /**
     * Parses the authority for the pre-parsed given JsonLdUrl.
     *
     * @param parsed the pre-parsed JsonLdUrl.
     */
    private static void parseAuthority(JsonLdUrl parsed) {
        // parse authority for unparsed relative network-path reference
        if (!parsed.href.contains(":") && parsed.href.indexOf("//") == 0
                && "".equals(parsed.host)) {
            // must parse authority from pathname
            parsed.pathname = parsed.pathname.substring(2);
            final int idx = parsed.pathname.indexOf("/");
            if (idx == -1) {
                parsed.authority = parsed.pathname;
                parsed.pathname = "";
            } else {
                parsed.authority = parsed.pathname.substring(0, idx);
                parsed.pathname = parsed.pathname.substring(idx);
            }
        } else {
            // construct authority
            parsed.authority = parsed.host;
            if (!"".equals(parsed.auth)) {
                parsed.authority = parsed.auth + "@" + parsed.authority;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy