ch.entwine.weblounge.common.url.UrlUtils.java Source code

Java tutorial

Introduction

Here is the source code for ch.entwine.weblounge.common.url.UrlUtils.java

Source

/*
 *  Weblounge: Web Content Management System
 *  Copyright (c) 2003 - 2011 The Weblounge Team
 *  http://entwinemedia.com/weblounge
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software Foundation
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

package ch.entwine.weblounge.common.url;

import ch.entwine.weblounge.common.site.Site;

import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.TreeSet;

import javax.servlet.http.HttpServletRequest;

/**
 * <code>UrlUtils</code> is a helper class to deal with urls.
 */
public final class UrlUtils {

    /**
     * This class should not be instantiated, since it provides static utility
     * methods only.
     */
    private UrlUtils() {
        // Nothing to be done here
    }

    /**
     * Sorts the given urls by path.
     * 
     * @param urls
     *          the urls to sort
     * @return the sorted urls
     */
    public static String[] sort(String[] urls) {
        TreeSet<String> set = new TreeSet<String>();
        for (int i = 0; i < urls.length; i++)
            set.add(urls[i]);
        String[] result = new String[urls.length];
        Iterator<String> i = set.iterator();
        int index = 0;
        while (i.hasNext()) {
            result[index++] = i.toString();
        }
        return result;
    }

    /**
     * Concatenates the url elements with respect to leading and trailing slashes.
     * The path will always end with a trailing slash.
     * 
     * @param urlElements
     *          the path elements
     * @return the concatenated url of the two arguments
     * @throws IllegalArgumentException
     *           if less than two path elements are provided
     */
    public static String concat(String... urlElements) throws IllegalArgumentException {
        if (urlElements == null || urlElements.length < 1)
            throw new IllegalArgumentException("Prefix cannot be null or empty");
        if (urlElements.length < 2)
            throw new IllegalArgumentException("Suffix cannot be null or empty");

        StringBuffer b = new StringBuffer();
        for (String s : urlElements) {
            if (StringUtils.isBlank(s))
                throw new IllegalArgumentException("Path element cannot be null");
            String element = checkSeparator(s);
            element = removeDoubleSeparator(element);

            if (b.length() == 0) {
                b.append(element);
            } else if (b.lastIndexOf("/") < b.length() - 1 && !element.startsWith("/")) {
                b.append("/").append(element);
            } else if (b.lastIndexOf("/") == b.length() - 1 && element.startsWith("/")) {
                b.append(element.substring(1));
            } else {
                b.append(element);
            }
        }

        return b.toString();
    }

    /**
     * Returns the trimmed url. Trimmed means that the url is free from leading or
     * trailing whitespace characters, and that a directory url like
     * <code>/news/</code> is closed by a slash (<code>/</code>).
     * 
     * @param url
     *          the url to trim
     * @return the trimmed url
     */
    public static String trim(String url) {
        if (url == null)
            throw new IllegalArgumentException("Url cannot be null");

        url = checkSeparator(url);
        url = removeDoubleSeparator(url);
        url = url.trim();

        if (url.endsWith("/") || (url.length() == 1))
            return url;

        int index = url.lastIndexOf("/");
        int dotIndex = url.indexOf(".", index);
        int anchorIndex = url.indexOf("#", index);
        if (dotIndex == -1 && anchorIndex == -1)
            url += "/";
        return url;
    }

    /**
     * Returns the link created from the given partition and path. This link will
     * include the weblounge mountpoint.
     * 
     * @param site
     *          the associated site
     * @param path
     *          the database path
     * @return the link
     */
    public static String getLink(Site site, String path) {
        return path;
    }

    /**
     * Checks that the path only contains the web path separator "/". If not,
     * wrong ones are replaced.
     */
    private static String checkSeparator(String path) {
        String sp = File.separator;
        if ("\\".equals(sp))
            sp = "\\\\";
        return path.replaceAll(sp, "/");
    }

    /**
     * Removes any occurrence of double separators ("//") and replaces it with
     * "/".
     * 
     * @param path
     *          the path to check
     * @return the corrected path
     */
    private static String removeDoubleSeparator(String path) {
        int protocolIndex = path.indexOf("://");
        protocolIndex += protocolIndex == -1 ? 0 : 3;
        int index = Math.max(0, protocolIndex);
        while ((index = path.indexOf("//", index)) != -1) {
            path = path.substring(0, index) + path.substring(index + 1);
        }
        return path;
    }

