001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.utils;
014
015import static org.apache.juneau.internal.ObjectUtils.*;
016
017import java.io.*;
018import java.util.*;
019import java.util.concurrent.*;
020
021import org.apache.juneau.internal.*;
022
023/**
024 * Class for retrieving and caching resource files from the classpath.
025 *
026 * @deprecated Use {@link org.apache.juneau.cp.ResourceManager}.
027 */
028@Deprecated
029public final class ClasspathResourceManager {
030
031   // Maps resource names+locales to found resources.
032   private final ConcurrentHashMap<ResourceKey,byte[]> byteCache;
033   private final ConcurrentHashMap<ResourceKey,String> stringCache;
034
035   private final Class<?> baseClass;
036   private final ClasspathResourceFinder resourceFinder;
037   private final boolean useCache;
038
039   /**
040    * Constructor.
041    *
042    * @param baseClass The default class to use for retrieving resources from the classpath.
043    * @param resourceFinder The resource finder implementation.
044    * @param useCache If <jk>true</jk>, retrieved resources are stored in an in-memory cache for fast lookup.
045    */
046   public ClasspathResourceManager(Class<?> baseClass, ClasspathResourceFinder resourceFinder, boolean useCache) {
047      this.baseClass = baseClass;
048      this.resourceFinder = resourceFinder;
049      this.useCache = useCache;
050      if (useCache) {
051         this.byteCache = new ConcurrentHashMap<>();
052         this.stringCache = new ConcurrentHashMap<>();
053      } else {
054         this.byteCache = null;
055         this.stringCache = null;
056      }
057   }
058
059   /**
060    * Constructor.
061    *
062    * <p>
063    * Uses default {@link ClasspathResourceFinderBasic} for finding resources.
064    *
065    * @param baseClass The default class to use for retrieving resources from the classpath.
066    */
067   public ClasspathResourceManager(Class<?> baseClass) {
068      this(baseClass, new ClasspathResourceFinderBasic(), false);
069   }
070
071   /**
072    * Finds the resource with the given name.
073    *
074    * @param name Name of the desired resource.
075    * @return An input stream to the object, or <jk>null</jk> if the resource could not be found.
076    * @throws IOException Thrown by underlying stream.
077    */
078   public InputStream getStream(String name) throws IOException {
079      return getStream(name, null);
080   }
081
082   /**
083    * Finds the resource with the given name for the specified locale and returns it as an input stream.
084    *
085    * @param name Name of the desired resource.
086    * @param locale The locale.  Can be <jk>null</jk>.
087    * @return An input stream to the object, or <jk>null</jk> if the resource could not be found.
088    * @throws IOException Thrown by underlying stream.
089    */
090   public InputStream getStream(String name, Locale locale) throws IOException {
091      return getStream(baseClass, name, locale);
092   }
093
094   /**
095    * Finds the resource with the given name for the specified locale and returns it as an input stream.
096    *
097    * @param baseClass
098    *    Overrides the default class to use for retrieving the classpath resource.
099    *    <br>If <jk>null</jk>, uses the base class passed in through the constructor of this class.
100    * @param name Name of the desired resource.
101    * @param locale The locale.  Can be <jk>null</jk>.
102    * @return An input stream to the object, or <jk>null</jk> if the resource could not be found.
103    * @throws IOException Thrown by underlying stream.
104    */
105   public InputStream getStream(Class<?> baseClass, String name, Locale locale) throws IOException {
106
107      if (baseClass == null)
108         baseClass = this.baseClass;
109
110      if (! useCache)
111         return resourceFinder.findResource(baseClass, name, locale);
112
113      ResourceKey key = new ResourceKey(name, locale);
114
115      byte[] r = byteCache.get(key);
116      if (r == null) {
117         try (InputStream is = resourceFinder.findResource(baseClass, name, locale)) {
118            if (is != null)
119               byteCache.putIfAbsent(key, IOUtils.readBytes(is, 1024));
120         }
121      }
122
123      r = byteCache.get(key);
124      return r == null ? null : new ByteArrayInputStream(r);
125   }
126
127   /**
128    * Finds the resource with the given name and converts it to a simple string.
129    *
130    * @param name Name of the desired resource.
131    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
132    * @throws IOException Thrown by underlying stream.
133    */
134   public String getString(String name) throws IOException {
135      return getString(baseClass, name, null);
136   }
137
138   /**
139    * Finds the resource with the given name and converts it to a simple string.
140    *
141    * @param baseClass
142    *    Overrides the default class to use for retrieving the classpath resource.
143    *    <br>If <jk>null</jk>, uses the base class passed in through the constructor of this class.
144    * @param name Name of the desired resource.
145    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
146    * @throws IOException Thrown by underlying stream.
147    */
148   public String getString(Class<?> baseClass, String name) throws IOException {
149      return getString(baseClass, name, null);
150   }
151
152   /**
153    * Finds the resource with the given name and converts it to a simple string.
154    *
155    * @param name Name of the desired resource.
156    * @param locale The locale.  Can be <jk>null</jk>.
157    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
158    * @throws IOException Thrown by underlying stream.
159    */
160   public String getString(String name, Locale locale) throws IOException {
161      return getString(baseClass, name, locale);
162   }
163
164   /**
165    * Finds the resource with the given name and converts it to a simple string.
166    *
167    * @param baseClass
168    *    Overrides the default class to use for retrieving the classpath resource.
169    *    <br>If <jk>null</jk>, uses the base class passed in through the constructor of this class.
170    * @param name Name of the desired resource.
171    * @param locale The locale.  Can be <jk>null</jk>.
172    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
173    * @throws IOException Thrown by underlying stream.
174    */
175   public String getString(Class<?> baseClass, String name, Locale locale) throws IOException {
176
177      if (baseClass == null)
178         baseClass = this.baseClass;
179
180      if (! useCache) {
181         try (InputStream is = resourceFinder.findResource(baseClass, name, locale)) {
182            return IOUtils.read(is, IOUtils.UTF8);
183         }
184      }
185
186      ResourceKey key = new ResourceKey(name, locale);
187
188      String r = stringCache.get(key);
189      if (r == null) {
190         try (InputStream is = resourceFinder.findResource(baseClass, name, locale)) {
191            if (is != null)
192               stringCache.putIfAbsent(key, IOUtils.read(is, IOUtils.UTF8));
193         }
194      }
195
196      return stringCache.get(key);
197   }
198
199   private class ResourceKey {
200      final String name;
201      final Locale locale;
202
203      ResourceKey(String name, Locale locale) {
204         this.name = name;
205         this.locale = locale;
206      }
207
208      @Override
209      public int hashCode() {
210         return name.hashCode() + (locale == null ? 0 : locale.hashCode());
211      }
212
213      @Override
214      public boolean equals(Object o) {
215         return (o instanceof ResourceKey) && eq(this, (ResourceKey)o, (x,y)->eq(x.name, y.name) && eq(x.locale, y.locale));
216      }
217   }
218}