1 19 20 package org.netbeans.api.java.classpath; 21 22 import java.net.URL ; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.Collections ; 26 import java.util.HashMap ; 27 import java.util.HashSet ; 28 import java.util.Iterator ; 29 import java.util.Set ; 30 import java.util.Map ; 31 import javax.swing.event.ChangeEvent ; 32 import javax.swing.event.ChangeListener ; 33 import org.netbeans.api.java.queries.SourceForBinaryQuery; 34 import org.netbeans.junit.MockServices; 35 import org.netbeans.junit.NbTestCase; 36 import org.netbeans.spi.java.classpath.support.ClassPathSupport; 37 import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation; 38 import org.openide.filesystems.FileObject; 39 import org.netbeans.spi.java.classpath.ClassPathFactory; 40 import org.netbeans.spi.java.classpath.ClassPathImplementation; 41 import org.netbeans.spi.java.classpath.FilteringPathResourceImplementation; 42 import org.netbeans.spi.java.classpath.support.PathResourceBase; 43 import org.openide.filesystems.FileStateInvalidException; 44 import org.openide.filesystems.FileUtil; 45 import org.openide.util.Lookup; 46 47 51 public class GlobalPathRegistryTest extends NbTestCase { 52 53 public GlobalPathRegistryTest(String name) { 54 super(name); 55 MockServices.setServices(SFBQImpl.class, DeadLockSFBQImpl.class); 56 } 57 58 private GlobalPathRegistry r; 59 private FileObject root; 60 private ClassPath cp1, cp2, cp3, cp4, cp5; 61 protected void setUp() throws Exception { 62 super.setUp(); 63 r = GlobalPathRegistry.getDefault(); 64 r.clear(); 65 clearWorkDir(); 66 root = FileUtil.toFileObject(getWorkDir()); 67 cp1 = ClassPathSupport.createClassPath(new FileObject[] {root.createFolder("1")}); 68 cp2 = ClassPathSupport.createClassPath(new FileObject[] {root.createFolder("2")}); 69 cp3 = ClassPathSupport.createClassPath(new FileObject[] {root.createFolder("3")}); 70 cp4 = ClassPathSupport.createClassPath(new FileObject[] {root.createFolder("4")}); 71 cp5 = ClassPathSupport.createClassPath(new FileObject[] {root.createFolder("5")}); 72 } 73 74 public void testBasicOperation() throws Exception { 75 assertEquals("initially no paths of type a", Collections.<ClassPath>emptySet(), r.getPaths("a")); 76 r.register("a", new ClassPath[] {cp1, cp2}); 77 assertEquals("added some paths of type a", new HashSet <ClassPath>(Arrays.asList(new ClassPath[] {cp1, cp2})), r.getPaths("a")); 78 r.register("a", new ClassPath[0]); 79 assertEquals("did not add any new paths to a", new HashSet <ClassPath>(Arrays.asList(new ClassPath[] {cp1, cp2})), r.getPaths("a")); 80 assertEquals("initially no paths of type b", Collections.<ClassPath>emptySet(), r.getPaths("b")); 81 r.register("b", new ClassPath[] {cp3, cp4, cp5}); 82 assertEquals("added some paths of type b", new HashSet <ClassPath>(Arrays.asList(new ClassPath[] {cp3, cp4, cp5})), r.getPaths("b")); 83 r.unregister("a", new ClassPath[] {cp1}); 84 assertEquals("only one path left of type a", Collections.<ClassPath>singleton(cp2), r.getPaths("a")); 85 r.register("a", new ClassPath[] {cp2, cp3}); 86 assertEquals("only one new path added of type a", new HashSet <ClassPath>(Arrays.asList(new ClassPath[] {cp2, cp3})), r.getPaths("a")); 87 r.unregister("a", new ClassPath[] {cp2}); 88 assertEquals("still have extra cp2 in a", new HashSet <ClassPath>(Arrays.asList(new ClassPath[] {cp2, cp3})), r.getPaths("a")); 89 r.unregister("a", new ClassPath[] {cp2}); 90 assertEquals("last cp2 removed from a", Collections.<ClassPath>singleton(cp3), r.getPaths("a")); 91 r.unregister("a", new ClassPath[] {cp3}); 92 assertEquals("a now empty", Collections.<ClassPath>emptySet(), r.getPaths("a")); 93 r.unregister("a", new ClassPath[0]); 94 assertEquals("a still empty", Collections.<ClassPath>emptySet(), r.getPaths("a")); 95 try { 96 r.unregister("a", new ClassPath[] {cp3}); 97 fail("should not have been permitted to unregister a nonexistent entry"); 98 } catch (IllegalArgumentException x) { 99 } 101 } 102 103 public void testListening() throws Exception { 104 assertEquals("initially no paths of type b", Collections.<ClassPath>emptySet(), r.getPaths("b")); 105 L l = new L (); 106 r.addGlobalPathRegistryListener(l); 107 r.register("b", new ClassPath[] {cp1, cp2}); 108 GlobalPathRegistryEvent e = l.event(); 109 assertNotNull("got an event", e); 110 assertTrue("was an addition", l.added()); 111 assertEquals("right registry", r, e.getRegistry()); 112 assertEquals("right ID", "b", e.getId()); 113 assertEquals("right changed paths", new HashSet <ClassPath>(Arrays.asList(new ClassPath[] {cp1, cp2})), e.getChangedPaths()); 114 r.register("b", new ClassPath[] {cp2, cp3}); 115 e = l.event(); 116 assertNotNull("got an event", e); 117 assertTrue("was an addition", l.added()); 118 assertEquals("right changed paths", Collections.<ClassPath>singleton(cp3), e.getChangedPaths()); 119 r.register("b", new ClassPath[] {cp3}); 120 e = l.event(); 121 assertNull("no event for adding a dupe", e); 122 r.unregister("b", new ClassPath[] {cp1, cp3, cp3}); 123 e = l.event(); 124 assertNotNull("got an event", e); 125 assertFalse("was a removal", l.added()); 126 assertEquals("right changed paths", new HashSet <ClassPath>(Arrays.asList(new ClassPath[] {cp1, cp3})), e.getChangedPaths()); 127 r.unregister("b", new ClassPath[] {cp2}); 128 e = l.event(); 129 assertNull("no event for removing an extra", e); 130 r.unregister("b", new ClassPath[] {cp2}); 131 e = l.event(); 132 assertNotNull("now an event for removing the last copy", e); 133 assertFalse("was a removal", l.added()); 134 assertEquals("right changed paths", Collections.<ClassPath>singleton(cp2), e.getChangedPaths()); 135 } 136 137 138 public void testGetSourceRoots () throws Exception { 139 SFBQImpl query = Lookup.getDefault().lookup(SFBQImpl.class); 140 assertNotNull ("SourceForBinaryQueryImplementation not found in lookup",query); 141 query.addPair(cp3.getRoots()[0].getURL(),new FileObject[0]); 142 ClassPathTest.TestClassPathImplementation cpChangingImpl = new ClassPathTest.TestClassPathImplementation(); 143 ClassPath cpChanging = ClassPathFactory.createClassPath(cpChangingImpl); 144 assertEquals("cpChangingImpl is empty", 0, cpChanging.getRoots().length); 145 r.register(ClassPath.SOURCE, new ClassPath[] {cp1, cp2, cpChanging}); 146 r.register (ClassPath.COMPILE, new ClassPath[] {cp3}); 147 Set <FileObject> result = r.getSourceRoots(); 148 assertEquals ("Wrong number of source roots",result.size(),cp1.getRoots().length + cp2.getRoots().length); 149 assertTrue ("Missing roots from cp1",result.containsAll (Arrays.asList(cp1.getRoots()))); 150 assertTrue ("Missing roots from cp2",result.containsAll (Arrays.asList(cp2.getRoots()))); 151 URL u = cp5.entries().get(0).getURL(); 153 cpChangingImpl.addResource(u); 154 assertEquals("cpChangingImpl is not empty", 1, cpChanging.getRoots().length); 155 result = r.getSourceRoots(); 156 assertEquals ("Wrong number of source roots",result.size(),cp1.getRoots().length + cp2.getRoots().length + cpChanging.getRoots().length); 157 assertTrue ("Missing roots from cp1",result.containsAll (Arrays.asList(cp1.getRoots()))); 158 assertTrue ("Missing roots from cp2",result.containsAll (Arrays.asList(cp2.getRoots()))); 159 cpChangingImpl.removeResource(u); 160 161 query.addPair(cp3.getRoots()[0].getURL(),cp4.getRoots()); 162 result = r.getSourceRoots(); 163 assertEquals ("Wrong number of source roots",result.size(),cp1.getRoots().length + cp2.getRoots().length+cp4.getRoots().length); 164 assertTrue ("Missing roots from cp1",result.containsAll (Arrays.asList(cp1.getRoots()))); 165 assertTrue ("Missing roots from cp2",result.containsAll (Arrays.asList(cp2.getRoots()))); 166 assertTrue ("Missing roots from cp4",result.containsAll (Arrays.asList(cp4.getRoots()))); 167 } 168 169 172 public void testGetSourceRootsDeadLock () throws Exception { 173 DeadLockSFBQImpl query = Lookup.getDefault().lookup(DeadLockSFBQImpl.class); 174 assertNotNull ("SourceForBinaryQueryImplementation not found in lookup",query); 175 r.register (ClassPath.COMPILE, new ClassPath[] {cp1}); 176 try { 177 query.setSynchronizedJob ( 178 new Runnable () { 179 public void run () { 180 r.register(ClassPath.COMPILE, new ClassPath[] {cp2}); 181 } 182 } 183 ); 184 r.getSourceRoots(); 185 } finally { 186 query.setSynchronizedJob (null); 187 } 188 } 189 190 public void testFindResource() throws Exception { 191 final FileObject src1 = root.createFolder("src1"); 192 FileObject src1included = FileUtil.createData(src1, "included/file"); 193 FileUtil.createData(src1, "excluded/file1"); 194 FileUtil.createData(src1, "excluded/file2"); 195 FileObject src2 = root.createFolder("src2"); 196 FileObject src2included = FileUtil.createData(src2, "included/file"); 197 FileObject src2excluded1 = FileUtil.createData(src2, "excluded/file1"); 198 class PRI extends PathResourceBase implements FilteringPathResourceImplementation { 199 public URL [] getRoots() { 200 try { 201 return new URL [] {src1.getURL()}; 202 } catch (FileStateInvalidException x) { 203 throw new AssertionError (x); 204 } 205 } 206 public boolean includes(URL root, String resource) { 207 return resource.startsWith("incl"); 208 } 209 public ClassPathImplementation getContent() { 210 return null; 211 } 212 } 213 r.register(ClassPath.SOURCE, new ClassPath[] { 214 ClassPathSupport.createClassPath(Collections.singletonList(new PRI())), 215 ClassPathSupport.createClassPath(new FileObject[] {src2}) 216 }); 217 assertTrue(Arrays.asList(src1included, src2included).contains(r.findResource("included/file"))); 218 assertEquals(src2excluded1, r.findResource("excluded/file1")); 219 assertEquals(null, r.findResource("excluded/file2")); 220 assertEquals(null, r.findResource("nonexistent")); 221 } 222 223 private static final class L implements GlobalPathRegistryListener { 224 225 private GlobalPathRegistryEvent e; 226 private boolean added; 227 228 public L() {} 229 230 public synchronized GlobalPathRegistryEvent event() { 231 GlobalPathRegistryEvent _e = e; 232 e = null; 233 return _e; 234 } 235 236 public boolean added() { 237 return added; 238 } 239 240 public synchronized void pathsAdded(GlobalPathRegistryEvent e) { 241 assertNull("checked for last event", this.e); 242 this.e = e; 243 added = true; 244 } 245 246 public synchronized void pathsRemoved(GlobalPathRegistryEvent e) { 247 assertNull("checked for last event", this.e); 248 this.e = e; 249 added = false; 250 } 251 252 } 253 254 255 public static class SFBQImpl implements SourceForBinaryQueryImplementation { 256 257 private Map <URL ,SourceForBinaryQuery.Result> pairs = new HashMap <URL ,SourceForBinaryQuery.Result> (); 258 259 void addPair (URL binaryRoot, FileObject[] sourceRoots) { 260 assert binaryRoot != null && sourceRoots != null; 261 Result r = (Result) this.pairs.get (binaryRoot); 262 if (r == null) { 263 r = new Result (sourceRoots); 264 this.pairs.put (binaryRoot, r); 265 } 266 else { 267 r.setSources(sourceRoots); 268 } 269 } 270 271 public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) { 272 Result result = (Result) this.pairs.get (binaryRoot); 273 return result; 274 } 275 276 277 private static class Result implements SourceForBinaryQuery.Result { 278 279 private FileObject[] sources; 280 private ArrayList <ChangeListener > listeners = new ArrayList <ChangeListener > (); 281 282 public Result (FileObject[] sources) { 283 this.sources = sources; 284 } 285 286 287 void setSources (FileObject[] sources) { 288 this.sources = sources; 289 this.fireChange (); 290 } 291 292 public synchronized void addChangeListener(javax.swing.event.ChangeListener l) { 293 this.listeners.add (l); 294 } 295 296 public FileObject[] getRoots() { 297 return this.sources; 298 } 299 300 public synchronized void removeChangeListener(javax.swing.event.ChangeListener l) { 301 this.listeners.remove (l); 302 } 303 304 private void fireChange () { 305 Iterator it; 306 synchronized (this) { 307 it = ((ArrayList )this.listeners.clone()).iterator(); 308 } 309 ChangeEvent e = new ChangeEvent (this); 310 while (it.hasNext()) { 311 ((ChangeListener )it.next()).stateChanged(e); 312 } 313 } 314 315 } 316 317 } 318 319 public static class DeadLockSFBQImpl extends Thread implements SourceForBinaryQueryImplementation { 320 321 private Runnable r; 322 323 public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) { 324 if (this.r != null) { 325 synchronized (this) { 326 this.start(); 327 try { 328 this.wait (); 329 } catch (InterruptedException ie) { 330 ie.printStackTrace(); 331 } 332 } 333 } 334 return null; 335 } 336 337 public synchronized void run () { 338 r.run(); 339 this.notify(); 340 } 341 342 public void setSynchronizedJob (Runnable r) { 343 this.r = r; 344 } 345 346 } 347 348 } 349 | Popular Tags |