blob: 756ab7b507feba9e0e4f99bf25990e393f3df84a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010-2014 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.commons;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class URLUtils {
// no instances, please!
private URLUtils() {
}
/**
* Utility method to convert an enumeration of URLs to a corresponding list.
*
* @param u the enumeration to evaluate, or <code>null</code>.
* @return a list if URLs, or an empty list.
*/
public static List<URL> asURLs(Enumeration<URL> u) {
List<URL> ret = new LinkedList<URL>();
if (u != null) {
while (u.hasMoreElements()) {
URL url = u.nextElement();
ret.add(url);
}
}
return ret;
}
/**
* Composes a {@link URI} from a given web locator and path.
* <p>
* This method is equivalent to {@link #asURI(String, String, String)
* asURI(webLocator, resourcePath, null)}.
*
* @param webLocator the web locator, e.g. <tt>http://localhost:8080</tt>. May be
* <code>null</code> or blank.
* @param resourcePath the absolute path of a resource, may be <code>null</code> or blank.
* A blank path will be interpreted as root path "/". If the path is not beginning with
* a slash it will be added on the fly.
*
* @return a URI, or <code>null</code> if the given resource path was <code>null</code>.
*/
public static URI asURI(String webLocator, String resourcePath) {
return asURI(webLocator, resourcePath, null);
}
/**
* Composes a {@link URI} from a given web locator, resource path and an optional query.
* <p>
* If the web locator is not specified, a <tt>file://</tt> URI will be returned.
* Otherwise web locator, path and query are concatenated and converted to
* an URI with {@link URI#URI(String)}. If that fails, the concatenated string is
* first converted to an {@link URL} with {@link URL#URL(String)} and then to an
* URI with {@link URI#URI(String, String, String, int, String, String, String)}.
* This sanitizes some otherwise broken URIs and properly encodes the path segments.
*
* @param webLocator the web locator, e.g. <tt>http://localhost:8080</tt>. May be
* <code>null</code> or blank.
* @param resourcePath the absolute path of a resource, may be <code>null</code> or blank.
* A blank path will be interpreted as root path "/". If the path is not beginning with
* a slash it will be added on the fly.
* @param query a query string, may be <code>null</code> or blank.
*
* @return a URI, or <code>null</code> if the given resource path was <code>null</code>.
*/
public static URI asURI(String webLocator, String resourcePath, String query) {
String absolutePath = addSlashBegin(resourcePath);
if (absolutePath == null) {
return null;
}
if (StringUtils.isBlank(webLocator)) {
try {
return new URI("file", null, absolutePath, query, null); //$NON-NLS-1$
} catch (URISyntaxException e) {
throw new IllegalArgumentException(
MessageFormat.format("Not a valid file URI: ''{0}''", absolutePath), e);
}
}
String uri = StringUtils.removeEnd(webLocator, "/") + absolutePath; //$NON-NLS-1$
if (StringUtils.isNotBlank(query)) {
uri = uri + "?" + query; //$NON-NLS-1$
}
try {
return new URI(uri);
} catch (URISyntaxException e) {
URL url;
try {
url = new URL(uri);
} catch (MalformedURLException ex) {
throw new IllegalArgumentException(
MessageFormat.format("Not a valid URL: ''{0}''", uri), ex);
}
try {
return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(),
url.getPath(), url.getQuery(), url.getRef());
} catch (URISyntaxException ex) {
throw new IllegalArgumentException(
MessageFormat.format("Not a valid URI: ''{0}''", uri), ex);
}
}
}
/**
* Converts a given string into a corresponding URL.
* <p>
* Encodes path and/or query parts of the given string according to
* {@link URI#URI(String, String, String, int, String, String, String)}.
* For example, blanks in the path are converted to <tt>%20</tt>.
*
* @param s the string to convert to an URL.
* @return an URL, or <code>null</code> if the string is <code>null</code>, empty or whitespace.
*
* @throws MalformedURLException if the given string is not a valid URL and cannot be
* "sanitized" to yield a valid URL even after proper encoding of its parts.
*/
public static URL stringToURL(String s) throws MalformedURLException {
if (StringUtils.isBlank(s)) {
return null;
}
URI uri = null;
try {
uri = new URI(s);
} catch (URISyntaxException e) {
URL url = new URL(s);
try {
uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(),
url.getPath(), url.getQuery(), url.getRef());
} catch (URISyntaxException e1) {
MalformedURLException e2 = new MalformedURLException(e1.getMessage());
e2.initCause(e1);
throw e2;
}
}
return new URL(uri.toASCIIString());
}
/**
* Ensures that the given string begins with a slash and removes
* whitespace from both ends of the string.
*
* @param s the string, may be <code>null</code>.
*
* @return the string beginning with a slash, or <code>null</code>
* if the string was <code>null</code>.
*/
@SuppressWarnings("nls")
public static String addSlashBegin(String s) {
String ret = StringUtils.trim(s);
return ret.startsWith("/") ? ret : "/" + ret;
}
/**
* Ensures that the given string ends with a slash and removes
* whitespace from both ends of the string.
*
* @param s the string, may be <code>null</code>.
*
* @return the string ending with a slash, or <code>null</code>
* if the string was <code>null</code>.
*/
@SuppressWarnings("nls")
public static String addSlashEnd(String s) {
String ret = StringUtils.trim(s);
return ret == null || ret.endsWith("/") ? ret : ret + "/";
}
/**
* Removes trailing and leading slashes and whitespace from the given string.
*
* @param s the string to transform, may be <code>null</code>.
*
* @return the string without leading and trailing slashes and whitespace,
* or <code>null</code> if the string was <code>null</code>.
*/
public static String removeSlashStartEnd(String s) {
String ret = StringUtils.trim(s);
if (!StringUtils.isEmpty(ret)) {
while (ret.startsWith("/")){ //$NON-NLS-1$
ret = ret.substring(1);
}
while (ret.endsWith("/")) { //$NON-NLS-1$
ret = ret.substring(0, ret.length() - 1);
}
}
return ret;
}
/**
* Constructs an URL from a web locator (something like
* <tt>"http://example.org:8080"</tt>) and given path segments.
* <p>
* This method handles leading and trailing slashes and whitespace
* in all arguments.
*
* @param webLocator a web locator, or <code>null</code>. If no web locator
* is specified, the returned string is just a path (without leading slash).
* @param pathSegments the path segments to concatenate. If no path segements
* are specified, the <code>webLocator</code> is returned.
*
* @return an URL, which may be an absolute URL with a web locator,
* or just a (relative) path. The result may be the empty string, but
* never <code>null</code>.
*/
public static String concat(String webLocator, Object... pathSegments) {
StringBuilder ret = new StringBuilder();
if (webLocator != null) {
ret.append(removeSlashStartEnd(webLocator));
}
if (pathSegments != null) {
for (Object next: pathSegments) {
String pathSegment = next != null ? removeSlashStartEnd(next.toString()) : null;
if (StringUtils.isNotBlank(pathSegment)) {
if (ret.length() > 0) {
ret.append('/');
}
ret.append(pathSegment);
}
}
}
return ret.toString();
}
}