1 19 20 package org.netbeans.modules.java.freeform; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.OutputStream ; 26 import java.net.MalformedURLException ; 27 import java.net.URL ; 28 import java.util.ArrayList ; 29 import java.util.Collection ; 30 import java.util.Collections ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Map ; 35 import java.util.Set ; 36 import java.util.StringTokenizer ; 37 import javax.swing.JButton ; 38 import javax.xml.parsers.ParserConfigurationException ; 39 import javax.xml.parsers.SAXParser ; 40 import javax.xml.parsers.SAXParserFactory ; 41 import org.netbeans.api.project.Project; 42 import org.netbeans.api.project.ProjectManager; 43 import org.netbeans.api.project.ProjectUtils; 44 import org.netbeans.modules.ant.freeform.spi.support.Util; 45 import org.netbeans.modules.java.freeform.jdkselection.JdkConfiguration; 46 import org.netbeans.modules.java.freeform.ui.ProjectModel; 47 import org.netbeans.spi.project.ActionProvider; 48 import org.netbeans.spi.project.AuxiliaryConfiguration; 49 import org.netbeans.spi.project.support.ant.AntProjectHelper; 50 import org.netbeans.spi.project.support.ant.PropertyEvaluator; 51 import org.netbeans.spi.project.support.ant.PropertyUtils; 52 import org.netbeans.spi.project.ui.CustomizerProvider; 53 import org.openide.DialogDisplayer; 54 import org.openide.ErrorManager; 55 import org.openide.NotifyDescriptor; 56 import org.openide.cookies.LineCookie; 57 import org.openide.filesystems.FileLock; 58 import org.openide.filesystems.FileObject; 59 import org.openide.filesystems.FileSystem; 60 import org.openide.filesystems.FileUtil; 61 import org.openide.loaders.DataObject; 62 import org.openide.loaders.DataObjectNotFoundException; 63 import org.openide.text.Line; 64 import org.openide.util.Exceptions; 65 import org.openide.util.Lookup; 66 import org.openide.util.NbBundle; 67 import org.openide.xml.XMLUtil; 68 import org.w3c.dom.Attr ; 69 import org.w3c.dom.Comment ; 70 import org.w3c.dom.Document ; 71 import org.w3c.dom.Element ; 72 import org.w3c.dom.NamedNodeMap ; 73 import org.w3c.dom.NodeList ; 74 import org.xml.sax.Attributes ; 75 import org.xml.sax.InputSource ; 76 import org.xml.sax.Locator ; 77 import org.xml.sax.SAXException ; 78 import org.xml.sax.helpers.DefaultHandler ; 79 80 84 final class JavaActions implements ActionProvider { 85 86 89 90 static final String JAVA_FILE_PATTERN = "\\.java$"; 91 92 private static final String [] ACTIONS = { 93 ActionProvider.COMMAND_COMPILE_SINGLE, 94 ActionProvider.COMMAND_DEBUG, 95 ActionProvider.COMMAND_RUN_SINGLE, 96 ActionProvider.COMMAND_DEBUG_SINGLE 97 }; 99 100 109 static final String FILE_SCRIPT_PATH = "nbproject/ide-file-targets.xml"; 115 static final String GENERAL_SCRIPT_PATH = "nbproject/ide-targets.xml"; 117 private final Project project; 118 private final AntProjectHelper helper; 119 private final PropertyEvaluator evaluator; 120 private final AuxiliaryConfiguration aux; 121 private boolean setOutputsNotified; 122 123 public JavaActions(Project project, AntProjectHelper helper, PropertyEvaluator evaluator, AuxiliaryConfiguration aux) { 124 this.project = project; 125 this.helper = helper; 126 this.evaluator = evaluator; 127 this.aux = aux; 128 } 129 130 public String [] getSupportedActions() { 131 return ACTIONS; 132 } 133 134 public boolean isActionEnabled(String command, Lookup context) throws IllegalArgumentException { 135 if (command.equals(ActionProvider.COMMAND_COMPILE_SINGLE)) { 136 return findPackageRoot(context) != null; 137 } else if (command.equals(ActionProvider.COMMAND_DEBUG)) { 138 return true; 139 } else if (command.equals(ActionProvider.COMMAND_RUN_SINGLE)) { 140 return (findPackageRoot(context) != null) && isSingleJavaFileSelected(context); 141 } else if (command.equals(ActionProvider.COMMAND_DEBUG_SINGLE)) { 142 return (findPackageRoot(context) != null) && isSingleJavaFileSelected(context); 143 } else { 144 throw new IllegalArgumentException (command); 145 } 146 } 147 148 public void invokeAction(final String command, final Lookup context) throws IllegalArgumentException { 149 try { 150 project.getProjectDirectory().getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 151 public void run() throws IOException { 152 try { 153 if (command.equals(ActionProvider.COMMAND_COMPILE_SINGLE)) { 154 handleCompileSingle(context); 155 } else if (command.equals(ActionProvider.COMMAND_DEBUG)) { 156 handleDebug(); 157 } else if (command.equals(ActionProvider.COMMAND_RUN_SINGLE)) { 158 handleRunSingle(context); 159 } else if (command.equals(ActionProvider.COMMAND_DEBUG_SINGLE)) { 160 handleDebugSingle(context); 161 } else { 162 throw new IllegalArgumentException (command); 163 } 164 } catch (SAXException e) { 165 throw (IOException ) new IOException (e.toString()).initCause(e); 166 } 167 } 168 }); 169 } catch (IOException e) { 170 ErrorManager.getDefault().notify(e); 171 } 172 } 173 174 180 private boolean alert(String commandDisplayName, String scriptPath) { 181 String projectDisplayName = ProjectUtils.getInformation(project).getDisplayName(); 182 String title = NbBundle.getMessage(JavaActions.class, "TITLE_generate_target_dialog", commandDisplayName, projectDisplayName); 183 String body = NbBundle.getMessage(JavaActions.class, "TEXT_generate_target_dialog", commandDisplayName, scriptPath); 184 NotifyDescriptor d = new NotifyDescriptor.Message(body, NotifyDescriptor.QUESTION_MESSAGE); 185 d.setTitle(title); 186 d.setOptionType(NotifyDescriptor.OK_CANCEL_OPTION); 187 JButton generate = new JButton (NbBundle.getMessage(JavaActions.class, "LBL_generate")); 188 generate.setDefaultCapable(true); 189 d.setOptions(new Object [] {generate, NotifyDescriptor.CANCEL_OPTION}); 190 return DialogDisplayer.getDefault().notify(d) == generate; 191 } 192 193 197 private boolean alertOutputs (String commandDisplayName) { 198 JButton setOutputOption = new JButton (NbBundle.getMessage(JavaActions.class,"CTL_SetOutput")); 199 setOutputOption.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(JavaActions.class,"AD_SetOutput")); 200 setOutputOption.setDefaultCapable(true); 201 String projectDisplayName = ProjectUtils.getInformation(project).getDisplayName(); 202 String title = NbBundle.getMessage(JavaActions.class, "TITLE_set_outputs_dialog", commandDisplayName, projectDisplayName); 203 String body = NbBundle.getMessage(JavaActions.class,"TEXT_set_outputs_dialog"); 204 NotifyDescriptor d = new NotifyDescriptor.Message (body, NotifyDescriptor.QUESTION_MESSAGE); 205 d.setTitle(title); 206 d.setOptionType(NotifyDescriptor.OK_CANCEL_OPTION); 207 d.setOptions(new Object [] {setOutputOption, NotifyDescriptor.CANCEL_OPTION}); 208 if (DialogDisplayer.getDefault().notify (d) == setOutputOption) { 209 CustomizerProvider customizerProvider = project.getLookup().lookup(CustomizerProvider.class); 210 assert customizerProvider != null; 211 customizerProvider.showCustomizer(); 212 return true; 213 } 214 return false; 215 } 216 217 220 private void handleCompileSingle(Lookup context) throws IOException , SAXException { 221 if (!alert(NbBundle.getMessage(JavaActions.class, "ACTION_compile.single"), FILE_SCRIPT_PATH)) { 223 return; 224 } 225 Document doc = readCustomScript(FILE_SCRIPT_PATH); 226 ensurePropertiesCopied(doc.getDocumentElement()); 227 Comment comm = doc.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_edit_target") + " "); 228 doc.getDocumentElement().appendChild(comm); 229 comm = doc.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_more_info_x.single") + " "); 230 doc.getDocumentElement().appendChild(comm); 231 String propertyName = "files"; AntLocation root = findPackageRoot(context); 233 assert root != null : context; 234 Element target = createCompileSingleTarget(doc, context, propertyName, root); 235 doc.getDocumentElement().appendChild(target); 236 writeCustomScript(doc, FILE_SCRIPT_PATH); 237 String targetName = target.getAttribute("name"); 239 addBinding(ActionProvider.COMMAND_COMPILE_SINGLE, FILE_SCRIPT_PATH, targetName, propertyName, root.virtual, JAVA_FILE_PATTERN, "relative-path", ","); jumpToBinding(ActionProvider.COMMAND_COMPILE_SINGLE); 241 jumpToBuildScript(FILE_SCRIPT_PATH, targetName); 242 } 243 244 Element createCompileSingleTarget(Document doc, Lookup context, String propertyName, AntLocation root) { 245 String targetName = "compile-selected-files-in-" + root.physical.getNameExt(); Element target = doc.createElement("target"); addJdkInitDeps(target); 249 target.setAttribute("name", targetName); Element fail = doc.createElement("fail"); fail.setAttribute("unless", propertyName); fail.appendChild(doc.createTextNode(NbBundle.getMessage(JavaActions.class, "COMMENT_must_set_property", propertyName))); 253 target.appendChild(fail); 254 String classesDir = findClassesOutputDir(root.virtual); 255 if (classesDir == null) { 256 target.appendChild(doc.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_must_set_build_classes_dir") + " ")); 257 classesDir = "${build.classes.dir}"; } 259 Element mkdir = doc.createElement("mkdir"); mkdir.setAttribute("dir", classesDir); target.appendChild(mkdir); 262 Element javac = doc.createElement("javac"); javac.setAttribute("srcdir", root.virtual); javac.setAttribute("destdir", classesDir); javac.setAttribute("includes", "${" + propertyName + "}"); String sourceLevel = findSourceLevel(root.virtual); 267 if (sourceLevel != null) { 268 javac.setAttribute("source", sourceLevel); } 270 String cp = findCUClasspath(root.virtual, "compile"); 271 if (cp != null) { 272 Element classpath = doc.createElement("classpath"); classpath.setAttribute("path", cp); javac.appendChild(classpath); 275 } 276 target.appendChild(javac); 277 return target; 278 } 279 280 private void handleDebug() throws IOException , SAXException { 281 if (!this.setOutputsNotified) { 282 ProjectModel pm = ProjectModel.createModel(Util.getProjectLocation(this.helper, this.evaluator), 283 FileUtil.toFile(project.getProjectDirectory()), this.evaluator, this.helper); 284 List <ProjectModel.CompilationUnitKey> cuKeys = pm.createCompilationUnitKeys(); 285 assert cuKeys != null; 286 boolean hasOutputs = false; 287 for (Iterator it = cuKeys.iterator(); it.hasNext();) { 288 ProjectModel.CompilationUnitKey ck = (ProjectModel.CompilationUnitKey) it.next(); 289 JavaProjectGenerator.JavaCompilationUnit cu = pm.getCompilationUnit(ck,false); 290 if (cu.output != null && cu.output.size()>0) { 291 hasOutputs = true; 292 break; 293 } 294 } 295 if (!hasOutputs) { 296 alertOutputs (NbBundle.getMessage(JavaActions.class, "ACTION_debug")); 297 this.setOutputsNotified = true; 298 return; 299 } 300 } 301 String [] bindings = findCommandBinding(ActionProvider.COMMAND_RUN); 302 Element task = null; 303 Element origTarget = null; 304 if (bindings != null && bindings.length <= 2) { 305 origTarget = findExistingBuildTarget(ActionProvider.COMMAND_RUN); 306 if (origTarget != null) { 308 task = targetUsesTaskExactlyOnce(origTarget, "java"); } 310 } 311 312 if (!alert(NbBundle.getMessage(JavaActions.class, "ACTION_debug"), task != null ? GENERAL_SCRIPT_PATH : FILE_SCRIPT_PATH)) { 313 return; 314 } 315 316 String generatedTargetName = "debug-nb"; String generatedScriptPath; 318 Document doc; 319 Element generatedTarget; 320 if (task != null) { 321 generatedScriptPath = GENERAL_SCRIPT_PATH; 323 doc = readCustomScript(GENERAL_SCRIPT_PATH); 324 ensureImports(doc.getDocumentElement(), bindings[0]); 325 generatedTarget = createDebugTargetFromTemplate(generatedTargetName, origTarget, task, doc); 326 } else { 327 generatedScriptPath = FILE_SCRIPT_PATH; 329 doc = readCustomScript(FILE_SCRIPT_PATH); 330 ensurePropertiesCopied(doc.getDocumentElement()); 331 generatedTarget = createDebugTargetFromScratch(generatedTargetName, doc); 332 } 333 Comment comm = doc.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_edit_target") + " "); 334 doc.getDocumentElement().appendChild(comm); 335 comm = doc.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_more_info_debug") + " "); 336 doc.getDocumentElement().appendChild(comm); 337 doc.getDocumentElement().appendChild(generatedTarget); 338 writeCustomScript(doc, generatedScriptPath); 339 addBinding(ActionProvider.COMMAND_DEBUG, generatedScriptPath, generatedTargetName, null, null, null, null, null); 340 jumpToBinding(ActionProvider.COMMAND_DEBUG); 341 jumpToBuildScript(generatedScriptPath, generatedTargetName); 342 } 343 344 private Element createNbjpdastart(Document ownerDocument) { 345 Element nbjpdastart = ownerDocument.createElement("nbjpdastart"); nbjpdastart.setAttribute("name", ProjectUtils.getInformation(project).getDisplayName()); nbjpdastart.setAttribute("addressproperty", "jpda.address"); nbjpdastart.setAttribute("transport", "dt_socket"); return nbjpdastart; 350 } 351 352 private static final String [] DEBUG_VM_ARGS = { 353 "-Xdebug", "-Xrunjdwp:transport=dt_socket,address=${jpda.address}", }; 356 private void addDebugVMArgs(Element java, Document ownerDocument) { 357 NamedNodeMap attrs = java.getAttributes(); 359 boolean found = false; 360 for (int i=0; i<attrs.getLength(); i++) { 361 Attr attr = (Attr ) attrs.item(i); 362 if ("fork".equals(attr.getName())) { String value = attr.getValue(); 364 if ("on".equalsIgnoreCase (value) || "true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value)) { found = true; 368 } 369 break; 370 } 371 } 372 if (!found) { 373 java.setAttribute("fork", "true"); } 375 for (int i = 0; i < DEBUG_VM_ARGS.length; i++) { 376 Element jvmarg = ownerDocument.createElement("jvmarg"); jvmarg.setAttribute("value", DEBUG_VM_ARGS[i]); java.appendChild(jvmarg); 379 } 380 } 381 382 Element createDebugTargetFromTemplate(String generatedTargetName, Element origTarget, Element origTask, Document ownerDocument) { 383 NodeList tasks = origTarget.getChildNodes(); 384 int taskIndex = -1; 385 for (int i = 0; i < tasks.getLength(); i++) { 386 if (tasks.item(i) == origTask) { 387 taskIndex = i; 388 break; 389 } 390 } 391 assert taskIndex != -1; 392 Element target = (Element ) ownerDocument.importNode(origTarget, true); 393 addJdkInitDeps(target); 394 Element task = (Element ) target.getChildNodes().item(taskIndex); 395 target.setAttribute("name", generatedTargetName); Element nbjpdastart = createNbjpdastart(ownerDocument); 397 String textualCp = task.getAttribute("classpath"); if (textualCp.length() > 0) { 399 Element classpath = ownerDocument.createElement("classpath"); classpath.setAttribute("path", textualCp); nbjpdastart.appendChild(classpath); 402 } else { 403 NodeList origClasspath = task.getElementsByTagName("classpath"); if (origClasspath.getLength() == 1) { 405 Element classpath = (Element ) ownerDocument.importNode(origClasspath.item(0), true); 406 nbjpdastart.appendChild(classpath); 407 } 408 } 409 target.insertBefore(nbjpdastart, task); 410 addDebugVMArgs(task, ownerDocument); 411 return target; 412 } 413 414 Element createDebugTargetFromScratch(String generatedTargetName, Document ownerDocument) { 415 Element target = ownerDocument.createElement("target"); 416 addJdkInitDeps(target); 417 target.setAttribute("name", generatedTargetName); Element path = ownerDocument.createElement("path"); path.setAttribute("id", "cp"); path.appendChild(ownerDocument.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_set_runtime_cp") + " ")); 422 target.appendChild(path); 423 Element nbjpdastart = createNbjpdastart(ownerDocument); 424 Element classpath = ownerDocument.createElement("classpath"); classpath.setAttribute("refid", "cp"); nbjpdastart.appendChild(classpath); 427 target.appendChild(nbjpdastart); 428 target.appendChild(ownerDocument.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_set_main_class") + " ")); 429 Element java = ownerDocument.createElement("java"); java.setAttribute("classname", "some.main.Class"); classpath = ownerDocument.createElement("classpath"); classpath.setAttribute("refid", "cp"); java.appendChild(classpath); 434 addDebugVMArgs(java, ownerDocument); 435 target.appendChild(java); 436 return target; 437 } 438 439 444 Document readCustomScript(String scriptPath) throws IOException , SAXException { 445 FileObject script = helper.getProjectDirectory().getFileObject(scriptPath); 447 Document doc; 448 if (script != null) { 449 InputStream is = script.getInputStream(); 450 try { 451 doc = XMLUtil.parse(new InputSource (is), false, true, null, null); 452 } finally { 453 is.close(); 454 } 455 } else { 456 doc = XMLUtil.createDocument("project", null, null, null); Element root = doc.getDocumentElement(); 458 String projname = ProjectUtils.getInformation(project).getDisplayName(); 459 root.setAttribute("name", NbBundle.getMessage(JavaActions.class, "LBL_generated_script_name", projname)); 460 } 461 if (helper.getProjectDirectory().getFileObject(JdkConfiguration.JDK_XML) != null) { 462 JdkConfiguration.insertJdkXmlImport(doc); 463 } 464 return doc; 465 } 466 467 478 void ensurePropertiesCopied(Element antProject) { 479 if (antProject.getAttribute("basedir").length() > 0) { 480 return; 482 } 483 antProject.setAttribute("basedir", ".."); Element data = Util.getPrimaryConfigurationData(helper); 486 Element properties = Util.findElement(data, "properties", Util.NAMESPACE); 487 if (properties != null) { 488 for (Element el : Util.findSubElements(properties)) { 489 Element nue = antProject.getOwnerDocument().createElement("property"); if (el.getLocalName().equals("property")) { String name = el.getAttribute("name"); assert name != null; 493 String text = Util.findText(el); 494 assert text != null; 495 nue.setAttribute("name", name); 496 nue.setAttribute("value", text); 497 } else if (el.getLocalName().equals("property-file")) { String text = Util.findText(el); 499 assert text != null; 500 nue.setAttribute("file", text); 501 } else { 502 assert false : el; 503 } 504 antProject.appendChild(nue); 505 } 506 } 507 } 508 509 518 void ensureImports(Element antProject, String origScriptPath) throws IOException , SAXException { 519 if (antProject.getAttribute("basedir").length() > 0) { 520 return; 522 } 523 String origScriptPathEval = evaluator.evaluate(origScriptPath); 524 if (origScriptPathEval == null) { 525 return; 527 } 528 String origScriptURI = helper.resolveFile(origScriptPathEval).toURI().toString(); 529 Document origScriptDocument = XMLUtil.parse(new InputSource (origScriptURI), false, true, null, null); 530 String origBasedir = origScriptDocument.getDocumentElement().getAttribute("basedir"); if (origBasedir.length() == 0) { 532 origBasedir = "."; } 534 String basedir, importPath; 535 File origScript = new File (origScriptPathEval); 536 if (origScript.isAbsolute()) { 537 importPath = origScriptPathEval; 539 if (new File (origBasedir).isAbsolute()) { 540 basedir = origBasedir; 541 } else { 542 basedir = PropertyUtils.resolveFile(origScript.getParentFile(), origBasedir).getAbsolutePath(); 543 } 544 } else { 545 String prefix = "../"; importPath = prefix + origScriptPathEval; 549 if (new File (origBasedir).isAbsolute()) { 550 basedir = origBasedir; 551 } else { 552 int slash = origScriptPathEval.replace(File.separatorChar, '/').lastIndexOf('/'); 553 if (slash == -1) { 554 basedir = prefix + origBasedir; 555 } else { 556 basedir = prefix + origScriptPathEval.substring(0, slash + 1) + origBasedir; 557 } 558 basedir = basedir.replaceAll("/\\.$", ""); } 561 } 562 antProject.setAttribute("basedir", basedir); Element importEl = antProject.getOwnerDocument().createElement("import"); importEl.setAttribute("file", importPath); antProject.appendChild(importEl); 566 } 567 568 572 void writeCustomScript(Document doc, String scriptPath) throws IOException { 573 FileObject script = helper.getProjectDirectory().getFileObject(scriptPath); 574 if (script == null) { 575 script = FileUtil.createData(helper.getProjectDirectory(), scriptPath); 576 } 577 FileLock lock = script.lock(); 578 try { 579 OutputStream os = script.getOutputStream(lock); 580 try { 581 XMLUtil.write(doc, os, "UTF-8"); } finally { 583 os.close(); 584 } 585 } finally { 586 lock.releaseLock(); 587 } 588 } 589 590 private List <Element > compilationUnits() { 591 Element java = aux.getConfigurationFragment(JavaProjectNature.EL_JAVA, JavaProjectNature.NS_JAVA_2, true); 592 if (java == null) { 593 return Collections.emptyList(); 594 } 595 return Util.findSubElements(java); 596 } 597 598 603 AntLocation findPackageRoot(Lookup context) { 604 for (Element compilationUnitEl : compilationUnits()) { 605 assert compilationUnitEl.getLocalName().equals("compilation-unit") : compilationUnitEl; 606 List <String > packageRootNames = Classpaths.findPackageRootNames(compilationUnitEl); 607 Map <String ,FileObject> packageRootsByName = Classpaths.findPackageRootsByName(helper, evaluator, packageRootNames); 608 for (Map.Entry <String ,FileObject> entry : packageRootsByName.entrySet()) { 609 FileObject root = entry.getValue(); 610 if (containsSelectedJavaSources(root, context)) { 611 return new AntLocation(entry.getKey(), root); 612 } 613 } 614 } 615 return null; 617 } 618 619 622 static boolean containsSelectedJavaSources(FileObject root, Lookup context) { 623 Set <FileObject> selection = new HashSet <FileObject>(context.lookupAll(FileObject.class)); 624 for (DataObject dob : context.lookupAll(DataObject.class)) { 625 selection.add(dob.getPrimaryFile()); 626 } 627 if (selection.isEmpty()) { 628 return false; 629 } 630 for (FileObject f : selection) { 631 if (f.isData() && !f.hasExt("java")) { return false; 633 } 634 if (f != root && !FileUtil.isParentOf(root, f)) { 635 return false; 636 } 637 } 638 return true; 639 } 640 641 645 static final class AntLocation { 646 public final String virtual; 647 public final FileObject physical; 648 public AntLocation(String virtual, FileObject physical) { 649 this.virtual = virtual; 650 this.physical = physical; 651 } 652 public String toString() { 653 return "AntLocation[" + virtual + "=" + physical + "]"; } 655 } 656 657 662 private Element findCompilationUnit(String sources) { 663 for (Element compilationUnitEl : compilationUnits()) { 664 for (Element packageRoot : Util.findSubElements(compilationUnitEl)) { 665 if (packageRoot.getLocalName().equals("package-root")) { if (Util.findText(packageRoot).equals(sources)) { 667 return compilationUnitEl; 668 } 669 } 670 } 671 } 672 return null; 673 } 674 675 680 String findClassesOutputDir(String sources) { 681 Element compilationUnitEl = findCompilationUnit(sources); 682 if (compilationUnitEl != null) { 683 return findClassesOutputDir(compilationUnitEl); 684 } else { 685 return null; 686 } 687 } 688 689 692 private String findClassesOutputDir(Element compilationUnitEl) { 693 for (Element builtTo : Util.findSubElements(compilationUnitEl)) { 695 if (builtTo.getLocalName().equals("built-to")) { String rawtext = Util.findText(builtTo); 697 String evaltext = evaluator.evaluate(rawtext); 699 if (evaltext != null) { 700 File dest = helper.resolveFile(evaltext); 701 URL destU; 702 try { 703 destU = dest.toURI().toURL(); 704 } catch (MalformedURLException e) { 705 throw new AssertionError (e); 706 } 707 if (!FileUtil.isArchiveFile(destU)) { 708 return rawtext; 710 } 711 } 712 } 713 } 714 return null; 715 } 716 717 722 String findSourceLevel(String sources) { 723 Element compilationUnitEl = findCompilationUnit(sources); 724 if (compilationUnitEl != null) { 725 Element sourceLevel = Util.findElement(compilationUnitEl, "source-level", JavaProjectNature.NS_JAVA_2); 726 if (sourceLevel != null) { 727 return Util.findText(sourceLevel); 728 } 729 } 730 return null; 731 } 732 733 738 String findCUClasspath(String sources, String moud) { 739 Element compilationUnitEl = findCompilationUnit(sources); 740 if (compilationUnitEl != null) { 741 for (Element classpath : Util.findSubElements(compilationUnitEl)) { 742 if (classpath.getLocalName().equals("classpath")) { String mode = classpath.getAttribute("mode"); if (mode.equals(moud)) { 745 return Util.findText(classpath); 746 } 747 } 748 } 749 } 750 return null; 751 } 752 753 758 private String [] findCUOutputs(String srcRoot) { 759 List <String > outputs = new ArrayList <String >(); 760 Element cuElem = findCompilationUnit(srcRoot); 761 if (cuElem != null) { 762 NodeList builts = cuElem.getElementsByTagName("built-to"); for (int i = 0; i < builts.getLength(); i++) { 764 outputs.add(builts.item(i).getTextContent()); 765 } 766 } 767 return outputs.toArray(new String [outputs.size()]); 768 } 769 770 private static final String [] rootElementsOrder = {"name", "properties", "folders", "ide-actions", "export", "view", "subprojects"}; 774 786 void addBinding(String command, String scriptPath, String target, String propertyName, String dir, String pattern, String format, String separator) throws IOException { 787 Element data = Util.getPrimaryConfigurationData(helper); 790 Element ideActions = Util.findElement(data, "ide-actions", Util.NAMESPACE); if (ideActions == null) { 792 ideActions = data.getOwnerDocument().createElementNS(Util.NAMESPACE, "ide-actions"); Util.appendChildElement(data, ideActions, rootElementsOrder); 795 } 796 Document doc = data.getOwnerDocument(); 797 Element action = doc.createElementNS(Util.NAMESPACE, "action"); action.setAttribute("name", command); Element script = doc.createElementNS(Util.NAMESPACE, "script"); script.appendChild(doc.createTextNode(scriptPath)); 801 action.appendChild(script); 802 Element targetEl = doc.createElementNS(Util.NAMESPACE, "target"); targetEl.appendChild(doc.createTextNode(target)); 804 action.appendChild(targetEl); 805 if (propertyName != null) { 806 Element context = doc.createElementNS(Util.NAMESPACE, "context"); Element property = doc.createElementNS(Util.NAMESPACE, "property"); property.appendChild(doc.createTextNode(propertyName)); 809 context.appendChild(property); 810 Element folder = doc.createElementNS(Util.NAMESPACE, "folder"); folder.appendChild(doc.createTextNode(dir)); 812 context.appendChild(folder); 813 if (pattern != null) { 814 Element patternEl = doc.createElementNS(Util.NAMESPACE, "pattern"); patternEl.appendChild(doc.createTextNode(pattern)); 816 context.appendChild(patternEl); 817 } 818 Element formatEl = doc.createElementNS(Util.NAMESPACE, "format"); formatEl.appendChild(doc.createTextNode(format)); 820 context.appendChild(formatEl); 821 Element arity = doc.createElementNS(Util.NAMESPACE, "arity"); if (separator != null) { 823 Element separatorEl = doc.createElementNS(Util.NAMESPACE, "separated-files"); separatorEl.appendChild(doc.createTextNode(separator)); 825 arity.appendChild(separatorEl); 826 } else { 827 arity.appendChild(doc.createElementNS(Util.NAMESPACE, "one-file-only")); } 829 context.appendChild(arity); 830 action.appendChild(context); 831 } else { 832 Element view = Util.findElement(data, "view", Util.NAMESPACE); if (view != null) { 836 Element contextMenu = Util.findElement(view, "context-menu", Util.NAMESPACE); if (contextMenu != null) { 838 Element ideAction = doc.createElementNS(Util.NAMESPACE, "ide-action"); ideAction.setAttribute("name", command); contextMenu.appendChild(ideAction); 841 } 842 } 843 } 844 ideActions.appendChild(action); 845 Util.putPrimaryConfigurationData(helper, data); 846 ProjectManager.getDefault().saveProject(project); 847 } 848 849 854 private void jumpToBuildScript(String scriptPath, String target) { 855 jumpToFile(scriptPath, target, "target", "name"); } 857 858 862 private void jumpToBinding(String command) { 863 jumpToFile(AntProjectHelper.PROJECT_XML_PATH, command, "action", "name"); } 865 866 873 private void jumpToFile(String path, String match, String elementLocalName, String elementAttributeName) { 874 FileObject file = helper.getProjectDirectory().getFileObject(path); 875 if (file == null) { 876 return; 877 } 878 int line; 879 try { 880 line = findLine(file, match, elementLocalName, elementAttributeName); 881 } catch (Exception e) { 882 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 883 return; 884 } 885 if (line == -1) { 886 line = 0; 888 } 889 DataObject fileDO; 890 try { 891 fileDO = DataObject.find(file); 892 } catch (DataObjectNotFoundException e) { 893 throw new AssertionError (e); 894 } 895 LineCookie lines = fileDO.getCookie(LineCookie.class); 896 if (lines != null) { 897 try { 898 lines.getLineSet().getCurrent(line).show(Line.SHOW_GOTO); 899 } catch (IndexOutOfBoundsException e) { 900 ErrorManager.getDefault().getInstance(JavaActions.class.getName()).log(ErrorManager.WARNING, e + " [file=" + file + " match=" + match + " line=" + line + "]"); lines.getLineSet().getCurrent(0).show(Line.SHOW_GOTO); 903 } 904 } 905 } 906 907 917 static final int findLine(FileObject file, final String match, final String elementLocalName, final String elementAttributeName) throws IOException , SAXException , ParserConfigurationException { 918 InputSource in = new InputSource (file.getURL().toString()); 919 SAXParserFactory factory = SAXParserFactory.newInstance(); 920 factory.setNamespaceAware(true); 921 SAXParser parser = factory.newSAXParser(); 922 final int[] line = new int[] {-1}; 923 class Handler extends DefaultHandler { 924 private Locator locator; 925 public void setDocumentLocator(Locator l) { 926 locator = l; 927 } 928 public void startElement(String uri, String localname, String qname, Attributes attr) throws SAXException { 929 if (line[0] == -1) { 930 if (localname.equals(elementLocalName) && match.equals(attr.getValue(elementAttributeName))) { line[0] = locator.getLineNumber() - 1; 932 } 933 } 934 } 935 } 936 parser.parse(in, new Handler ()); 937 return line[0]; 938 } 939 940 945 Element findExistingBuildTarget(String command) throws IOException , SAXException { 946 String [] binding = findCommandBinding(command); 947 if (binding == null) { 948 return null; 949 } 950 String scriptName = binding[0]; 951 assert scriptName != null; 952 String targetName; 953 if (binding.length == 1) { 954 targetName = null; 955 } else if (binding.length == 2) { 956 targetName = binding[1]; 957 } else { 958 return null; 960 } 961 String scriptPath = evaluator.evaluate(scriptName); 962 if (scriptPath == null) { 963 return null; 964 } 965 File scriptFile = helper.resolveFile(scriptPath); 966 String scriptURI = scriptFile.toURI().toString(); 967 Document doc = XMLUtil.parse(new InputSource (scriptURI), false, true, null, null); 968 if (targetName == null) { 969 targetName = doc.getDocumentElement().getAttribute("default"); if (targetName == null) { 971 return null; 972 } 973 } 974 for (Element target : Util.findSubElements(doc.getDocumentElement())) { 975 if (target.getLocalName().equals("target") && targetName.equals(target.getAttribute("name"))) { return target; 977 } 978 } 979 return null; 980 } 981 982 988 String [] findCommandBinding(String command) { 989 Element data = Util.getPrimaryConfigurationData(helper); 990 Element ideActions = Util.findElement(data, "ide-actions", Util.NAMESPACE); if (ideActions == null) { 992 return null; 993 } 994 String scriptName = "build.xml"; for (Element action : Util.findSubElements(ideActions)) { 996 assert action.getLocalName().equals("action"); 997 if (action.getAttribute("name").equals(command)) { 998 Element script = Util.findElement(action, "script", Util.NAMESPACE); if (script != null) { 1000 scriptName = Util.findText(script); 1001 } 1002 List <String > scriptPlusTargetNames = new ArrayList <String >(); 1003 scriptPlusTargetNames.add(scriptName); 1004 for (Element target : Util.findSubElements(action)) { 1005 if (target.getLocalName().equals("target")) { scriptPlusTargetNames.add(Util.findText(target)); 1007 } 1008 } 1009 if (scriptName.equals(JdkConfiguration.NBJDK_XML) && scriptPlusTargetNames.size() > 1) { 1010 FileObject nbjdkFO = helper.getProjectDirectory().getFileObject(JdkConfiguration.NBJDK_XML); 1012 if (nbjdkFO != null) { 1013 try { 1014 Document nbjdk = XMLUtil.parse(new InputSource (nbjdkFO.getURL().toString()), false, false, null, null); 1015 NodeList nl = nbjdk.getElementsByTagName("target"); for (int i = 0; i < nl.getLength(); i++) { 1017 if (((Element ) nl.item(i)).getAttribute("name").equals(scriptPlusTargetNames.get(1))) { NodeList nl2 = ((Element ) nl.item(i)).getElementsByTagName("ant"); if (nl2.getLength() == 1) { 1020 String antfile = ((Element ) nl2.item(0)).getAttribute("antfile"); if (antfile.length() == 0) { 1022 antfile = "build.xml"; } 1024 scriptPlusTargetNames.set(0, antfile); 1025 break; 1026 } 1027 } 1028 } 1029 } catch (Exception x) { 1030 Exceptions.printStackTrace(x); 1031 } 1032 } 1033 } 1034 return scriptPlusTargetNames.toArray(new String [scriptPlusTargetNames.size()]); 1035 } 1036 } 1037 return null; 1038 } 1039 1040 1046 Element targetUsesTaskExactlyOnce(Element target, String taskName) { 1047 Element foundTask = null; 1049 for (Element task : Util.findSubElements(target)) { 1050 if (task.getLocalName().equals(taskName)) { 1051 if (foundTask != null) { 1052 return null; 1054 } else { 1055 foundTask = task; 1056 } 1057 } 1058 } 1059 return foundTask; 1060 } 1061 1062 private void handleRunSingle(Lookup context) throws IOException , SAXException { 1063 if (!alert(NbBundle.getMessage(JavaActions.class, "ACTION_run.single"), FILE_SCRIPT_PATH)) { 1064 return; 1065 } 1066 Document doc = readCustomScript(FILE_SCRIPT_PATH); 1067 AntLocation root = handleInitials(doc, context); 1068 assert root != null : context; 1069 String propertyName = "run.class"; String targetName = "run-selected-file-in-" + root.physical.getNameExt(); Element target = createRunSingleTargetElem(doc, targetName, propertyName, root); 1072 doc.getDocumentElement().appendChild(target); 1073 writeCustomScript(doc, FILE_SCRIPT_PATH); 1074 addBinding(ActionProvider.COMMAND_RUN_SINGLE, FILE_SCRIPT_PATH, targetName, 1075 propertyName, root.virtual, JAVA_FILE_PATTERN, "java-name", null); jumpToBinding(ActionProvider.COMMAND_RUN_SINGLE); 1077 jumpToBuildScript(FILE_SCRIPT_PATH, targetName); 1078 } 1079 1080 private void handleDebugSingle(Lookup context) throws IOException , SAXException { 1081 if (!alert(NbBundle.getMessage(JavaActions.class, "ACTION_debug.single"), FILE_SCRIPT_PATH)) { 1082 return; 1083 } 1084 Document doc = readCustomScript(FILE_SCRIPT_PATH); 1085 AntLocation root = handleInitials(doc, context); 1086 assert root != null : context; 1087 String propertyName = "debug.class"; String targetName = "debug-selected-file-in-" + root.physical.getNameExt(); Element targetElem = createDebugSingleTargetElem(doc, targetName, propertyName, root); 1090 doc.getDocumentElement().appendChild(targetElem); 1091 writeCustomScript(doc, FILE_SCRIPT_PATH); 1092 addBinding(ActionProvider.COMMAND_DEBUG_SINGLE, FILE_SCRIPT_PATH, targetName, 1093 propertyName, root.virtual, JAVA_FILE_PATTERN, "java-name", null); jumpToBinding(ActionProvider.COMMAND_DEBUG_SINGLE); 1095 jumpToBuildScript(FILE_SCRIPT_PATH, targetName); 1096 } 1097 1098 Element createRunSingleTargetElem(Document doc, String tgName, 1099 String propName, AntLocation root) throws IOException , SAXException { 1100 1101 Element targetElem = doc.createElement("target"); addJdkInitDeps(targetElem); 1103 targetElem.setAttribute("name", tgName); Element failElem = doc.createElement("fail"); failElem.setAttribute("unless", propName); failElem.appendChild(doc.createTextNode(NbBundle.getMessage(JavaActions.class, 1107 "COMMENT_must_set_property", propName))); 1108 targetElem.appendChild(failElem); 1109 1110 String depends[] = getRunDepends(); 1111 if (depends != null) { 1112 targetElem.appendChild(createAntElem(doc, depends[0], depends[1])); 1113 } 1114 1115 Element javaElem = doc.createElement("java"); javaElem.setAttribute("classname", "${" + propName + "}"); javaElem.setAttribute("fork", "true"); javaElem.setAttribute("failonerror", "true"); 1120 Element cpElem = getPathFromCU(doc, root.virtual, "classpath"); 1121 if (cpElem.getChildNodes().getLength() == 0) { 1123 cpElem.appendChild(doc.createComment(" " + NbBundle.getMessage(JavaActions.class, 1124 "COMMENT_set_runtime_cp") + " ")); 1125 } 1126 javaElem.appendChild(cpElem); 1127 targetElem.appendChild(javaElem); 1128 return targetElem; 1129 } 1130 1131 Element createDebugSingleTargetElem(Document doc, String tgName, 1132 String propName, AntLocation root) throws IOException , SAXException { 1133 1134 Element targetElem = doc.createElement("target"); addJdkInitDeps(targetElem); 1136 targetElem.setAttribute("name", tgName); Element failElem = doc.createElement("fail"); failElem.setAttribute("unless", propName); failElem.appendChild(doc.createTextNode(NbBundle.getMessage(JavaActions.class, 1140 "COMMENT_must_set_property", propName))); 1141 targetElem.appendChild(failElem); 1142 1143 String depends[] = getRunDepends(); 1144 if (depends != null) { 1145 targetElem.appendChild(createAntElem(doc, depends[0], depends[1])); 1146 } 1147 1148 Element pElem = getPathFromCU(doc, root.virtual, "path"); pElem.setAttribute("id", "cp"); if (pElem.getChildNodes().getLength() == 0) { 1152 pElem.appendChild(doc.createComment(" " + NbBundle.getMessage(JavaActions.class, 1153 "COMMENT_set_runtime_cp") + " ")); 1154 } 1155 targetElem.appendChild(pElem); 1156 1157 Element nbjpdastartElem = createNbjpdastart(doc); 1158 Element cpElem = doc.createElement("classpath"); cpElem.setAttribute("refid", "cp"); nbjpdastartElem.appendChild(cpElem); 1161 targetElem.appendChild(nbjpdastartElem); 1162 1163 Element javaElem = doc.createElement("java"); javaElem.setAttribute("classname", "${" + propName + "}"); 1166 cpElem = doc.createElement("classpath"); cpElem.setAttribute("refid", "cp"); javaElem.appendChild(cpElem); 1169 addDebugVMArgs(javaElem, doc); 1170 1171 targetElem.appendChild(javaElem); 1172 return targetElem; 1173 } 1174 1175 private AntLocation handleInitials(Document doc, Lookup context) { 1176 ensurePropertiesCopied(doc.getDocumentElement()); 1177 Comment comm = doc.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_edit_target") + " "); 1178 doc.getDocumentElement().appendChild(comm); 1179 comm = doc.createComment(" " + NbBundle.getMessage(JavaActions.class, "COMMENT_more_info_run.single") + " "); 1180 doc.getDocumentElement().appendChild(comm); 1181 return findPackageRoot(context); 1182 } 1183 1184 1187 String [] getRunDepends() throws IOException , SAXException { 1188 String depends[] = null; 1189 Element targetElem = findExistingBuildTarget(ActionProvider.COMMAND_RUN); 1190 if (targetElem == null) 1191 return null; 1192 String [] bindings = findCommandBinding(ActionProvider.COMMAND_RUN); 1193 String dep = targetElem.getAttribute("depends"); if (bindings != null && bindings.length <= 2 && !"".equals(dep)) { 1195 depends = new String [2]; 1196 depends[0] = bindings[0]; 1197 depends[1] = dep; 1198 } 1199 return depends; 1200 } 1201 1202 1206 Element getPathFromCU(Document doc, String srcRoot, String type) { 1207 String cp = findCUClasspath(srcRoot, "execute"); Element pElem = null; 1209 if (cp != null) { 1210 pElem = createPathLikeElem(doc, type, null, new String [] {cp}, null, null, null); 1212 } else { 1213 cp = findCUClasspath(srcRoot, "compile"); String paths[] = cp == null ? null : new String [] {cp}; 1216 String outputs[] = findCUOutputs(srcRoot); 1217 pElem = createPathLikeElem(doc, type, null, paths, outputs, null, null); 1218 } 1219 return pElem; 1220 } 1221 1222 1225 Element createPathLikeElem(Document doc, String type, String id, 1226 String [] paths, String [] locations, String refid, String comm) { 1227 1228 Element pElem = doc.createElement(type); if (id != null) 1230 pElem.setAttribute("id", id); if (refid != null) 1232 pElem.setAttribute("refid", refid); if (comm != null) 1234 pElem.appendChild(doc.createComment(comm)); 1235 if (paths != null && paths.length > 0) { 1236 for (int i = 0; i < paths.length; i++) { 1237 Element pathelElem = doc.createElement("pathelement"); pathelElem.setAttribute("path", paths[i]); pElem.appendChild(pathelElem); 1240 } 1241 } 1242 if (locations != null && locations.length > 0) { 1243 for (int j = 0; j < locations.length; j++) { 1244 Element pathelElem = doc.createElement("pathelement"); pathelElem.setAttribute("location", locations[j]); pElem.appendChild(pathelElem); 1247 } 1248 } 1249 return pElem; 1250 } 1251 1252 1255 Element createAntElem(Document doc, String antFile, String deps) { 1256 assert antFile != null; 1257 Element antElem = doc.createElement("ant"); antElem.setAttribute("antfile", antFile); 1259 antElem.setAttribute("inheritall", "false"); StringTokenizer st = new StringTokenizer (deps, ","); if (st.countTokens() > 1) { 1262 while (st.hasMoreTokens()) { 1263 String dep = st.nextToken(); 1264 Element tgElem = doc.createElement("target"); tgElem.setAttribute("name", dep.trim()); antElem.appendChild(tgElem); 1267 } 1268 } else { 1269 antElem.setAttribute("target", deps); } 1271 return antElem; 1272 } 1273 1274 private boolean isSingleJavaFileSelected(Lookup context) { 1275 Collection <? extends DataObject> selectedDO = context.lookupAll(DataObject.class); 1276 if (selectedDO.size() == 1 && selectedDO.iterator().next().getPrimaryFile().hasExt("java")) { 1277 return true; 1278 } 1279 return false; 1280 } 1281 1282 private void addJdkInitDeps(Element target) { 1283 if (helper.getProjectDirectory().getFileObject(JdkConfiguration.JDK_XML) != null) { 1284 String deps = target.getAttribute("depends"); target.setAttribute("depends", deps.length() == 0 ? "-jdk-init" : "-jdk-init," + deps); } 1287 } 1288 1289} 1290 | Popular Tags |