aQute.libg.uri.URIUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biz.aQute.bnd Show documentation
Show all versions of biz.aQute.bnd Show documentation
This command line utility is the Swiss army knife of OSGi. It provides you with a breadth of tools to understand and manage OSGi based systems. This project basically uses bndlib.
package aQute.libg.uri;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.Optional;
import java.util.regex.Pattern;
public final class URIUtil {
private static final Pattern WINDOWS_FILE_PATTERN = Pattern.compile("(?:\\p{Alpha}:[\\\\/]|\\\\\\\\|//)");
/**
* Resolves a URI reference against a base URI. Work-around for bugs in
* java.net.URI
* (e.g.http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535)
*
* @param baseURI
* @param reference
* @return the resolved {@code URI}
* @throws URISyntaxException
*/
public static URI resolve(URI baseURI, String reference) throws URISyntaxException {
if (reference.isEmpty()) {
return new URI(baseURI.getScheme(), baseURI.getSchemeSpecificPart(), null);
}
// A Windows path such as "C:\Users" is interpreted as a URI with
// a scheme of "C". Use a regex that matches the colon-backslash
// combination to handle this specifically as an absolute file URI.
if (WINDOWS_FILE_PATTERN.matcher(reference)
.lookingAt()) {
return new File(reference).toURI();
}
reference = reference.replace('\\', '/');
URI refURI;
try {
refURI = new URI(reference);
} catch (URISyntaxException e) {
refURI = new URI(null, reference, null);
}
return baseURI.resolve(refURI);
}
private static final URI EMPTYURI = URI.create("");
/**
* Attempts to fetch a path on the file system for the given URI string.
* Tries a few more tricks than the standard method of
* Paths.get(new URI(uriString)) - it can handle plain paths, and
* also nested URI pseudo-schemes like reference: and
* jar:. Examples:
*
* - /path/to/file => /path/to/file
* - reference:file:/path/to/file => /path/to/file
* - jar:file:/path/to/file.jar!/some/contained/element =>
* /path/to/file.jar
* - http://server/path/to/file => null
*
*
* @param uriString The URI string for which we are attempting to construct
* a path.
* @return The method's best guess as to which file on the local filesystem
* this URI refers, or an empty Optional if it's invalid or not a
* local filesystem URI.
*/
public static Optional pathFromURI(String uriString) {
if (uriString == null) {
return Optional.empty();
}
try {
URI uri = resolve(EMPTYURI, uriString);
return pathFromURI(uriString, uri);
} catch (URISyntaxException e1) {
return Optional.empty();
}
}
/**
* Attempts to fetch a path on the file system for the given URI. Tries a
* few more tricks than the standard method of Paths.get(uri) - it
* can handle plain paths, and also nested URI pseudo-schemes like
* reference: and jar:. Examples:
*
* - /path/to/file => /path/to/file
* - reference:file:/path/to/file => /path/to/file
* - jar:file:/path/to/file.jar!/some/contained/element =>
* /path/to/file.jar
* - http://server/path/to/file => null
*
*
* @param uri The URI for which we are attempting to construct a path.
* @return The method's best guess as to which file on the local filesystem
* this URI refers, or an empty Optional if it's invalid or not a
* local filesystem URI.
*/
public static Optional pathFromURI(URI uri) {
if (uri == null) {
return Optional.empty();
}
return pathFromURI(uri.getSchemeSpecificPart(), uri);
}
private static Optional pathFromURI(String uriString, URI uri) {
try {
while (!EMPTYURI.equals(uri)) {
final String scheme = uri.getScheme();
if (scheme == null) {
try {
return Optional.of(Paths.get(uriString));
} catch (InvalidPathException e) {
return Optional.empty();
}
}
switch (scheme.toLowerCase(Locale.ROOT)) {
case "file" :
return Optional.of(Paths.get(uri));
case "jar" :
case "bundle" :
case "zip" :
uriString = uri.getSchemeSpecificPart();
int index = uriString.indexOf("!/");
if (index >= 0) {
uriString = uriString.substring(0, index);
}
uri = resolve(EMPTYURI, uriString);
break;
case "reference" :
uriString = uri.getSchemeSpecificPart();
uri = resolve(EMPTYURI, uriString);
break;
default :
uriString = uri.getSchemeSpecificPart();
uri = new URI(uriString);
if (uri.getScheme() == null) {
return Optional.empty();
}
break;
}
}
} catch (URISyntaxException e1) {}
return Optional.empty();
}
/**
* Answer if the given URL is on the local system or remote
*/
public static boolean isRemote(URI uri) {
String scheme = uri.getScheme();
if (scheme == null)
return false;
return switch (scheme.toLowerCase(Locale.ROOT)) {
case "file", "jar", "data" -> false;
default -> true;
};
}
public static int getDefaultPort(String scheme) {
return switch (scheme) {
case "http" -> 80;
case "https" -> 443;
case "ftp" -> 20;
default -> -1;
};
}
public static String encodePath(String path) {
if ((path == null) || path.isEmpty()) {
return path;
}
byte[] bytes = path.getBytes(UTF_8);
final int length = bytes.length;
byte[] encoded = new byte[length * 3];
int i = 0;
for (byte b : bytes) {
if (isPathAllowed(b)) {
encoded[i++] = b;
} else {
encoded[i++] = '%';
encoded[i++] = (byte) Character.forDigit((b >> 4) & 0xF, 16);
encoded[i++] = (byte) Character.forDigit(b & 0xF, 16);
}
}
if (i > length) {
return new String(encoded, 0, i, UTF_8);
}
return path;
}
static boolean isPathAllowed(int b) {
return switch (b) {
case '/', // path_segments
';', // segment
':', // pchar
'-', // mark
'@', '&', '=', '+', '$', ',', '_', '.', '!', '~', '*', '\'', '(', ')' -> true;
default -> isAlphanum(b);
};
}
static boolean isAlphanum(int b) {
return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
}
public static String decode(String source) {
if ((source == null) || source.isEmpty()) {
return source;
}
final int length = source.length();
byte[] decoded = new byte[length];
int i = 0;
for (int j = 0; j < length; j++) {
int c = source.charAt(j);
if (c == '%') {
decoded[i++] = (byte) ((Character.digit(source.charAt(++j), 16) << 4)
| Character.digit(source.charAt(++j), 16));
} else {
decoded[i++] = (byte) c;
}
}
if (i < length) {
return new String(decoded, 0, i, UTF_8);
}
return source;
}
}