com.helger.commons.url.URLHelper Maven / Gradle / Ivy
/**
* Copyright (C) 2014-2015 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* 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 com.helger.commons.url;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import javax.annotation.CheckForSigned;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.annotation.PresentForCodeCoverage;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.callback.INonThrowingRunnableWithParameter;
import com.helger.commons.charset.CCharset;
import com.helger.commons.codec.IDecoder;
import com.helger.commons.codec.IEncoder;
import com.helger.commons.collection.CollectionHelper;
import com.helger.commons.debug.GlobalDebug;
import com.helger.commons.exception.InitializationException;
import com.helger.commons.io.file.FilenameHelper;
import com.helger.commons.io.resource.ClassPathResource;
import com.helger.commons.io.stream.StreamHelper;
import com.helger.commons.lang.ClassHelper;
import com.helger.commons.lang.ClassLoaderHelper;
import com.helger.commons.microdom.util.XMLMapHandler;
import com.helger.commons.mime.IMimeType;
import com.helger.commons.string.StringHelper;
import com.helger.commons.wrapper.IMutableWrapper;
import com.helger.commons.wrapper.Wrapper;
/**
* URL utilities.
*
* @author Philip Helger
*/
@ThreadSafe
public final class URLHelper
{
/** Default URL charset is UTF-8 */
public static final String CHARSET_URL = CCharset.CHARSET_UTF_8;
/** Default URL charset is UTF-8 */
public static final Charset CHARSET_URL_OBJ = CCharset.CHARSET_UTF_8_OBJ;
/** Separator before first param: ? */
public static final char QUESTIONMARK = '?';
public static final String QUESTIONMARK_STR = Character.toString (QUESTIONMARK);
/** Separator between params: & */
public static final char AMPERSAND = '&';
public static final String AMPERSAND_STR = Character.toString (AMPERSAND);
/** Separator between param name and param value: = */
public static final char EQUALS = '=';
public static final String EQUALS_STR = Character.toString (EQUALS);
/** Separator between URL path and anchor name: # */
public static final char HASH = '#';
public static final String HASH_STR = Character.toString (HASH);
/** The protocol for file resources */
public static final String PROTOCOL_FILE = "file";
private static final Logger s_aLogger = LoggerFactory.getLogger (URLHelper.class);
private static char [] s_aCleanURLOld;
private static char [] [] s_aCleanURLNew;
/** Internal debug logging flag */
private static final boolean DEBUG_GET_IS = false;
@PresentForCodeCoverage
private static final URLHelper s_aInstance = new URLHelper ();
private URLHelper ()
{}
/**
* URL-decode the passed value automatically handling charset issues. The used
* char set is determined by {@link #CHARSET_URL}.
*
* @param sValue
* The value to be decoded. May not be null
.
* @return The decoded value.
*/
@Nonnull
public static String urlDecode (@Nonnull final String sValue)
{
return urlDecode (sValue, CHARSET_URL);
}
/**
* URL-decode the passed value automatically handling charset issues.
*
* @param sValue
* The value to be decoded. May not be null
.
* @param aCharset
* The charset to use. May not be null
.
* @return The decoded value.
*/
@Nonnull
public static String urlDecode (@Nonnull final String sValue, @Nonnull final Charset aCharset)
{
ValueEnforcer.notNull (aCharset, "Charset");
return urlDecode (sValue, aCharset.name ());
}
/**
* URL-decode the passed value automatically handling charset issues.
*
* @param sValue
* The value to be decoded. May not be null
.
* @param sCharset
* The charset to use. May not be null
.
* @return The decoded value.
*/
@SuppressWarnings ("deprecation")
@Nonnull
public static String urlDecode (@Nonnull final String sValue, @Nonnull @Nonempty final String sCharset)
{
try
{
return URLDecoder.decode (sValue, sCharset);
}
catch (final UnsupportedEncodingException ex)
{
// Using the charset determined by the system property file.encoding
return URLDecoder.decode (sValue);
}
}
/**
* URL-encode the passed value automatically handling charset issues. The used
* char set is determined by {@link #CHARSET_URL}.
*
* @param sValue
* The value to be encoded. May not be null
.
* @return The encoded value.
*/
@Nonnull
public static String urlEncode (@Nonnull final String sValue)
{
return urlEncode (sValue, CHARSET_URL);
}
/**
* URL-encode the passed value automatically handling charset issues.
*
* @param sValue
* The value to be encoded. May not be null
.
* @param aCharset
* The charset to use. May not be null
.
* @return The encoded value.
*/
@Nonnull
public static String urlEncode (@Nonnull final String sValue, @Nonnull final Charset aCharset)
{
ValueEnforcer.notNull (aCharset, "Charset");
return urlEncode (sValue, aCharset.name ());
}
/**
* URL-encode the passed value automatically handling charset issues.
*
* @param sValue
* The value to be encoded. May not be null
.
* @param sCharset
* The charset to use. May not be null
.
* @return The encoded value.
*/
@SuppressWarnings ("deprecation")
@Nonnull
public static String urlEncode (@Nonnull final String sValue, @Nonnull @Nonempty final String sCharset)
{
try
{
return URLEncoder.encode (sValue, sCharset);
}
catch (final UnsupportedEncodingException ex)
{
// Using the charset determined by the system property file.encoding
return URLEncoder.encode (sValue);
}
}
private static void _initCleanURL ()
{
// This one cannot be in the static initializer of the class, because
// ClassPathResource internally uses
// URLUtils.getInputStream and this static initialization code of this class
// can therefore not use ClasspathResource because it would create a
// recursive dependency!
// Ever trickier is the when running multiple threads for reading XML (e.g.
// in the unit test) this code would wait forever in the static initializer
// because XMLMapHandler internally also acquires an XML reader....
final Map aCleanURLMap = new HashMap ();
if (XMLMapHandler.readMap (new ClassPathResource ("codelists/cleanurl-data.xml"), aCleanURLMap).isFailure ())
throw new InitializationException ("Failed to init CleanURL data!");
s_aCleanURLOld = new char [aCleanURLMap.size ()];
s_aCleanURLNew = new char [aCleanURLMap.size ()] [];
// Convert to char array
int i = 0;
for (final Map.Entry aEntry : aCleanURLMap.entrySet ())
{
final String sKey = aEntry.getKey ();
if (sKey.length () != 1)
throw new IllegalStateException ("Clean URL source character has an invalid length: " + sKey.length ());
s_aCleanURLOld[i] = sKey.charAt (0);
s_aCleanURLNew[i] = aEntry.getValue ().toCharArray ();
++i;
}
}
/**
* Clean an URL part from nasty Umlauts. This mapping needs extension!
*
* @param sURLPart
* The original URL part. May be null
.
* @return The cleaned version or null
if the input was
* null
.
*/
@Nullable
public static String getCleanURLPartWithoutUmlauts (@Nullable final String sURLPart)
{
if (s_aCleanURLOld == null)
_initCleanURL ();
final char [] ret = StringHelper.replaceMultiple (sURLPart, s_aCleanURLOld, s_aCleanURLNew);
return new String (ret);
}
@Nonnull
public static IURLData getAsURLData (@Nonnull final String sHref)
{
return getAsURLData (sHref, null);
}
/**
* Parses the passed URL into a structured form
*
* @param sHref
* The URL to be parsed
* @param aParameterDecoder
* The parameter decoder to use. May be null
.
* @return the corresponding {@link IURLData} representation of the passed URL
*/
@Nonnull
public static IURLData getAsURLData (@Nonnull final String sHref, @Nullable final IDecoder aParameterDecoder)
{
ValueEnforcer.notNull (sHref, "Href");
final String sRealHref = sHref.trim ();
// Is it a protocol that does not allow for query parameters?
final IURLProtocol eProtocol = URLProtocolRegistry.getInstance ().getProtocol (sRealHref);
if (eProtocol != null && !eProtocol.allowsForQueryParameters ())
return new URLData (sRealHref, null, null);
if (GlobalDebug.isDebugMode ())
if (eProtocol != null)
try
{
new URL (sRealHref);
}
catch (final MalformedURLException ex)
{
s_aLogger.warn ("java.net.URL claims URL '" + sRealHref + "' to be invalid: " + ex.getMessage ());
}
String sPath;
Map aParams = null;
String sAnchor;
// First get the anchor out
String sRemainingHref = sRealHref;
final int nIndexAnchor = sRemainingHref.indexOf (HASH);
if (nIndexAnchor >= 0)
{
// Extract anchor
sAnchor = sRemainingHref.substring (nIndexAnchor + 1).trim ();
sRemainingHref = sRemainingHref.substring (0, nIndexAnchor).trim ();
}
else
sAnchor = null;
// Find parameters
final int nQuestionIndex = sRemainingHref.indexOf (QUESTIONMARK);
if (nQuestionIndex >= 0)
{
// Use everything after the '?'
final String sQueryString = sRemainingHref.substring (nQuestionIndex + 1).trim ();
// Maybe empty, if the URL ends with a '?'
if (StringHelper.hasText (sQueryString))
aParams = getQueryStringAsMap (sQueryString, aParameterDecoder);
sPath = sRemainingHref.substring (0, nQuestionIndex).trim ();
}
else
sPath = sRemainingHref;
return new URLData (sPath, aParams, sAnchor);
}
@Nonnull
@ReturnsMutableCopy
public static Map getQueryStringAsMap (@Nullable final String sQueryString,
@Nullable final IDecoder aParameterDecoder)
{
final Map aMap = new LinkedHashMap ();
if (StringHelper.hasText (sQueryString))
{
for (final String sKeyValuePair : StringHelper.getExploded (AMPERSAND, sQueryString))
if (sKeyValuePair.length () > 0)
{
final List aParts = StringHelper.getExploded (EQUALS, sKeyValuePair, 2);
final String sKey = aParts.get (0);
// Maybe empty when passing something like "url?=value"
if (StringHelper.hasText (sKey))
{
final String sValue = aParts.size () == 2 ? aParts.get (1) : "";
if (sValue == null)
throw new NullPointerException ("parameter value may not be null");
if (aParameterDecoder != null)
{
// Now decode the name and the value
aMap.put (aParameterDecoder.getDecoded (sKey), aParameterDecoder.getDecoded (sValue));
}
else
aMap.put (sKey, sValue);
}
}
}
return aMap;
}
@Nonnull
@ReturnsMutableCopy
public static Map getQueryStringAsMap (@Nullable final String sQueryString)
{
return getQueryStringAsMap (sQueryString, null);
}
@Nonnull
public static String getURLString (@Nonnull final IURLData aURL, @Nullable final Charset aParameterCharset)
{
return getURLString (aURL.getPath (), aURL.getAllParams (), aURL.getAnchor (), aParameterCharset);
}
/**
* Get the final representation of the URL using the specified elements.
*
* @param sPath
* The main path. May be null
.
* @param sQueryParams
* The set of all query parameters already concatenated with the
* correct characters (& and =). May be null
.
* @param sAnchor
* An optional anchor to be added. May be null
.
* @return May be null
if path, anchor and parameters are
* null
.
*/
@Nullable
public static String getURLString (@Nullable final String sPath,
@Nullable final String sQueryParams,
@Nullable final String sAnchor)
{
final boolean bHasPath = StringHelper.hasText (sPath);
final boolean bHasQueryParams = StringHelper.hasText (sQueryParams);
final boolean bHasAnchor = StringHelper.hasText (sAnchor);
// return URL as is?
if (!bHasQueryParams && !bHasAnchor)
{
// Return URL as is (may be null)
return sPath;
}
final StringBuilder aSB = new StringBuilder ();
if (bHasPath)
{
aSB.append (sPath);
if (sPath.contains (QUESTIONMARK_STR))
s_aLogger.warn ("Path contains the question mark ('?') character: '" + sPath + "'");
if (sPath.contains (AMPERSAND_STR))
s_aLogger.warn ("Path contains the ampersand ('&') character: '" + sPath + "'");
if (sPath.contains (HASH_STR))
s_aLogger.warn ("Path contains the hash ('#') character: '" + sPath + "'");
}
if (bHasQueryParams)
{
if (sQueryParams.contains (QUESTIONMARK_STR))
s_aLogger.warn ("Query parameters contain the question mark ('?') character: '" + sQueryParams + "'");
final boolean bHasQuestionMark = aSB.indexOf (QUESTIONMARK_STR) >= 0;
if (bHasQuestionMark)
{
// Only if the "?" is not the last char otherwise the base href already
// contains a parameter!
final char cLast = StringHelper.getLastChar (aSB);
if (cLast != QUESTIONMARK && cLast != AMPERSAND)
aSB.append (AMPERSAND);
}
else
{
// First parameter
aSB.append (QUESTIONMARK);
}
// add all parameters
aSB.append (sQueryParams);
}
// Append anchor
if (bHasAnchor)
{
if (sAnchor.contains (HASH_STR))
s_aLogger.warn ("Anchor contains the hash ('#') character: '" + sAnchor + "'");
if (StringHelper.getLastChar (aSB) != HASH)
aSB.append (HASH);
aSB.append (sAnchor);
}
// Avoid empty URLs
if (aSB.length () == 0)
return QUESTIONMARK_STR;
return aSB.toString ();
}
@Nullable
public static String getQueryParametersAsString (@Nullable final Map aQueryParams,
@Nullable final IEncoder aQueryParameterEncoder)
{
if (CollectionHelper.isEmpty (aQueryParams))
return null;
final StringBuilder aSB = new StringBuilder ();
// add all values
for (final Map.Entry aEntry : aQueryParams.entrySet ())
{
// Key
final String sKey = aEntry.getKey ();
if (aQueryParameterEncoder != null)
aSB.append (aQueryParameterEncoder.getEncoded (sKey));
else
aSB.append (sKey);
// Value
final String sValue = aEntry.getValue ();
if (StringHelper.hasText (sValue))
if (aQueryParameterEncoder != null)
aSB.append (EQUALS).append (aQueryParameterEncoder.getEncoded (sValue));
else
aSB.append (EQUALS).append (sValue);
// Separator
aSB.append (AMPERSAND);
}
// delete the last AMPERSAND
aSB.deleteCharAt (aSB.length () - 1);
return aSB.toString ();
}
/**
* Get the final representation of the URL using the specified elements.
*
* @param sPath
* The main path. May be null
.
* @param aQueryParams
* The set of query parameters to be appended. May be null
* .
* @param sAnchor
* An optional anchor to be added. May be null
.
* @param aQueryParameterEncoder
* The parameters encoding to be used. May be null
.
* @return May be null
if path, anchor and parameters are
* null
.
*/
@Nullable
public static String getURLString (@Nullable final String sPath,
@Nullable final Map aQueryParams,
@Nullable final String sAnchor,
@Nullable final IEncoder aQueryParameterEncoder)
{
return getURLString (sPath, getQueryParametersAsString (aQueryParams, aQueryParameterEncoder), sAnchor);
}
/**
* Get the final representation of the URL using the specified elements.
*
* @param sPath
* The main path. May be null
.
* @param aQueryParams
* The set of parameters to be appended. May be null
.
* @param sAnchor
* An optional anchor to be added. May be null
.
* @param aParameterCharset
* If not null
the parameters are encoded using this
* charset.
* @return May be null
if all parameters are null
.
*/
@Nullable
public static String getURLString (@Nullable final String sPath,
@Nullable final Map aQueryParams,
@Nullable final String sAnchor,
@Nullable final Charset aParameterCharset)
{
final IEncoder aQueryParameterEncoder = aParameterCharset == null ? null
: new URLParameterEncoder (aParameterCharset);
return getURLString (sPath, getQueryParametersAsString (aQueryParams, aQueryParameterEncoder), sAnchor);
}
/**
* Get the passed String as an URL. If the string is empty or not an URL
* null
is returned.
*
* @param sURL
* Source URL. May be null
.
* @return null
if the passed URL is empty or invalid.
*/
@Nullable
public static URL getAsURL (@Nullable final String sURL)
{
if (StringHelper.hasText (sURL))
try
{
return new URL (sURL);
}
catch (final MalformedURLException ex)
{
// fall-through
}
return null;
}
/**
* Get the passed URI as an URL. If the URI is null or cannot be converted to
* an URL null
is returned.
*
* @param aURI
* Source URI. May be null
.
* @return null
if the passed URI is null or cannot be converted
* to an URL.
*/
@Nullable
public static URL getAsURL (@Nullable final URI aURI)
{
if (aURI != null)
try
{
return aURI.toURL ();
}
catch (final MalformedURLException ex)
{
// fall-through
}
return null;
}
/**
* Get the passed String as an URI. If the string is empty or not an URI
* null
is returned.
*
* @param sURI
* Source URI. May be null
.
* @return null
if the passed URI is empty or invalid.
*/
@Nullable
public static URI getAsURI (@Nullable final String sURI)
{
if (StringHelper.hasText (sURI))
try
{
return new URI (sURI);
}
catch (final URISyntaxException ex)
{
// fall-through
}
return null;
}
/**
* Get the passed URL as an URI. If the URL is null or not an URI
* null
is returned.
*
* @param aURL
* Source URL. May be null
.
* @return null
if the passed URL is empty or invalid.
*/
@Nullable
public static URI getAsURI (@Nullable final URL aURL)
{
if (aURL != null)
try
{
return aURL.toURI ();
}
catch (final URISyntaxException ex)
{
// fall-through
}
return null;
}
/**
* Get an input stream from the specified URL. By default caching is disabled.
* This method only handles GET requests - POST requests are not possible.
*
* @param aURL
* The URL to use. May not be null
.
* @param nConnectTimeoutMS
* Connect timeout milliseconds. 0 == infinite. < 0: ignored.
* @param nReadTimeoutMS
* Read timeout milliseconds. 0 == infinite. < 0: ignored.
* @param aConnectionModifier
* An optional callback object to modify the URLConnection before it is
* opened.
* @param aExceptionHolder
* An optional exception holder for further outside investigation.
* @return null
if the input stream could not be opened.
*/
@Nullable
public static InputStream getInputStream (@Nonnull final URL aURL,
@CheckForSigned final int nConnectTimeoutMS,
@CheckForSigned final int nReadTimeoutMS,
@Nullable final INonThrowingRunnableWithParameter aConnectionModifier,
@Nullable final IMutableWrapper aExceptionHolder)
{
ValueEnforcer.notNull (aURL, "URL");
if (DEBUG_GET_IS)
s_aLogger.info ("getInputStream ('" +
aURL +
"', " +
nConnectTimeoutMS +
", " +
nReadTimeoutMS +
", " +
aConnectionModifier +
", " +
aExceptionHolder +
")",
new Exception ());
URLConnection aConnection;
HttpURLConnection aHTTPConnection = null;
try
{
aConnection = aURL.openConnection ();
if (nConnectTimeoutMS >= 0)
aConnection.setConnectTimeout (nConnectTimeoutMS);
if (nReadTimeoutMS >= 0)
aConnection.setReadTimeout (nReadTimeoutMS);
if (aConnection instanceof HttpURLConnection)
aHTTPConnection = (HttpURLConnection) aConnection;
// Disable caching
aConnection.setUseCaches (false);
// Apply optional callback
if (aConnectionModifier != null)
aConnectionModifier.run (aConnection);
if (aConnection instanceof JarURLConnection)
{
final JarEntry aJarEntry = ((JarURLConnection) aConnection).getJarEntry ();
if (aJarEntry != null)
{
// Directories are identified by ending with a "/"
if (aJarEntry.isDirectory ())
{
// Cannot open an InputStream on a directory
return null;
}
// Heuristics for directories not ending with a "/"
if (aJarEntry.getSize () == 0 && aJarEntry.getCrc () == 0)
{
// Cannot open an InputStream on a directory
s_aLogger.warn ("Heuristically determined " + aURL + " to be a directory!");
return null;
}
}
}
// by default follow-redirects is true for HTTPUrlConnections
final InputStream ret = aConnection.getInputStream ();
if (DEBUG_GET_IS)
s_aLogger.info (" returning " + ret);
return ret;
}
catch (final IOException ex)
{
if (aExceptionHolder != null)
{
// Remember the exception
aExceptionHolder.set (ex);
}
else
{
if (ex instanceof SocketTimeoutException)
s_aLogger.warn ("Timeout to open input stream for '" +
aURL +
"': " +
ex.getClass ().getName () +
" - " +
ex.getMessage ());
else
s_aLogger.warn ("Failed to open input stream for '" +
aURL +
"': " +
ex.getClass ().getName () +
" - " +
ex.getMessage ());
}
if (aHTTPConnection != null)
{
// Read error completely for keep-alive (see
// http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html)
InputStream aErrorIS = null;
try
{
aErrorIS = aHTTPConnection.getErrorStream ();
if (aErrorIS != null)
{
final byte [] aBuf = new byte [1024];
// read the response body
while (aErrorIS.read (aBuf) > 0)
{
// Read next
}
}
}
catch (final IOException ex2)
{
// deal with the exception
s_aLogger.warn ("Failed to consume error stream for '" +
aURL +
"': " +
ex2.getClass ().getName () +
" - " +
ex2.getMessage ());
}
finally
{
StreamHelper.close (aErrorIS);
}
}
}
return null;
}
/**
* POST something to a URL.
*
* @param aURL
* The destination URL. May not be null
.
* @param nConnectTimeoutMS
* Connect timeout milliseconds. 0 == infinite. < 0: ignored.
* @param nReadTimeoutMS
* Read timeout milliseconds. 0 == infinite. < 0: ignored.
* @param aContentType
* The MIME type to be send as the Content-Type
header.
* May be null
.
* @param aContentBytes
* The main content to be send via POST. May not be null
* but maybe empty. The Content-Length
HTTP header is
* automatically filled with the specified byte length.
* @param aAdditionalHTTPHeaders
* An optional map of HTTP headers to be send. This map should not
* contain the Content-Type
and the
* Content-Length
headers. May be null
.
* @param aConnectionModifier
* An optional callback object to modify the URLConnection before it is
* opened.
* @param aExceptionHolder
* An optional exception holder for further outside investigation.
* @return null
if the input stream could not be opened.
* @deprecated Use Apache http client or the like for a much better handling
*/
@Nullable
@Deprecated
public static InputStream postAndGetInputStream (@Nonnull final URL aURL,
final int nConnectTimeoutMS,
final int nReadTimeoutMS,
@Nullable final IMimeType aContentType,
@Nonnull final byte [] aContentBytes,
@Nullable final Map aAdditionalHTTPHeaders,
@Nullable final INonThrowingRunnableWithParameter aConnectionModifier,
@Nullable final IMutableWrapper aExceptionHolder)
{
ValueEnforcer.notNull (aURL, "URL");
ValueEnforcer.notNull (aContentBytes, "ContentBytes");
final Wrapper aOpenedOS = new Wrapper ();
final INonThrowingRunnableWithParameter aPOSTModifier = new INonThrowingRunnableWithParameter ()
{
public void run (@Nonnull final URLConnection aURLConnection)
{
final HttpURLConnection aHTTPURLConnection = (HttpURLConnection) aURLConnection;
try
{
aHTTPURLConnection.setRequestMethod ("POST");
aHTTPURLConnection.setDoInput (true);
aHTTPURLConnection.setDoOutput (true);
if (aContentType != null)
aHTTPURLConnection.setRequestProperty ("Content-Type", aContentType.getAsString ());
aHTTPURLConnection.setRequestProperty ("Content-Length", Integer.toString (aContentBytes.length));
if (aAdditionalHTTPHeaders != null)
for (final Map.Entry aEntry : aAdditionalHTTPHeaders.entrySet ())
aHTTPURLConnection.setRequestProperty (aEntry.getKey (), aEntry.getValue ());
final OutputStream aOS = aHTTPURLConnection.getOutputStream ();
aOpenedOS.set (aOS);
aOS.write (aContentBytes);
aOS.flush ();
}
catch (final IOException ex)
{
throw new IllegalStateException ("Failed to POST data to " + aURL.toExternalForm (), ex);
}
// Run provided modifier (if any)
if (aConnectionModifier != null)
aConnectionModifier.run (aURLConnection);
}
};
try
{
return getInputStream (aURL, nConnectTimeoutMS, nReadTimeoutMS, aPOSTModifier, aExceptionHolder);
}
finally
{
// Close the OutputStream opened for POSTing
StreamHelper.close (aOpenedOS.get ());
}
}
/**
* Create a parameter string suitable for POST body (e.g. for web form
* submission).
*
* @param aParams
* Parameter map. May be null
or empty.
* @param aParameterEncoder
* The encoder to be used to encode parameter names and parameter
* values. May be null
. This may be e.g. a
* {@link URLParameterEncoder}.
* @return A non-null
string
*/
@Nonnull
public static String getApplicationFormEncoded (@Nullable final Map aParams,
@Nullable final IEncoder aParameterEncoder)
{
if (CollectionHelper.isEmpty (aParams))
return "";
final StringBuilder aSB = new StringBuilder ();
if (aParams != null)
for (final Map.Entry aEntry : aParams.entrySet ())
{
// Separator
if (aSB.length () > 0)
aSB.append (AMPERSAND);
// Key
final String sKey = aEntry.getKey ();
if (aParameterEncoder != null)
aSB.append (aParameterEncoder.getEncoded (sKey));
else
aSB.append (sKey);
// Value
final String sValue = aEntry.getValue ();
if (StringHelper.hasText (sValue))
if (aParameterEncoder != null)
aSB.append (EQUALS).append (aParameterEncoder.getEncoded (sValue));
else
aSB.append (EQUALS).append (sValue);
}
return aSB.toString ();
}
@Nonnull
public static File getAsFile (@Nonnull final URL aURL)
{
ValueEnforcer.notNull (aURL, "URL");
if (!PROTOCOL_FILE.equals (aURL.getProtocol ()))
throw new IllegalArgumentException ("Not a file URL: " + aURL.toExternalForm ());
String sPath;
File aFile;
try
{
sPath = aURL.toURI ().getSchemeSpecificPart ();
aFile = new File (sPath);
}
catch (final URISyntaxException ex)
{
// Fallback for URLs that are not valid URIs
sPath = aURL.getPath ();
aFile = new File (sPath);
}
// In case the URL starts with a slash, make it absolute
if (FilenameHelper.startsWithPathSeparatorChar (sPath))
aFile = aFile.getAbsoluteFile ();
// This file may be non-existing
return aFile;
}
@Nullable
public static File getAsFileOrNull (@Nonnull final URL aURL)
{
if (aURL != null)
try
{
return getAsFile (aURL);
}
catch (final IllegalArgumentException ex)
{
// Happens for non-file URLs
}
return null;
}
/**
* Get the URL for the specified path using automatic class loader handling.
* The class loaders are iterated in the following order:
*
* - Default class loader (usually the context class loader)
* - The class loader of this class
* - The system class loader
*
*
* @param sPath
* The path to be resolved. May neither be null
nor empty.
* @return null
if the path could not be resolved.
*/
@Nullable
public static URL getClassPathURL (@Nonnull @Nonempty final String sPath)
{
ValueEnforcer.notEmpty (sPath, "Path");
// Use the default class loader. Returns null if not found
URL ret = ClassLoaderHelper.getResource (ClassLoaderHelper.getDefaultClassLoader (), sPath);
if (ret == null)
{
// This is essential if we're running as a web application!!!
ret = ClassHelper.getResource (URLHelper.class, sPath);
if (ret == null)
{
// this is a fix for a user that needed to have the application
// loaded by the bootstrap class loader
ret = ClassLoaderHelper.getResource (ClassLoaderHelper.getSystemClassLoader (), sPath);
}
}
return ret;
}
/**
* Get the input stream of the passed resource using the specified class
* loader only.
*
* @param sPath
* The path to be resolved. May neither be null
nor empty.
* @param aClassLoader
* The class loader to be used. May not be null
.
* @return null
if the path could not be resolved using the
* specified class loader.
*/
@Nullable
@Deprecated
public static URL getClassPathURL (@Nonnull @Nonempty final String sPath, @Nonnull final ClassLoader aClassLoader)
{
return ClassLoaderHelper.getResource (aClassLoader, sPath);
}
public static boolean isClassPathURLExisting (@Nonnull @Nonempty final String sPath)
{
return getClassPathURL (sPath) != null;
}
public static boolean isClassPathURLExisting (@Nonnull @Nonempty final String sPath,
@Nonnull final ClassLoader aClassLoader)
{
return ClassLoaderHelper.getResource (aClassLoader, sPath) != null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy