package com.ctc.wstx.util;

import java.io.*;
import java.net.*;
import java.util.regex.Pattern;

public final class URLUtil
{
    
While URIs that contain pipe are wrong, we'll work around that for [WSTX-275].
/** * While URIs that contain pipe are wrong, we'll work around that * for [WSTX-275]. */
private final static Pattern URI_WINDOWS_FILE_PATTERN = Pattern.compile("^file:///\\p{Alpha}|.*$"); private URLUtil() { }
Method that tries to figure out how to create valid URL from a system id, without additional contextual information. If we could use URIs this might be easier to do, but they are part of JDK 1.4, and preferably code should only require 1.2 (or maybe 1.3)
/** * Method that tries to figure out how to create valid URL from a system * id, without additional contextual information. * If we could use URIs this might be easier to do, but they are part * of JDK 1.4, and preferably code should only require 1.2 (or maybe 1.3) */
public static URL urlFromSystemId(String sysId) throws IOException { try { sysId = cleanSystemId(sysId); /* Ok, does it look like a full URL? For one, you need a colon. Also, * to reduce likelihood of collision with Windows paths, let's only * accept it if there are 3 preceding other chars... * Not sure if Mac might be a problem? (it uses ':' as file path * separator, alas, at least prior to MacOS X) */ int ix = sysId.indexOf(':', 0); /* Also, protocols are generally fairly short, usually 3 or 4 * chars (http, ftp, urn); so let's put upper limit of 8 chars too */ if (ix >= 3 && ix <= 8) { return new URL(sysId); } // Ok, let's just assume it's local file reference... /* 24-May-2006, TSa: Amazingly, this single call does show in * profiling, for small docs. The problem is that deep down it * tries to check physical file system, to check if the File * pointed to is a directory: and that is (relatively speaking) * a very expensive call. Since in this particular case it * should never be a dir (and/or doesn't matter), let's just * implement conversion locally */ String absPath = new java.io.File(sysId).getAbsolutePath(); // Need to convert colons/backslashes to regular slashes? { char sep = File.separatorChar; if (sep != '/') { absPath = absPath.replace(sep, '/'); } } if (absPath.length() > 0 && absPath.charAt(0) != '/') { absPath = "/" + absPath; } return new URL("file", "", absPath); } catch (MalformedURLException e) { throwIOException(e, sysId); return null; // never gets here } }
Since:4.1
/** * @since 4.1 */
public static URI uriFromSystemId(final String sysId) throws IOException { // as per [WSTX-275] // note: mostly a copy of matching method above, but with URI instead of URL try { if (sysId.indexOf('|', 0) > 0) { if (URI_WINDOWS_FILE_PATTERN.matcher(sysId).matches()) { return new URI(sysId.replace('|', ':')); } } final int ix = sysId.indexOf(':', 0); if (ix >= 3 && ix <= 8) { return new URI(sysId); } String absPath = new java.io.File(sysId).getAbsolutePath(); final char sep = File.separatorChar; if (sep != '/') { absPath = absPath.replace(sep, '/'); } if (absPath.length() > 0 && absPath.charAt(0) != '/') { absPath = "/" + absPath; } return new URI("file", absPath, null); } catch (final URISyntaxException e) { throwIOException(e, sysId); return null; // never gets here } } public static URL urlFromSystemId(String sysId, URL ctxt) throws IOException { if (ctxt == null) { return urlFromSystemId(sysId); } try { sysId = cleanSystemId(sysId); return new URL(ctxt, sysId); } catch (MalformedURLException e) { throwIOException(e, sysId); return null; // never gets here } }
Method that tries to create and return URL that denotes current working directory. Usually used to create a context, when one is not explicitly passed.
/** * Method that tries to create and return URL that denotes current * working directory. Usually used to create a context, when one is * not explicitly passed. */
public static URL urlFromCurrentDir() throws IOException /* MalformedURLException or such */ { /* This seems to work; independent of whether there happens to * be such/file dir or not. */ File parent = new File("a").getAbsoluteFile().getParentFile(); return toURL(parent); }
Method that tries to get a stream (ideally, optimal one) to read from the specified URL. Currently it just means creating a simple file input stream if the URL points to a (local) file, and otherwise relying on URL classes input stream creation method.
/** * Method that tries to get a stream (ideally, optimal one) to read from * the specified URL. * Currently it just means creating a simple file input stream if the * URL points to a (local) file, and otherwise relying on URL classes * input stream creation method. */
public static InputStream inputStreamFromURL(URL url) throws IOException { if ("file".equals(url.getProtocol())) { /* As per [WSTX-82], can not do this if the path refers * to a network drive on windows. This fixes the problem; * might not be needed on all platforms (NFS?), but should not * matter a lot: performance penalty of extra wrapping is more * relevant when accessing local file system. */ String host = url.getHost(); if (host == null || host.length() == 0) { /* One more test: if there are quoted characters, need * to decoded [WSTX-207]: */ String path = url.getPath(); if (path.indexOf('%') >= 0) { path = URLDecoder.decode(path, "UTF-8"); } return new FileInputStream(path); } } return url.openStream(); }
Method that tries to get a stream (ideally, optimal one) to write to the resource specified by given URL. Currently it just means creating a simple file output stream if the URL points to a (local) file, and otherwise relying on URL classes input stream creation method.
/** * Method that tries to get a stream (ideally, optimal one) to write to * the resource specified by given URL. * Currently it just means creating a simple file output stream if the * URL points to a (local) file, and otherwise relying on URL classes * input stream creation method. */
public static OutputStream outputStreamFromURL(URL url) throws IOException { if ("file".equals(url.getProtocol())) { /* As per [WSTX-82], can not do this if the path refers * to a network drive on windows. */ String host = url.getHost(); if (host == null || host.length() == 0) { return new FileOutputStream(url.getPath()); } } return url.openConnection().getOutputStream(); }
Helper method that will convert given file into equivalent URL. Encapsulated as a separate method to allow for working around problems with deprecation of File.toURL method.
/** * Helper method that will convert given file into equivalent URL. * Encapsulated as a separate method to allow for working around * problems with deprecation of {@link File#toURL} method. */
public static URL toURL(File f) throws IOException { return f.toURI().toURL(); } /* /////////////////////////////////////////// // Private helper methods /////////////////////////////////////////// */ private static String cleanSystemId(final String sysId) { int ix = sysId.indexOf('|'); if (ix > 0 && URI_WINDOWS_FILE_PATTERN.matcher(sysId).matches()) { StringBuilder sb = new StringBuilder(sysId); sb.setCharAt(ix, ':'); return sb.toString(); } return sysId; }
Helper method that tries to fully convert strange URL-specific exception to more general IO exception. Also, to try to use JDK 1.4 feature without creating requirement, uses reflection to try to set the root cause, if we are running on JDK1.4
/** * Helper method that tries to fully convert strange URL-specific exception * to more general IO exception. Also, to try to use JDK 1.4 feature without * creating requirement, uses reflection to try to set the root cause, if * we are running on JDK1.4 */
private static void throwIOException(Exception mex, String sysId) throws IOException { String msg = "[resolving systemId '"+sysId+"']: "+mex.toString(); throw ExceptionUtil.constructIOException(msg, mex); } }