1 19 20 package org.netbeans.core.projects; 21 22 import java.io.BufferedInputStream ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.net.URL ; 27 import java.text.MessageFormat ; 28 import java.util.ArrayList ; 29 import java.util.Arrays ; 30 import java.util.Collection ; 31 import java.util.Enumeration ; 32 import java.util.HashMap ; 33 import java.util.HashSet ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.Set ; 37 import java.util.jar.Manifest ; 38 import java.util.logging.Handler ; 39 import java.util.logging.Level ; 40 import java.util.logging.LogRecord ; 41 import java.util.logging.Logger ; 42 import junit.framework.Test; 43 import org.netbeans.core.startup.layers.BinaryCacheManager; 44 import org.netbeans.core.startup.layers.ParsingLayerCacheManager; 45 import org.netbeans.junit.NbTestCase; 46 import org.netbeans.junit.NbTestSuite; 47 import org.openide.cookies.InstanceCookie; 48 import org.openide.filesystems.FileObject; 49 import org.openide.filesystems.FileSystem; 50 import org.openide.filesystems.Repository; 51 import org.openide.filesystems.XMLFileSystem; 52 import org.openide.loaders.DataObject; 53 import org.openide.loaders.DataShadow; 54 import org.openide.modules.Dependency; 55 import org.openide.modules.ModuleInfo; 56 import org.openide.util.Lookup; 57 import org.openide.util.Mutex; 58 59 63 public class ValidateLayerConsistencyTest extends NbTestCase { 64 65 private ClassLoader contextClassLoader; 66 67 public ValidateLayerConsistencyTest(String name) { 68 super (name); 69 } 70 71 public static Test suite() { 72 return new NbTestSuite(ValidateLayerConsistencyTest.class); 73 } 74 75 public void setUp() throws Exception { 76 clearWorkDir(); 77 Mutex.EVENT.readAccess(new Mutex.Action<Void >() { 78 public Void run() { 79 contextClassLoader = Thread.currentThread().getContextClassLoader(); 80 Thread.currentThread().setContextClassLoader((ClassLoader )Lookup.getDefault().lookup(ClassLoader .class)); 81 return null; 82 } 83 }); 84 } 85 86 public void tearDown() { 87 Mutex.EVENT.readAccess(new Mutex.Action<Void >() { 88 public Void run() { 89 Thread.currentThread().setContextClassLoader(contextClassLoader); 90 return null; 91 } 92 }); 93 } 94 95 protected boolean runInEQ() { 96 return true; 97 } 98 99 public void testAreAttributesFine () { 100 List <String > errors = new ArrayList <String >(); 101 102 Enumeration <? extends FileObject> files = Repository.getDefault().getDefaultFileSystem().getRoot().getChildren(true); 103 while (files.hasMoreElements()) { 104 FileObject fo = files.nextElement(); 105 106 if("Windows2/Modes/debugger".equals(fo.getPath()) || "Windows2/Modes/explorer".equals(fo.getPath())) { continue; 111 } 112 113 if ( 114 "Keymaps/NetBeans/D-BACK_QUOTE.shadow".equals(fo.getPath()) || 115 "Keymaps/Emacs/D-BACK_QUOTE.shadow".equals(fo.getPath()) 116 ) { 117 continue; 119 } 120 121 Enumeration <String > attrs = fo.getAttributes(); 122 while (attrs.hasMoreElements()) { 123 String name = attrs.nextElement(); 124 125 if (fo.getAttribute(name) == null) { 126 errors.add ("\n File " + fo + " attribute name " + name); 127 } 128 } 129 } 130 131 if (!errors.isEmpty()) { 132 fail ("Some attributes in files are unreadable" + errors); 133 } 134 } 135 136 public void testValidShadows () { 137 List <String > errors = new ArrayList <String >(); 139 140 FileObject root = Repository.getDefault().getDefaultFileSystem().getRoot(); 141 142 Enumeration <? extends FileObject> en = root.getChildren(true); 143 int cnt = 0; 144 while (en.hasMoreElements()) { 145 FileObject fo = en.nextElement(); 146 cnt++; 147 148 if("Windows2/Modes/debugger".equals(fo.getPath()) || "Windows2/Modes/explorer".equals(fo.getPath())) { continue; 153 } 154 155 if ( 156 "Keymaps/NetBeans/D-BACK_QUOTE.shadow".equals(fo.getPath()) || 157 "Keymaps/Emacs/D-BACK_QUOTE.shadow".equals(fo.getPath()) 158 ) { 159 continue; 161 } 162 163 try { 164 DataObject obj = DataObject.find (fo); 165 DataShadow ds = obj.getCookie(DataShadow.class); 166 if (ds != null) { 167 Object o = ds.getOriginal(); 168 if (o == null) { 169 errors.add("\nFile " + fo + " has no original."); 170 } 171 } 172 else if ("shadow".equals(fo.getExt())) { 173 errors.add("\nFile " + fo + " is not a valid DataShadow."); 174 } 175 } catch (Exception ex) { 176 ex.printStackTrace(); 177 errors.add ("\n File " + fo + " thrown exception " + ex); 178 } 179 } 180 181 if (!errors.isEmpty()) { 182 fail ("Some shadow files in NetBeans profile are broken:" + errors); 183 } 184 185 if (ValidateLayerConsistencyTest.class.getClassLoader() == ClassLoader.getSystemClassLoader()) { 186 return; 189 } 190 191 192 if (cnt == 0) { 193 fail("No file objects on system file system!"); 194 } 195 } 196 197 198 public void testContentCanBeRead () { 199 List <String > errors = new ArrayList <String >(); 200 byte[] buffer = new byte[4096]; 201 202 Enumeration <? extends FileObject> files = Repository.getDefault().getDefaultFileSystem().getRoot().getChildren(true); 203 while (files.hasMoreElements()) { 204 FileObject fo = files.nextElement(); 205 206 if (!fo.isData ()) { 207 continue; 208 } 209 long size = fo.getSize(); 210 211 try { 212 long read = 0; 213 InputStream is = fo.getInputStream(); 214 try { 215 for (;;) { 216 int len = is.read (buffer); 217 if (len == -1) break; 218 read += len; 219 } 220 } finally { 221 is.close (); 222 } 223 224 if (size != -1) { 225 assertEquals ("The amount of data in stream is the same as the length", size, read); 226 } 227 228 } catch (IOException ex) { 229 errors.add ("\n File " + fo + " cannot be read " + ex); 230 } 231 } 232 233 if (!errors.isEmpty()) { 234 fail ("Some files are unreadable" + errors); 235 } 236 } 237 238 public void testInstantiateAllInstances () { 239 List <String > errors = new ArrayList <String >(); 240 241 Enumeration <? extends FileObject> files = Repository.getDefault().getDefaultFileSystem().getRoot().getChildren(true); 242 while (files.hasMoreElements()) { 243 FileObject fo = files.nextElement(); 244 245 if (skipFile(fo.getPath())) { 246 continue; 247 } 248 249 try { 250 DataObject obj = DataObject.find (fo); 251 InstanceCookie ic = obj.getCookie(InstanceCookie.class); 252 if (ic != null) { 253 Object o = ic.instanceCreate (); 254 } 255 } catch (Exception ex) { 256 ex.printStackTrace(); 257 errors.add ("\n File " + fo + " thrown exception " + ex); 258 } 259 } 260 261 if (!errors.isEmpty()) { 262 fail ("Some instances cannot be created " + errors); 263 } 264 } 265 266 public void testIfOneFileIsDefinedTwiceByDifferentModulesTheyNeedToHaveMutualDependency() throws Exception { 267 ClassLoader l = Lookup.getDefault().lookup(ClassLoader .class); 268 assertNotNull ("In the IDE mode, there always should be a classloader", l); 269 270 Map <String ,List <String >> files = new HashMap <String ,List <String >>(); 272 class ContentAndAttrs { 273 final byte[] contents; 274 final Map <String ,Object > attrs; 275 ContentAndAttrs(byte[] contents, Map <String ,Object > attrs) { 276 this.contents = contents; 277 this.attrs = attrs; 278 } 279 } 280 281 Map <String ,ContentAndAttrs> contents = new HashMap <String ,ContentAndAttrs>(); 282 283 Map <String ,Map <String ,ContentAndAttrs>> differentContents = new HashMap <String ,Map <String ,ContentAndAttrs>>(); 284 285 boolean atLeastOne = false; 286 Enumeration <URL > en = l.getResources("META-INF/MANIFEST.MF"); 287 while (en.hasMoreElements ()) { 288 URL u = en.nextElement(); 289 InputStream is = u.openStream(); 290 Manifest mf; 291 try { 292 mf = new Manifest (is); 293 } finally { 294 is.close(); 295 } 296 String module = mf.getMainAttributes ().getValue ("OpenIDE-Module"); 297 if (module == null) continue; 298 String layer = mf.getMainAttributes ().getValue ("OpenIDE-Module-Layer"); 299 if (layer == null) continue; 300 301 atLeastOne = true; 302 URL layerURL = new URL (u, "../" + layer); 303 java.net.URLConnection connect = layerURL.openConnection (); 304 connect.setDefaultUseCaches (false); 305 FileSystem fs = new XMLFileSystem(layerURL); 306 307 Enumeration <? extends FileObject> all = fs.getRoot().getChildren(true); 308 while (all.hasMoreElements ()) { 309 FileObject fo = all.nextElement (); 310 if (!fo.isData ()) continue; 311 312 String path = fo.getPath(); 313 List <String > list = files.get(path); 314 if (list == null) { 315 list = new ArrayList <String >(); 316 files.put (path, list); 317 list.add (module); 318 contents.put(path, new ContentAndAttrs(getFileContent(fo), getAttributes(fo))); 319 } else { 320 ContentAndAttrs contentAttrs = contents.get(path); 321 byte[] foc = getFileContent(fo); 322 Map <String ,Object > foa = getAttributes(fo); 323 if (!Arrays.equals(foc, contentAttrs.contents) || !foa.equals(contentAttrs.attrs)) { 324 Map <String ,ContentAndAttrs> diffs = differentContents.get(path); 325 if (diffs == null) { 326 diffs = new HashMap <String ,ContentAndAttrs>(); 327 differentContents.put(path, diffs); 328 diffs.put(list.get(0), contentAttrs); 329 } 330 diffs.put(module, new ContentAndAttrs(foc, foa)); 331 list.add (module); 332 } 333 } 334 } 335 connect.getInputStream ().close (); 337 } 338 contents = null; 340 StringBuffer sb = new StringBuffer (); 341 for (Map.Entry <String ,List <String >> e : files.entrySet()) { 342 List <String > list = e.getValue(); 343 if (list.size () == 1) continue; 344 345 Collection <? extends ModuleInfo> res = Lookup.getDefault().lookupAll(ModuleInfo.class); 346 assertFalse("Some modules found", res.isEmpty()); 347 348 for (String name : new ArrayList <String >(list)) { 349 for (ModuleInfo info : res) { 350 if (name.equals (info.getCodeName ())) { 351 for (Dependency d : info.getDependencies()) { 353 list.remove (d.getName ()); 354 } 355 } 356 } 357 } 358 if (list.size () <= 1) continue; 360 361 sb.append (e.getKey ()).append( " is provided by: " ).append(list).append('\n'); 362 Map <String ,ContentAndAttrs> diffList = differentContents.get(e.getKey()); 363 if (diffList != null) { 364 if (list.size() == 2) { 365 String module1 = list.get(0); 366 String module2 = list.get(1); 367 ContentAndAttrs contentAttrs1 = diffList.get(module1); 368 ContentAndAttrs contentAttrs2 = diffList.get(module2); 369 if (!Arrays.equals(contentAttrs1.contents, contentAttrs2.contents)) { 370 sb.append(' ').append(module1).append(": content = '").append(new String (contentAttrs1.contents)).append('\n'); 371 sb.append(' ').append(module2).append(": content = '").append(new String (contentAttrs2.contents)).append('\n'); 372 } 373 if (!contentAttrs1.attrs.equals(contentAttrs2.attrs)) { 374 Map <String ,Object > attr1 = contentAttrs1.attrs; 375 Map <String ,Object > attr2 = contentAttrs2.attrs; 376 Set <String > keys = new HashSet <String >(attr1.keySet()); 377 keys.retainAll(attr2.keySet()); 378 for (String attribute : keys) { 379 Object value1 = attr1.get(attribute); 380 Object value2 = attr2.get(attribute); 381 if (value1 == value2 || (value1 != null && value1.equals(value2))) { 382 attr1.remove(attribute); 384 attr2.remove(attribute); 385 } 386 } 387 sb.append(' ').append(module1).append(": different attributes = '").append(contentAttrs1.attrs).append('\n'); 388 sb.append(' ').append(module2).append(": different attributes = '").append(contentAttrs2.attrs).append('\n'); 389 } 390 } else { 391 for (String module : list) { 392 ContentAndAttrs contentAttrs = diffList.get(module); 393 sb.append(" " + module + ": content = '" + new String (contentAttrs.contents) + "', attributes = " + contentAttrs.attrs + "\n"); 394 } 395 } 396 } 397 } 398 399 assertTrue ("At least one layer file is usually used", atLeastOne); 400 401 if (sb.length () > 0) { 402 fail ("Some modules override their files and do not depend on each other\n" + sb); 403 } 404 } 405 406 public void testNoWarningsFromLayerParsing() throws Exception { 407 ClassLoader l = Lookup.getDefault().lookup(ClassLoader .class); 408 assertNotNull ("In the IDE mode, there always should be a classloader", l); 409 410 List <URL > urls = new ArrayList <URL >(); 411 boolean atLeastOne = false; 412 Enumeration <URL > en = l.getResources("META-INF/MANIFEST.MF"); 413 while (en.hasMoreElements ()) { 414 URL u = en.nextElement(); 415 InputStream is = u.openStream(); 416 Manifest mf; 417 try { 418 mf = new Manifest (is); 419 } finally { 420 is.close(); 421 } 422 String module = mf.getMainAttributes ().getValue ("OpenIDE-Module"); 423 if (module == null) continue; 424 String layer = mf.getMainAttributes ().getValue ("OpenIDE-Module-Layer"); 425 if (layer == null) continue; 426 427 atLeastOne = true; 428 URL layerURL = new URL (u, "../" + layer); 429 urls.add(layerURL); 430 } 431 432 File cacheDir; 433 File workDir = getWorkDir(); 434 int i = 0; 435 do { 436 cacheDir = new File (workDir, "layercache"+i); 437 i++; 438 } while (!cacheDir.mkdir()); 439 440 BinaryCacheManager bcm = new BinaryCacheManager(cacheDir); 441 Logger err = Logger.getLogger("org.netbeans.core.projects.cache"); 442 LayerParsehandler h = new LayerParsehandler(); 443 err.addHandler(h); 444 bcm.store(urls); 445 assertEquals("No errors or warnings during layer parsing: "+h.errors().toString(), 0, h.errors().size()); 446 } 447 448 private static class LayerParsehandler extends Handler { 449 List <String > errors = new ArrayList <String >(); 450 451 LayerParsehandler () {} 452 453 public void publish(LogRecord rec) { 454 if (Level.WARNING.equals(rec.getLevel()) || Level.SEVERE.equals(rec.getLevel())) { 455 errors.add(MessageFormat.format(rec.getMessage(), rec.getParameters())); 456 } 457 } 458 459 List <String > errors() { 460 return errors; 461 } 462 463 public void flush() { 464 } 465 466 public void close() throws SecurityException { 467 } 468 } 469 470 private static byte[] getFileContent(FileObject fo) throws IOException { 471 BufferedInputStream in = new BufferedInputStream (fo.getInputStream()); 472 int size = (int) fo.getSize(); 473 byte[] content = new byte[size]; 474 int length = 0; 475 while(length < size) { 476 int readLength = in.read(content, length, size - length); 477 if (readLength <= 0) { 478 throw new IOException ("Bad size for "+fo+", size = "+size+", but actual length is "+length); 479 } 480 length +=readLength; 481 } 482 return content; 483 } 484 485 private static Map <String ,Object > getAttributes(FileObject fo) { 486 Map <String ,Object > attrs = new HashMap <String ,Object >(); 487 Enumeration <String > en = fo.getAttributes(); 488 while (en.hasMoreElements()) { 489 String attrName = en.nextElement(); 490 Object attr = fo.getAttribute(attrName); 491 attrs.put(attrName, attr); 492 } 493 return attrs; 494 } 495 496 private boolean skipFile (String s) { 497 if (s.startsWith ("Templates/") && !s.startsWith ("Templates/Services")) { 498 if (s.endsWith (".shadow") || s.endsWith (".java")) { 499 return true; 500 } 501 } 502 503 if (s.startsWith ("Templates/GUIForms")) return true; 504 if (s.startsWith ("Palette/Borders/javax-swing-border-")) return true; 505 if (s.startsWith ("Palette/Layouts/javax-swing-BoxLayout")) return true; 506 if (s.startsWith ("Templates/Beans/")) return true; 507 if (s.startsWith ("PaletteUI/org-netbeans-modules-form-palette-CPComponent")) return true; 508 if (s.startsWith ("Templates/Ant/CustomTask.java")) return true; 509 if (s.startsWith ("Templates/Privileged/Main.shadow")) return true; 510 if (s.startsWith ("Templates/Privileged/JFrame.shadow")) return true; 511 if (s.startsWith ("Templates/Privileged/Class.shadow")) return true; 512 if (s.startsWith ("Templates/Classes")) return true; 513 if (s.startsWith ("Templates/JSP_Servlet")) return true; 514 if (s.startsWith ("EnvironmentProviders/ProfileTypes/Execution/nb-j2ee-deployment.instance")) return true; 515 if (s.startsWith ("Shortcuts/D-BACK_QUOTE.shadow")) return true; 516 517 return false; 518 } 519 } 520 | Popular Tags |