    /**
     * Returns <code>true</code> if url <code>a</code> is a direct prefix of url
     * <code>b</code>. For example, <code>/news</code> is the parent of
     * <code>/news/today</code>.
     * <p>
     * Note that <code>a</code> is also an extended prefix of <code>b</code> if
     * <code>a</code> and <code>b</code> are equal.
     * 
     * @param a
     *          the first url
     * @param b
     *          the second url
     * @return <code>true</code> if <code>a</code> is the direct prefix of
     *         <code>b</code>
     */
    public static boolean isPrefix(String a, String b) {
        if (isExtendedPrefix(a, b)) {
            if (a.length() < b.length()) {
                String bRest = b.substring(a.length() + 1);
                if (bRest.endsWith("/"))
                    bRest = bRest.substring(0, bRest.length() - 2);
                return bRest.indexOf("/", 1) < 0;
            } else {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns <code>true</code> if url <code>a</code> is a prefix of url
     * <code>b</code>. For example, <code>/news</code> is an ancestor of
     * <code>/news/today/morning</code>.
     * <p>
     * Note that <code>a</code> is also an extended prefix of <code>b</code> if
     * <code>a</code> and <code>b</code> are equal.
     * 
     * @param a
     *          the first url
     * @param b
     *          the second url
     * @return <code>true</code> if <code>a</code> is a prefix of <code>b</code>
     */
    public static boolean isExtendedPrefix(String a, String b) {
        if (b.startsWith(a)) {
            if (b.length() > a.length())
                return a.endsWith("/") || b.substring(a.length()).startsWith("/");
            else
                return true;
        }
        return false;
    }

    /**
     * Returns the url extension that <code>url</code> defines over
     * <code>prefix</code>. For example, the extension of url
     * <code>/news/today</code> and prefix <code>/news</code> is
     * <code>today</code>.
     * <p>
     * If <code>prefix</code> is not a prefix of <code>url</code>, this method
     * returns <code>null</code>, if <code>url</code> and <code>prefix</code>
     * match, the empty string is returned.
     * 
     * @param prefix
     *          the url prefix
     * @param url
     *          the url
     * @return the url extension over the prefix
     */
    public static String getExtension(String prefix, String url) {
        prefix = prefix.trim();
        if (isExtendedPrefix(prefix, url)) {
            if (url.length() > prefix.length()) {
                String extension = url.substring(prefix.length() + 1);
                if (extension.endsWith("/")) {
                    extension = extension.substring(0, extension.length() - 1);
                }
                return extension;
            } else
                return "";
        }
        return null;
    }

    /**
     * Returns the extension that is encoded into the url. Possible extensions
     * are:
     * <ul>
     * <li>/*</li>
     * <li>/**</li>
     * <li><code>null</code></li>
     * </ul>
     * 
     * @param url
     *          the url with extension
     * @return the url extension or <code>null</code> if no extension can be found
     */
    public static String getExtension(String url) {
        if (url.endsWith("/**"))
            return "/**";
        else if (url.endsWith("/*"))
            return "/*";
        else
            return null;
    }

    /**
     * Strips off the extension and returns the pure url.
     * 
     * @param url
     *          the url with extension
     * @return the url
     */
    public static String stripExtension(String url) {
        String extension = getExtension(url);
        if (extension == null)
            return url;
        else
            return url.substring(0, url.length() - extension.length());
    }

    /**
     * Returns <code>true</code> if the url is valid, that is, if it contains only
     * allowed characters.
     * 
     * @return <code>true</code> or the invalid character
     */
    public static boolean isValid(String url) {
        return (checkUrl(url) == null);
    }

    /**
     * Returns <code>null</code> if the url is valid, that is, if it contains only
     * allowed characters. otherwise, the invalid character is returned.
     * 
     * @return <code>null</code> or the invalid character
     */
    public static Character getInvalidCharacter(String url) {
        Character c = checkUrl(url);
        return c;
    }

    /**
     * Returns <code>null</code> if the url is valid, that is, if it contains only
     * allowed characters. otherwise, the invalid character is returned.
     * 
     * @return <code>null</code> or the invalid character
     */
    private static Character checkUrl(String url) {
        StringBuffer original = new StringBuffer(url);
        for (int i = 0; i < original.length(); i++) {
            int value = original.charAt(i);
            // a-z
            if (value >= 'a' && value <= 'z') {
                continue;
            }
            // A-Z
            if (value >= 'A' && value <= 'Z') {
                continue;
            }
            // 0-9
            if (value >= '0' && value <= '9') {
                continue;
            }
            // Special characters
            if (value == '-' || value == '_' || value == '.' || value == ',' || value == ';') {
                continue;
            }
            return original.charAt(i);
        }
        return null;
    }

    /**
     * Returns the request url as a string.
     * 
     * @param request
     *          the request
     * @param includePath
     *          <code>true</code> to also include the request uri
     * @param includeQuery
     *          <code>true</code> to include the query string
     * @return the url as a string
     */
    public static URL toURL(HttpServletRequest request, boolean includePath, boolean includeQuery) {
        try {
            StringBuffer buf = new StringBuffer(request.getScheme());
            buf.append("://");
            buf.append(request.getServerName());
            if (request.getServerPort() != 80)
                buf.append(":").append(request.getServerPort());
            if (includePath && request.getRequestURI() != null)
                buf.append(request.getRequestURI());
            if (includeQuery && StringUtils.isNotBlank(request.getQueryString()))
                buf.append(request.getQueryString());
            return new URL(buf.toString());
        } catch (MalformedURLException e) {
            throw new IllegalStateException(e);
        }
    }

}