1 7 8 package java.util; 9 10 import java.io.BufferedReader ; 11 import java.io.IOException ; 12 import java.io.InputStream ; 13 import java.io.InputStreamReader ; 14 import java.net.URL ; 15 import java.util.ArrayList ; 16 import java.util.Enumeration ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.NoSuchElementException ; 20 21 22 163 164 public final class ServiceLoader<S> 165 implements Iterable <S> 166 { 167 168 private static final String PREFIX = "META-INF/services/"; 169 170 private Class <S> service; 172 173 private ClassLoader loader; 175 176 private LinkedHashMap <String ,S> providers = new LinkedHashMap <String ,S>(); 178 179 private LazyIterator lookupIterator; 181 182 193 public void reload() { 194 providers.clear(); 195 lookupIterator = new LazyIterator(service, loader); 196 } 197 198 private ServiceLoader(Class <S> svc, ClassLoader cl) { 199 service = svc; 200 loader = cl; 201 reload(); 202 } 203 204 private static void fail(Class service, String msg, Throwable cause) 205 throws ServiceConfigurationError 206 { 207 throw new ServiceConfigurationError (service.getName() + ": " + msg, 208 cause); 209 } 210 211 private static void fail(Class service, String msg) 212 throws ServiceConfigurationError 213 { 214 throw new ServiceConfigurationError (service.getName() + ": " + msg); 215 } 216 217 private static void fail(Class service, URL u, int line, String msg) 218 throws ServiceConfigurationError 219 { 220 fail(service, u + ":" + line + ": " + msg); 221 } 222 223 private int parseLine(Class service, URL u, BufferedReader r, int lc, 227 List <String > names) 228 throws IOException , ServiceConfigurationError 229 { 230 String ln = r.readLine(); 231 if (ln == null) { 232 return -1; 233 } 234 int ci = ln.indexOf('#'); 235 if (ci >= 0) ln = ln.substring(0, ci); 236 ln = ln.trim(); 237 int n = ln.length(); 238 if (n != 0) { 239 if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) 240 fail(service, u, lc, "Illegal configuration-file syntax"); 241 int cp = ln.codePointAt(0); 242 if (!Character.isJavaIdentifierStart(cp)) 243 fail(service, u, lc, "Illegal provider-class name: " + ln); 244 for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { 245 cp = ln.codePointAt(i); 246 if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) 247 fail(service, u, lc, "Illegal provider-class name: " + ln); 248 } 249 if (!providers.containsKey(ln) && !names.contains(ln)) 250 names.add(ln); 251 } 252 return lc + 1; 253 } 254 255 private Iterator <String > parse(Class service, URL u) 273 throws ServiceConfigurationError 274 { 275 InputStream in = null; 276 BufferedReader r = null; 277 ArrayList <String > names = new ArrayList <String >(); 278 try { 279 in = u.openStream(); 280 r = new BufferedReader (new InputStreamReader (in, "utf-8")); 281 int lc = 1; 282 while ((lc = parseLine(service, u, r, lc, names)) >= 0); 283 } catch (IOException x) { 284 fail(service, "Error reading configuration file", x); 285 } finally { 286 try { 287 if (r != null) r.close(); 288 if (in != null) in.close(); 289 } catch (IOException y) { 290 fail(service, "Error closing configuration file", y); 291 } 292 } 293 return names.iterator(); 294 } 295 296 private class LazyIterator 299 implements Iterator <S> 300 { 301 302 Class <S> service; 303 ClassLoader loader; 304 Enumeration <URL > configs = null; 305 Iterator <String > pending = null; 306 String nextName = null; 307 308 private LazyIterator(Class <S> service, ClassLoader loader) { 309 this.service = service; 310 this.loader = loader; 311 } 312 313 public boolean hasNext() { 314 if (nextName != null) { 315 return true; 316 } 317 if (configs == null) { 318 try { 319 String fullName = PREFIX + service.getName(); 320 if (loader == null) 321 configs = ClassLoader.getSystemResources(fullName); 322 else 323 configs = loader.getResources(fullName); 324 } catch (IOException x) { 325 fail(service, "Error locating configuration files", x); 326 } 327 } 328 while ((pending == null) || !pending.hasNext()) { 329 if (!configs.hasMoreElements()) { 330 return false; 331 } 332 pending = parse(service, configs.nextElement()); 333 } 334 nextName = pending.next(); 335 return true; 336 } 337 338 public S next() { 339 if (!hasNext()) { 340 throw new NoSuchElementException (); 341 } 342 String cn = nextName; 343 nextName = null; 344 try { 345 S p = service.cast(Class.forName(cn, true, loader) 346 .newInstance()); 347 providers.put(cn, p); 348 return p; 349 } catch (ClassNotFoundException x) { 350 fail(service, 351 "Provider " + cn + " not found"); 352 } catch (Throwable x) { 353 fail(service, 354 "Provider " + cn + " could not be instantiated: " + x, 355 x); 356 } 357 throw new Error (); } 359 360 public void remove() { 361 throw new UnsupportedOperationException (); 362 } 363 364 } 365 366 406 public Iterator <S> iterator() { 407 return new Iterator <S>() { 408 409 Iterator <Map.Entry <String ,S>> knownProviders 410 = providers.entrySet().iterator(); 411 412 public boolean hasNext() { 413 if (knownProviders.hasNext()) 414 return true; 415 return lookupIterator.hasNext(); 416 } 417 418 public S next() { 419 if (knownProviders.hasNext()) 420 return knownProviders.next().getValue(); 421 return lookupIterator.next(); 422 } 423 424 public void remove() { 425 throw new UnsupportedOperationException (); 426 } 427 428 }; 429 } 430 431 446 public static <S> ServiceLoader <S> load(Class <S> service, 447 ClassLoader loader) 448 { 449 return new ServiceLoader <S>(service, loader); 450 } 451 452 473 public static <S> ServiceLoader <S> load(Class <S> service) { 474 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 475 return ServiceLoader.load(service, cl); 476 } 477 478 502 public static <S> ServiceLoader <S> loadInstalled(Class <S> service) { 503 ClassLoader cl = ClassLoader.getSystemClassLoader(); 504 ClassLoader prev = null; 505 while (cl != null) { 506 prev = cl; 507 cl = cl.getParent(); 508 } 509 return ServiceLoader.load(service, prev); 510 } 511 512 517 public String toString() { 518 return "java.util.ServiceLoader[" + service.getName() + "]"; 519 } 520 521 } 522 | Popular Tags |