Sunday May 11, 2008

JFugue Music Application Platform

I suddenly realized that instead of turning Matt Warman's whole JFrets application into a single NetBeans module, I could turn each of its parts into separate modules. The cool thing is that JFrets provides a number of different tools that help with learning to play the guitar, such as a scale selector and a metronome. Here's the JFrets metronome:

I've always wanted a metronome in the JFugue Music NotePad... and now I do:

I simply copied the metronome parts of JFrets into a separate NetBeans module (which makes sense since both the original application and the destination application use Swing) and then slightly reorganized the ui so that it would fit snugly into the explorer view. When you click Start, the JFugue API is used under the hood to start the audible tick-tocking of the metronome, using the settings you set for the tempo, until you press Stop (which is what the Start button turns into once started). This means that I am now treating the JFugue Music NotePad as an application platform. Simply download the binary and then register it as a NetBeans Platform (under the Tools menu in the IDE). All the modules in the JFugue Music NotePad are then available to your own modules. One of these modules is the module that wraps the JFugue API JAR. So in your own module, such as the one which provides the JFrets metronome, you'd simply declare a dependency on JFugue, which the application made available. Then you can deploy the modules you create in the IDE to the JFugue Music NotePad, from within the IDE, via a menu item that would then start up the JFugue Music NotePad and install your module into it.

Now that the JFrets metronome is a module, I can do the same with all the other JFrets tools, as well as the main window itself. Then I could set up an update center that contains these additional modules. The update center would be automatically registered in the JFugue Music NotePad. All its users would then be able to install additional features, such as a metronome and scale selector, which originally all came from the same JFrets application. Of course, anyone else would also be able to install these tools into their own NetBeans Platform applications, such as the IDE. Not necessarily useful to have a metronome in the IDE, but it is at least possible.

Saturday May 10, 2008

Coding a Swing Explorer Plugin for NetBeans IDE

One of the cool encounters at JavaOne was with Maxim Zakharenkov, who is from Latvia, and his https://swingexplorer.dev.java.net/ project. The tool lets you introspect Swing applications and is discussed on Javalobby as well. Max told me that there's already an Eclipse plugin for his tool, but nothing for NetBeans IDE. We spent some time together yesterday and made quite some progress.

First, you need to be able to launch the Swing Explorer together with your own application. You can simply use Ant to do so:

    <target name="swingexplorer-run" description="swingexplorer-run" depends="jar">
        <property file="nbproject/project.properties"/>
        <java classpath="${run.classpath}" classname="org.swingexplorer.Launcher" fork="true">
            <arg value="${main.class}"/>
            <jvmarg line="-Dswex.mport=1099 -Dcom.sun.management.jmxremote"/>
        </java>
    </target>

Put the swexpl.jar from the Swing Explorer project on your classpath and you're good to go. When you then run the above script, your own app will start as well as the Swing Explorer, where you can then inspect the insides of your application and play its creation back to you (which needs to be seen to be believed).

So, that's how it works from Ant. However, what do we need to do to create a plugin so that a menu item can be selected on the project which would then launch the above?

In addition, the Eclipse plugin lets you, when you play an application, jump from each played line to the line in the editor. So, as each method is played, you can click in the Swing Explorer and then the file that is being played is opened, with the cursor landing on the appropriate line. This is made possible via JMX. For diagnostics purposes, Max and I set up VisualVM and subscribed to notifications, so that we could see how this part of the application worked and to see the properties that are exposed:

