001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019 package org.apache.shiro.io;
020
021 import org.apache.shiro.util.ClassUtils;
022 import org.slf4j.Logger;
023 import org.slf4j.LoggerFactory;
024
025 import java.io.FileInputStream;
026 import java.io.IOException;
027 import java.io.InputStream;
028 import java.net.URL;
029
030 /**
031 * Static helper methods for loading {@code Stream}-backed resources.
032 *
033 * @see #getInputStreamForPath(String)
034 * @since 0.2
035 */
036 public class ResourceUtils {
037
038 /**
039 * Resource path prefix that specifies to load from a classpath location, value is <b>{@code classpath:}</b>
040 */
041 public static final String CLASSPATH_PREFIX = "classpath:";
042 /**
043 * Resource path prefix that specifies to load from a url location, value is <b>{@code url:}</b>
044 */
045 public static final String URL_PREFIX = "url:";
046 /**
047 * Resource path prefix that specifies to load from a file location, value is <b>{@code file:}</b>
048 */
049 public static final String FILE_PREFIX = "file:";
050
051 /**
052 * Private internal log instance.
053 */
054 private static final Logger log = LoggerFactory.getLogger(ResourceUtils.class);
055
056 /**
057 * Prevent instantiation.
058 */
059 private ResourceUtils() {
060 }
061
062 /**
063 * Returns {@code true} if the resource path is not null and starts with one of the recognized
064 * resource prefixes ({@link #CLASSPATH_PREFIX CLASSPATH_PREFIX},
065 * {@link #URL_PREFIX URL_PREFIX}, or {@link #FILE_PREFIX FILE_PREFIX}), {@code false} otherwise.
066 *
067 * @param resourcePath the resource path to check
068 * @return {@code true} if the resource path is not null and starts with one of the recognized
069 * resource prefixes, {@code false} otherwise.
070 * @since 0.9
071 */
072 @SuppressWarnings({"UnusedDeclaration"})
073 public static boolean hasResourcePrefix(String resourcePath) {
074 return resourcePath != null &&
075 (resourcePath.startsWith(CLASSPATH_PREFIX) ||
076 resourcePath.startsWith(URL_PREFIX) ||
077 resourcePath.startsWith(FILE_PREFIX));
078 }
079
080 /**
081 * Returns {@code true} if the resource at the specified path exists, {@code false} otherwise. This
082 * method supports scheme prefixes on the path as defined in {@link #getInputStreamForPath(String)}.
083 *
084 * @param resourcePath the path of the resource to check.
085 * @return {@code true} if the resource at the specified path exists, {@code false} otherwise.
086 * @since 0.9
087 */
088 public static boolean resourceExists(String resourcePath) {
089 InputStream stream = null;
090 boolean exists = false;
091
092 try {
093 stream = getInputStreamForPath(resourcePath);
094 exists = true;
095 } catch (IOException e) {
096 stream = null;
097 } finally {
098 if (stream != null) {
099 try {
100 stream.close();
101 } catch (IOException ignored) {
102 }
103 }
104 }
105
106 return exists;
107 }
108
109
110 /**
111 * Returns the InputStream for the resource represented by the specified path, supporting scheme
112 * prefixes that direct how to acquire the input stream
113 * ({@link #CLASSPATH_PREFIX CLASSPATH_PREFIX},
114 * {@link #URL_PREFIX URL_PREFIX}, or {@link #FILE_PREFIX FILE_PREFIX}). If the path is not prefixed by one
115 * of these schemes, the path is assumed to be a file-based path that can be loaded with a
116 * {@link FileInputStream FileInputStream}.
117 *
118 * @param resourcePath the String path representing the resource to obtain.
119 * @return the InputStraem for the specified resource.
120 * @throws IOException if there is a problem acquiring the resource at the specified path.
121 */
122 public static InputStream getInputStreamForPath(String resourcePath) throws IOException {
123
124 InputStream is;
125 if (resourcePath.startsWith(CLASSPATH_PREFIX)) {
126 is = loadFromClassPath(stripPrefix(resourcePath));
127
128 } else if (resourcePath.startsWith(URL_PREFIX)) {
129 is = loadFromUrl(stripPrefix(resourcePath));
130
131 } else if (resourcePath.startsWith(FILE_PREFIX)) {
132 is = loadFromFile(stripPrefix(resourcePath));
133
134 } else {
135 is = loadFromFile(resourcePath);
136 }
137
138 if (is == null) {
139 throw new IOException("Resource [" + resourcePath + "] could not be found.");
140 }
141
142 return is;
143 }
144
145 private static InputStream loadFromFile(String path) throws IOException {
146 if (log.isDebugEnabled()) {
147 log.debug("Opening file [" + path + "]...");
148 }
149 return new FileInputStream(path);
150 }
151
152 private static InputStream loadFromUrl(String urlPath) throws IOException {
153 log.debug("Opening url {}", urlPath);
154 URL url = new URL(urlPath);
155 return url.openStream();
156 }
157
158 private static InputStream loadFromClassPath(String path) {
159 log.debug("Opening resource from class path [{}]", path);
160 return ClassUtils.getResourceAsStream(path);
161 }
162
163 private static String stripPrefix(String resourcePath) {
164 return resourcePath.substring(resourcePath.indexOf(":") + 1);
165 }
166
167 /**
168 * Convenience method that closes the specified {@link InputStream InputStream}, logging any
169 * {@link IOException IOException} that might occur. If the {@code InputStream}
170 * argument is {@code null}, this method does nothing. It returns quietly in all cases.
171 *
172 * @param is the {@code InputStream} to close, logging any {@code IOException} that might occur.
173 */
174 public static void close(InputStream is) {
175 if (is != null) {
176 try {
177 is.close();
178 } catch (IOException e) {
179 log.warn("Error closing input stream.", e);
180 }
181 }
182 }
183 }