990 next = null; 991 992 // attempt to load provider 993 Module module = provider.module(); 994 String cn = provider.providerName(); 995 Class<?> clazz = loadProviderInModule(module, cn); 996 return new ProviderImpl<T>(service, clazz, acc); 997 } 998 } 999 1000 /** 1001 * Implements lazy service provider lookup where the service providers are 1002 * configured via service configuration files. Service providers in named 1003 * modules are silently ignored by this lookup iterator. 1004 */ 1005 private final class LazyClassPathLookupIterator<T> 1006 implements Iterator<Provider<T>> 1007 { 1008 static final String PREFIX = "META-INF/services/"; 1009 1010 Enumeration<URL> configs; 1011 Iterator<String> pending; 1012 Class<?> nextClass; 1013 String nextErrorMessage; // when hasNext fails with CNFE 1014 1015 LazyClassPathLookupIterator() { } 1016 1017 /** 1018 * Parse a single line from the given configuration file, adding the 1019 * name on the line to the names list. 1020 */ 1021 private int parseLine(URL u, BufferedReader r, int lc, Set<String> names) 1022 throws IOException 1023 { 1024 String ln = r.readLine(); 1025 if (ln == null) { 1026 return -1; 1027 } 1028 int ci = ln.indexOf('#'); 1029 if (ci >= 0) ln = ln.substring(0, ci); 1030 ln = ln.trim(); 1031 int n = ln.length(); 1032 if (n != 0) { 1033 if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) 1034 fail(service, u, lc, "Illegal configuration-file syntax"); 1035 int cp = ln.codePointAt(0); 1036 if (!Character.isJavaIdentifierStart(cp)) 1037 fail(service, u, lc, "Illegal provider-class name: " + ln); 1038 int start = Character.charCount(cp); 1039 for (int i = start; i < n; i += Character.charCount(cp)) { 1040 cp = ln.codePointAt(i); 1041 if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) 1042 fail(service, u, lc, "Illegal provider-class name: " + ln); 1043 } 1044 names.add(ln); 1045 } 1046 return lc + 1; 1047 } 1048 1049 /** 1050 * Parse the content of the given URL as a provider-configuration file. 1051 */ 1052 private Iterator<String> parse(URL u) { 1053 Set<String> names = new LinkedHashSet<>(); // preserve insertion order 1054 try { 1055 URLConnection uc = u.openConnection(); 1056 uc.setUseCaches(false); 1057 try (InputStream in = uc.getInputStream(); 1058 BufferedReader r 1059 = new BufferedReader(new InputStreamReader(in, "utf-8"))) 1060 { 1061 int lc = 1; 1062 while ((lc = parseLine(u, r, lc, names)) >= 0); 1063 } 1064 } catch (IOException x) { 1065 fail(service, "Error accessing configuration file", x); 1066 } 1067 return names.iterator(); 1068 } 1069 1070 private boolean hasNextService() { 1071 if (nextClass != null || nextErrorMessage != null) { 1072 return true; 1073 } 1074 1075 Class<?> clazz = null; 1076 do { 1077 if (configs == null) { 1078 try { 1079 String fullName = PREFIX + service.getName(); 1080 if (loader == null) { 1081 configs = ClassLoader.getSystemResources(fullName); 1082 } else if (loader == ClassLoaders.platformClassLoader()) { 1083 // The platform classloader doesn't have a class path, 1084 // but the boot loader might. 1085 if (BootLoader.hasClassPath()) { 1086 configs = BootLoader.findResources(fullName); 1087 } else { 1088 configs = Collections.emptyEnumeration(); 1089 } 1090 } else { 1091 configs = loader.getResources(fullName); 1092 } 1093 } catch (IOException x) { 1094 fail(service, "Error locating configuration files", x); 1095 } | 990 next = null; 991 992 // attempt to load provider 993 Module module = provider.module(); 994 String cn = provider.providerName(); 995 Class<?> clazz = loadProviderInModule(module, cn); 996 return new ProviderImpl<T>(service, clazz, acc); 997 } 998 } 999 1000 /** 1001 * Implements lazy service provider lookup where the service providers are 1002 * configured via service configuration files. Service providers in named 1003 * modules are silently ignored by this lookup iterator. 1004 */ 1005 private final class LazyClassPathLookupIterator<T> 1006 implements Iterator<Provider<T>> 1007 { 1008 static final String PREFIX = "META-INF/services/"; 1009 1010 Set<String> providerNames = new HashSet<>(); // to avoid duplicates 1011 Enumeration<URL> configs; 1012 Iterator<String> pending; 1013 Class<?> nextClass; 1014 String nextErrorMessage; // when hasNext fails with CNFE 1015 1016 LazyClassPathLookupIterator() { } 1017 1018 /** 1019 * Parse a single line from the given configuration file, adding the 1020 * name on the line to set of names if not already seen. 1021 */ 1022 private int parseLine(URL u, BufferedReader r, int lc, Set<String> names) 1023 throws IOException 1024 { 1025 String ln = r.readLine(); 1026 if (ln == null) { 1027 return -1; 1028 } 1029 int ci = ln.indexOf('#'); 1030 if (ci >= 0) ln = ln.substring(0, ci); 1031 ln = ln.trim(); 1032 int n = ln.length(); 1033 if (n != 0) { 1034 if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) 1035 fail(service, u, lc, "Illegal configuration-file syntax"); 1036 int cp = ln.codePointAt(0); 1037 if (!Character.isJavaIdentifierStart(cp)) 1038 fail(service, u, lc, "Illegal provider-class name: " + ln); 1039 int start = Character.charCount(cp); 1040 for (int i = start; i < n; i += Character.charCount(cp)) { 1041 cp = ln.codePointAt(i); 1042 if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) 1043 fail(service, u, lc, "Illegal provider-class name: " + ln); 1044 } 1045 if (providerNames.add(ln)) { 1046 names.add(ln); 1047 } 1048 } 1049 return lc + 1; 1050 } 1051 1052 /** 1053 * Parse the content of the given URL as a provider-configuration file. 1054 */ 1055 private Iterator<String> parse(URL u) { 1056 Set<String> names = new LinkedHashSet<>(); // preserve insertion order 1057 try { 1058 URLConnection uc = u.openConnection(); 1059 uc.setUseCaches(false); 1060 try (InputStream in = uc.getInputStream(); 1061 BufferedReader r 1062 = new BufferedReader(new InputStreamReader(in, "utf-8"))) 1063 { 1064 int lc = 1; 1065 while ((lc = parseLine(u, r, lc, names)) >= 0); 1066 } 1067 } catch (IOException x) { 1068 fail(service, "Error accessing configuration file", x); 1069 } 1070 return names.iterator(); 1071 } 1072 1073 private boolean hasNextService() { 1074 if (nextClass != null || nextErrorMessage != null) { 1075 return true; 1076 } 1077 1078 Class<?> clazz; 1079 do { 1080 if (configs == null) { 1081 try { 1082 String fullName = PREFIX + service.getName(); 1083 if (loader == null) { 1084 configs = ClassLoader.getSystemResources(fullName); 1085 } else if (loader == ClassLoaders.platformClassLoader()) { 1086 // The platform classloader doesn't have a class path, 1087 // but the boot loader might. 1088 if (BootLoader.hasClassPath()) { 1089 configs = BootLoader.findResources(fullName); 1090 } else { 1091 configs = Collections.emptyEnumeration(); 1092 } 1093 } else { 1094 configs = loader.getResources(fullName); 1095 } 1096 } catch (IOException x) { 1097 fail(service, "Error locating configuration files", x); 1098 } |