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