Thursday July 31, 2008
Groovy: Bridge Between Eclipse and NetBeans IDE?
If you're able to use a Groovy script to generate a NetBeans Platform application (as shown over the past few days in this blog), then why not go a step further and also generate two additional files—".project" and ".classpath", as shown below...
...because those two files happen to be all that's needed for an application to be an Eclipse project. You can then simply open the NetBeans Platform application right inside Eclipse:
And then you can use NetBeans IDE to generate various NetBeans API implementations, since Eclipse doesn't have the cool wizards that NetBeans IDE makes available for this purpose. After that, simply continue using Eclipse, if you're more comfortable with that editor or if one/more of your team mates use Eclipse while you prefer NetBeans.
By the way, I really like how an Eclispe project's classpath is declared in the above shown external ".classpath" file, because that means that I'm able to include as many NetBeans Platform JARs as I want in the process that generates the file. I.e., when the Eclipse project is opened in Eclipse, all the NetBeans Platform JARs (or as many/few as are set in the Groovy script) are on the Eclipse project's classpath.
Previously, I'd need Maven to achieve the result above. Now, via Groovy, I can generate an IDE-polyglot project in an easily customizable style and language. Thanks, Groovy, you're groovy.
Jul 31 2008, 11:08:21 AM PDT Permalink
World's Simplest GroovyBuilder
Here's a GroovyBuilder for generating NetBeans projects such as the ones I showed in the past days:
package generators
import groovy.util.BuilderSupport
class NBProjectGenerator extends BuilderSupport {
protected void setParent(Object parent, Object child) {
}
protected Object createNode(Object name) {
return null
}
//Here we receive the path to a folder that should be created:
protected Object createNode(Object name, Object value) {
def folder = new File(value)
folder.mkdirs()
}
//Here we create a new file in a specified location
//and with a specified content:
protected Object createNode(Object name, Map attrs) {
new File(attrs.get("loc") + File.separator + attrs.get("name")).write(attrs.get("file"))
}
protected Object createNode(Object name, Map attrs, Object value) {
return null
}
}
It could be used for generating any kind of source structure, not only NetBeans projects at all, with folders and files being the two only items of concern. This is how it would be used to create a new NetBeans module:
NBProjectGenerator nbProjectGenerator = new NBProjectGenerator()
nbProjectGenerator.generate() {
//Root folder:
folderProp(folder)
//Source folder:
srcProp(src)
//NetBeans project folder:
nbprojectProp(nbproject)
//Main package:
pkgsProp(pkgs)
//Ant build.xml script:
buildXmlProp(loc:folder, file:build_xml, name:"build.xml")
//Build-impl.xml script:
buildImplXmlProp(loc:nbproject, file:build_impl_xml, name:"build-impl.xml")
//Bundle.properties:
bundleProp(loc:pkgs, file:bundle_properties, name:"Bundle.properties")
//Layer file:
layerXmlProp(loc:pkgs, file:layer_xml, name:"layer.xml")
//Manifest file:
manifestMfProp(loc:folder, file:manifest_mf, name:"manifest.mf")
//Platform properties:
platformProp(loc:nbproject, file:platform_properties, name:"platform.properties")
//Project properties:
projectProp(loc:nbproject, file:project_properties, name:"project.properties")
//Project XML file:
projectXmlProp(loc:nbproject, file:project_xml, name:"project.xml")
}
Using the very same GroovyBuilder, you can generate a NetBeans Platform application. Only remember to exclude several of the statements above, since a NetBeans Platform application doesn't have its own build.xml, for example:
NBProjectGenerator nbProjectGenerator = new NBProjectGenerator()
nbProjectGenerator.generate() {
//Root folder:
folderProp(folder)
//NetBeans project folder:
nbprojectProp(nbproject)
//Platform properties:
platformProp(loc:nbproject, file:platform_properties, name:"platform.properties")
//Project properties:
projectProp(loc:nbproject, file:project_properties, name:"project.properties")
//Project XML file:
projectXmlProp(loc:nbproject, file:project_xml, name:"project.xml")
}
Something similar could be done for NetBeans web applications too, for example. The only thing that needs to be done is for the values to be retrieved somehow. Right now I have them hardcoded in my Groovy script (as shown in the blog entries of the last two days). However, I could access a file on disk via Groovy and set that as the value that is passed to the GroovyBuilder. And I could create another GroovyBuilder to simplify that in the same way as the above. I'd then be accessing two GroovyBuilders from within the same Groovy script and then generating NetBeans projects very quickly, efficiently, and transparently. The Groovy script itself would end up being pretty short and with no superfluous, repetitive boilerplate code, because that's moved to the GroovyBuilder class. All that's pretty neat!
Jul 30 2008, 06:26:11 AM PDT Permalink
Groovy Generation of NetBeans Modules
I'm continuing to be impressed with the usefulness of Groovy in getting started with source structures for applications. Yesterday I showed how to generate a NetBeans Platform application from a Groovy script. Today I present... a Groovy script that will generate a NetBeans module. This is pretty much the absolutely barest NetBeans module imaginable. Nonetheless, a NetBeans module is what it is, and no different from the one you get via the "New Module" wizard in the "New Project" dialog. And once you've run this script, you'll be able to open the module in the IDE and begin adding features to it right away.
package generators
def id = new Date().time
def folder = System.getProperty("user.home") + "/NewModule" + id;
def name = "NewModule" + id;
def pkgs = "org/netbeans/modules/demo"
println "Generating project ${name} in folder ${folder}";
def manifest_mf = """\
Manifest-Version: 1.0
OpenIDE-Module: ${name}
OpenIDE-Module-Layer: ${pkgs}/layer.xml
OpenIDE-Module-Localizing-Bundle: ${pkgs}/Bundle.properties
OpenIDE-Module-Specification-Version: 1.0
"""
def build_xml = """\
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
<!-- for some information on what you could do (e.g. targets to override). -->
<!-- If you delete this file and reopen the project it will be recreated. -->
<project name="${name}" basedir=".">
<description>Builds, tests, and runs the project ${name}.</description>
<import file="nbproject/build-impl.xml"/>
</project>
"""
def layer_xml = """\
<?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>
</filesystem>
"""
def bundle_properties = """\
OpenIDE-Module-Name=${name}
"""
def build_impl_xml = """\
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
-->
<project name="${name}-impl" basedir="..">
<property file="nbproject/private/platform-private.properties"/>
<property file="nbproject/platform.properties"/>
<macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="\${@{value}}"/>
</sequential>
</macrodef>
<property file="\${user.properties.file}"/>
<nbmproject2:property name="harness.dir" value="nbplatform.\${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
<nbmproject2:property name="netbeans.dest.dir" value="nbplatform.\${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
<fail message="You must define 'nbplatform.\${nbplatform.active}.harness.dir'">
<condition>
<not>
<available file="\${harness.dir}" type="dir"/>
</not>
</condition>
</fail>
<import file="\${harness.dir}/build.xml"/>
</project>
"""
def platform_properties = """\
nbplatform.active=default
"""
def project_properties = """\
javac.source=1.5
javac.compilerargs=-Xlint -Xlint:-serial
"""
def project_xml = """\
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.apisupport.project</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
<code-name-base>${name}</code-name-base>
<standalone/>
<module-dependencies/>
<public-packages/>
</data>
</configuration>
</project>
"""
def base = new File(folder);
base.mkdirs();
def src = new File(folder + File.separator + "src" + File.separator + "${pkgs}");
src.mkdirs();
def nbproject = new File(folder + File.separator + "nbproject");
nbproject.mkdirs();
new File(folder + File.separator +"build.xml").write(build_xml);
new File(folder + File.separator +"manifest.mf").write(manifest_mf);
new File("${src}" + File.separator + "layer.xml").write(layer_xml);
new File("${src}" + File.separator + "Bundle.properties").write(bundle_properties);
new File("${nbproject}" + File.separator + "build-impl.xml").write(build_impl_xml);
new File("${nbproject}" + File.separator + "platform.properties").write(platform_properties);
new File("${nbproject}" + File.separator + "project.properties").write(project_properties);
new File("${nbproject}" + File.separator + "project.xml").write(project_xml);
println("Done.")
The screenshot below has two nodes highlighted. The first is the node of the Groovy script that I ran to generate the whole of the source structure represented by the second highlighted node:
I.e., running the above script gives you a compilable starting point for creating NetBeans modules, without needing to go through any wizards to do so. The script runs in the space of a split second, generating everything I need. Plus, it's very simple to tweak the script to make it generate something different. Imagine, for example, how easy it would be to have a few predefined actions or windows in your module? Just go through the motions using the IDE's tools and then copy the generated code into the script above and then you'll never need to create them again via wizards, but always via your script instead.
Jul 29 2008, 06:33:02 AM PDT Permalink
Groovy Generation of Modular Desktop Applications
I came across a rather cool blog entry today (via the always excellent http://groovyblogs.org/), ICEFaces Project Generation Using Groovy, by Rob Mayhew. Very cool that he included all his code. A few tweaks later I was able to generate a new NetBeans Platform application from Groovy:
package generators
def folder = "/home/geertjan/Desktop/wonderful";
def name = "MyWonderfulApplication";
println "Generating project ${name} in folder ${folder}";
def build = """\
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
<!-- for some information on what you could do (e.g. targets to override). -->
<!-- If you delete this file and reopen the project it will be recreated. -->
<project name="${name}" basedir=".">
<description>Builds the module suite ${name}.</description>
<import file="nbproject/build-impl.xml"/>
</project>
"""
def build_impl_xml = """\
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
-->
<project name="${name}-impl" basedir=".." xmlns:sproject="http://www.netbeans.org/ns/nb-module-suite-project/1">
<property file="nbproject/private/platform-private.properties"/>
<property file="nbproject/platform.properties"/>
<macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-suite-project/1">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="\${@{value}}"/>
</sequential>
</macrodef>
<property file="\${user.properties.file}"/>
<sproject:property name="harness.dir" value="nbplatform.\${nbplatform.active}.harness.dir"/>
<sproject:property name="netbeans.dest.dir" value="nbplatform.\${nbplatform.active}.netbeans.dest.dir"/>
<fail message="You must define 'nbplatform.\${nbplatform.active}.harness.dir'">
<condition>
<not>
<available file="\${harness.dir}" type="dir"/>
</not>
</condition>
</fail>
<import file="\${harness.dir}/suite.xml"/>
</project>
"""
def platform_properties = """\
disabled.clusters=\
apisupport1,\
enterprise5,\
groovy1,\
gsf1,\
harness,\
ide10,\
java2,\
nb6.5,\
profiler3,\
visualweb2,\
webcommon1,\
websvccommon1,\
xml2
disabled.modules=\
org.netbeans.libs.jsr223,\
org.openide.compat,\
org.netbeans.modules.autoupdate.services,\
org.netbeans.api.visual,\
org.netbeans.core.execution,\
org.netbeans.core.multiview,\
org.openide.execution,\
org.openide.options,\
org.netbeans.modules.favorites,\
org.netbeans.modules.templates,\
org.netbeans.modules.autoupdate.ui,\
org.openide.util.enumerations,\
org.netbeans.modules.core.kit
enabled.clusters=\
platform9
nbplatform.active=default
"""
def project_properties = """\
app.name=token
app.title=${name}
branding.token=\${app.name}
modules=
"""
def project_xml = """\
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.apisupport.project.suite</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/nb-module-suite-project/1">
<name>${name}</name>
</data>
</configuration>
</project>
"""
def base = new File(folder);
base.mkdirs();
def nbproject = new File(folder + File.separator + "nbproject");
nbproject.mkdirs();
new File(folder + File.separator +"build.xml").write(build);
new File(folder + File.separator + "nbproject" + File.separator + "build-impl.xml").write(build_impl_xml);
new File(folder + File.separator + "nbproject" + File.separator + "platform.properties").write(platform_properties);
new File(folder + File.separator + "nbproject" + File.separator + "project.properties").write(project_properties);
new File(folder + File.separator + "nbproject" + File.separator + "project.xml").write(project_xml);
println("Done.")
Rather wonderfully, running the above script will give you a NetBeans project which, when you open it, will give you this:
That's a NetBeans Platform application which, when deployed, gives you this:
Now... imagine that you were to create different Groovy scripts, each providing different starting points for developing an application on the NetBeans Platform. One Groovy script would provide the application above, i.e., the same as you get via the NetBeans Platform Application wizard in the New Project dialog. Another one, however, could include a few basic modules that provide a more fleshed out layout. Or maybe you'd like to have the Plugin Manager available by default? Simply tweak the script to include the applicable modules, which you could simulate via the ui in the IDE and then copy the generated tags over to your Groovy script. In the end, you'd never need to go through a template in the IDE again, because you could, in the blink of an eye, generate everything you need via Groovy. And the script could be run, of course, from within the IDE.
Jul 28 2008, 06:10:13 AM PDT Permalink
NetBeans IDE 6.1 Java Editor Refcard
Here it is:
Click the above or click this link: http://refcardz.dzone.com/announcements/netbeans
It specifically covers the Java editor (no way could it cover everything the IDE offers, so choices had to be made), future NetBeans cards could cover other languages (Ruby, PHP, Groovy, etc) or specific technologies (Mobility, Java EE, etc), for which proposals are welcome. Also, it is specifically focused on NetBeans IDE 6.1, an update will be published when 6.5 is released. Suggestions for improvements (and corrections) that will then be implemented in that release are welcome. Thanks very much to the reviewers (listed at the end of the card) and Jill Tomich from DZone for being patient and great to work with.
Jul 27 2008, 07:02:20 PM PDT Permalink
Idiomatic Groovy
The code shown in my screenshot yesterday was correct Groovy but not idiomatic Groovy. This was the method in question:
String setSearchString(searchString) {
def xml = proxy.GetSpeech(searchString)
def XmlParser parser = new XmlParser()
def speech = parser.parseText (xml)
"PLAY: " + speech.PLAY.text() +
"\nSPEAKER:" + speech.SPEAKER.text() +
"\nTEXT:" + speech.text()
}
In Java, new lines need to be closed with a quote and contain the "+" character. In Groovy, although the above is perfectly acceptable, one can use triple-quotes for multi-lines. Even nicer, in this case, is to use GStrings (expressions declared inside double-quotes), together with Expandos (dynamic collections), instead:
String setSearchString(searchString) {
def xml = proxy.GetSpeech(searchString)
def XmlParser parser = new XmlParser()
def speech = parser.parseText (xml)
Expando result = new Expando()
result.play = "PLAY: ${speech.PLAY.text()}"
result.speaker = "SPEAKER: ${speech.SPEAKER.text()}"
result.text = "TEXT: ${speech.text()}"
result.all = "$result.play\n$result.speaker\n$result.text"
}
Much neater, more readable, and the result is the same as before. Plus, it could probably be improved even further.
Jul 25 2008, 09:57:08 AM PDT Permalink
Parsing XML with Groovy
The web service looked at yesterday returns a Shakespeare speech in XML format based on the search string that is sent via Groovy from a Swing form created in Matisse. Groovy isn't only useful in interacting with the web service—parsing the returned XML is also a trivial activity with Groovy:
As shown yesterday, the Groovy method shown above is called from the button in the form, that you see deployed in the screenshot above. On the return of the XML, Groovy takes a tiny number of lines to break up the payload and then (without the "return" statement being necessary, as pointed out in the comments yesterday by Alex Tkachman) is returned to the Swing form.
Jul 24 2008, 01:49:46 PM PDT Permalink
Groovy Makes Web Services Embarrassingly Easy
Meera pointed me to another very cool article she's written, RESTful Web Services in 60 Seconds, and (because I've been in an intensely groovy frame of mind for a few days now), I immediately associated it with my earlier experiments with Groovy and web services, in a blog entry entitled Groovy Web Service from the end of last year, based on some key learnings from the official Groovy web service site, (which has expanded a lot since then, I noticed today). At the time, I needed to hack things quite a bit to get web services to work with Groovy in NetBeans IDE (as honestly recorded in that blog entry).
So, I thought, how do things stand today in terms of Groovy and web services in NetBeans IDE? To be perfectly honest, the improvement couldn't have been much better, aside from the currently incomplete code completion (which is a work in progress still). In fact, I was able to mix and match Matisse with a Groovy web service, although you can't tell from the result:
This is the actionPerformed in the JButton in the Matisse form that you see above:
ShakesWSClient shakes = new ShakesWSClient();
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
String searchString = shakes.setSearchString(searchTextArea.getText());
resultTextArea.setText(searchString);
}
And this is the ENTIRE web service client:
package org.me.hello
import groovyx.net.ws.WSClient
class ShakesWSClient {
def proxy = new WSClient("http://www.xmlme.com/WSShakespeare.asmx?WSDL", ShakesWSClient.class.classLoader)
String setSearchString(searchString) {
def newQuote = proxy.GetSpeech(searchString)
return newQuote
}
}
Really, that's just a bit ridiculous. And I'm sure that the Groovy experts could cut the above code down a few lines and characters further. And I didn't need to hack anything in NetBeans. The Groovy class behaved seamlessly with the Java class.
Jul 23 2008, 09:33:20 AM PDT Permalink
Creating a Grails Plugin in NetBeans IDE
Let's create a plugin for Grails. Grails is, after all, modular and pluggable. Here's the ultimate simple Grails plugin, just to give an idea what is involved, from start to finish. The most useful references I have found so far are these:
Between those three, you should have enough to figure things out. I still found it hard, despite those instructions and so to avoid having to figure things out again some time in the future, I'll write absolutely everything here.
Creating the Plugin
- On the command line, run this:
grails create-plugin SamplePlugin
Now you have a Grails plugin. However, at the same time it is just another Grails application, which means you can simply open it in NetBeans IDE. (I.e., there is no import process and no NetBeans artifacts are added to the plugin in order to be able to open it in the IDE.)
- So open the plugin in the IDE. The Projects window isn't very interesting, it just shows you the same as you would normally see for Grails applications:
The Files window (Ctrl-2) however, shows a lot more:
Open the "SamplePluginGrailsPlugin.groovy" file and there you see the following:
class SamplePluginGrailsPlugin { def version = 0.1 def dependsOn = [:] def doWithSpring = { // TODO Implement runtime spring config (optional) } def doWithApplicationContext = { applicationContext -> // TODO Implement post initialization spring config (optional) } def doWithWebDescriptor = { xml -> // TODO Implement additions to web.xml (optional) } def doWithDynamicMethods = { ctx -> // TODO Implement registering dynamic methods to classes (optional) } def onChange = { event -> // TODO Implement code that is executed when this class plugin class is changed // the event contains: event.application and event.applicationContext objects } def onApplicationChange = { event -> // TODO Implement code that is executed when any class in a GrailsApplication changes // the event contain: event.source, event.application and event.applicationContext objects } }I.e., you have hooks for integrating your code into meaningful places in the plugin.
- Now we'll create code that will let our plugin provide a new "constraint". (If you don't know what that is, you will know by the time you finish reading all this.) To do so, we will need to extend org.codehaus.groovy.grails.validation.AbstractConstraint, in a package within src/groovy:
import org.codehaus.groovy.grails.validation.AbstractConstraint import org.springframework.validation.Errors class BestFrameworkConstraint extends AbstractConstraint { private static final String DEFAULT_MESSAGE_CODE = "default.answer.invalid.message"; public static final String NAME = "oneCorrectResponse"; private boolean validateConstraint //The parameter which the constraint is validated against: @Override public void setParameter(Object constraintParameter) { if (!(constraintParameter instanceof Boolean)) throw new IllegalArgumentException("Parameter for constraint [" + NAME + "] of property [" + constraintPropertyName + "] of class [" + constraintOwningClass + "] must be a boolean value"); this.validateConstraint = ((Boolean) constraintParameter).booleanValue() super.setParameter(constraintParameter); } //Returns the default message for the given message code in the current locale: @Override protected void processValidate(Object target, Object propertyValue, Errors errors) { if (validateConstraint && !validate(target, propertyValue)) { def args = (Object[]) [constraintPropertyName, constraintOwningClass, propertyValue] super.rejectValue(target, errors, DEFAULT_MESSAGE_CODE, "not." + NAME, args); } } //Returns whether the constraint supports being applied against the specified type: @Override boolean supports(Class type) { return type != null && String.class.isAssignableFrom(type); } //The name of the constraint, which the user of the plugin will use //when working with your plugin. @Override String getName() { return NAME; } //Validate this constraint against a property value, //In this case, ONLY "Grails" is valid, everything else will cause an error: @Override boolean validate(target, propertyValue) { propertyValue ==~ /^Grails$/ } } - Next, back in the Groovy plugin class that we looked at earlier, hook the above class into the plugin, using the "doWithSpring" closure to do so:
def doWithSpring = { ConstrainedProperty.registerNewConstraint( BestFrameworkConstraint.NAME, BestFrameworkConstraint.class); } - Now, back on the command line, navigate to within the "SamplePlugin" folder. There, run the following:
grails package-plugin
Back in the IDE, examine the ZIP file that the above command created:
That ZIP file is your Grails plugin.
Installing the Plugin
Now we will install our plugin in a new application.
- First, create a new Grails application by going to the New Project wizard (Ctrl-Shift-N) and choosing Groovy | Grails Application. Click Next and type "SampleApplication" and then click Finish.
- After the IDE has finished running the "grails create-app" command for you, you will see the new application open in the IDE. Right-click it and choose "Plugins", as shown here:
- In the Grails Plugins dialog, notice that the list gets filled with many potential plugins that you might want to install, from the Grails plugins repository. Instead, we'll install our own. Click Browse and browse to the ZIP file that we created three steps ago and notice that it appears in the text field at the bottom of the dialog:
- Click "Install" and then a progress bar appears, ending with the plugin being installed. Notice that you can also uninstall it:
- Take a look at your application and notice (in the Files window) what's happened to the plugin. It's been unzipped, plus the ZIP file is still there. And all that's been done in the "plugins" folder. Nothing else has changed, which means that uninstallation is as simple as removing the folder from the "plugins" folder:
Thanks to "convention over configuration", Grails knows exactly where everything is—so that, for example, the "plugin.xml" file that you see above, if found within the folder structure you see above, is the indicator to Grails that a plugin is available for use.
Using the Functionality Provided By the Plugin
- Let's now use our plugin. Create a domain class called "Quiz", after right-clicking the "Domain Classes" node and choosing "Create new Domain Class":
- Right-click the "Controllers" node and choose "Create new controller". Type "Quiz" and then click Finish. Use the Groovy editor to add one line for adding the scaffolding (and uncomment the other line):
- Back in the "Quiz" domain class, add your property and use the "oneCorrectResponse" constraint defined in your plugin, as shown here:
Note: The "oneCorrectResponse" constraint that you see above is the name of the constraint defined in the plugin.
- And then add the message to the messages.properties file, which is within the "Messages Bundles" node:
- Run the application and you will see that your constraint will prevent anything other than "Grails" from being considered acceptable, when "Create" is clicked below:
Congratulations, you've created, installed, and used your first Grails plugin!
Jul 22 2008, 04:55:12 PM PDT Permalink
Integrating Meera with Grails and NetBeans
My DZone colleague Meera Subbarao took the new Grails/Groovy support in NetBeans IDE for a spin, with great results. Part of her concluding remarks are: "If you are a Groovy or a Grails fan, download the latest version of NetBeans and give it a try. You can develop, test and run your Grails application without ever opening a command window." Click the pic below to read the whole story:
Jul 21 2008, 02:09:47 PM PDT Permalink
Grails: This Time With Tools
Here's how to get started with Grails in NetBeans IDE 6.5.
- Prepare the Environment
- Read the Grails Quick Start, which presents the scenario that we will reproduce in the sections that follow.
- Download and install the "Web & Java EE" distribution of NetBeans IDE 6.5 Milestone 1 or later. (Everything done below is done with the latest development build, which is probably the best thing to get for getting to know the IDE's Grails support, if you're okay with unexpected errors now and then.)
- Download and unzip Grails.
- In the IDE, go to the Options window and set the location of Grails in the "Groovy" panel. If you want to use Groovy, also set the location of Groovy there.
- Create the Application
Choose the Grails Application project in the New Project wizard (Ctrl-Shift-N):
Click Next and type the name of the project:
Click Finish and you should see this:
Expand the folders and have a look around:
Also look at the generated files and notice that many of them have default values filled in:
- Create the Domain Class
Right-click on the Domains classes node:
Name the domain class "Book" and then fill in the following two lines within the generated class:
String title String author
You should now see this:
Create some initial values in the Bootstrap.groovy class:
new Book(author:"Stephen King",title:"The Shining").save() new Book(author:"James Patterson",title:"Along Came a Spider").save()
Use Ctrl-Space to call up code completion and then have a look at the other ways of completing the statements above:
You should now see this:
- Create the Controller
Right-click the Controllers node:
Type "Book" and notice that you are shown that the generated class will be called "BookController":
Then comment out the one line generated within the braces and add this one:
def scaffold = Book
You should now see this:
- Run the Application
Right-click the application and choose "Run". The application is deployed to Jetty, as you can see in the Services window:
The URL is printed to the Output window. Paste it into a browser and then you'll see your application. Click the "BookController" link and you'll see this:
Click New Book and then create a new entry:
When you click Create, note that you can edit or delete the entry:
...and that the entry is reflected in the list of entries:
There are several other Grails-specific features, such as a Grails shell, support for installing Grails plugins, and menu items for things like Grails stats, upgrade, and WAR-file creation. I will blog about these soon.
Jul 20 2008, 08:19:32 AM PDT Permalink
Search the Guardian from a NetBeans Platform Application without Coding At All
By default, the Quick Search feature is hidden in NetBeans Platform applications. Below, I show how to enable it in the layer.xml file and also how to enable the web search provider (this provider searches Google and returns pages that match your search string), which is defined in the NetBeans sources but not declared by default in the NetBeans Platform:
<folder name="QuickSearch">
<!-- Optionally, we've hidden the existing quick search providers: -->
<file name="Actions_hidden"/>
<file name="GoToOption_hidden"/>
<file name="Help_hidden"/>
<!-- Enabling the WebQuickSearchProviderImpl: -->
<folder name="Guardian">
<file name="org-netbeans-modules-quicksearch-web-WebQuickSearchProviderImpl.instance"/>
</folder>
</folder>
<!-- Showing the Quick Search feature: -->
<folder name="Toolbars">
<folder name="QuickSearch">
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.guardiansearch.Bundle"/>
<file name="org-netbeans-modules-quicksearch-QuickSearchAction.shadow">
<attr name="originalFile" stringvalue="Actions/Edit/org-netbeans-modules-quicksearch-QuickSearchAction.instance"/>
</file>
</folder>
</folder>
Finally, in our branding folder, we create the folder hierarchy below and set the two properties that you see there (read about these properties at the bottom of this page):
In the IDE, the above properties are hardcoded to the following, but for the NetBeans Platform they are undefined and hence need to be branded as the above:
quicksearch.web.site=netbeans.org quicksearch.web.url_patterns=.*netbeans\.org/kb.*,.*wiki\.netbeans\.org/.*faq.*,.*wiki\.netbeans\.org/.*howto.*,.*platform\.netbeans\.org/tutorials.*
You've done no coding at all, right? So now run the application and you'll be able to search the Guardian (or whatever you set in the branded Bundle file that you see above):
When you click an item above, the related article opens in your browser.
So here's all I did to be able to search Jon Stewart's show:
quicksearch.web.site=thedailyshow.com quicksearch.web.url_patterns=.*
And here's the result:
All of the above is possible from 6.5 Milestone 1 onwards.
Jul 19 2008, 02:04:36 PM PDT Permalink
Quick Search API Sample
I noticed in recent builds that the appearance of the new 6.5 Quick Search feature has improved recently. It looks a lot better and provides more functionality. First, you can see in the final category below that there is a "..." elipsis if the list of results is longer than the length of the visible list:
So you can click on that elipsis and see all the results. Also, if you're looking at the screenshot above and wondering: "He typed 'tip' but several of the results do NOT have 'tip' in the title," then you should look at this screenshot:
Here you can see that the search string "lookup" is in NONE of the returned titles. However, I happen to know for a fact that "lookup" is mentioned in the content of each of the above items, which means that the search does more than a title search, it actually looks into the body of the help topics, which is great news.
Finally, the categories are shown like this, so that you can limit the search to the category of your choice:
And maybe you're wondering about the categories "User FAQs" and "NetBeans Zone" in the screenshots above? Those come from the sample I'm turning into a tutorial describing the API that makes the above integrations possible. It is to be called "Quick Search Integration Tutorial" and will hopefully be available at the beginning of next week. However, the sample code is already available in the Plugin Portal:
http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=11179
Remember that you'll need a recent 6.5 build (Milestone 1 should be fine, I think) if you want to play with the sample.
Jul 18 2008, 03:11:33 PM PDT Permalink
My 1st Contribution to NetBeans API Javadoc!
For a very long time, Jaroslav Tulach has been asking me to add links to documentation (blogs as well as tutorials) to the NetBeans API Javadoc. I always said I would do so but then ended up being too scared—it seemed strange to add additonal Javadoc comments to code that someone else had written and I thought that somehow the build would break if I did so. (And I was also concerned that the documentation in question might be wrong or misleading, while the fact that it was linked from the Javadoc might imply that it was somehow official.)
A few days ago I promised to do so again, but this time we were in a pub and he recorded me making the promise that I would add two links the next day. So there was no way back and so two days ago I finally did it:
http://hg.netbeans.org/main/rev/55ff702a6ccd
And today you can see the result:
So, now you can expect to see a lot more cross references from NetBeans API Javadoc to various bits of documentation that should be helpful when implementing the API in question!
Jul 17 2008, 01:10:57 AM PDT Permalink
Notes for NetBeans Platform 6.5 (Part 2)
Another change, comparable to the registration of the action class within the layer.xml that I showed yesterday, is the way in which actions that are "always enabled" will be created & registered in 6.5. In 6.5, if you make this selection in the New Action wizard:
...everything in the wizard will be the same as it always was. I.e., in the next panel, you'll specify where the "always enabled" action should appear and then, in the panel that appears after that, you will specify the name of the class and the package. However, when you complete the wizard, you will see that the generated class looks exactly like this:
package org.netbeans.modules.demo;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public final class MyWonderfulAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
// TODO implement action body
}
}
And this is how the class will have been registered in the layer.xml by the wizard:
<filesystem>
<folder name="Actions">
<folder name="Edit">
<file name="org-netbeans-modules-demo-MyWonderfulAction.instance">
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.demo.Bundle"/>
<attr name="delegate" newvalue="org.netbeans.modules.demo.MyWonderfulAction"/>
<attr name="displayName" bundlevalue="org.netbeans.modules.demo.Bundle#CTL_MyWonderfulAction"/>
<attr name="iconBase" stringvalue="org/netbeans/modules/demo/icon.png"/>
<attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/>
<attr name="noIconInMenu" stringvalue="false"/>
</file>
</folder>
</folder>
<folder name="Menu">
<folder name="Edit">
<file name="org-netbeans-modules-demo-MyWonderfulAction.shadow">
<attr name="originalFile" stringvalue="Actions/Edit/org-netbeans-modules-demo-MyWonderfulAction.instance"/>
<attr name="position" intvalue="100"/>
</file>
</folder>
</folder>
</filesystem>
In other words, the "always enabled" action will, from 6.5 onwards, assuming you use the wizard, delegate to a plain old standard Java ActionListener class. And you will be able to focus on the purpose of the action within the class, while all the ancillary information is found within the layer.xml file (take special note of the new bundlevalue attribute), i.e., these properties are available even without the object having been instantiated. (You can go on using CallableSystemAction or AbstractAction if you want, but that's not code that the wizard will generate for you.)
However, while the situation where we don't have code completion in the layer.xml file continues, it will be hard to know exactly which attributes are available. (This has always been a problem, but is exacerbated now that even more is found in that file than before.) In that sense, we currently have better support for Spring RCP!
In other news. One of the current best blogs in the NetBeans world is the newish one by the NetBeans PHP development team: http://blogs.sun.com/netbeansphp/. The actual engineers in that team write that blog, with new developments as they happen. Bookmark it! One of the best blog entries I've seen (ever) in the software development world comes from there, click here to read it and see how immediate the interaction between users and engineers is and how directly one can impact the developments of the PHP team.
Jul 16 2008, 04:16:51 PM PDT Permalink





