View Javadoc
1   /* ***************************************************************************
2    * Copyright (c) 2008 Brabenetz Harald, Austria.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   * 
16   *****************************************************************************/
17  package org.settings4j.contentresolver;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.net.URL;
22  
23  import org.apache.commons.io.IOUtils;
24  import org.settings4j.ContentResolver;
25  
26  /**
27   * {@link ContentResolver} implementation to read content from the Classpath.
28   * <p>
29   * Uses the default ClassLoader: typically the thread context ClassLoader
30   * see {@link #getClassLoader()}.
31   * <p>
32   * Optional Path Prefix is "classpath:".
33   * 
34   * @author Harald.Brabenetz
35   *
36   */
37  public class ClasspathContentResolver implements ContentResolver {
38  
39      /** General Logger for this Class. */
40      private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ClasspathContentResolver.class);
41  
42      /** Pseudo URL prefix for loading from the class path: "classpath:". */
43      public static final String CLASSPATH_URL_PREFIX = "classpath:";
44  
45  
46      /** {@inheritDoc} */
47      public void addContentResolver(final ContentResolver contentResolver) {
48          throw new UnsupportedOperationException("ClasspathContentResolver cannot add other ContentResolvers");
49      }
50  
51      /** {@inheritDoc} */
52      public byte[] getContent(final String key) {
53          final String normalizedKey = normalizeKey(key);
54  
55          try {
56              final InputStream is = getClassLoader().getResourceAsStream(normalizedKey);
57              if (is != null) {
58                  return IOUtils.toByteArray(is);
59              }
60              // else
61              return null;
62          } catch (final IOException e) {
63              LOG.error(e.getMessage(), e);
64              return null;
65          }
66      }
67  
68      /**
69       * Method to get onlx the URL for the given Key.
70       * <p>
71       * 
72       * @param key the key (could have a 'classpath:' prefix or not)
73       * @return The {@link URL}, see {@link ClassLoader#getResource(String)}.
74       */
75      public static URL getResource(final String key) {
76          final String normalizedKey = normalizeKey(key);
77  
78          return getClassLoader().getResource(normalizedKey);
79      }
80  
81  
82      /**
83       * Return the default ClassLoader to use: typically the thread context ClassLoader, if available; the ClassLoader
84       * that loaded the ClasspathContentResolver class will be used as fallback.
85       * <p>
86       * Call this method if you intend to use the thread context ClassLoader in a scenario where you absolutely need a
87       * non-null ClassLoader reference: for example, for class path resource loading (but not necessarily for
88       * <code>Class.forName</code>, which accepts a <code>null</code> ClassLoader reference as well).
89       * 
90       * @return the default ClassLoader (never <code>null</code>)
91       * @see java.lang.Thread#getContextClassLoader()
92       */
93      public static ClassLoader getClassLoader() {
94          ClassLoader cl = null;
95          try {
96              cl = Thread.currentThread().getContextClassLoader();
97          } catch (final Throwable ex) {
98              LOG.debug("Cannot access thread context ClassLoader - falling back to system class loader", ex);
99          }
100         if (cl == null) {
101             // No thread context class loader -> use class loader of this class.
102             cl = ClasspathContentResolver.class.getClassLoader(); 
103         }
104         return cl;
105     }
106 
107     private static String normalizeKey(final String key) {
108         String normalizedKey = key;
109         if (normalizedKey.startsWith(CLASSPATH_URL_PREFIX)) {
110             normalizedKey = normalizedKey.substring(CLASSPATH_URL_PREFIX.length());
111         }
112         if (normalizedKey.startsWith("/")) {
113             normalizedKey = normalizedKey.substring(1);
114         }
115         return normalizedKey;
116     }
117 }