001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.camel.util; 018 019 import java.io.File; 020 import java.io.FileInputStream; 021 import java.io.FileNotFoundException; 022 import java.io.IOException; 023 import java.io.InputStream; 024 import java.net.HttpURLConnection; 025 import java.net.MalformedURLException; 026 import java.net.URI; 027 import java.net.URISyntaxException; 028 import java.net.URL; 029 import java.net.URLConnection; 030 import java.net.URLDecoder; 031 import java.util.Map; 032 033 import org.apache.camel.spi.ClassResolver; 034 import org.slf4j.Logger; 035 import org.slf4j.LoggerFactory; 036 037 /** 038 * Helper class for loading resources on the classpath or file system. 039 */ 040 public final class ResourceHelper { 041 042 private static final Logger LOG = LoggerFactory.getLogger(ResourceHelper.class); 043 044 private ResourceHelper() { 045 // utility class 046 } 047 048 /** 049 * Determines whether the URI has a scheme (e.g. file:, classpath: or http:) 050 * 051 * @param uri the URI 052 * @return <tt>true</tt> if the URI starts with a scheme 053 */ 054 public static boolean hasScheme(String uri) { 055 if (uri == null) { 056 return false; 057 } 058 059 return uri.startsWith("file:") || uri.startsWith("classpath:") || uri.startsWith("http:"); 060 } 061 062 /** 063 * Gets the scheme from the URI (e.g. file:, classpath: or http:) 064 * 065 * @param uri the uri 066 * @return the scheme, or <tt>null</tt> if no scheme 067 */ 068 public static String getScheme(String uri) { 069 if (hasScheme(uri)) { 070 return uri.substring(0, uri.indexOf(":") + 1); 071 } else { 072 return null; 073 } 074 } 075 076 /** 077 * Resolves the mandatory resource. 078 * <p/> 079 * If possible recommended to use {@link #resolveMandatoryResourceAsUrl(org.apache.camel.spi.ClassResolver, String)} 080 * 081 * @param classResolver the class resolver to load the resource from the classpath 082 * @param uri URI of the resource 083 * @return the resource as an {@link InputStream}. Remember to close this stream after usage. 084 * @throws java.io.IOException is thrown if the resource file could not be found or loaded as {@link InputStream} 085 */ 086 public static InputStream resolveMandatoryResourceAsInputStream(ClassResolver classResolver, String uri) throws IOException { 087 InputStream is = resolveResourceAsInputStream(classResolver, uri); 088 if (is == null) { 089 String resolvedName = resolveUriPath(uri); 090 throw new FileNotFoundException("Cannot find resource: " + resolvedName + " in classpath for URI: " + uri); 091 } else { 092 return is; 093 } 094 } 095 096 /** 097 * Resolves the resource. 098 * <p/> 099 * If possible recommended to use {@link #resolveMandatoryResourceAsUrl(org.apache.camel.spi.ClassResolver, String)} 100 * 101 * @param classResolver the class resolver to load the resource from the classpath 102 * @param uri URI of the resource 103 * @return the resource as an {@link InputStream}. Remember to close this stream after usage. Or <tt>null</tt> if not found. 104 * @throws java.io.IOException is thrown if error loading the resource 105 */ 106 public static InputStream resolveResourceAsInputStream(ClassResolver classResolver, String uri) throws IOException { 107 if (uri.startsWith("file:")) { 108 uri = ObjectHelper.after(uri, "file:"); 109 uri = tryDecodeUri(uri); 110 LOG.trace("Loading resource: {} from file system", uri); 111 return new FileInputStream(uri); 112 } else if (uri.startsWith("http:")) { 113 URL url = new URL(uri); 114 LOG.trace("Loading resource: {} from HTTP", uri); 115 URLConnection con = url.openConnection(); 116 con.setUseCaches(false); 117 try { 118 return con.getInputStream(); 119 } catch (IOException e) { 120 // close the http connection to avoid 121 // leaking gaps in case of an exception 122 if (con instanceof HttpURLConnection) { 123 ((HttpURLConnection) con).disconnect(); 124 } 125 throw e; 126 } 127 } else if (uri.startsWith("classpath:")) { 128 uri = ObjectHelper.after(uri, "classpath:"); 129 uri = tryDecodeUri(uri); 130 } 131 132 // load from classpath by default 133 String resolvedName = resolveUriPath(uri); 134 LOG.trace("Loading resource: {} from classpath", resolvedName); 135 return classResolver.loadResourceAsStream(resolvedName); 136 } 137 138 /** 139 * Resolves the mandatory resource. 140 * 141 * @param classResolver the class resolver to load the resource from the classpath 142 * @param uri uri of the resource 143 * @return the resource as an {@link java.net.URL}. 144 * @throws java.io.FileNotFoundException is thrown if the resource file could not be found 145 * @throws java.net.MalformedURLException if the URI is malformed 146 */ 147 public static URL resolveMandatoryResourceAsUrl(ClassResolver classResolver, String uri) throws FileNotFoundException, MalformedURLException { 148 URL url = resolveResourceAsUrl(classResolver, uri); 149 if (url == null) { 150 String resolvedName = resolveUriPath(uri); 151 throw new FileNotFoundException("Cannot find resource: " + resolvedName + " in classpath for URI: " + uri); 152 } else { 153 return url; 154 } 155 } 156 157 /** 158 * Resolves the resource. 159 * 160 * @param classResolver the class resolver to load the resource from the classpath 161 * @param uri uri of the resource 162 * @return the resource as an {@link java.net.URL}. Or <tt>null</tt> if not found. 163 * @throws java.net.MalformedURLException if the URI is malformed 164 */ 165 public static URL resolveResourceAsUrl(ClassResolver classResolver, String uri) throws MalformedURLException { 166 if (uri.startsWith("file:")) { 167 // check if file exists first 168 String name = ObjectHelper.after(uri, "file:"); 169 uri = tryDecodeUri(uri); 170 LOG.trace("Loading resource: {} from file system", uri); 171 File file = new File(name); 172 if (!file.exists()) { 173 return null; 174 } 175 return new URL(uri); 176 } else if (uri.startsWith("http:")) { 177 LOG.trace("Loading resource: {} from HTTP", uri); 178 return new URL(uri); 179 } else if (uri.startsWith("classpath:")) { 180 uri = ObjectHelper.after(uri, "classpath:"); 181 uri = tryDecodeUri(uri); 182 } 183 184 // load from classpath by default 185 String resolvedName = resolveUriPath(uri); 186 LOG.trace("Loading resource: {} from classpath", resolvedName); 187 return classResolver.loadResourceAsURL(resolvedName); 188 } 189 190 /** 191 * Is the given uri a http uri? 192 * 193 * @param uri the uri 194 * @return <tt>true</tt> if the uri starts with <tt>http:</tt> or <tt>https:</tt> 195 */ 196 public static boolean isHttpUri(String uri) { 197 if (uri == null) { 198 return false; 199 } 200 return uri.startsWith("http:") || uri.startsWith("https:"); 201 } 202 203 /** 204 * Appends the parameters to the given uri 205 * 206 * @param uri the uri 207 * @param parameters the additional parameters (will clear the map) 208 * @return a new uri with the additional parameters appended 209 * @throws URISyntaxException is thrown if the uri is invalid 210 */ 211 public static String appendParameters(String uri, Map<String, Object> parameters) throws URISyntaxException { 212 // add additional parameters to the resource uri 213 if (!parameters.isEmpty()) { 214 String query = URISupport.createQueryString(parameters); 215 URI u = new URI(uri); 216 u = URISupport.createURIWithQuery(u, query); 217 parameters.clear(); 218 return u.toString(); 219 } else { 220 return uri; 221 } 222 } 223 224 /** 225 * Helper operation used to remove relative path notation from 226 * resources. Most critical for resources on the Classpath 227 * as resource loaders will not resolve the relative paths correctly. 228 * 229 * @param name the name of the resource to load 230 * @return the modified or unmodified string if there were no changes 231 */ 232 private static String resolveUriPath(String name) { 233 // compact the path and use / as separator as that's used for loading resources on the classpath 234 return FileUtil.compactPath(name, '/'); 235 } 236 237 /** 238 * Tries decoding the uri. 239 * 240 * @param uri the uri 241 * @return the decoded uri, or the original uri 242 */ 243 private static String tryDecodeUri(String uri) { 244 try { 245 // try to decode as the uri may contain %20 for spaces etc 246 uri = URLDecoder.decode(uri, "UTF-8"); 247 } catch (Exception e) { 248 LOG.trace("Error URL decoding uri using UTF-8 encoding: {}. This exception is ignored.", uri); 249 // ignore 250 } 251 return uri; 252 } 253 254 }