1 19 20 package org.netbeans.modules.web.freeform; 21 22 import java.io.BufferedOutputStream ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.OutputStream ; 26 import java.util.Iterator ; 27 import javax.swing.JButton ; 28 import javax.xml.parsers.ParserConfigurationException ; 29 import javax.xml.parsers.SAXParser ; 30 import javax.xml.parsers.SAXParserFactory ; 31 import org.netbeans.api.java.project.JavaProjectConstants; 32 import org.netbeans.api.project.Project; 33 import org.netbeans.api.project.ProjectInformation; 34 import org.netbeans.api.project.ProjectManager; 35 import org.netbeans.api.project.ProjectUtils; 36 import org.netbeans.modules.ant.freeform.spi.support.Util; 37 import org.netbeans.modules.web.api.webmodule.WebProjectConstants; 38 import org.netbeans.spi.project.ActionProvider; 39 import org.netbeans.spi.project.AuxiliaryConfiguration; 40 import org.netbeans.spi.project.support.ant.AntProjectHelper; 41 import org.netbeans.spi.project.support.ant.EditableProperties; 42 import org.openide.DialogDisplayer; 43 import org.openide.ErrorManager; 44 import org.openide.NotifyDescriptor; 45 import org.openide.cookies.EditCookie; 46 import org.openide.cookies.LineCookie; 47 import org.openide.filesystems.FileLock; 48 import org.openide.filesystems.FileObject; 49 import org.openide.filesystems.FileUtil; 50 import org.openide.loaders.DataObject; 51 import org.openide.loaders.DataObjectNotFoundException; 52 import org.openide.text.Line; 53 import org.openide.util.NbBundle; 54 import org.openide.xml.XMLUtil; 55 import org.w3c.dom.Comment ; 56 import org.w3c.dom.Document ; 57 import org.w3c.dom.Element ; 58 import org.xml.sax.Attributes ; 59 import org.xml.sax.InputSource ; 60 import org.xml.sax.Locator ; 61 import org.xml.sax.SAXException ; 62 import org.xml.sax.helpers.DefaultHandler ; 63 64 69 public class WebFreeFormActionProvider implements ActionProvider { 70 71 80 static final String FILE_SCRIPT_PATH = "nbproject/ide-file-targets.xml"; 82 87 static final String GENERAL_SCRIPT_PATH = "nbproject/ide-targets.xml"; 89 private static final String LOAD_PROPS_TARGET = "-load-props"; private static final String CHECK_PROPS_TARGET = "-check-props"; private static final String INIT_TARGET = "-init"; private static final String DEBUG_TARGET = "debug-nb"; private static final String DISPLAY_BROWSER = "debug-display-browser"; 95 private static final String [] DEBUG_PROPERTIES = new String [] { 96 WebFreeformProperties.JPDA_SESSION_NAME, 97 WebFreeformProperties.JPDA_HOST, 98 WebFreeformProperties.JPDA_ADDRESS, 99 WebFreeformProperties.JPDA_TRANSPORT, 100 WebFreeformProperties.DEBUG_SOURCEPATH, 101 WebFreeformProperties.CLIENT_URL 102 }; 103 104 private static final String DEBUG_PROPERTIES_TEMPLATE = "/org/netbeans/modules/web/freeform/resources/debug-properties.template"; 106 private final Project project; 107 private final AntProjectHelper helper; 108 private final AuxiliaryConfiguration aux; 109 110 private static final String [] SUPPORTED_ACTIONS = { 111 ActionProvider.COMMAND_DEBUG, 112 }; 113 114 115 public WebFreeFormActionProvider(Project aProject, AntProjectHelper aHelper, AuxiliaryConfiguration aAux) { 116 project = aProject; 117 helper = aHelper; 118 aux = aAux; 119 } 120 121 public boolean isActionEnabled(String command, org.openide.util.Lookup context) throws IllegalArgumentException { 122 boolean enabled = false; 123 if (command.equals(ActionProvider.COMMAND_DEBUG)) 124 enabled = true; 125 return enabled; 126 } 127 128 public void invokeAction(String command, org.openide.util.Lookup context) throws IllegalArgumentException { 129 try { 130 try { 131 if (command.equals(ActionProvider.COMMAND_DEBUG)) 132 handleDebug(); 133 } catch (SAXException e) { 134 throw (IOException ) new IOException (e.toString()).initCause(e); 135 } 136 } catch (IOException e) { 137 ErrorManager.getDefault().notify(e); 138 } 139 } 140 141 public String [] getSupportedActions() { 142 return SUPPORTED_ACTIONS; 143 } 144 145 private void handleDebug() throws IOException , SAXException { 146 if (!alert(NbBundle.getMessage(WebFreeFormActionProvider.class, "ACTION_debug"), GENERAL_SCRIPT_PATH)) 148 return; 149 150 String propertiesFile = writeDebugProperties(); 152 153 Document script = readCustomScript(GENERAL_SCRIPT_PATH); 155 if (script == null) script = createCustomScript(); 157 158 writeComments(script); 160 writeTargets(script, propertiesFile); 161 162 writeCustomScript(script, GENERAL_SCRIPT_PATH); 164 165 addBinding(ActionProvider.COMMAND_DEBUG, GENERAL_SCRIPT_PATH, DEBUG_TARGET, null, null, null, null, null); 167 168 jumpToBinding(ActionProvider.COMMAND_DEBUG); 170 jumpToBuildScript(GENERAL_SCRIPT_PATH, DEBUG_TARGET); 171 openFile(propertiesFile); 172 } 173 174 180 private boolean alert(String commandDisplayName, String scriptPath) { 181 String projectDisplayName = ProjectUtils.getInformation(project).getDisplayName(); 182 String title = NbBundle.getMessage(WebFreeFormActionProvider.class, "TITLE_generate_target_dialog", commandDisplayName, projectDisplayName); 183 String body = NbBundle.getMessage(WebFreeFormActionProvider.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(WebFreeFormActionProvider.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 198 Document readCustomScript(String scriptPath) throws IOException , SAXException { 199 200 Document script = null; 201 FileObject scriptFile = helper.getProjectDirectory().getFileObject(scriptPath); 202 if (scriptFile != null) { 203 InputStream is = scriptFile.getInputStream(); 204 try { 205 script = XMLUtil.parse(new InputSource (is), false, true, null, null); 206 } finally { 207 is.close(); 208 } 209 } 210 211 return script; 212 } 213 214 218 Document createCustomScript() { 219 Document script = XMLUtil.createDocument("project", null, null, null); Element scriptRoot = script.getDocumentElement(); 222 scriptRoot.setAttribute("basedir", ".."); String projname = ProjectUtils.getInformation(project).getDisplayName(); 224 scriptRoot.setAttribute("name", NbBundle.getMessage(WebFreeFormActionProvider.class, "LBL_generated_script_name", projname)); 225 226 copyProperties(Util.getPrimaryConfigurationData(helper), scriptRoot); 228 229 return script; 230 } 231 232 239 private void copyProperties(Element config, Element script) { 240 243 Element data = Util.getPrimaryConfigurationData(helper); 244 Element properties = Util.findElement(data, "properties", Util.NAMESPACE); if (properties != null) { 246 Iterator propertiesIt = Util.findSubElements(properties).iterator(); 247 while (propertiesIt.hasNext()) { 248 Element el = (Element ) propertiesIt.next(); 249 Element nue = script.getOwnerDocument().createElement("property"); if (el.getLocalName().equals("property")) { String name = el.getAttribute("name"); assert name != null; 253 String text = Util.findText(el); 254 assert text != null; 255 nue.setAttribute("name", name); nue.setAttribute("value", text); } else if (el.getLocalName().equals("property-file")) { String text = Util.findText(el); 259 assert text != null; 260 nue.setAttribute("file", text); } else { 262 assert false : el; 263 } 264 script.appendChild(nue); 265 } 266 } 267 } 268 269 273 private void writeComments(Document script) { 274 Comment comm4Edit = script.createComment(" " + NbBundle.getMessage(WebFreeFormActionProvider.class, "COMMENT_edit_target") + " "); Comment comm4Info = script.createComment(" " + NbBundle.getMessage(WebFreeFormActionProvider.class, "COMMENT_more_info_debug") + " "); 277 Element scriptRoot = script.getDocumentElement(); 278 scriptRoot.appendChild(comm4Edit); 279 scriptRoot.appendChild(comm4Info); 280 } 281 282 286 private void writeTargets(Document script, String propertiesFile) { 287 createLoadPropertiesTarget(script, propertiesFile); 288 createCheckPropertiesTarget(script); 289 createInitTarget(script); 290 createDebugTarget(script); 291 createDisplayBrowserTarget(script); 292 } 293 294 301 private void createLoadPropertiesTarget(Document script, String propertiesFile) { 302 Element target = script.createElement("target"); target.setAttribute("name", LOAD_PROPS_TARGET); Element property = script.createElement("property"); property.setAttribute("file", propertiesFile); target.appendChild(property); 307 script.getDocumentElement().appendChild(target); 308 } 309 310 322 private void createCheckPropertiesTarget(Document script) { 323 Element target = script.createElement("target"); target.setAttribute("name", CHECK_PROPS_TARGET); Element fail; 326 for (int i = 0; i < DEBUG_PROPERTIES.length; i++) { 327 fail = script.createElement("fail"); fail.setAttribute("unless", DEBUG_PROPERTIES[i]); target.appendChild(fail); 330 } 331 332 script.getDocumentElement().appendChild(target); 333 } 334 335 340 private void createInitTarget(Document script) { 341 Element target = script.createElement("target"); target.setAttribute("name", INIT_TARGET); target.setAttribute("depends", LOAD_PROPS_TARGET + ", " + CHECK_PROPS_TARGET); script.getDocumentElement().appendChild(target); 345 } 346 347 359 private void createDebugTarget(Document script) { 360 Element target = script.createElement("target"); 361 target.setAttribute("name", DEBUG_TARGET); target.setAttribute("depends", INIT_TARGET); target.setAttribute("if", "netbeans.home"); Element nbjpdaconnect = script.createElement("nbjpdaconnect"); nbjpdaconnect.setAttribute("name", "${" + WebFreeformProperties.JPDA_SESSION_NAME + "}"); nbjpdaconnect.setAttribute("host", "${" + WebFreeformProperties.JPDA_HOST + "}"); nbjpdaconnect.setAttribute("address", "${" + WebFreeformProperties.JPDA_ADDRESS + "}"); nbjpdaconnect.setAttribute("transport", "${" + WebFreeformProperties.JPDA_TRANSPORT + "}"); Element sourcepath = script.createElement("sourcepath"); Element path = script.createElement("path"); path.setAttribute("path", "${debug.sourcepath}"); sourcepath.appendChild(path); 373 nbjpdaconnect.appendChild(sourcepath); 374 target.appendChild(nbjpdaconnect); 375 Element antcall = script.createElement("antcall"); antcall.setAttribute("target", DISPLAY_BROWSER); target.appendChild(antcall); 378 379 script.getDocumentElement().appendChild(target); 380 } 381 382 389 private void createDisplayBrowserTarget(Document script) { 390 Element target = script.createElement("target"); target.setAttribute("name", DISPLAY_BROWSER); Element nbbrowse = script.createElement("nbbrowse"); nbbrowse.setAttribute("url", "${client.url}"); target.appendChild(nbbrowse); 395 396 script.getDocumentElement().appendChild(target); 397 } 398 399 404 void writeCustomScript(Document script, String scriptPath) throws IOException { 405 FileObject scriptFile = helper.getProjectDirectory().getFileObject(scriptPath); 406 if (scriptFile == null) { 407 scriptFile = FileUtil.createData(helper.getProjectDirectory(), scriptPath); 408 } 409 FileLock lock = scriptFile.lock(); 410 try { 411 OutputStream os = scriptFile.getOutputStream(lock); 412 try { 413 XMLUtil.write(script, os, "UTF-8"); } finally { 415 os.close(); 416 } 417 } finally { 418 lock.releaseLock(); 419 } 420 } 421 422 434 void addBinding(String command, String scriptPath, String target, String propertyName, String dir, String pattern, String format, String separator) throws IOException { 435 Element data = Util.getPrimaryConfigurationData(helper); 438 Element ideActions = Util.findElement(data, "ide-actions", Util.NAMESPACE); if (ideActions == null) { 440 return; 443 } 444 Document doc = data.getOwnerDocument(); 445 Element action = doc.createElementNS(Util.NAMESPACE, "action"); action.setAttribute("name", command); Element script = doc.createElementNS(Util.NAMESPACE, "script"); script.appendChild(doc.createTextNode(scriptPath)); 449 action.appendChild(script); 450 Element targetEl = doc.createElementNS(Util.NAMESPACE, "target"); targetEl.appendChild(doc.createTextNode(target)); 452 action.appendChild(targetEl); 453 ideActions.appendChild(action); 454 455 if (propertyName != null) { 456 Element context = doc.createElementNS(Util.NAMESPACE, "context"); Element property = doc.createElementNS(Util.NAMESPACE, "property"); property.appendChild(doc.createTextNode(propertyName)); 459 context.appendChild(property); 460 Element folder = doc.createElementNS(Util.NAMESPACE, "folder"); folder.appendChild(doc.createTextNode(dir)); 462 context.appendChild(folder); 463 if (pattern != null) { 464 Element patternEl = doc.createElementNS(Util.NAMESPACE, "pattern"); patternEl.appendChild(doc.createTextNode(pattern)); 466 context.appendChild(patternEl); 467 } 468 Element formatEl = doc.createElementNS(Util.NAMESPACE, "format"); formatEl.appendChild(doc.createTextNode(format)); 470 context.appendChild(formatEl); 471 Element arity = doc.createElementNS(Util.NAMESPACE, "arity"); if (separator != null) { 473 Element separatorEl = doc.createElementNS(Util.NAMESPACE, "separated-files"); separatorEl.appendChild(doc.createTextNode(separator)); 475 arity.appendChild(separatorEl); 476 } else { 477 arity.appendChild(doc.createElementNS(Util.NAMESPACE, "one-file-only")); } 479 context.appendChild(arity); 480 action.appendChild(context); 481 } else { 482 Element view = Util.findElement(data, "view", Util.NAMESPACE); if (view != null) { 486 Element contextMenu = Util.findElement(view, "context-menu", Util.NAMESPACE); if (contextMenu != null) { 488 Element ideAction = doc.createElementNS(Util.NAMESPACE, "ide-action"); ideAction.setAttribute("name", command); contextMenu.appendChild(ideAction); 491 } 492 } 493 } 494 495 Util.putPrimaryConfigurationData(helper, data); 496 ProjectManager.getDefault().saveProject(project); 497 } 498 499 private String writeDebugProperties() throws IOException { 500 String fileName = "debug"; String file; 502 int i = 0; 503 do { 504 file = "nbproject/" + fileName + (i != 0 ? String.valueOf(i) : "") + ".properties"; i++; 506 } while (helper.resolveFileObject(file) != null); 507 FileObject fo = FileUtil.createData(project.getProjectDirectory(), file); 508 FileLock lock = fo.lock(); 509 OutputStream out = null; 510 InputStream in = null; 511 try { 512 out = new BufferedOutputStream (fo.getOutputStream(lock)); 513 in = getClass().getResourceAsStream(DEBUG_PROPERTIES_TEMPLATE); 514 byte[] buffer = new byte[4096]; 515 int read; 516 do { 517 read = in.read(buffer); 518 out.write(buffer, 0, read); 519 } while (read == buffer.length); 520 } 521 finally { 522 if (in != null) 523 in.close(); 524 if (out != null) 525 out.close(); 526 lock.releaseLock(); 527 } 528 529 EditableProperties ep = helper.getProperties(file); 531 ProjectInformation pi = ProjectUtils.getInformation(project); 532 ep.setProperty(WebFreeformProperties.JPDA_SESSION_NAME, pi.getName()); 533 ep.setProperty(WebFreeformProperties.SRC_FOLDERS, findSourceFolders(JavaProjectConstants.SOURCES_TYPE_JAVA)); 534 ep.setProperty(WebFreeformProperties.WEB_DOCBASE_DIR, findSourceFolders(WebProjectConstants.TYPE_DOC_ROOT)); 535 String contextPath = findContextPath(); 536 ep.setProperty(WebFreeformProperties.CLIENT_URL, ep.getProperty(WebFreeformProperties.CLIENT_URL) + (contextPath != null ? contextPath : "/")); helper.putProperties(file, ep); 538 539 return file; 540 } 541 542 546 private void jumpToBinding(String command) { 547 jumpToFile(AntProjectHelper.PROJECT_XML_PATH, command, "action", "name"); } 549 550 555 private void jumpToBuildScript(String scriptPath, String target) { 556 jumpToFile(scriptPath, target, "target", "name"); } 558 559 566 private void jumpToFile(String path, String match, String elementLocalName, String elementAttributeName) { 567 FileObject file = helper.getProjectDirectory().getFileObject(path); 568 if (file == null) { 569 return; 570 } 571 int line; 572 try { 573 line = findLine(file, match, elementLocalName, elementAttributeName); 574 } catch (IOException e) { 575 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 576 return; 577 } catch (SAXException e) { 578 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 579 return; 580 } catch (ParserConfigurationException e) { 581 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 582 return; 583 } 584 if (line == -1) { 585 line = 0; 587 } 588 DataObject fileDO; 589 try { 590 fileDO = DataObject.find(file); 591 } catch (DataObjectNotFoundException e) { 592 throw new AssertionError (e); 593 } 594 LineCookie lines = (LineCookie) fileDO.getCookie(LineCookie.class); 595 if (lines != null) { 596 try { 597 lines.getLineSet().getCurrent(line).show(Line.SHOW_GOTO); 598 } catch (IndexOutOfBoundsException e) { 599 ErrorManager.getDefault().getInstance(WebFreeFormActionProvider.class.getName()).log( 601 ErrorManager.WARNING, e + " [file=" + file + " match=" + match + " line=" + line + "]"); lines.getLineSet().getCurrent(0).show(Line.SHOW_GOTO); 603 } 604 } 605 } 606 607 private void openFile(String path) { 608 FileObject file = helper.getProjectDirectory().getFileObject(path); 609 if (file == null) 610 return; 611 612 DataObject fileDO; 613 try { 614 fileDO = DataObject.find(file); 615 } 616 catch (DataObjectNotFoundException e) { 617 throw new AssertionError (e); 618 } 619 620 EditCookie edit = (EditCookie)fileDO.getCookie(EditCookie.class); 621 if (edit != null) { 622 edit.edit(); 623 } 624 } 625 626 636 static final int findLine(FileObject file, final String match, final String elementLocalName, final String elementAttributeName) throws IOException , SAXException , ParserConfigurationException { 637 InputSource in = new InputSource (file.getURL().toString()); 638 SAXParserFactory factory = SAXParserFactory.newInstance(); 639 factory.setNamespaceAware(true); 640 SAXParser parser = factory.newSAXParser(); 641 final int[] line = new int[] {-1}; 642 class Handler extends DefaultHandler { 643 private Locator locator; 644 public void setDocumentLocator(Locator l) { 645 locator = l; 646 } 647 public void startElement(String uri, String localname, String qname, Attributes attr) throws SAXException { 648 if (line[0] == -1) { 649 if (localname.equals(elementLocalName) && match.equals(attr.getValue(elementAttributeName))) { line[0] = locator.getLineNumber() - 1; 651 } 652 } 653 } 654 } 655 parser.parse(in, new Handler ()); 656 return line[0]; 657 } 658 659 private String findSourceFolders(String type) { 660 StringBuffer result = new StringBuffer (); 661 Element data = Util.getPrimaryConfigurationData(helper); 662 Element foldersEl = Util.findElement(data, "folders", Util.NAMESPACE); if (foldersEl != null) { 664 for (Iterator i = Util.findSubElements(foldersEl).iterator(); i.hasNext();) { 665 Element sourceFolderEl = (Element )i.next(); 666 Element typeEl = Util.findElement(sourceFolderEl , "type", Util.NAMESPACE); if (typeEl == null || !Util.findText(typeEl).equals(type)) 668 continue; 669 Element locationEl = Util.findElement(sourceFolderEl , "location", Util.NAMESPACE); if (locationEl == null) 671 continue; 672 String location = Util.findText(locationEl); 673 if (result.length() > 0) 674 result.append(":"); result.append(location); 676 } 677 } 678 return result.toString(); 679 } 680 681 private String findContextPath() { 682 Element data = aux.getConfigurationFragment("web-data", WebProjectNature.NS_WEB, true); Element webModulEl = Util.findElement(data, "web-module", WebProjectNature.NS_WEB); if (webModulEl == null) 685 return null; 686 Element contextPathEl = Util.findElement(webModulEl, "context-path", WebProjectNature.NS_WEB); if (contextPathEl == null) 688 return null; 689 return Util.findText(contextPathEl); 690 } 691 692 } 693 | Popular Tags |