Monday March 31, 2008
OpenOffice.org... has its own Plugin Portal!
The OpenOffice.org developers of the NetBeans plugin for OpenOffice.org are in Prague today. I attended an interesting presentation where they demoed their plugin this morning. One of several things I learned about was their very cool Extensions site:
http://extensions.services.openoffice.org/
Unfortunately, however, you cannot see (currently) from inside OpenOffice.org which extensions are available. On the other hand, this is a feature that NetBeans IDE 6.1 Beta does have support for (at least, on my machine, thanks to a plugin I created) because I integrated their various application-specific extension feeds into the IDE's toolbar:
When I get some time, I will try to create an OpenOffice.org Add-On (using the NetBeans/OpenOffice.org plugin) which will attempt to do the same thing from within OpenOffice.org.
Here's the relevant code in the JPanel, which I added to the toolbar via CallableSystemAction.getToolbarPresenter:
public class OOExtensionsPanel extends javax.swing.JPanel {
DefaultComboBoxModel model = new DefaultComboBoxModel();
/** Creates new form OOExtensionsPanel */
public OOExtensionsPanel() {
initComponents();
//appList is the list of OpenOffice.org applications:
appList.addActionListener(new AppListListener());
//extList is the list of OpenOffice.org extensions:
extList.setModel(model);
}
private class AppListListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
model.removeAllElements();
BufferedReader in = null;
try {
//InputOutput io = IOProvider.getDefault().getIO("OpenOffice Extensions", true);
JComboBox box = (JComboBox) ev.getSource();
String selectedApp = box.getSelectedItem().toString();
URL url = null;
if (selectedApp.equals("Writer")) {
url = new URL("http://extensions.services.openoffice.org/taxonomy/term/2/0/feed");
} else if (selectedApp.equals("Calc")) {
url = new URL("http://extensions.services.openoffice.org/taxonomy/term/1/0/feed");
} else if (selectedApp.equals("Draw")) {
url = new URL("http://extensions.services.openoffice.org/taxonomy/term/4/0/feed");
} else if (selectedApp.equals("Impress")) {
url = new URL("http://extensions.services.openoffice.org/taxonomy/term/3/0/feed");
} else if (selectedApp.equals("Chart")) {
url = new URL("http://extensions.services.openoffice.org/taxonomy/term/21/0/feed");
}
in = new BufferedReader(new InputStreamReader(url.openStream()));
InputSource source = new InputSource(in);
org.w3c.dom.Document doc = XMLUtil.parse(source, false, false, null, null);
org.w3c.dom.NodeList list = doc.getElementsByTagName("*");
int length = list.getLength();
//io.select();
for (int i = 0; i < length; i++) {
org.w3c.dom.Node mainNode = list.item(i);
String nodeName = mainNode.getNodeName();
String value = mainNode.getTextContent();
if (nodeName.equals("title")) {
//io.getOut().println("Extension: " + value);
model.addElement(value);
}
}
//io.getOut().close();
} catch (SAXException ex) {
Exceptions.printStackTrace(ex);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} finally {
try {
in.close();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
}
...
...
...
Today on NetBeans Zone. Overview of NetBeans Java API Samples in Plugin Portal.
Mar 31 2008, 04:49:37 AM PDT Permalink
Extension to Extended Java Project (Part 2)
I published version 2 of the Extended Java Project Sample. There is one very big improvement: FreeMarker is used. As a result, you can perform iterations and other code logic right within the template, instead of needing to do so in the code. There's also a lot less code in general in the sample now. One reason for that is that I discovered a simpler way of accessing a file inside the module's sources. This is how the WordLibrary.ftl file is located, instead of reading input streams and so on:
URL wordLibraryClass = new URL("nbfs:/SystemFileSystem/Templates/Project/Standard/file/WordLibrary");
The "nbfs" protocol lets you get files from the System FileSystem! You can register the files you need your module to have access to like shown below (register the file anywhere in the System Filesystem, but probably preferable to put it very close to the resources that will be needing it, as in this case, where I put the file very close to the project template that needs it):
<folder name="Templates">
<folder name="Project">
<folder name="Standard">
<file name="MyAnagramGameProject.zip" url="MyAnagramGameProject.zip">
<attr name="SystemFileSystem.icon" urlvalue="nbresloc:/org/netbeans/modules/java/j2seproject/ui/resources/j2seProject.png"/>
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.nb.extendedjavaproject.Bundle"/>
<attr name="instantiatingIterator" methodvalue="org.nb.extendedjavaproject.MyAnagramGameWizardIterator.createIterator"/>
<attr name="instantiatingWizardURL" urlvalue="nbresloc:/org/nb/extendedjavaproject/MyAnagramGameDescription.html"/>
<attr name="template" boolvalue="true"/>
</file>
<folder name="file">
<file name="WordLibrary" url="WordLibrary.ftl">
<attr name="template" boolvalue="true"/>
<attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
</file>
</folder>
</folder>
</folder>
</folder>
The layer.xml file and the WordLibrary.ftl file are in the same directory, hence the url attribute above is simply set to WordLibrary.ftl.
And so now I can simply do this:
private FileObject insertSpecifiedWords() throws IOException {
//Get the folder where the files should be created,
//note that we don't give the user an option here:
File projectFolder = FileUtil.normalizeFile((File) wiz.getProperty("projdir"));
FileObject targetFolder = FileUtil.toFileObject(new File(projectFolder + "/src/com/toy/anagrams/lib"));
DataFolder df = DataFolder.findFolder(targetFolder);
//Find the template in the System Filesystem:
URL wordLibraryClass = new URL("nbfs:/SystemFileSystem/Templates/Project/Standard/file/WordLibrary");
//Map the template to a FileObject:
FileObject fo = URLMapper.findFileObject(wordLibraryClass);
//Convert to a DataObject:
DataObject dTemplate = DataObject.find(fo);
//Get the unscrambled words from the panel:
String[] unscrambleds = new String[]{
(String) wiz.getProperty("unScrambledWord1"),
(String) wiz.getProperty("unScrambledWord2"),
(String) wiz.getProperty("unScrambledWord3"),
(String) wiz.getProperty("unScrambledWord4"),
(String) wiz.getProperty("unScrambledWord5"),
(String) wiz.getProperty("unScrambledWord6"),
(String) wiz.getProperty("unScrambledWord7")
};
//Get the scrambled words from the panel:
String[] scrambleds = new String[]{
(String) wiz.getProperty("scrambledWord1"),
(String) wiz.getProperty("scrambledWord2"),
(String) wiz.getProperty("scrambledWord3"),
(String) wiz.getProperty("scrambledWord4"),
(String) wiz.getProperty("scrambledWord5"),
(String) wiz.getProperty("scrambledWord6"),
(String) wiz.getProperty("scrambledWord7")
};
//Create a map for passing the words to the FreeMarker template,
//where it will be processed:
Map args = new HashMap();
args.put("unscrambleds", unscrambleds);
args.put("scrambleds", scrambleds);
//Create a new DataObject from the template that we defined above,
//by providing a folder, the name of the file to be created,
//and the map that should be passed to the FreeMarker template for processing:
DataObject dobj = dTemplate.createFromTemplate(df, "WordLibrary.java", args);
//Get the FileObject from the DataObject:
FileObject createdFile = dobj.getPrimaryFile();
//Return the FileObject:
return createdFile;
}
And then in the instantiate method, I add the above to the result set.
And, thanks to FreeMarker, I can send in my two string arrays via a map, constructed above, which I can then iterate through (using syntax coloring and code completion from my own module which is in the Plugin Portal) in the template:
Pretty cool. But the best trick or, at least, the only one that was news to me, was the thing with the "nbfs" protocol. That provides a very easy way to access files in the System FileSystem, including those that you register there yourself, of course.
Mar 30 2008, 12:38:55 AM PDT Permalink
Integrating Ubuntu into NetBeans IDE
I like Ubuntu's text editor, especially for XML files it's great—gives you very nice syntax coloring. So I created a menu item on XML file nodes in NetBeans IDE, especially for opening an XML file into Ubuntu's text editor. That way, I simply have an extra window for editing XML. Not super useful functionality, but handy sometimes.
To create this action, use the New Action wizard to create a new conditional action (i.e., not "always enabled"), for DataObjects. Specify that it should be invoked from the text/xml-mime MIME type. Then set dependencies on Datasystems API, Execution API, File System API, Nodes API, and Utilities API.
Then fill out the CookieAction.performAction as follows, taking note of the line in bold below, because that's where all the action happens:
protected void performAction(Node[] activatedNodes) {
try {
DataObject dataObject = activatedNodes[0].getLookup().lookup(DataObject.class);
FileObject fo = dataObject.getPrimaryFile();
String file = fo.getURL().getFile();
try {
NbProcessDescriptor desc = new NbProcessDescriptor("gedit", file);
desc.exec();
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex);
}
} catch (FileStateInvalidException ex) {
Exceptions.printStackTrace(ex);
}
}
You should be using the following import statements:
import java.io.IOException; import javax.swing.JOptionPane; import org.openide.execution.NbProcessDescriptor; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileStateInvalidException; import org.openide.loaders.DataObject; import org.openide.nodes.Node; import org.openide.util.Exceptions; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CookieAction;
And that's it. Install the module and notice the new menu item on XML files (mine is called "Open in Text Editor"). When the menu item is selected, the selected XML file opens in Ubuntu's (or any other Linux or whatever system) text editor (or some other application), displaying your file.
This is how you would open a file programmatically in OpenOffice.org, just replacing the important line above with this one:
NbProcessDescriptor desc = new NbProcessDescriptor("ooffice", " -writer " +file);
I tried to open a file in both Eclipse and IntelliJ, using the above line of code, but—even though both applications start up successfully—in neither case does the file open when the application has started up. Maybe there's a special command line for opening a file in Eclipse or IntelliJ when they start up? (Something like -file fileName.) But I suspect that, unlike NetBeans IDE, they don't have an option like that. It seems to me that the other two IDEs are not able to have a specific file be opened on start up, based on a command line setting specified at start up.
Mar 29 2008, 02:23:43 PM PDT Permalink
Extension to Extended Java Project (Part 1)
A few days ago, based on a request from a user, I published a sample to the Plugin Portal to show how a project template can be extended with a new panel. Now I've extended it to do what the user probably really wants to do: use the new panel to generate a file which, in this case, is a class.
The plugin that you get from the Plugin Portal will, once installed, give you a new plugin sample in the NetBeans Modules category in the New Project wizard. Once you install that, you'll have a new Java application that generates the Anagram Game. However, there's a new panel, where you can set the scrambled/unscrambled word pairs:
So, once you click Finish, you will have the whole Anagram Game. However, the WordLibrary.java file will not have the words that are normally found there, i.e., "batsartcoin", etc. Instead, the words set in the panel above will be used to populate those parts of the WordLibrary.java file:
General instructions for creating something similar yourself are provided on the same page where you can get the plugin:
http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=6743.
Mar 28 2008, 02:26:22 PM PDT Permalink
Java Hint Generator for NetBeans IDE 6.1 Beta
I've blogged about hints before and about how cool it would be for users out there to create hints so as to increase (even further) the power of the NetBeans Java Editor. But now it's a simplified process:
http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=6784
Install that plugin and read the accompanying instructions.
Here's where you'll find the new template, once you've installed the above plugin:

Mar 27 2008, 01:34:10 PM PDT Permalink
Resizing Images in NetBeans IDE
Small(ish) but annoying pet peeve of mine: I need an image for an application that I'm coding in NetBeans IDE. I go on-line and find the image that I need. I right-click the image on-line and save it right there, from my browser, into my application's source structure.
Then... dang! I open the image in the IDE and see that... its size is not what I would want it to be. So... I need to go outside the IDE (where it is cold, cold, cold) and change the image size there. Why? Because when you open the image in the IDE, you can only zoom. Not resize.
So, I've added a "Resize" menu item on image nodes in the explorer views:
When the menu item is selected, the image opens in a new dialog, which should be a TopComponent at some point, where you can resize the image (thanks to the Visual Library):
When you click OK, a new image is created (so, no worries, nothing will happen to your original image), in the same place as the old one, with a new name, consisting of the original name, plus the dimensions of your new image.
It is not perfect yet, but it is definitely already usable in most cases:
http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=6726
If your original image is very large and you want to make it smaller, you'll have problems, because the original image and the image you're resizing will overlap. As the image you're resizing gets smaller, you won't be able to see it anymore because the original image will cover it. Need to fix that. It works better if you want to make the image larger than the original.
The latest version of the plugin (1.2) includes antialiasing, but the quality of the image will definitely decrease as you increase its size. Advice on this point is very welcome.
Mar 26 2008, 01:25:27 AM PDT Permalink
org.openide.xml.XMLUtil
I suddenly realized that my ruminations on org.openide.xml.XMLUtil, yesterday, might be helpful to someone I met at the NetBeans booth at Sun Tech Days in Johannesburg, a few weeks ago. He wanted to create a NetBeans plugin that would generate language-specific client stubs from a WSDL file. The basic concept is that you would open the WSDL file in the IDE, right-click inside it, and then choose a menu item that says, something like, "Generate Client Stubs". And then you'd get a new HTML file with a list of client stubs for interacting with the service exposed via the WSDL. You'd get a stub in JavaScript, in C++, in Java, and in anything else that's relevant. You, as the provider of the WSDL, would then post your WSDL on your server and then ALSO post the HTML file with client stubs. The user of your WSDL would then have a starting point, for whatever language they're coding in.
I thought it was a great suggestion and coded a basic plugin as a starting point, which he copied onto his USB stick. I could have gone a lot further than I did, had I known about org.openide.xml.XMLUtil at the time. So, here's complete instructions for creating your own language-specific client stubs from a WSDL file:
- Create a new module project, name it whatever you like.
- Make sure the distro of NetBeans IDE that you are using has specific support for WSDL files (i.e., to check this, create a file with a WSDL extension or open one with that extension, and then see if a special icon is shown for it and that the editor has lots of WSDL-specific support or not). If not, go to the Plugin Manager, search for "wsdl" and then install the WSDL plugin.
- Create a class that extends CookieAction. (If you use the Action wizard, specify that the action should be conditionally enabled, for the EditorCookie class, and the text/x-wsdl+xml MIME type under "Editor Context Menu Item").
- Registration of the class in the layer.xml would probably be like this:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd"> <filesystem> <folder name="Actions"> <folder name="Tools"> <file name="org-netbeans-webservicemenuitem-SomeAction.instance"/> </folder> </folder> <folder name="Editors"> <folder name="text"> <folder name="x-wsdl+xml"> <folder name="Popup"> <file name="org-netbeans-webservicemenuitem-SomeAction.shadow"> <attr name="originalFile" stringvalue="Actions/Tools/org-netbeans-webservicemenuitem-SomeAction.instance"/> <attr name="position" intvalue="0"/> </file> </folder> </folder> </folder> </folder> </filesystem> - Define the CookieAction.performAction as follows, taking note of the line in bold, as well as all the FQN for DOM objects (because that's the point of this blog entry):
protected void performAction(Node[] activatedNodes) { try { InputOutput io = IOProvider.getDefault().getIO("WSDL Elements and Attributes", true); EditorCookie ec = activatedNodes[0].getLookup().lookup(EditorCookie.class); StyledDocument sd = ec.getDocument(); String text = sd.getText(0, sd.getLength()); InputSource source = new InputSource(new StringReader(text)); org.w3c.dom.Document doc = XMLUtil.parse(source, false, false, null, null); org.w3c.dom.NodeList list = doc.getElementsByTagName("*"); int length = list.getLength(); io.select(); for (int i = 0; i < length; i++) { org.w3c.dom.Node mainNode = list.item(i); org.w3c.dom.NamedNodeMap map = mainNode.getAttributes(); String nodeName = mainNode.getNodeName(); StringBuilder attrBuilder = new StringBuilder(); for (int j = 0; j < map.getLength(); j++) { org.w3c.dom.Node attrNode = map.item(j); String attrName = attrNode.getNodeName(); attrBuilder.append(" --> "+ attrName); } io.getOut().println("ELEMENT: " + nodeName + " --> ATTRIBUTES: " + attrBuilder.toString()); } io.getOut().close(); } catch (IOException ex) { Exceptions.printStackTrace(ex); } catch (SAXException ex) { Exceptions.printStackTrace(ex); } catch (BadLocationException ex) { Exceptions.printStackTrace(ex); } }The above will print out the elements and attributes in your WSDL file to the Output window:
That's pretty cool. Because now you have the basis of your client stub generator. After all, you can now simply use everything that the org.w3c.dom package gives you to parse the output and, once you have the elements that you want, you can use StyledDocument.insertString(offset, string, attributeSet) to insert whatever you want into the editor. Alternatively, create a new FileObject (such as an HTML file) and then write whatever you want into it.
In other words, the first benefit of org.openide.xml.XMLUtil is that its parse method returns a plain old org.w3c.dom.Document, which you can manipulate however you like using the JDK's org.w3c.dom package.
- However, let's look more closely at the XMLUtil.parse method. First of all, you can hook your own org.xml.sax.ErrorHandler into the parser, very easily:
org.w3c.dom.Document doc = XMLUtil.parse(source, false, false, new WSDLParseErrorhandler(), null);
And then create your own org.xml.sax.ErrorHandler, while benefiting from the IDE's code completion:
Here's a very handy org.xml.sax.ErrorHandler, which writes error messages to the Output window:
class WSDLParseErrorhandler implements org.xml.sax.ErrorHandler { InputOutput io = IOProvider.getDefault().getIO("WSDL Errors", true); private void generateOutput(SAXParseException exception, String type) { int line = exception.getLineNumber(); String message = exception.getMessage(); io.select(); io.getOut().println(type + " in line " + line + ": " + message); } public void warning(SAXParseException exception) throws SAXException { generateOutput(exception, "Warning"); } public void error(SAXParseException exception) throws SAXException { generateOutput(exception, "Error"); } public void fatalError(SAXParseException exception) throws SAXException { generateOutput(exception, "Fatal error"); } } - Let's now look at another argument to the XMLUtil.parse method. Simply change the first false boolean to true:
org.w3c.dom.Document doc = XMLUtil.parse(source, true, false, new WSDLParseErrorhandler(), null);
By setting that argument to true, your WSDL file (or whatever file you're working with, of course) will be validated against its DTD declaration or Schema declaration. And now make sure to declare a DTD or Schema to which your WSDL file does not comply. For example, I simply cut and pasted the DTD reference at the top of my layer.xml file into my WSDL file. Obviously, that's not going to resolve very well (or, at all):
- The final argument to the XMLUtil.parse method is amply described in the related Javadoc. The point is that even if you have set the first boolean to false, i.e., even if you do NOT want to validate, the ui will still be blocked if you have a DTD declaration or Schema declaration. The ui will be blocked because a network connection will be made, based on the URL specified in the DTD declaration or Schema declaration. You can speed up parsing by defining an entity resolver, as described in the related Javadoc.
- And what about the second boolean? That, if true, makes your parser namespace aware. As this document tells you: "A parser that is namespace aware can recognize the structure of names in a namespace-with a colon separating the namespace prefix from the name. A namespace aware parser can report the URI and local name separately for each element and attribute. A parser that is not namespace aware will report only an element or attribute name as a single name even when it contains a colon. In other words, a parser that is not namespace aware will treat a colon as just another character that is part of a name."
At this point, we haven't really examined org.openide.xml.XMLUtil at all. We've only looked at its parse method. In other words, there's a lot more that this class can give you. But, clearly, already, it is clear that the org.openide.xml.XMLUtil class is a very useful addition to the NetBeans Platform indeed!
Mar 25 2008, 05:58:04 AM PDT Permalink
Hello Spring (Part 2)
The cool thing about the new Spring support in NetBeans IDE 6.1 is the fact that you can extend it. A very simple entry point into the Spring support is its dedicated MIME type, x-springconfig+xml. Via this MIME type, you can add a new menu item, either to the editor or to the node in the explorer view, specifically for Spring configuration files. Using this technique, I added a menu item called "Generate Java from Beans":
What happens when the menu item is selected? You get some Java code generated at the bottom of the file, for accessing each bean, which you can then copy into your Java classes, wherever the code is needed. Maybe it would be nice if this were integrated into the Java classes, so that the beans would appear during code completion, but that's a couple of bridges too far for me at the moment, I'd need to do a bit of research for that. Currently I'm only supporting the util:list bean, but it would be simple to expand this to all other types. Here's the result for the above two beans, i.e., everything that is commented out below is generated when the menu item above is selected:
And here's the relevant performAction in my CookieAction. Take particular note of org.openide.xml.XMLUtil which, if you're not aware of it, is very useful indeed (even more so if you're aware of it):
protected void performAction(Node[] activatedNodes) {
//Figure out the name of the configuration file,
//plus its packages, plus "src",
//which is what the org.springframework.core.io.FileSystemResource class needs:
DataObject dobj = activatedNodes[0].getLookup().lookup(DataObject.class);
FileObject fo = dobj.getPrimaryFile();
setFileName(fo.getPath().substring(fo.getPath().indexOf("src")));
try {
//Figure out the document and parse it:
EditorCookie editorCookie = activatedNodes[0].getLookup().lookup(EditorCookie.class);
StyledDocument styledDoc = editorCookie.openDocument();
String allText = styledDoc.getText(0, styledDoc.getLength());
InputSource source = new InputSource(new StringReader(allText));
//No validation, not namespace aware, no entity resolver, no error handler:
Document doc = XMLUtil.parse(source, false, false, null, null);
//Figure out the list of elements:
NodeList list = doc.getElementsByTagName("*");
int docLength = list.getLength();
for (int i = 0; i < docLength; i++) {
org.w3c.dom.Node node = list.item(i);
//Figure out the list of attributes:
NamedNodeMap map = node.getAttributes();
int mapLength = map.getLength();
for (int j = 0; j < mapLength; j++) {
org.w3c.dom.Node attr = map.item(j);
//Insert the template, with values filled in,
//if the attribute is "id":
if (attr.getNodeName().equals("id")) {
setBeanId(attr.getNodeValue());
styledDoc.insertString(styledDoc.getLength(),
"\n<!-- How to access the \"" + attr.getNodeValue() +
"\" bean:\n" + getTemplate(), null);
}
}
}
} catch (SAXException ex) {
Exceptions.printStackTrace(ex);
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
And, FWIW, here's the template:
private String getTemplate() {
template =
"\nBeanFactory factory = new XmlBeanFactory(new FileSystemResource(\"" + getFileName() + "\"));" +
"\nArrayList list = (ArrayList) factory.getBean(\""+getBeanId()+"\");" +
"\nIterator it = list.iterator();" +
"\nint count = 0;" +
"\nwhile (it.hasNext()) {" +
"\n count = count + 1;" +
"\n System.out.println(\""+getBeanId()+" \" + count + \": \" + it.next().toString());" +
"\n}" +
"\n-->\n";
return template;
}Mar 24 2008, 03:31:06 PM PDT Permalink
Hello Spring (Part 1)
My first encounter with Spring is through its Util schema. I used NetBeans IDE 6.1 Beta, since this version of NetBeans IDE sports a set of features specifically for Spring, for the first time. There's support for web applications (which I will discuss in a future blog entry), but also for Java SE applications. Here's my first Spring configuration file in a Java SE application:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<util:list id="emails">
<value>john@smith.org</value>
<value>jack@harry.org</value>
<value>peter@piper.org</value>
<value>pavel@prochazka.org</value>
</util:list>
</beans>
To help me while coding the above file, I have context-sensitive code completion to help me:
And here's how I created it, i.e., using a new template...
... which also lets me choose one or more namespaces, so that I don't need to think about the header of the Spring configuration file at all:
Here's my simple Java class for accessing (and using) the above Spring configuration file:
package hellospring;
import java.util.ArrayList;
import java.util.Iterator;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
public class Main {
public static void main(String[] args) {
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("src/hellospring/demo.xml"));
ArrayList list = (ArrayList) factory.getBean("emails");
Iterator it = list.iterator();
int count = 0;
while (it.hasNext()) {
count = count + 1;
System.out.println("Email " + count + ": " + it.next().toString());
}
}
}
I am also able to get Java code completion in my Spring configuration file, whenever I need it, specifically for class attributes:
And then I can simply click the class references, which then results in the class being opened in the editor:

Finally, I can organize my Spring configuration files. On the Project Properties node of Java SE applications, there's a new node that appears when the Spring JARs are on my classpath, for grouping my Spring configuration files:

Finally, for more info on the new Spring support, see Improved Spring Framework Support in NetBeans 6.1: XML-Config Files in Ramon Ramos's blog.
Mar 23 2008, 08:05:56 AM PDT Permalink
Brand New Template for NetBeans Platform Applications
Very recent 6.1 development builds should bring joy to those of us who have long argued for improvements in the discoverability of tools for NetBeans Platform development. There is now a brand new template for this purpose:
When you complete the wizard, you have an empty application, i.e., unlike the module suite template, which comes with all the IDE's modules installed. Simply run it, without doing anything special beforehand, and you have an empty application, with all the basic bells and whistles (i.e., menus and toolbars) available:
Many thanks to Jesse for creating this template and to Ondrej for recently arguing the need for its creation.
Mar 19 2008, 06:38:53 AM PDT Permalink
Pluggable Photo Album Ported to the NetBeans Platform
A few days ago I blogged about using the NetBeans Lookup API outside the NetBeans Platform. I referred to the very handy Creating Extensible Applications With the Java Platform, by John O'Conner, and then wrote How to Create a Pluggable Photo Album in Java on Javalobby. The next logical step was to move my pluggable photo album to the NetBeans Platform:
Now, instead of three Java applications, I have three modules. The first (module 1) provides the TopComponent, an SPI for photos, and a service that acts as a bridge between the SPI and the providers (module 2 and module 3). The photos are NOT in module 1. They come from module 2 and module 3. Below you see the content of module 2, which is the same structure as module 3. Both implement the Photo class provides by module 1. They also use the META-INF/services folder to register their Photo implementation:
Next, I will explore the special features that the Lookup class provides over those provided by the JDK 6 ServiceLoader class. For example... the LookupListener class, which should be very interesting to examine in this context. And I am expecting other benefits too.
By the way, I highly recommend the procedure I used to get to this point: take a NetBeans API through its paces outside the NetBeans Platform, where possible, and then port the application to the NetBeans Platform to reap the additional rewards that the NetBeans Platform gives you.
Mar 18 2008, 03:13:29 PM PDT Permalink
A different way of starting the IDE
Drag and drop a desktop icon of a file onto the NetBeans desktop icon...
...and the IDE will start up, with the specified file open in the editor. That's always been possible, but is [as far as I am aware] completely unknown.
Mar 17 2008, 10:38:08 PM PDT Permalink
Lookup API Outside the NetBeans Platform
Today an e-mail came in to the dev@openide.netbeans.org mailing list (the place you want to be if you're interested in the NetBeans Platform or in NetBeans plugin development generally) from Mark Nuttall. He asks: "Where do I snag the current Lookup API from if I want to use it outside of the NetBeans Platform." The short answer to that question is: go to the IDE's installation directory and then to the platform8/lib folder, where you will find the org-openide-util.jar. Just attach that JAR to your application's classpath and you're good to go.
The longer answer is... even better! On java.sun.com, there is an excellent article by John O'Conner, Creating Extensible Applications With the Java Platform. Not only does he describe the benefits of the Lookup API, and how to use it outside of the NetBeans Platform, but he also contrasts it to the Java SE 6 java.util.ServiceLoader class. (And, if you read Rich Client Programming: Plugging into the NetBeans Platform, you'll find out lots about these contrasts too, in chapter 4 and 5.)
However, I can't recommend John's article highly enough. He shows you how to build a pluggable application (outside of the NetBeans Platform) using both the Java SE 6 approach and the NetBeans Platform approach (and discusses the differences between the two). The article includes the complete sample code, everything, and, in fact, you end up with two different implementations of a Dictionary application. Below you see the result, i.e., everything in the screenshot below comes straight from the downloadable sources from John's article. So you end up with three applications, the first providing the user interface, and the other two are registered services (I have also highlighted the Lookup API JAR below so that you can see its name):
Anyone new to, or confused about, Lookup is advised to read the above article, download the sources, play with them, see how they relate to each other, read the article again, and then try and make something similar yourself to see if you really understand it. The NetBeans Lookup API isn't discussed to its full extent and so reading chapter 4 and 5 of "Rich Client Programming: Plugging into the NetBeans Platform" is a very worthwhile thing to do after you've understood everything that John's article provides. It is basically an excellent primer on loosely coupled communication between a system's components.
In other news. Check out the NetBeans blogging contest!
Mar 16 2008, 05:31:12 AM PDT Permalink
Deployment History Window (Part 2)
My Deployment History plugin is basically finished. I think it is self explanatory from the screenshot below. The nice thing is that an application can even be redeployed if it isn't open in the IDE anymore:
However, note that the latest version of the application is always run (i.e., I don't save the application as such, so you can't go back in time and run an earlier version of your application, which would be cool and is something I'll investigate). I'm going to add some more features, such as the ability to clear individual items from the list and to clear the whole list in one go. It would also be pretty cool if the entries could be stored via NbPreferences and then reloaded upon restarts. Thanks a lot, Gareth Uren, for suggesting this plugin while visiting the NetBeans booth at Sun Tech Days in Johannesburg!
In other news. Join Roumen and others at the NetBeans party at EclipseCon! I wonder what will happen there. Maybe Brian will do his demo of how to convert Eclipse applications to NetBeans projects, while pretending that his presentation is an official sequel to one of the EclipseCon presentations? (He could start like this: "In part 1, you learned how to create some cool applications in Eclipse. Now, in part 2, we'll look at how to get them where they will feel much happier—NetBeans IDE!") Maybe Roumen will pull one of his notorious pranks? Should be interesting, whatever happens.
Mar 15 2008, 07:30:55 AM PDT Permalink
Deployment History Window (Part 1)
I'm halfway done with Gareth Uren's suggestion, as recorded in my blog entry yesterday: "a drop down button factory displaying recently run projects that can then be selected and then immediately run again". It isn't implemented in a drop down button factory, but a window. And the entries in the window can't be redeployed yet (so, right now, only a new entry is generated upon deployment, no redeployment can be peformed yet). However, it's pretty cool to see the deployed app's name (and deployment time) added to the window upon deployment:
How is this done? Mainly via an Ant Logger. It's a little bit hacky, but I think it should do the job in 99% of cases. I locate the project.xml file, where the project name is set, and then identify the <name> element, which is the element that defines the name. That's all. The most important method, where everything happens, is the targetStarted method in the org.apache.tools.ant.module.spi.AntLogger class:
@Override
public void targetStarted(AntEvent event) {
BufferedReader br = null;
try {
//Identify the build-impl.xml file:
File buildImplXML = event.getScriptLocation();
//Hacky approach to getting the project.xml file instead:
File projectXML = new File(buildImplXML.getCanonicalPath().replace("build-impl.xml", "project.xml"));
//Read the project.xml file:
br = new BufferedReader(new InputStreamReader(new FileInputStream(projectXML)));
//Get the target's name, so we can test if it is the "run" target or not:
String name = event.getTargetName();
while ((inputLine = br.readLine()) != null) {
//If the target name is "run" and the line starts with <name>:
if (name.equals("run") && inputLine.trim().startsWith("<name>")) {
//Strip the line for the project name:
String projectName = inputLine.trim().replace("<name>", "").replace("</name>", "");
//Get today's date:
java.util.Date today = new Date();
//Create a timestamp:
Timestamp stamp = new java.sql.Timestamp(today.getTime());
//Send everything to the TopComponent, where the "set" method populates the JTextArea:
ListDeployedAppsTopComponent.setProjectNames(projectName + "\n (at" + stamp +")\n");
}
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} finally {
try {
br.close();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
The next step is to let the user double-click an entry. When this is done, a Run target will be executed, with the project name as the application to be run. Or, at least, that's my plan.
Mar 14 2008, 02:15:40 PM PDT Permalink


