/* * $Id$ * This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc * * Copyright (c) 2000-2012 Stephane GALLAND. * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports, * Universite de Technologie de Belfort-Montbeliard. * Copyright (c) 2013-2016 The original authors, and other authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.arakhne.afc.vmutil; import java.io.InputStream; import java.net.URL; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.xtext.xbase.lib.Inline; import org.eclipse.xtext.xbase.lib.Pure; /** * This utility class provides to load resources according to * several heuristics:<ul> * <li>search the resource in class paths;</li> * <li>search the resource in ./resources subdirectory in class paths.</li> * </ul> * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ * @since 4.2 */ public final class Resources { /** Character used to separate paths on an resource name. */ public static final String NAME_SEPARATOR = "/"; //$NON-NLS-1$ private static ResourceWrapper currentResourceInstance; static { URLHandlerUtil.installArakhneHandlers(); ResourceWrapper wrapper = null; switch (OperatingSystem.getCurrentOS()) { case ANDROID: wrapper = new AndroidResourceWrapper(); break; case AIX: case BSD: case FREEBSD: case HPUX: case LINUX: case MACOSX: case NETBSD: case OPENBSD: case OTHER: case SOLARIS: case WIN: default: } if (wrapper == null) { currentResourceInstance = new StandardJREResourceWrapper(); } else { currentResourceInstance = wrapper; } } private Resources() { // } /** Replies the URL of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames. * * <p>The class loader replied by {@link ClassLoaderFinder} is used. * If it is <code>null</code>, the class loader of * the Resources class is used. * * @param path is the absolute path of the resource. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. */ @Pure public static URL getResource(String path) { return getResource((ClassLoader) null, path); } /** * Replies the URL of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames. * * <p>The name of {@code packagename} is translated into a resource * path (by replacing the dots by slashes) and the given path * is append to. For example, the two following codes are equivalent:<pre><code> * Resources.getResources(Package.getPackage("org.arakhne.afc"), "/a/b/c/d.png"); * Resources.getResources("org/arakhne/afc/a/b/c/d.png"); * </code></pre> * * <p>If the {@code classLoader} parameter is <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * If this last is <code>null</code>, the class loader of * the Resources class is used. * * @param classLoader is the research scope. If <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * @param packagename is the package in which the resource should be located. * @param path is the relative path of the resource in the package. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. * @since 6.2 */ @Pure public static URL getResource(ClassLoader classLoader, Package packagename, String path) { if (packagename == null || path == null) { return null; } final StringBuilder b = new StringBuilder(); b.append(packagename.getName().replaceAll( Pattern.quote("."), //$NON-NLS-1$ Matcher.quoteReplacement(NAME_SEPARATOR))); if (!path.startsWith(NAME_SEPARATOR)) { b.append(NAME_SEPARATOR); } b.append(path); return getResource(packagename.getClass().getClassLoader(), b.toString()); } /** * Replies the URL of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames. * * <p>The name of {@code classname} is translated into a resource * path (by remove the name of the class and replacing the dots by slashes) and the given path * is append to. For example, the two following codes are equivalent:<pre><code> * Resources.getResources(Resources.class, "/a/b/c/d.png"); * Resources.getResources("org/arakhne/vmutil/a/b/c/d.png"); * </code></pre> * * <p>The class loader of the given class is used. If it is <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * If it is also <code>null</code>, the class loader of this Resources * class is used. * * @param classname is located in the package in which the resource should be also located. * @param path is the absolute path of the resource. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. */ @Pure public static URL getResource(Class<?> classname, String path) { if (classname == null) { return null; } URL u = getResource(classname.getClassLoader(), classname.getPackage(), path); if (u == null) { u = getResource(classname.getClassLoader(), path); } return u; } /** * Replies the URL of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames. * * <p>If the {@code classLoader} parameter is <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * If this last is <code>null</code>, the class loader of * the Resources class is used. * * @param classLoader is the research scope. If <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * @param path is the absolute path of the resource. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. */ @Pure public static URL getResource(ClassLoader classLoader, String path) { return currentResourceInstance.getResource(classLoader, path); } /** * Replies the input stream of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames, and may not start the * path with a slash. * * <p>The class loader replied by {@link ClassLoaderFinder} is used. * If it is <code>null</code>, the class loader of * the Resources class is used. * * @param path is the absolute path of the resource. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. */ @Pure public static InputStream getResourceAsStream(String path) { return getResourceAsStream((ClassLoader) null, path); } /** * Replies the input stream of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames. * * <p>The name of {@code packagename} is translated into a resource * path (by replacing the dots by slashes) and the given path * is append to. For example, the two following codes are equivalent:<pre><code> * Resources.getResources(Package.getPackage("org.arakhne.afc"), "/a/b/c/d.png"); * Resources.getResources("org/arakhne/afc/a/b/c/d.png"); * </code></pre> * * <p>If the {@code classLoader} parameter is <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * If this last is <code>null</code>, the class loader of * the Resources class is used. * * @param classLoader is the research scope. If <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * @param packagename is the package in which the resource should be located. * @param path is the relative path of the resource in the package. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. * @since 6.2 */ @Pure public static InputStream getResourceAsStream(ClassLoader classLoader, Package packagename, String path) { if (packagename == null || path == null) { return null; } final StringBuilder b = new StringBuilder(); b.append(packagename.getName().replaceAll( Pattern.quote("."), //$NON-NLS-1$ Matcher.quoteReplacement(NAME_SEPARATOR))); if (!path.startsWith(NAME_SEPARATOR)) { b.append(NAME_SEPARATOR); } b.append(path); return getResourceAsStream(classLoader, b.toString()); } /** * Replies the input stream of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames. * * <p>The name of {@code classname} is translated into a resource * path (by remove the name of the class and replacing the dots by slashes) and the given path * is append to. For example, the two following codes are equivalent:<pre><code> * Resources.getResources(Resources.class, "/a/b/c/d.png"); * Resources.getResources("org/arakhne/vmutil/a/b/c/d.png"); * </code></pre> * * <p>The class loader of the given class is used. If it is <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * If it is also <code>null</code>, the class loader of this Resources * class is used. * * @param classname is located in the package in which the resource should be also located. * @param path is the absolute path of the resource. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. */ @Pure @SuppressWarnings("resource") public static InputStream getResourceAsStream(Class<?> classname, String path) { if (classname == null) { return null; } InputStream is = getResourceAsStream(classname.getClassLoader(), classname.getPackage(), path); if (is == null) { is = getResourceAsStream(classname.getClassLoader(), path); } return is; } /** * Replies the input stream of a resource. * * <p>You may use Unix-like syntax to write the resource path, ie. * you may use slashes to separate filenames, and may not start the * path with a slash. * * <p>If the {@code classLoader} parameter is <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * If this last is <code>null</code>, the class loader of * the Resources class is used. * * @param classLoader is the research scope. If <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * @param path is the absolute path of the resource. * @return the url of the resource or <code>null</code> if the resource was * not found in class paths. */ @Pure public static InputStream getResourceAsStream(ClassLoader classLoader, String path) { return currentResourceInstance.getResourceAsStream(classLoader, path); } /** * Replies the URL of a property resource that is associated to the given class. * * @param classname is the class for which the property resource should be replied. * @param locale is the expected localization of the resource file; or <code>null</code> * for the default. * @return the url of the property resource or <code>null</code> if the resource was * not found in class paths. * @since 7.0 */ @Pure @Inline(value = "Resources.getPropertyFile(($1).getClassLoader(), ($1), ($2))", imported = {Resources.class}) public static URL getPropertyFile(Class<?> classname, Locale locale) { return getPropertyFile(classname.getClassLoader(), classname, locale); } /** * Replies the URL of a property resource that is associated to the given class. * * @param classLoader is the research scope. If <code>null</code>, * the class loader replied by {@link ClassLoaderFinder} is used. * @param classname is the class for which the property resource should be replied. * @param locale is the expected localization of the resource file; or <code>null</code> * for the default. * @return the url of the property resource or <code>null</code> if the resource was * not found in class paths. */ @Pure public static URL getPropertyFile(ClassLoader classLoader, Class<?> classname, Locale locale) { final StringBuilder name = new StringBuilder(); // Localized file if (locale != null) { final String country = locale.getCountry(); if (country != null && !country.isEmpty()) { name.append(classname.getSimpleName()); name.append("_"); //$NON-NLS-1$ name.append(country); name.append(".properties"); //$NON-NLS-1$ final URL url = getResource(classLoader, classname.getPackage(), name.toString()); if (url != null) { return url; } } } // Default property file name.setLength(0); name.append(classname.getSimpleName()); name.append(".properties"); //$NON-NLS-1$ return getResource(classLoader, classname.getPackage(), name.toString()); } /** Translate the given resource name according to the current JVM standard. * * <p>The <code>resourceName</code> argument should be a fully * qualified class name. However, for compatibility with earlier * versions, Sun's Java SE Runtime Environments do not verify this, * and so it is possible to access <code>PropertyResourceBundle</code>s * by specifying a path name (using "/") instead of a fully * qualified class name (using "."). * In several VM, such as Dalvik, the translation from "." to "/" is not * automatically done by the VM to retreive the file. * * @param resourceName the name to translate. * @return the translated resource name. * @since 7.0 */ @Pure public static String translateResourceName(String resourceName) { return currentResourceInstance.translateResourceName(resourceName); } }