// Parse a single line from the given configuration file, adding the name // on the line to the names list. // private int parseLine(Class<?> service, URL u, BufferedReader r, int lc, List<String> names) throws IOException, ServiceConfigurationError { String ln = r.readLine(); if (ln == null) { return -1; } int ci = ln.indexOf('#'); if (ci >= 0) ln = ln.substring(0, ci); ln = ln.trim(); int n = ln.length(); if (n != 0) { if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) fail(service, u, lc, "Illegal configuration-file syntax"); int cp = ln.codePointAt(0); if (!Character.isJavaIdentifierStart(cp)) fail(service, u, lc, "Illegal provider-class name: " + ln); for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { cp = ln.codePointAt(i); if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) fail(service, u, lc, "Illegal provider-class name: " + ln); } if (!providers.containsKey(ln) && !names.contains(ln)) names.add(ln); } return lc + 1; }
// Parse the content of the given URL as a provider-configuration file. // // @param service // The service type for which providers are being sought; // used to construct error detail strings // // @param u // The URL naming the configuration file to be parsed // // @return A (possibly empty) iterator that will yield the provider-class // names in the given configuration file that are not yet members // of the returned set // // @throws ServiceConfigurationError // If an I/O error occurs while reading from the given URL, or // if a configuration-file format error is detected // private Iterator<String> parse(Class<?> service, URL u) throws ServiceConfigurationError { InputStream in = null; ArrayList<String> names = new ArrayList<>(); try { // The problem is that by default, streams opened with // u.openInputStream use a cached reference to a JarFile, which // is separate from the reference used by URLClassLoader, and // which is not closed by URLClassLoader.close(). // The workaround is to disable caching for this specific jar file, // so that the reference to the jar file can be closed when the // file has been read. // Original code: // in = u.openStream(); // Workaround ... URLConnection uc = u.openConnection(); uc.setUseCaches(false); in = uc.getInputStream(); // ... end of workaround. try (BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"))) { int lc = 1; while ((lc = parseLine(service, u, r, lc, names)) >= 0) ; } } catch (IOException x) { fail(service, "Error reading configuration file", x); } finally { try { if (in != null) in.close(); } catch (IOException y) { fail(service, "Error closing configuration file", y); } } return names.iterator(); }
private static void fail(Class<?> service, URL u, int line, String msg) throws ServiceConfigurationError { fail(service, u + ":" + line + ": " + msg); }