(Would be nice if the columns in the table above could be resized and that a tooltip would appear displaying a column's content.)

Therefore, what the NetBeans plugin needs to do is listen for changes on the related JMX notifications and then open the editor when the "src" button is clicked in the Swing Explorer.

  1. First create an action on project nodes, from which you'll run the Swing Explorer in combination with your own applicaation:

    <folder name="Projects">
         <folder name="Actions">
             <file name="org-netbeans-swingexplorerplugin-LaunchSE.instance"/>
             <attr name="position" intvalue="0"/>
         </folder>
    </folder>

    Open issue: How to make the action available only to Java applications, but no other project type? Currently, the menu item is displayed on all project types, which is inappropriate.

  2. In the above action's performAction, create and run the Ant script:

    protected void performAction(Node[] activatedNodes) {
        Project project = activatedNodes[0].getLookup().lookup(Project.class);
        String script = "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>" +
                "<project name=\\"SwingExplorerRun\\" default=\\"swingexplorer-run\\" basedir=\\".\\">" +
                "<import file=\\"nbproject/build-impl.xml\\"/>" +
                "<target name=\\"swingexplorer-run\\" description=\\"swingexplorer-run\\" depends=\\"jar\\">" +
                "<property file=\\"nbproject/project.properties\\"/>" +
                "<java classpath=\\"${run.classpath}\\" classname=\\"org.swingexplorer.Launcher\\" fork=\\"true\\">" +
                "<arg value=\\"${main.class}\\"/>" +
                "<jvmarg line=\\"-Dswex.mport=1099 -Dcom.sun.management.jmxremote\\"/>" +
                "</java>" +
                "</target>" +
                "</project>";
        try {
            FileObject zfO = FileUtil.createData(project.getProjectDirectory(), "ant-swe.xml");
            File zf = FileUtil.toFile(zfO);
            BufferedWriter out = new BufferedWriter(new FileWriter(zf.getAbsoluteFile()));
            out.write(script);
            out.close();
            FileObject zfo = FileUtil.toFileObject(FileUtil.normalizeFile(zf));
            ActionUtils.runTarget(zfo, new String[]{"swingexplorer-run"}, null);
            zf.deleteOnExit();
        } catch (IOException e) {
            System.out.println("IO error: " + e);
        }
    }

    Open issue: Maybe use ContextualAwareAction instead of CookieAction, to somehow prevent the menu item from being shown when the current project is not a Java project? But what distinguishes Java projects from other projects?

    Another open issue is that ideally the JAR files would be put on the classpath in the background. Currently I'm putting them there manually. They should be hidden from the user, though, so that they're not visible in the Libraries node and are definitely not packaged into the application's JAR.

  3. Implement an Ant logger that listens for the above target and then connects to JMX:

    public class SwingExplorerListener extends org.apache.tools.ant.module.spi.AntLogger {
    
        @Override
        public boolean interestedInSession(AntSession session) {
            return true;
        }
    
        @Override
        public boolean interestedInAllScripts(AntSession session) {
            return true;
        }
    
        @Override
        public String[] interestedInTargets(AntSession session) {
            return AntLogger.ALL_TARGETS;
        }
    
        @Override
        public void targetStarted(AntEvent event) {
            String targetName = event.getTargetName();
            if (targetName.equals("swingexplorer-run")) {
                Thread thread = new Thread() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(5000);
                            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:" + "1099" + "/server");
                            JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
                            MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
                            ObjectName name = new ObjectName("org.swingexplorer:name=IDESupport");
                            ActOpenSourceLine actOpenSourceLine = new ActOpenSourceLine();
                            mbsc.addNotificationListener(name, actOpenSourceLine, null, null);
                        } catch (Exception ex) {
                            Logger.getLogger(SwingExplorerListener.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                };
                thread.start();
            }
        }
    }

    For the above to work, you need a file called 'org.apache.tools.ant.module.spi.AntLogger' in META-INF/Services. In that file, simply put the FQN of the above class: 'org.netbeans.swingexplorerplugin.SwingExplorerListener'.

  4. Define the NotificationListener as follows:

    public class ActOpenSourceLine implements NotificationListener {
        public void handleNotification(Notification notification, Object handback) {
            HashMap map = (HashMap) notification.getUserData();
            String className = (String) map.get("className");
            int lineNumber = (Integer) map.get("lineNumber");
            OutputWriter writer;
            InputOutput io = IOProvider.getDefault().getIO("Hello Output", false);
            writer = io.getOut();
            writer.println("Swing Explorer Output: " + className + " at " + lineNumber);
        }
    }

    Result:

    Open issue: Now that I have the class name and the line number, how do I open the class into the IDE's Java editor?

Of course, once this is all working, it would be cool to get it to work for NetBeans Platform applications too. Then we'd be able to replay the creation of the entire NetBeans IDE...

Friday May 09, 2008

Navigate Between Marked Occurrences

One of the dozens of interesting things I've picked up at JavaOne is... a very cool new keyboard shortcut that is in post-6.1 development builds. I.e., this is not in 6.1. You'd need to get a development build. Once you've done so, put your cursor on an identifier in your Java code, as shown below:

Great, all the occurrences of the selected identifier are marked, as in 6.0 and 6.1. Now how do you navigate between those marked occurrences? Wouldn't it be cool if you could hold down the Alt key and then use the Up arrow and Down arrow to navigate up and down the occurrences that have been marked? You can't do that in 6.1, but in development builds, that's exactly what you can do.

Vladimir Voskresensky from the NetBeans C/C++ development team in St. Petersburg told me about this on NetBeans Day. It's something he committed to the NetBeans sources, after having initially created it for the C++ editor. Thanks Vladimir. One thing I noticed is that the selected identifier suddenly changes while I am navigating, so that I can't navigate all the way down the list because the marked occurrence suddenly changes.

Thursday May 08, 2008

https://nbrichfacessupport.dev.java.net

Go to https://nbrichfacessupport.dev.java.net/index.html and you will be able to read all about this new project and check out the sources. Join the project and contribute, especially if you have cool snippets that should be added to the RichFaces palette.

I will start populating the Issue database with new requests for enhancements soon.

Tuesday May 06, 2008

RichFaces for NetBeans IDE 6.1 (Part 3)

I did a short demo of RichFaces support during NetBeans Day yesterday. It went without a hitch, producing this result in the browser:

Note especially the "Zoom" slider at the bottom of the page, which works as you would expect, i.e., the map is zoomed as the slider position changes. Here's the editor, containing everything needed for the above, while also showing the palette with two new items, one for the map and one for the slider:

I made several small changes to the support modules, such as a new JSP template which contains the taglib declarations for RichFaces (as requested by Wouter in the blog comments recently). Finally, I requested a project called 'nbrichfacessupport' on java.net, so watch this space about announcements around that and also for opportunities in that regard for getting involved!

Sunday May 04, 2008

RichFaces for NetBeans IDE 6.1 (Part 2)

In the comments to my announcement about RichFaces in NetBeans IDE 6.1, yesterday, someone asked for tag completion. Well, that's already possible automatically when you install the plugin I mentioned yesterday. Since the libraries are on the classpath and the necessary declarations are generated right into the JSP page, you can immediately use tag completion (Ctrl-Space) in the generated page, as well as in any other JSP page where you add the declarations, which will result in you getting documentation as well as tag completion:

Also, you can use code completion to access managed beans...

...as well as their content:

Secondly, I created the start of a RichFaces palette, which you can get here:

http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=8968

Currently only two code snippets for RichFaces are in the palette (Aristotle Onassis and Donald Trump, haha) representing a RichFaces calendar and a RichFaces ComboBox. The tooltip shows exactly what will be generated when you drag/drop the item into the JSP page:

I am no RichFaces expert (having only heard of it the first time 2 days ago), so please tell me what else to add, any code snippets that you think are essential in this context, just leave a message at the end of this blog entry and I will extend the palette. Also, note that you can manually add your own snippets to the RichFaces palette, if you follow the instructions on the abovementioned plugins page.

Saturday May 03, 2008

RichFaces for NetBeans IDE 6.1 (Part 1)

Yesterday I met with Wouter van Reeven, here in San Francisco, who mentioned the RichFaces framework to me. In particular, people in a JBoss-oriented world are likely to want to use RichFaces (as well as ICEfaces, Seam, and Facelets). For ICEfaces, a NetBeans plugin exists (here), though it works in 6.0 only. I've tried it, it's a pretty cool thing: you get support both for traditional web applications and for Visual Web applications. I'm hoping they'll upgrade to 6.1 soon (shouldn't be hard, I expect they only have a dependency change to fix).

However, no such thing exists for RichFaces. What's the difference between ICEfaces and RichFaces? No idea. Didn't know they existed until yesterday. However, they piqued my interest because of AJAX, which is a theme at NetBeans Day on Monday. So I created some basic NetBeans support for RichFaces, based on a cool and simple example application that Wouter sent me today. Go here to download the new support I created and then read on to learn about what it can do for you:

http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=8934

Download that ZIP file, you will have two NBM files in the ZIP file, install them both in NetBeans IDE 6.1.

Now do the following:

  1. Create a new web application.

  2. Make sure to set GlassFish as your server, because this server bundles JSF libraries and RichFaces is an extension of JSF. If you want to use Tomcat or some other server, make sure JSF is available to the server in question.

  3. In the Frameworks panel, choose Java Server Faces AND RichFaces:

    Click Finish.

  4. Inspect the generated sources. In addition to your standard JSF application, you have the RichFaces JARs in the Libraries node, you have RichFaces entries in your web.xml, your welcomeJSF.jsp contains some RichFaces-specific code, and you have a managed JSF Java bean in a new package in your source structure, automatically registered in faces-config.xml. Here's the whole thing:

  5. Run the application and you have your first AJAX application via RichFaces:

    Notice that the text to the right of the field is automatically updated as you type in the field itself. That's AJAX, partial page refresh, faster response to the user, etc.

  6. Want to change the "skin" of the application? Drop this into the web.xml:

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>server</param-value>
    </context-param>
    <context-param>
        <param-name>org.richfaces.SKIN</param-name>
        <param-value>blueSky</param-value>
    </context-param>

    Run the app again and notice the "skin" is different:

Now continue learning about RichFaces via online resources. Next, I will create a palette that provides items that you can drag and drop into a JSP page, for RichFaces. However, I doubt I will ever create RichFaces support for Visual Web applications, because that's an area I have little knowledge (nor very much interest) in. If someone wants to help me, such as in the area of Visual Web, feel free to leave a message here and let me know!

Thursday May 01, 2008

Wicket 1.3.3 Support for NetBeans IDE 6.1

Today we uploaded the latest NBMs of our Wicket support into the Plugin Portal:

http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=3586

There are several changes, some mentioned recently in this blog. Basically, the names of the generated templates are friendlier, the JARs are Wicket 1.3.3 instead of 1.3.0, some useless options have been removed from the Frameworks panel, the Wicket Stylesheet support is part of the generated code, the Wicket filter is used in web.xml instead of the Wicket servlet, a header panel is always created... so mostly quite simple enhancements that, I believe, will make the user experience a lot better. Click the above link, then the Download button on the Plugin Portal page, unzip the ZIP that you then get and install the three NBMs. There is no need to download Wicket JARs from the Wicket site, because one of the three NBMs provides these and registers them in the IDE when you install the NBM.

I've installed them into 6.1, though they should probably also work in 6.0. Here's a quick scenario that should show you most of the Wicket support provided by this plugin, together with some nice Wicket/Ajax integration:

  1. Create a new web application and choose Wicket in the Frameworks panel:

  2. When you click Finish you have a nice simple source structure to begin your adventures with Wicket:

    (From a NetBeans API point of view, the coolest thing about the above screenshot is that you see exactly that when you complete the wizard, i.e., the package opens automatically and the HomePage.java is also opened automatically, so that you can begin coding there right away. It's a small thing, but pretty cool.)

  3. Right-click on the package (not on the project node, else you'll come across a known bug in this plugin) and choose New | Other and then choose the Panel template from the New File dialog:

  4. Name your panel:

  5. Click Finish and you have the skeleton of a new panel, i.e., both the Java side and the HTML side:

  6. Add a text field to the HTML side of the new panel, with a Wicket ID that will connect the HTML to the Java side of the panel:

  7. On the Java side of the Country Panel, use Wicket's AutoCompleteTextField class, as follows, making sure to pass the 'countries' ID, which connects the Java side with the HTML side defined in the previous step:

    final AutoCompleteTextField field = new AutoCompleteTextField("countries", new Model("")) {
    
        @Override
        protected Iterator getChoices(String input) {
            if (Strings.isEmpty(input)) {
                return Collections.EMPTY_LIST.iterator();
            }
            List choices = new ArrayList(10);
            Locale[] locales = Locale.getAvailableLocales();
            for (int i = 0; i < locales.length; i++) {
                final Locale locale = locales[i];
                final String country = locale.getDisplayCountry();
                if (country.toUpperCase().startsWith(input.toUpperCase())) {
                    choices.add(country);
                    if (choices.size() == 10) {
                        break;
                    }
                }
            }
            return choices.iterator();
        }
    };

    Above, the bits in bold is Wicket, the rest is just standard JDK code for getting the country names for the available locales. Here we're just building up a collection that will be displayed in the auto complete text field that we are creating here. The collection could contain anything at all, but Wicket provides the class that will make the text field behave in a way that we've come to expect from Ajax.

  8. Now add the field to the panel, on the Java side, by adding the one line below that is in bold, in the constructor:

    CountryPanel(String id) {
        super(id);
        add(field);
    }
  9. Hurray. You've just defined your first reusable panel. Now let's actually make use of it. In the HomePage.html, add a new tag below the existing tag, i.e., add the tag that is in bold below:

    <html>
      <head>
        <title></title>
        <link wicket:id='stylesheet'/>
      </head>
      <body>
        <span wicket:id='mainNavigation'/>
        <span wicket:id='countryPanel'/>
      </body>
    </html>

    The Wicket ID you specify here could be anything, so long as it is matched by the Wicket ID we add to the Java side, in the next step.

  10. In the HomePage.java, instantiate the Country Panel, by simply adding the line in bold (all the rest was generated by the Frameworks panel in the Web Application wizard):

    package com.myapp.wicket;           
    
    import org.apache.wicket.model.CompoundPropertyModel; 
    
    public class HomePage extends BasePage {
    
        public HomePage() {
    
            setModel(new CompoundPropertyModel(this));
            add(new CountryPanel("countryPanel"));
    
        }
    }

    In the same way that you've instantiated the Country Panel above, you could do so anywhere else, such as in the generated Header Panel. You just need to make sure that the Wicket ID is the same on both sides, i.e., in the HTML file and in the Java file.

  11. Hurray, you're done. Deploy the application to the server of your choice. Notice that you now have an auto complete text field in your browser:

What have you learned? Firstly, you've learned that NetBeans IDE has cool support for Wicket (and you haven't seen everything yet, for example, when you refactor a Java class, the related HTML side will be refactored at the same time and you can cause a hyperlink to be created on the Wicket ID on the HTML side, which will let you open the Java side from inside the HTML page, plus the Navigator shows the Wicket tags in the page, plus there's Wicket samples in the New Project wizard). Secondly, you've learned about one of Wicket's Ajax classes (go here for more). Thirdly... how much JavaScript have you used in order to create a very typical Ajax component? Well... ummm... none. So, you can use Ajax without leaving the comfortable world of Java. Fourthly, in the debug mode, which is Wicket's default mode, there's a cool debug console right inside the HTML page, which provides a lot of useful information about the current session. Fifthly (but something you can't see here), if the browser doesn't support JavaScript, Wicket provides fallback behavior to handle this for you. Finally, isn't it cool that you can wrap your Ajax behavior in your own Wicket components and then reuse them, so easily?

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« May 2008 »
SunMonTueWedThuFriSat
    
2
5
7
16
20
22
25
28
       
Today