1 19 20 package org.openide.util.lookup; 21 22 import java.io.BufferedReader ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.InputStreamReader ; 26 import java.net.URL ; 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.Enumeration ; 30 import java.util.HashSet ; 31 import java.util.LinkedHashSet ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 import java.util.WeakHashMap ; 36 import java.util.logging.Level ; 37 import java.util.logging.Logger ; 38 import org.openide.util.Lookup; 39 import org.openide.util.SharedClassObject; 40 import org.openide.util.WeakSet; 41 42 55 final class MetaInfServicesLookup extends AbstractLookup { 56 57 private static final Logger LOGGER = Logger.getLogger(MetaInfServicesLookup.class.getName()); 58 59 private static final Map <Class ,Object > knownInstances = new WeakHashMap <Class ,Object >(); 60 61 67 private final Set <Class > classes = new WeakSet<Class >(); 69 70 private final ClassLoader loader; 71 72 75 public MetaInfServicesLookup() { 76 this(MetaInfServicesLookup.class.getClassLoader()); 77 } 78 79 81 public MetaInfServicesLookup(ClassLoader loader) { 82 this.loader = loader; 83 84 LOGGER.log(Level.FINE, "Created: {0}", this); 85 } 86 87 public String toString() { 88 return "MetaInfServicesLookup[" + loader + "]"; } 90 91 93 protected final void beforeLookup(Lookup.Template t) { 94 Class c = t.getType(); 95 96 HashSet <AbstractLookup.R> listeners; 97 98 synchronized (this) { 99 if (classes.add(c)) { 100 LinkedHashSet <AbstractLookup.Pair<?>> arr = getPairsAsLHS(); 102 search(c, arr); 103 104 listeners = setPairsAndCollectListeners(arr); 107 } else { 108 return; 110 } 111 } 112 113 notifyCollectedListeners(listeners); 114 } 115 116 121 private void search(Class <?> clazz, Collection <AbstractLookup.Pair<?>> result) { 122 if (LOGGER.isLoggable(Level.FINER)) { 123 LOGGER.log(Level.FINER, "Searching for " + clazz.getName() + " in " + clazz.getClassLoader() + " from " + this); 124 } 125 126 String res = "META-INF/services/" + clazz.getName(); Enumeration <URL > en; 128 129 try { 130 en = loader.getResources(res); 131 } catch (IOException ioe) { 132 ioe.printStackTrace(); 135 136 return; 137 } 138 139 List <Item> foundClasses = new ArrayList <Item>(); 144 Collection <Class > removeClasses = new ArrayList <Class >(); 145 146 boolean foundOne = false; 147 148 while (en.hasMoreElements()) { 149 if (!foundOne) { 150 foundOne = true; 151 152 Class realMcCoy = null; 163 164 try { 165 realMcCoy = loader.loadClass(clazz.getName()); 166 } catch (ClassNotFoundException cnfe) { 167 } 169 170 if (realMcCoy != clazz) { 171 if (LOGGER.isLoggable(Level.FINER)) { 174 if (realMcCoy != null) { 175 LOGGER.log(Level.FINER, 176 clazz.getName() + " is not the real McCoy! Actually found it in " + 177 realMcCoy.getClassLoader() 178 ); } else { 180 LOGGER.log(Level.FINER, clazz.getName() + " could not be found in " + loader); } 182 } 183 184 return; 185 } 186 } 187 188 URL url = en.nextElement(); 189 Item currentItem = null; 190 191 try { 192 InputStream is = url.openStream(); 193 194 try { 195 BufferedReader reader = new BufferedReader (new InputStreamReader (is, "UTF-8")); 197 while (true) { 198 String line = reader.readLine(); 199 200 if (line == null) { 201 break; 202 } 203 204 line = line.trim(); 205 206 if (line.startsWith("#position=")) { 208 if (currentItem == null) { 209 LOGGER.log(Level.WARNING, "Found line '{0}' in {1} but there is no item to associate it with", new Object [] {line, url}); 210 continue; 211 } 212 213 try { 214 currentItem.position = Integer.parseInt(line.substring(10)); 215 } catch (NumberFormatException e) { 216 e.printStackTrace(); 219 } 220 } 221 222 if (currentItem != null) { 223 insertItem(currentItem, foundClasses); 224 currentItem = null; 225 } 226 227 if (line.length() == 0) { 229 continue; 230 } 231 232 boolean remove = false; 233 234 if (line.charAt(0) == '#') { 235 if ((line.length() == 1) || (line.charAt(1) != '-')) { 236 continue; 237 } 238 239 remove = true; 241 line = line.substring(2); 242 } 243 244 Class inst = null; 245 246 try { 247 inst = Class.forName(line, false, loader); 249 } catch (ClassNotFoundException cnfe) { 250 if (remove) { 251 continue; 254 } else { 255 throw cnfe; 257 } 258 } 259 260 if (!clazz.isAssignableFrom(inst)) { 261 throw new ClassNotFoundException (inst.getName() + " not a subclass of " + clazz.getName()); } 263 264 if (remove) { 265 removeClasses.add(inst); 266 } else { 267 currentItem = new Item(); 271 currentItem.clazz = inst; 272 } 273 } 274 275 if (currentItem != null) { 276 insertItem(currentItem, foundClasses); 277 currentItem = null; 278 } 279 } finally { 280 is.close(); 281 } 282 } catch (ClassNotFoundException ex) { 283 LOGGER.log(Level.WARNING, null, ex); 284 } catch (IOException ex) { 285 LOGGER.log(Level.WARNING, null, ex); 286 } 287 } 288 289 LOGGER.log(Level.FINER, "Found impls of {0}: {1} and removed: {2} from: {3}", new Object [] {clazz.getName(), foundClasses, removeClasses, this}); 290 291 foundClasses.removeAll(removeClasses); 292 293 for (Item item : foundClasses) { 294 if (removeClasses.contains(item.clazz)) { 295 continue; 296 } 297 298 result.add(new P(item.clazz)); 299 } 300 } 301 302 305 private void insertItem(Item item, List <Item> list) { 306 if (item.position == -1) { 308 list.add(item); 309 310 return; 311 } 312 313 int index = -1; 314 for (Item i : list) { 315 index++; 316 317 if (i.position == -1) { 318 list.add(index, item); 319 320 return; 321 } else { 322 if (i.position > item.position) { 323 list.add(index, item); 324 325 return; 326 } 327 } 328 } 329 330 list.add(item); 331 } 332 333 private static class Item { 334 private Class clazz; 335 private int position = -1; 336 @Override 337 public String toString() { 338 return "MetaInfServicesLookup.Item[" + clazz.getName() + "]"; } 340 } 341 342 344 private static final class P extends AbstractLookup.Pair<Object > { 345 350 private Object object; 351 352 public P(Class <?> clazz) { 353 this.object = clazz; 354 } 355 356 358 private Class <? extends Object > clazz() { 359 Object o = object; 360 361 if (o instanceof Class ) { 362 return (Class <? extends Object >) o; 363 } else if (o != null) { 364 return o.getClass(); 365 } else { 366 return Object .class; 368 } 369 } 370 371 public boolean equals(Object o) { 372 if (o instanceof P) { 373 return ((P) o).clazz().equals(clazz()); 374 } 375 376 return false; 377 } 378 379 public int hashCode() { 380 return clazz().hashCode(); 381 } 382 383 protected boolean instanceOf(Class <?> c) { 384 return c.isAssignableFrom(clazz()); 385 } 386 387 public Class <?> getType() { 388 return clazz(); 389 } 390 391 public Object getInstance() { 392 Object o = object; 394 if (o instanceof Class ) { 396 synchronized (o) { 399 try { 400 Class <?> c = ((Class ) o); 401 402 synchronized (knownInstances) { o = knownInstances.get(c); 404 } 405 406 if (o == null) { 407 if (SharedClassObject.class.isAssignableFrom(c)) { 408 o = SharedClassObject.findObject(c.asSubclass(SharedClassObject.class), true); 409 } else { 410 o = c.newInstance(); 411 } 412 413 synchronized (knownInstances) { knownInstances.put(c, o); 415 } 416 } 417 418 object = o; 423 } catch (Exception ex) { 424 LOGGER.log(Level.WARNING, null, ex); 425 object = null; 426 } 427 } 428 } 429 430 return object; 431 } 432 433 public String getDisplayName() { 434 return clazz().getName(); 435 } 436 437 public String getId() { 438 return clazz().getName(); 439 } 440 441 protected boolean creatorOf(Object obj) { 442 return obj == object; 443 } 444 } 445 } 446 | Popular Tags |