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.FileUtils.*; 016 017import java.io.*; 018import java.util.*; 019import java.util.ResourceBundle.*; 020 021import org.apache.juneau.cp.*; 022 023/** 024 * Utility class for finding resources for a class. 025 * 026 * <p> 027 * Same as {@link Class#getResourceAsStream(String)} except looks for resources with localized file names. 028 * 029 * <p> 030 * If the <c>locale</c> is specified, then we look for resources whose name matches that locale. 031 * For example, if looking for the resource <js>"MyResource.txt"</js> for the Japanese locale, we will look for 032 * files in the following order: 033 * <ol> 034 * <li><js>"MyResource_ja_JP.txt"</js> 035 * <li><js>"MyResource_ja.txt"</js> 036 * <li><js>"MyResource.txt"</js> 037 * </ol> 038 * 039 * @deprecated Use {@link SimpleResourceFinder}. 040 */ 041@Deprecated 042public class ClasspathResourceFinderSimple implements ClasspathResourceFinder { 043 044 /** 045 * Reusable instance. 046 */ 047 public static final ClasspathResourceFinderSimple INSTANCE = new ClasspathResourceFinderSimple(); 048 049 private static final ResourceBundle.Control RB_CONTROL = ResourceBundle.Control.getControl(Control.FORMAT_DEFAULT); 050 private static final List<Locale> ROOT_LOCALE = Arrays.asList(Locale.ROOT); 051 052 053 @Override /* ClasspathResourceFinder */ 054 public InputStream findResource(Class<?> baseClass, String name, Locale locale) throws IOException { 055 return findClasspathResource(baseClass, name, locale); 056 } 057 058 /** 059 * Workhorse method for retrieving a resource from the classpath. 060 * 061 * <p> 062 * This method can be overridden by subclasses to provide customized handling of resource retrieval from the classpath. 063 * 064 * @param baseClass The base class providing the classloader. 065 * @param name The resource name. 066 * @param locale 067 * The resource locale. 068 * <br>If <jk>null</jk>, won't look for localized file names. 069 * @return The resource stream, or <jk>null</jk> if it couldn't be found. 070 * @throws IOException Thrown by underlying stream. 071 */ 072 protected InputStream findClasspathResource(Class<?> baseClass, String name, Locale locale) throws IOException { 073 074 if (locale == null) 075 return getResourceAsStream(baseClass, name); 076 077 for (String n : getCandidateFileNames(name, locale)) { 078 InputStream is = getResourceAsStream(baseClass, n); 079 if (is != null) 080 return is; 081 } 082 return null; 083 } 084 085 private InputStream getResourceAsStream(Class<?> baseClass, String name) { 086 return baseClass.getResourceAsStream(name); 087 } 088 089 /** 090 * Returns the candidate file names for the specified file name in the specified locale. 091 * 092 * <p> 093 * For example, if looking for the <js>"MyResource.txt"</js> file in the Japanese locale, the iterator will return 094 * names in the following order: 095 * <ol> 096 * <li><js>"MyResource_ja_JP.txt"</js> 097 * <li><js>"MyResource_ja.txt"</js> 098 * <li><js>"MyResource.txt"</js> 099 * </ol> 100 * 101 * <p> 102 * If the locale is <jk>null</jk>, then it will only return <js>"MyResource.txt"</js>. 103 * 104 * @param fileName The name of the file to get candidate file names on. 105 * @param l 106 * The locale. 107 * <br>If <jk>null</jk>, won't look for localized file names. 108 * @return An iterator of file names to look at. 109 */ 110 protected static Iterable<String> getCandidateFileNames(final String fileName, final Locale l) { 111 return new Iterable<String>() { 112 @Override 113 public Iterator<String> iterator() { 114 return new Iterator<String>() { 115 final Iterator<Locale> locales = getCandidateLocales(l).iterator(); 116 String baseName, ext; 117 118 @Override 119 public boolean hasNext() { 120 return locales.hasNext(); 121 } 122 123 @Override 124 public String next() { 125 Locale l2 = locales.next(); 126 if (l2.toString().isEmpty()) 127 return fileName; 128 if (baseName == null) 129 baseName = getBaseName(fileName); 130 if (ext == null) 131 ext = getExtension(fileName); 132 return baseName + "_" + l2.toString() + (ext.isEmpty() ? "" : ('.' + ext)); 133 } 134 @Override 135 public void remove() { 136 throw new UnsupportedOperationException(); 137 } 138 }; 139 } 140 }; 141 } 142 143 /** 144 * Returns the candidate locales for the specified locale. 145 * 146 * <p> 147 * For example, if <c>locale</c> is <js>"ja_JP"</js>, then this method will return: 148 * <ol> 149 * <li><js>"ja_JP"</js> 150 * <li><js>"ja"</js> 151 * <li><js>""</js> 152 * </ol> 153 * 154 * @param locale The locale to get the list of candidate locales for. 155 * @return The list of candidate locales. 156 */ 157 static final List<Locale> getCandidateLocales(Locale locale) { 158 if (locale == null) 159 return ROOT_LOCALE; 160 return RB_CONTROL.getCandidateLocales("", locale); 161 } 162}