/* Aalto XML processor * * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in the file LICENSE which is * included with the source code. * You may not use this file except in compliance with the License. * * 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.fasterxml.aalto.util; import java.io.*; import java.net.URL; import java.net.MalformedURLException; public final class URLUtil { private URLUtil() { } /** * Method that tries to figure out how to create valid URL from a system * id, without additional contextual information. We could perhaps use * java.net.URI class in future? */ public static URL urlFromSystemId(String sysId) throws IOException { try { /* 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); } return fileToURL(new File(sysId)); } catch (MalformedURLException 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 { 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. */ public static URL urlFromCurrentDir() throws IOException /* an IOException */ { /* This seems to work; independent of whether there happens to * be such/file dir or not. */ return fileToURL(new File("a").getAbsoluteFile().getParentFile()); } /** * 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())) { /* On Windows, we can only create file readers for local * files... not sure about NFS, but let's be conservative: */ String host = url.getHost(); if (host == null || host.length() == 0) { return new FileInputStream(url.getPath()); } } 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. */ public static OutputStream outputStreamFromURL(URL url) throws IOException { if ("file".equals(url.getProtocol())) { // as with inputStreamFromURL, avoid probs with Windows network mounts: String host = url.getHost(); if (host == null || host.length() == 0) { return new FileOutputStream(url.getPath()); } } return url.openConnection().getOutputStream(); } /** * This method is added because the default conversion using * <code>file.toURL()</code> turns out to be rather slow, as * it tries to figure out if the file is actually a directory. * Now, for our use cases this is irrelevant, so we can optimize * out that expensive part. */ public static URL fileToURL(File f) throws IOException { /* Based on earlier experiences, looked like using * File.toURL() is rather expensive (at least on jdk1.4/1.5), * so let's just use a faster replacement */ String absPath = f.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); } public static String fileToSystemId(File f) throws IOException { return fileToURL(f).toExternalForm(); } public static String urlToSystemId(URL u) { return u.toExternalForm(); } /* /////////////////////////////////////////// // Private helper methods /////////////////////////////////////////// */ /** * 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(MalformedURLException mex, String sysId) throws IOException { IOException ie = new IOException("[resolving systemId '"+sysId +"']: "+mex.toString()); ie.initCause(mex); throw ie; } }