All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.time4j.base.ResourceLoader Maven / Gradle / Ivy

There is a newer version: 4.38
Show newest version
/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2016 Meno Hochschild, 
 * -----------------------------------------------------------------------
 * This file (ResourceLoader.java) is part of project Time4J.
 *
 * Time4J is free software: You can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * Time4J is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Time4J. If not, see .
 * -----------------------------------------------------------------------
 */

package net.time4j.base;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ServiceLoader;


/**
 * 

Defines a general access point of loading any text resources and services.

* *

Specification: * All external subclasses must have a public no-arg constructor.

* * @author Meno Hochschild * @since 3.5/4.3 */ /*[deutsch] *

Definiert einen allgemeinen Zugriffspunkt zum Laden von Textressourcen und Services.

* *

Specification: * All external subclasses must have a public no-arg constructor.

* * @author Meno Hochschild * @since 3.5/4.3 */ public abstract class ResourceLoader { //~ Statische Felder/Initialisierungen -------------------------------- /** *

Name of system property responsible for getting an external instance as fully qualified class name.

* *

Time4J will throw an {@code Error} if the configuration entry is wrong.

*/ /** *

Name der system property, über die eine externe Instanz mittels eines vollständig * qualifizierten Klassennamens verwendet wird.

* *

Time4J wird einen {@code Error} werfen, wenn der Konfigurationseintrag falsch ist.

*/ public static final String EXTERNAL_RESOURCE_LOADER = "net.time4j.base.ResourceLoader"; /** *

Name of system property controlling if the use of classloader should be enforced instead * of trying an URI-construction first.

* *

The value is either "true" or "false" (default). This property will be * ignored on Android platforms.

* * @since 3.16/4.13 */ /** *

Name der system property, die kontrolliert, ob nur der Classloader statt einer * URI-Konstruktion verwendet werden soll.

* *

Der Wert ist entweder "true" oder "false" (Vorgabe). Auf Android wird * diese Eigenschaft ignoriert.

* * @since 3.16/4.13 */ public static final String USE_OF_CLASSLOADER_ONLY = "net.time4j.base.useClassloaderOnly"; private static final boolean ANDROID; private static final ResourceLoader INSTANCE; private static final boolean ENFORCE_USE_OF_CLASSLOADER; static { ANDROID = "Dalvik".equalsIgnoreCase(System.getProperty("java.vm.name")); ENFORCE_USE_OF_CLASSLOADER = !ANDROID && Boolean.getBoolean(USE_OF_CLASSLOADER_ONLY); String rl = System.getProperty(EXTERNAL_RESOURCE_LOADER); if (rl == null) { INSTANCE = new StdResourceLoader(); } else { try { INSTANCE = (ResourceLoader) Class.forName(rl).newInstance(); } catch (Exception e) { throw new AssertionError( "Wrong configuration of external resource loader: " + e.getMessage()); } } } //~ Konstruktoren ----------------------------------------------------- /** * For subclasses only. * * @see #getInstance() */ protected ResourceLoader() { super(); } //~ Methoden ---------------------------------------------------------- /** *

Applications should never use the constructor but this static method to achieve a general instance.

* * @return {@code ResourceLoader} * @since 3.5/4.3 */ /*[deutsch] *

Anwendungen sollte niemals den Konstruktor, sondern diese statische Fabrikmethode benutzen, um eine * allgemeine Instanz zu erhalten.

* * @return {@code ResourceLoader} * @since 3.5/4.3 */ public static ResourceLoader getInstance() { return INSTANCE; } /** *

Constructs an URI for given module resource.

* *

Attention: Some implementations might yield an uri without verifying if the uri resource really exists.

* * @param moduleName name of related time4j-module * @param moduleRef module-specific class reference * @param path path to text resource * @return uri of resource or {@code null} if unable to locate the resource * @since 3.5/4.3 */ /*[deutsch] *

Erstellt einen URI für die angegebene Ressource.

* *

Achtung: Einige Implementierungen können einen URI liefern, ohne die reale Existenz der URI-Ressource * zu prüfen.

* * @param moduleName name of related time4j-module * @param moduleRef module-specific class reference * @param path path to text resource * @return uri of resource or {@code null} if unable to locate the resource * @since 3.5/4.3 */ public abstract URI locate( String moduleName, Class moduleRef, String path ); /** *

Loads given URI-resource as input stream.

* *

Callers are responsible for closing the result stream.

* * @param uri uniform resource identifier as result of locate-method (optional) * @param noCache avoid caching? * @return input stream or {@code null} if the resource could not be opened * @see #locate(String, Class, String) * @since 3.5/4.3 */ /*[deutsch] *

Lädt die angegebene URI-Ressource als {@code InputStream}.

* *

Aufrufer sind dafür verantwortlich, den Eingabestrom zu schließen

* * @param uri uniform resource identifier as result of locate-method (optional) * @param noCache avoid caching? * @return input stream or {@code null} if the resource could not be opened * @see #locate(String, Class, String) * @since 3.5/4.3 */ public abstract InputStream load( URI uri, boolean noCache ); /** *

Loads a resource as input stream based on the classloader of given module reference.

* *

Callers are responsible for closing the result stream.

* * @param moduleRef module-specific class reference * @param path path to text resource (must be understandable by class loaders) * @param noCache avoid caching? * @return input stream * @throws IOException if the stream cannot be opened or if this method is called on Android platforms * @since 3.16/4.13 */ /*[deutsch] *

Lädt eine Ressource als {@code InputStream}, indem der Classloader der * angegebenen Modulreferenz herangezogen wird.

* *

Aufrufer sind dafür verantwortlich, den Eingabestrom zu schließen

* * @param moduleRef module-specific class reference * @param path path to text resource (must be understandable by class loaders) * @param noCache avoid caching? * @return input stream * @throws IOException if the stream cannot be opened or if this method is called on Android platforms * @since 3.16/4.13 */ public final InputStream load( Class moduleRef, String path, boolean noCache ) throws IOException { if (ANDROID) { throw new FileNotFoundException(path); } URL url = moduleRef.getClassLoader().getResource(path); if (noCache) { URLConnection conn = url.openConnection(); conn.setUseCaches(false); conn.connect(); // explicit for clarity return conn.getInputStream(); } else { return url.openStream(); } } /** *

Finds a collection of service providers available for given service provider interface.

* * @param generic service type * @param serviceInterface service provider interface * @return iterable collection of service providers * @since 3.5/4.3 */ /*[deutsch] *

Findet eine Menge von Service Provider-Objekten, die zum angegebenen Interface * verfügbar sind.

* * @param generic service type * @param serviceInterface service provider interface * @return iterable collection of service providers * @since 3.5/4.3 */ public abstract Iterable services(Class serviceInterface); //~ Innere Klassen ---------------------------------------------------- private static class StdResourceLoader extends ResourceLoader { //~ Konstruktoren ------------------------------------------------- protected StdResourceLoader() { super(); if (ANDROID) { throw new IllegalStateException("The module time4j-android is not active. Check your configuration."); } } //~ Methoden ------------------------------------------------------ @Override public URI locate( String moduleName, Class moduleRef, String path ) { // try uri construction whose initialization time is much quicker than querying the class loader String constructedUri = null; try { ProtectionDomain pd = moduleRef.getProtectionDomain(); // null on android platform CodeSource cs = ((pd == null) ? null : pd.getCodeSource()); if (cs != null) { constructedUri = cs.getLocation().toExternalForm(); if (constructedUri.endsWith(".jar")) { constructedUri = "jar:" + constructedUri + "!/"; } constructedUri += path; return new URI(constructedUri); } } catch (SecurityException se) { // use fallback via class loader later } catch (URISyntaxException e) { System.err.println("Warning: malformed resource path = " + constructedUri); } return null; } @Override public InputStream load( URI uri, boolean noCache ) { if ((uri == null) || ENFORCE_USE_OF_CLASSLOADER) { return null; } try { URL url = uri.toURL(); if (noCache) { URLConnection conn = url.openConnection(); conn.setUseCaches(false); conn.connect(); // explicit for clarity return conn.getInputStream(); } else { return url.openStream(); } } catch (IOException ioe) { if (uri.toString().contains(".repository")) { // print warning for tzdata-repository only System.err.println( "Warning: Loading of resource " + uri + " failed (" + ioe.getMessage() + "). " + "Consider setting the system property \"" + USE_OF_CLASSLOADER_ONLY + "\" for reducing overhead."); ioe.printStackTrace(System.err); } return null; } } @Override public Iterable services(Class serviceInterface) { return ServiceLoader.load(serviceInterface, serviceInterface.getClassLoader()); } } }