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

jsyntaxpane.util.JarServiceProvider Maven / Gradle / Ivy

There is a newer version: 5.3.2
Show newest version
/*
 * Copyright 2008 Ayman Al-Sairafi [email protected]
 * 
 * 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 jsyntaxpane.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author subwiz
 * @author Ayman Al-Sairafi
 */
public class JarServiceProvider {

	public static final String SERVICES_ROOT = "META-INF/services/";
	private static final Logger LOG = Logger.getLogger(JarServiceProvider.class.getName());

	/**
	 * Prevent anyone from instantiating this class.
	 * Just use the static method
	 */
	private JarServiceProvider() {
	}

	private static ClassLoader getClassLoader() {
		ClassLoader cl = JarServiceProvider.class.getClassLoader();
		return cl == null ? ClassLoader.getSystemClassLoader() : cl;
	}

	/**
	 * Return an Object array from the file in META-INF/resources/{classname}
	 * @param cls
	 * @return
	 * @throws java.io.IOException
	 */
	public static List getServiceProviders(Class cls) throws IOException {
		ArrayList l = new ArrayList();
		ClassLoader cl = getClassLoader();
		String serviceFile = SERVICES_ROOT + cls.getName();
		Enumeration e = cl.getResources(serviceFile);
		while (e.hasMoreElements()) {
			URL u = e.nextElement();
			InputStream is = u.openStream();
			BufferedReader br = null;
			try {
				br = new BufferedReader(
					new InputStreamReader(is, Charset.forName("UTF-8")));
				String str = null;
				while ((str = br.readLine()) != null) {
					int commentStartIdx = str.indexOf("#");
					if (commentStartIdx != -1) {
						str = str.substring(0, commentStartIdx);
					}
					str = str.trim();
					if (str.length() == 0) {
						continue;
					}
					try {
						Object obj = cl.loadClass(str).newInstance();
						l.add(obj);
					} catch (Exception ex) {
						LOG.warning("Could not load: " + str);
						LOG.warning(ex.getMessage());
					}
				}
			} finally {
				if (br != null) {
					br.close();
				}
			}
		}
		return l;
	}

	/**
	 * Read a file in the META-INF/services location.  File name will be
	 * fully qualified classname, in all lower-case, appended with ".properties"
	 * If no file is found, then a an empty Property instance will be returned
	 * @param clazz
	 * @return Property file read.
	 */
	public static Properties readProperties(Class clazz) {
		return readProperties(clazz.getName());
	}

	/**
	 * Read a file in the META-INF/services named name appended with
	 * ".properties"
	 *
	 * If no file is found, then a an empty Property instance will be returned
	 * @param name name of file (use dots to separate subfolders).
	 * @return Property file read.
	 */
	public static Properties readProperties(String name) {
		Properties props = new Properties();
		String serviceFile = name.toLowerCase();
		if (!serviceFile.endsWith(".properties")) {
			serviceFile += ".properties";
		}
		InputStream is = findResource(serviceFile);
		if (is != null) {
			try {
				props.load(new InputStreamReader(is, "UTF-8"));
			} catch (IOException ex) {
				Logger.getLogger(JarServiceProvider.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
		return props;
	}

    /**
     * Read language specific files in the META-INF/services named name appended 
     * with ".properties". The contents of the files are merged as follows:
     * 
    *
  • First the default language file (<name>.properties) is read
  • *
  • Then the general language variant of the file * (<name>_<lang>.properties) is read and its * entries are added to/overwrite the entries of the default life
  • *
  • Last the country specific language variant of the file * (<name>_<lang>_<country>.properties) is read and its * entries are added to/overwrite the existing entries
  • *
* Example: You have three files: *
    *
  • config.properties which contains the complete configuration * (most likely with English menus, tooltips)
  • *
  • config_de.properties which only contains menu names and tooltips * in German language
  • *
  • config_de_CH which might just contain entries for specific * Swiss spelling variant of some words in a tooltip
  • *
      * * If no filesis found, then a an empty Property instance will be returned * @param name name of file (use dots to separate subfolders). * @param locale The locale for which to read the files * @return Property file read. */ public static Properties readProperties(String name, Locale locale) { // If name already ends in ".properties", then cut this off name = name.toLowerCase(); int idx = name.lastIndexOf(".properties"); if (idx > 0) { name = name.substring(0, idx); } // 1. Read properties of default langauge Properties props = readProperties(name); // 2. Read properties of general language variant if (locale != null && locale.getLanguage() != null) { name += "_"+locale.getLanguage(); Properties langProps = readProperties(name); props.putAll(langProps); } // 3. Read properties of country specific language variant if (locale != null && locale.getCountry() != null) { name += "_"+locale.getCountry(); Properties countryProps = readProperties(name); props.putAll(countryProps); } return props; } /** * Read a file in the META-INF/services named name appended with * ".properties", and returns it as a Map * If no file is found, then a an empty Property instance will be returned * @param name name of file (use dots to separate subfolders). * @return Map of keys and values */ public static Map readStringsMap(String name) { Properties props = readProperties(name); HashMap map = new HashMap(); if (props != null) { for (Map.Entry e : props.entrySet()) { map.put(e.getKey().toString(), e.getValue().toString()); } } return map; } /** * Read the given URL and returns a List of Strings for each input line * Each line will not have the line terminator. * * The resource is searched in /META-INF/services/url, then in * url, then the url is treated as a location in the current classpath * and an attempt to read it from that location is done. * * @param url location of file to read * @return List of Strings for each line read. or EMPTY_LIST if URL is not found */ @SuppressWarnings("unchecked") public static List readLines(String url) { InputStream is = findResource(url); if (is == null) { return Collections.EMPTY_LIST; } List lines = new ArrayList(); try { BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); for (String line = br.readLine(); line != null; line = br.readLine()) { // Trim and unescape some control chars line = line.trim().replace("\\n", "\n").replace("\\t", "\t"); lines.add(line); } } catch (IOException ex) { LOG.log(Level.SEVERE, null, ex); } finally { try { is.close(); } catch (IOException ex) { LOG.log(Level.SEVERE, null, ex); } return lines; } } /** * Attempt to find a location url. The following locations are searched in * sequence: * url, * SERVICES_ROOT/url * all classpath/url * @param url * @param cl classloader * @return InputSTream at that location, or null if not found * @see JarServiceProvider#findResource(java.lang.String) */ public static InputStream findResource(String url, ClassLoader cl) { InputStream is = null; URL loc = cl.getResource(url); if (loc == null) { loc = cl.getResource(url); } if (loc == null) { loc = cl.getResource(SERVICES_ROOT + url); } if (loc == null) { is = ClassLoader.getSystemResourceAsStream(url); } else { try { is = loc.openStream(); } catch (IOException ex) { Logger.getLogger(JarServiceProvider.class.getName()).log(Level.SEVERE, null, ex); } } return is; } /** * Attempt to find a location url. The following locations are searched in * sequence: * url, * SERVICES_ROOT/url * all classpath/url * The System ClassLoader is used. * @param url * @return InputSTream at that location, or null if not found * @see JarServiceProvider#findResource(java.lang.String, java.lang.ClassLoader) */ public static InputStream findResource(String url) { return findResource(url, getClassLoader()); } }