/* * Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com * * 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<Object> getServiceProviders(Class cls) throws IOException { ArrayList<Object> l = new ArrayList<Object>(); ClassLoader cl = getClassLoader(); String serviceFile = SERVICES_ROOT + cls.getName(); Enumeration<URL> 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(); // JPEXS: Added locale support for menu actions String propSuffix = ".properties"; if (serviceFile.endsWith(propSuffix)) { serviceFile = serviceFile.substring(0, serviceFile.length() - propSuffix.length()); } Locale defaultLocale = Locale.getDefault(); String langName = defaultLocale.getLanguage(); InputStream is = null; is = findResource(serviceFile + "_" + langName + propSuffix); if (is == null) { is = findResource(serviceFile + propSuffix); } if (is != null) { try { props.load(is); } catch (IOException ex) { Logger.getLogger(JarServiceProvider.class.getName()).log(Level.SEVERE, null, ex); } } return props; } /** * Read a file in the META-INF/services named name appended with * ".properties", and returns it as a * <code>Map<String, String></code> 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<String, String> readStringsMap(String name) { Properties props = readProperties(name); HashMap<String, String> map = new HashMap<String, String>(); 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<String> readLines(String url) { InputStream is = findResource(url); if (is == null) { return Collections.EMPTY_LIST; } List<String> lines = new ArrayList<String>(); try { BufferedReader br = new BufferedReader(new InputStreamReader(is)); 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()); } }