ca.uhn.fhir.util.UrlUtil.java Source code

Java tutorial

Introduction

Here is the source code for ca.uhn.fhir.util.UrlUtil.java

Source

package ca.uhn.fhir.util;

import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;

import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

/*
 * #%L
 * HAPI FHIR - Core Library
 * %%
 * Copyright (C) 2014 - 2016 University Health Network
 * %%
 * 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.
 * #L%
 */

public class UrlUtil {
    private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UrlUtil.class);

    /**
     * Resolve a relative URL - THIS METHOD WILL NOT FAIL but will log a warning and return theEndpoint if the input is invalid.
     */
    public static String constructAbsoluteUrl(String theBase, String theEndpoint) {
        if (theEndpoint == null) {
            return null;
        }
        if (isAbsolute(theEndpoint)) {
            return theEndpoint;
        }
        if (theBase == null) {
            return theEndpoint;
        }

        try {
            return new URL(new URL(theBase), theEndpoint).toString();
        } catch (MalformedURLException e) {
            ourLog.warn(
                    "Failed to resolve relative URL[" + theEndpoint + "] against absolute base[" + theBase + "]",
                    e);
            return theEndpoint;
        }
    }

    public static String constructRelativeUrl(String theParentExtensionUrl, String theExtensionUrl) {
        if (theParentExtensionUrl == null) {
            return theExtensionUrl;
        }
        if (theExtensionUrl == null) {
            return theExtensionUrl;
        }

        int parentLastSlashIdx = theParentExtensionUrl.lastIndexOf('/');
        int childLastSlashIdx = theExtensionUrl.lastIndexOf('/');

        if (parentLastSlashIdx == -1 || childLastSlashIdx == -1) {
            return theExtensionUrl;
        }

        if (parentLastSlashIdx != childLastSlashIdx) {
            return theExtensionUrl;
        }

        if (!theParentExtensionUrl.substring(0, parentLastSlashIdx)
                .equals(theExtensionUrl.substring(0, parentLastSlashIdx))) {
            return theExtensionUrl;
        }

        if (theExtensionUrl.length() > parentLastSlashIdx) {
            return theExtensionUrl.substring(parentLastSlashIdx + 1);
        }

        return theExtensionUrl;
    }

    /**
     * URL encode a value
     */
    public static String escape(String theValue) {
        if (theValue == null) {
            return null;
        }
        try {
            return URLEncoder.encode(theValue, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new Error("UTF-8 not supported on this platform");
        }
    }

    public static boolean isAbsolute(String theValue) {
        String value = theValue.toLowerCase();
        return value.startsWith("http://") || value.startsWith("https://");
    }

    public static boolean isValid(String theUrl) {
        if (theUrl == null || theUrl.length() < 8) {
            return false;
        }

        String url = theUrl.toLowerCase();
        if (url.charAt(0) != 'h') {
            return false;
        }
        if (url.charAt(1) != 't') {
            return false;
        }
        if (url.charAt(2) != 't') {
            return false;
        }
        if (url.charAt(3) != 'p') {
            return false;
        }
        int slashOffset;
        if (url.charAt(4) == ':') {
            slashOffset = 5;
        } else if (url.charAt(4) == 's') {
            if (url.charAt(5) != ':') {
                return false;
            }
            slashOffset = 6;
        } else {
            return false;
        }

        if (url.charAt(slashOffset) != '/') {
            return false;
        }
        if (url.charAt(slashOffset + 1) != '/') {
            return false;
        }

        return true;
    }

    public static void main(String[] args) {
        System.out.println(escape("http://snomed.info/sct?fhir_vs=isa/126851005"));
    }

    public static Map<String, String[]> parseQueryString(String theQueryString) {
        HashMap<String, List<String>> map = new HashMap<String, List<String>>();
        parseQueryString(theQueryString, map);
        return toQueryStringMap(map);
    }

    public static Map<String, String[]> parseQueryStrings(String... theQueryString) {
        HashMap<String, List<String>> map = new HashMap<String, List<String>>();
        for (String next : theQueryString) {
            parseQueryString(next, map);
        }
        return toQueryStringMap(map);
    }

    private static Map<String, String[]> toQueryStringMap(HashMap<String, List<String>> map) {
        HashMap<String, String[]> retVal = new HashMap<String, String[]>();
        for (Entry<String, List<String>> nextEntry : map.entrySet()) {
            retVal.put(nextEntry.getKey(), nextEntry.getValue().toArray(new String[nextEntry.getValue().size()]));
        }
        return retVal;
    }

    private static void parseQueryString(String theQueryString, HashMap<String, List<String>> map) {
        String query = theQueryString;
        if (query.startsWith("?")) {
            query = query.substring(1);
        }

        StringTokenizer tok = new StringTokenizer(query, "&");
        while (tok.hasMoreTokens()) {
            String nextToken = tok.nextToken();
            if (isBlank(nextToken)) {
                continue;
            }

            int equalsIndex = nextToken.indexOf('=');
            String nextValue;
            String nextKey;
            if (equalsIndex == -1) {
                nextKey = nextToken;
                nextValue = "";
            } else {
                nextKey = nextToken.substring(0, equalsIndex);
                nextValue = nextToken.substring(equalsIndex + 1);
            }

            nextKey = unescape(nextKey);
            nextValue = unescape(nextValue);

            List<String> list = map.get(nextKey);
            if (list == null) {
                list = new ArrayList<String>();
                map.put(nextKey, list);
            }
            list.add(nextValue);
        }
    }

    //@formatter:off
    /** 
     * Parse a URL in one of the following forms:
     * <ul>
     * <li>[Resource Type]?[Search Params]
     * <li>[Resource Type]/[Resource ID]
     * <li>[Resource Type]/[Resource ID]/_history/[Version ID]
     * </ul>
     */
    //@formatter:on
    public static UrlParts parseUrl(String theUrl) {
        String url = theUrl;
        UrlParts retVal = new UrlParts();
        if (url.startsWith("http")) {
            if (url.startsWith("/")) {
                url = url.substring(1);
            }

            int qmIdx = url.indexOf('?');
            if (qmIdx != -1) {
                retVal.setParams(defaultIfBlank(url.substring(qmIdx + 1), null));
                url = url.substring(0, qmIdx);
            }

            IdDt id = new IdDt(url);
            retVal.setResourceType(id.getResourceType());
            retVal.setResourceId(id.getIdPart());
            retVal.setVersionId(id.getVersionIdPart());
            return retVal;
        } else {
            if (url.matches("\\/[a-zA-Z]+\\?.*")) {
                url = url.substring(1);
            }
            int nextStart = 0;
            boolean nextIsHistory = false;

            for (int idx = 0; idx < url.length(); idx++) {
                char nextChar = url.charAt(idx);
                boolean atEnd = (idx + 1) == url.length();
                if (nextChar == '?' || nextChar == '/' || atEnd) {
                    int endIdx = (atEnd && nextChar != '?') ? idx + 1 : idx;
                    String nextSubstring = url.substring(nextStart, endIdx);
                    if (retVal.getResourceType() == null) {
                        retVal.setResourceType(nextSubstring);
                    } else if (retVal.getResourceId() == null) {
                        retVal.setResourceId(nextSubstring);
                    } else if (nextIsHistory) {
                        retVal.setVersionId(nextSubstring);
                    } else {
                        if (nextSubstring.equals(Constants.URL_TOKEN_HISTORY)) {
                            nextIsHistory = true;
                        } else {
                            throw new InvalidRequestException("Invalid FHIR resource URL: " + url);
                        }
                    }
                    if (nextChar == '?') {
                        if (url.length() > idx + 1) {
                            retVal.setParams(url.substring(idx + 1, url.length()));
                        }
                        break;
                    }
                    nextStart = idx + 1;
                }
            }

            return retVal;
        }
    }

    public static String unescape(String theString) {
        if (theString == null) {
            return null;
        }
        for (int i = 0; i < theString.length(); i++) {
            char nextChar = theString.charAt(i);
            if (nextChar == '%' || nextChar == '+') {
                try {
                    return URLDecoder.decode(theString, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new Error("UTF-8 not supported, this shouldn't happen", e);
                }
            }
        }
        return theString;
    }

    public static class UrlParts {
        private String myParams;
        private String myResourceId;
        private String myResourceType;
        private String myVersionId;

        public String getParams() {
            return myParams;
        }

        public String getResourceId() {
            return myResourceId;
        }

        public String getResourceType() {
            return myResourceType;
        }

        public String getVersionId() {
            return myVersionId;
        }

        public void setParams(String theParams) {
            myParams = theParams;
        }

        public void setResourceId(String theResourceId) {
            myResourceId = theResourceId;
        }

        public void setResourceType(String theResourceType) {
            myResourceType = theResourceType;
        }

        public void setVersionId(String theVersionId) {
            myVersionId = theVersionId;
        }
    }

}