View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.io;
20  
21  import org.apache.shiro.util.ClassUtils;
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import java.io.FileInputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.net.URL;
29  
30  /**
31   * Static helper methods for loading {@code Stream}-backed resources.
32   *
33   * @see #getInputStreamForPath(String)
34   * @since 0.2
35   */
36  public class ResourceUtils {
37  
38      /**
39       * Resource path prefix that specifies to load from a classpath location, value is <b>{@code classpath:}</b>
40       */
41      public static final String CLASSPATH_PREFIX = "classpath:";
42      /**
43       * Resource path prefix that specifies to load from a url location, value is <b>{@code url:}</b>
44       */
45      public static final String URL_PREFIX = "url:";
46      /**
47       * Resource path prefix that specifies to load from a file location, value is <b>{@code file:}</b>
48       */
49      public static final String FILE_PREFIX = "file:";
50  
51      /**
52       * Private internal log instance.
53       */
54      private static final Logger log = LoggerFactory.getLogger(ResourceUtils.class);
55  
56      /**
57       * Prevent instantiation.
58       */
59      private ResourceUtils() {
60      }
61  
62      /**
63       * Returns {@code true} if the resource path is not null and starts with one of the recognized
64       * resource prefixes ({@link #CLASSPATH_PREFIX CLASSPATH_PREFIX},
65       * {@link #URL_PREFIX URL_PREFIX}, or {@link #FILE_PREFIX FILE_PREFIX}), {@code false} otherwise.
66       *
67       * @param resourcePath the resource path to check
68       * @return {@code true} if the resource path is not null and starts with one of the recognized
69       *         resource prefixes, {@code false} otherwise.
70       * @since 0.9
71       */
72      @SuppressWarnings({"UnusedDeclaration"})
73      public static boolean hasResourcePrefix(String resourcePath) {
74          return resourcePath != null &&
75                  (resourcePath.startsWith(CLASSPATH_PREFIX) ||
76                          resourcePath.startsWith(URL_PREFIX) ||
77                          resourcePath.startsWith(FILE_PREFIX));
78      }
79  
80      /**
81       * Returns {@code true} if the resource at the specified path exists, {@code false} otherwise.  This
82       * method supports scheme prefixes on the path as defined in {@link #getInputStreamForPath(String)}.
83       *
84       * @param resourcePath the path of the resource to check.
85       * @return {@code true} if the resource at the specified path exists, {@code false} otherwise.
86       * @since 0.9
87       */
88      public static boolean resourceExists(String resourcePath) {
89          InputStream stream = null;
90          boolean exists = false;
91  
92          try {
93              stream = getInputStreamForPath(resourcePath);
94              exists = true;
95          } catch (IOException e) {
96              stream = null;
97          } finally {
98              if (stream != null) {
99                  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 InputStream 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 }