1 19 20 package org.apache.tools.ant.module.bridge.impl; 21 22 import java.beans.Introspector ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.io.PrintStream ; 27 import java.lang.reflect.Constructor ; 28 import java.lang.reflect.Field ; 29 import java.lang.reflect.Method ; 30 import java.lang.reflect.Modifier ; 31 import java.net.URL ; 32 import java.util.Collection ; 33 import java.util.HashMap ; 34 import java.util.HashSet ; 35 import java.util.LinkedHashSet ; 36 import java.util.List ; 37 import java.util.Map ; 38 import java.util.Set ; 39 import java.util.Vector ; 40 import java.util.WeakHashMap ; 41 import java.util.logging.Level ; 42 import java.util.logging.Logger ; 43 import org.apache.tools.ant.BuildException; 44 import org.apache.tools.ant.DemuxOutputStream; 45 import org.apache.tools.ant.IntrospectionHelper; 46 import org.apache.tools.ant.Main; 47 import org.apache.tools.ant.Project; 48 import org.apache.tools.ant.ProjectHelper; 49 import org.apache.tools.ant.module.AntModule; 50 import org.apache.tools.ant.module.AntSettings; 51 import org.apache.tools.ant.module.api.IntrospectedInfo; 52 import org.apache.tools.ant.module.bridge.AntBridge; 53 import org.apache.tools.ant.module.bridge.BridgeInterface; 54 import org.apache.tools.ant.module.bridge.IntrospectionHelperProxy; 55 import org.apache.tools.ant.module.bridge.impl.NbBuildLogger; 56 import org.apache.tools.ant.module.bridge.impl.NbInputHandler; 57 import org.apache.tools.ant.types.EnumeratedAttribute; 58 import org.apache.tools.ant.types.Path; 59 import org.netbeans.api.progress.ProgressHandle; 60 import org.openide.ErrorManager; 61 import org.openide.awt.StatusDisplayer; 62 import org.openide.filesystems.FileObject; 63 import org.openide.filesystems.FileStateInvalidException; 64 import org.openide.filesystems.FileSystem; 65 import org.openide.filesystems.FileUtil; 66 import org.openide.util.Exceptions; 67 import org.openide.util.NbBundle; 68 import org.openide.util.NbCollections; 69 import org.openide.util.RequestProcessor; 70 import org.openide.windows.OutputWriter; 71 72 76 public class BridgeImpl implements BridgeInterface { 77 78 79 private static final int STOP_TIMEOUT = 3000; 80 81 private static boolean classpathInitialized = false; 82 83 87 private static final Map <Thread ,NbBuildLogger> loggersByThread = new WeakHashMap <Thread ,NbBuildLogger>(); 88 89 public BridgeImpl() { 90 } 91 92 public String getAntVersion() { 93 try { 94 return Main.getAntVersion(); 95 } catch (BuildException be) { 96 AntModule.err.notify(ErrorManager.INFORMATIONAL, be); 97 return NbBundle.getMessage(BridgeImpl.class, "LBL_ant_version_unknown"); 98 } 99 } 100 101 public boolean isAnt16() { 102 try { 103 Class.forName("org.apache.tools.ant.taskdefs.Antlib"); return true; 105 } catch (ClassNotFoundException e) { 106 return false; 108 } 109 } 110 111 public IntrospectionHelperProxy getIntrospectionHelper(Class clazz) { 112 return new IntrospectionHelperImpl(clazz); 113 } 114 115 public boolean toBoolean(String val) { 116 return Project.toBoolean(val); 117 } 118 119 public String [] getEnumeratedValues(Class c) { 120 if (EnumeratedAttribute.class.isAssignableFrom(c)) { 121 try { 122 return ((EnumeratedAttribute)c.newInstance()).getValues(); 123 } catch (Exception e) { 124 AntModule.err.notify(ErrorManager.INFORMATIONAL, e); 125 } 126 } else if (Enum .class.isAssignableFrom(c)) { try { 128 Enum <?>[] vals = (Enum <?>[]) c.getMethod("values").invoke(null); 129 String [] names = new String [vals.length]; 130 for (int i = 0; i < vals.length; i++) { 131 names[i] = vals[i].name(); 132 } 133 return names; 134 } catch (Exception x) { 135 Exceptions.printStackTrace(x); 136 } 137 } 138 return null; 139 } 140 141 public boolean run(File buildFile, List <String > targets, InputStream in, OutputWriter out, OutputWriter err, 142 Map <String ,String > properties, int verbosity, String displayName, Runnable interestingOutputCallback, ProgressHandle handle) { 143 if (!classpathInitialized) { 144 classpathInitialized = true; 145 Path.systemClasspath = new Path(null, AntBridge.getMainClassPath()); 148 } 149 150 boolean ok = false; 151 152 final boolean ant16 = isAnt16(); 154 155 ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); 159 ClassLoader newCCL = Project.class.getClassLoader(); 160 if (AntModule.err.isLoggable(ErrorManager.INFORMATIONAL)) { 161 AntModule.err.log("Fixing CCL: " + oldCCL + " -> " + newCCL); 162 } 163 Thread.currentThread().setContextClassLoader(newCCL); 164 AntBridge.fakeJavaClassPath(); 165 try { 166 167 final Project project; 168 169 final NbBuildLogger logger = new NbBuildLogger(buildFile, out, err, verbosity, displayName, interestingOutputCallback, handle); 172 Vector <String > targs; 173 try { 174 project = new Project(); 175 project.addBuildListener(logger); 176 project.init(); 177 try { 178 addCustomDefs(project); 179 } catch (IOException e) { 180 throw new BuildException(e); 181 } 182 project.setUserProperty("ant.file", buildFile.getAbsolutePath()); project.setUserProperty("ant.version", Main.getAntVersion()); File antHome = AntSettings.getAntHome(); 186 if (antHome != null) { 187 project.setUserProperty("ant.home", antHome.getAbsolutePath()); } 189 for (Map.Entry <String ,String > entry : properties.entrySet()) { 190 project.setUserProperty(entry.getKey(), entry.getValue()); 191 } 192 if (in != null && ant16) { 193 try { 194 Method m = Project.class.getMethod("setDefaultInputStream", InputStream .class); m.invoke(project, in); 196 } catch (Exception e) { 197 AntModule.err.notify(ErrorManager.INFORMATIONAL, e); 198 } 199 } 200 if (AntModule.err.isLoggable(ErrorManager.INFORMATIONAL)) { 201 AntModule.err.log("CCL when configureProject is called: " + Thread.currentThread().getContextClassLoader()); 202 } 203 ProjectHelper projhelper = ProjectHelper.getProjectHelper(); 204 project.addReference("ant.projectHelper", projhelper); projhelper.parse(project, buildFile); 207 208 project.setInputHandler(new NbInputHandler(interestingOutputCallback)); 209 210 if (targets != null) { 211 targs = new Vector <String >(targets); 212 } else { 213 targs = new Vector <String >(1); 214 targs.add(project.getDefaultTarget()); 215 } 216 logger.setActualTargets(targets != null ? targets.toArray(new String [targets.size()]) : null); 217 } 218 catch (BuildException be) { 219 logger.buildInitializationFailed(be); 220 logger.shutdown(); 221 if (in != null) { 222 try { 223 in.close(); 224 } catch (IOException e) { 225 AntModule.err.notify(e); 226 } 227 } 228 return false; 229 } 230 231 project.fireBuildStarted(); 232 233 InputStream is = System.in; 235 if (in != null && ant16) { 236 try { 237 Class <? extends InputStream > dis = Class.forName("org.apache.tools.ant.DemuxInputStream").asSubclass(InputStream .class); Constructor <? extends InputStream > c = dis.getConstructor(Project.class); 239 is = c.newInstance(project); 240 } catch (Exception e) { 241 AntModule.err.notify(ErrorManager.INFORMATIONAL, e); 242 } 243 } 244 AntBridge.pushSystemInOutErr(is, 245 new PrintStream (new DemuxOutputStream(project, false)), 246 new PrintStream (new DemuxOutputStream(project, true))); 247 248 Thread currentThread = Thread.currentThread(); 249 synchronized (loggersByThread) { 250 assert !loggersByThread.containsKey(currentThread); 251 loggersByThread.put(currentThread, logger); 252 } 253 try { 254 project.executeTargets(targs); 257 project.fireBuildFinished(null); 259 ok = true; 260 } catch (Throwable t) { 261 project.fireBuildFinished(t); 264 } finally { 265 AntBridge.restoreSystemInOutErr(); 266 if (in != null) { 267 try { 268 in.close(); 269 } catch (IOException e) { 270 AntModule.err.notify(e); 271 } 272 } 273 synchronized (loggersByThread) { 274 loggersByThread.remove(currentThread); 275 } 276 } 277 278 RequestProcessor.getDefault().post(new Runnable () { 280 public void run() { 281 IntrospectedInfo custom = AntSettings.getCustomDefs(); 282 Map <String ,Map <String ,Class >> defs = new HashMap <String ,Map <String ,Class >>(); 283 defs.put("task", NbCollections.checkedMapByCopy(project.getTaskDefinitions(), String .class, Class .class, true)); 284 defs.put("type", NbCollections.checkedMapByCopy(project.getDataTypeDefinitions(), String .class, Class .class, true)); 285 custom.scanProject(defs); 286 AntSettings.setCustomDefs(custom); 287 logger.shutdown(); 288 refreshFilesystemsTask.schedule(0); 290 gutProject(project); 291 if (!ant16) { 292 RequestProcessor.getDefault().post(new Runnable () { 294 public void run() { 295 hack36393(); 296 } 297 }); 298 } 299 } 300 }); 301 302 } finally { 303 AntBridge.unfakeJavaClassPath(); 304 if (AntModule.err.isLoggable(ErrorManager.INFORMATIONAL)) { 305 AntModule.err.log("Restoring CCL: " + oldCCL); 306 } 307 Thread.currentThread().setContextClassLoader(oldCCL); 308 } 309 310 return ok; 311 } 312 313 private static final RequestProcessor.Task refreshFilesystemsTask = RequestProcessor.getDefault().create(new Runnable () { 314 public void run() { 315 for (FileSystem fs : getFileSystems()) { 318 Logger.getLogger(BridgeImpl.class.getName()).log(Level.FINE, "Refreshing filesystem {0}", fs); 319 fs.refresh(false); 320 } 321 } 322 }); 323 324 public void stop(final Thread process) { 325 NbBuildLogger logger; 326 synchronized (loggersByThread) { 327 logger = loggersByThread.get(process); 328 } 329 if (logger != null) { 330 StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(BridgeImpl.class, "MSG_stopping", logger.getDisplayNameNoLock())); 332 logger.stop(); 333 RequestProcessor.getDefault().create(new Runnable () { 336 public void run () { 337 forciblyStop(process); 338 } 339 }).schedule(STOP_TIMEOUT); 340 } else { 341 forciblyStop(process); 343 } 344 } 345 346 private void forciblyStop(Thread process) { 347 if (process.isAlive()) { 348 StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(BridgeImpl.class, "MSG_halting")); 349 stopThread(process); 351 } 352 } 353 354 @SuppressWarnings ("deprecation") 355 private static void stopThread(Thread process) { 356 process.stop(); 357 } 358 359 366 private static FileSystem[] fileSystems; 367 368 private static FileSystem[] getFileSystems() { 369 if (fileSystems != null) { 370 return fileSystems; 371 } 372 File [] roots = File.listRoots(); 373 Set <FileSystem> allRoots = new LinkedHashSet <FileSystem>(); 374 assert roots != null && roots.length > 0 : "Could not list file roots"; 376 for (File root : roots) { 377 FileObject random = FileUtil.toFileObject(root); 378 if (random == null) continue; 379 380 FileSystem fs; 381 try { 382 fs = random.getFileSystem(); 383 allRoots.add(fs); 384 385 389 390 if (fs != null) { 391 break; 392 } 393 } catch (FileStateInvalidException e) { 394 throw new AssertionError (e); 395 } 396 } 397 assert !allRoots.isEmpty() : "Could not get any filesystem"; return fileSystems = allRoots.toArray(new FileSystem[allRoots.size()]); 399 } 400 401 private static void addCustomDefs(Project project) throws BuildException, IOException { 402 long start = System.currentTimeMillis(); 403 if (AntBridge.getInterface().isAnt16()) { 404 Map <String ,ClassLoader > antlibLoaders = AntBridge.getCustomDefClassLoaders(); 405 for (Map.Entry <String ,ClassLoader > entry : antlibLoaders.entrySet()) { 406 String cnb = entry.getKey(); 407 ClassLoader l = entry.getValue(); 408 String resource = cnb.replace('.', '/') + "/antlib.xml"; URL antlib = l.getResource(resource); 410 if (antlib == null) { 411 throw new IOException ("Could not find " + antlib + " in ant/nblib/" + cnb.replace('.', '-') + ".jar"); } 413 NbAntlib.process(project, antlib, null, l); 415 String antlibUri = "antlib:" + cnb; NbAntlib.process(project, antlib, antlibUri, l); 418 } 419 } else { 420 Map <String ,Map <String ,Class >> customDefs = AntBridge.getCustomDefsNoNamespace(); 422 for (Map.Entry <String ,Class > entry : customDefs.get("task").entrySet()) { project.addTaskDefinition(entry.getKey(), entry.getValue()); 424 } 425 for (Map.Entry <String ,Class > entry : customDefs.get("type").entrySet()) { project.addDataTypeDefinition(entry.getKey(), entry.getValue()); 427 } 428 } 429 if (AntModule.err.isLoggable(ErrorManager.INFORMATIONAL)) { 430 AntModule.err.log("addCustomDefs took " + (System.currentTimeMillis() - start) + "msec"); 431 } 432 } 433 434 private static boolean doHack36393 = true; 435 440 private static void hack36393() { 441 if (!doHack36393) { 442 return; 444 } 445 try { 446 Class shutdownC = Class.forName("java.lang.Shutdown"); Class wrappedHookC = Class.forName("java.lang.Shutdown$WrappedHook"); Field hooksF = shutdownC.getDeclaredField("hooks"); hooksF.setAccessible(true); 450 Field hookF = wrappedHookC.getDeclaredField("hook"); hookF.setAccessible(true); 452 Field lockF = shutdownC.getDeclaredField("lock"); lockF.setAccessible(true); 454 Object lock = lockF.get(null); 455 Set <Thread > toRemove = new HashSet <Thread >(); 456 synchronized (lock) { 457 @SuppressWarnings ("unchecked") 458 Set <Object > hooks = (Set ) hooksF.get(null); 459 for (Object wrappedHook : hooks) { 460 Thread hook = (Thread )hookF.get(wrappedHook); 461 if (hook.getClass().getName().equals("org.apache.tools.ant.taskdefs.ProcessDestroyer")) { toRemove.add(hook); 464 } 465 } 466 } 467 for (Thread hook : toRemove) { 468 if (!Runtime.getRuntime().removeShutdownHook(hook)) { 469 throw new IllegalStateException ("Hook was not really registered!"); } 471 AntModule.err.log("#36393: removing an unwanted ProcessDestroyer shutdown hook"); 472 hook.start(); 474 } 475 } catch (Exception e) { 476 AntModule.err.notify(ErrorManager.INFORMATIONAL, e); 478 doHack36393 = false; 479 } 480 } 481 482 private static boolean doGutProject = !Boolean.getBoolean("org.apache.tools.ant.module.bridge.impl.BridgeImpl.doNotGutProject"); 483 489 private static void gutProject(Project p) { 490 if (!doGutProject) { 491 return; 492 } 493 try { 496 String s = p.getName(); 497 AntModule.err.log("Gutting extra references in project \"" + s + "\""); 498 Field [] fs = Project.class.getDeclaredFields(); 499 for (int i = 0; i < fs.length; i++) { 500 if (Modifier.isStatic(fs[i].getModifiers())) { 501 continue; 502 } 503 if (fs[i].getType().isPrimitive()) { 504 continue; 505 } 506 fs[i].setAccessible(true); 507 Object o = fs[i].get(p); 508 try { 509 if (o instanceof Collection ) { 510 ((Collection ) o).clear(); 511 continue; 513 } else if (o instanceof Map ) { 514 ((Map ) o).clear(); 515 continue; 516 } 517 } catch (UnsupportedOperationException e) { 518 } 520 if (Modifier.isFinal(fs[i].getModifiers())) { 521 continue; 522 } 523 fs[i].set(p, null); 524 } 525 Field helpersF; 527 try { 528 helpersF = IntrospectionHelper.class.getDeclaredField("helpers"); 529 } catch (NoSuchFieldException x) { helpersF = IntrospectionHelper.class.getDeclaredField("HELPERS"); 531 } 532 helpersF.setAccessible(true); 533 Object helpersO = helpersF.get(null); 534 Map helpersM = (Map ) helpersO; 535 helpersM.clear(); 536 Introspector.flushCaches(); 538 } catch (Exception e) { 539 AntModule.err.notify(ErrorManager.INFORMATIONAL, e); 541 doGutProject = false; 542 } 543 } 544 545 } 546 | Popular Tags |