Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

Sunday, March 9, 2008

More First Class Methods Code

I'm still experimenting with the prototype implementation of the FCM closures proposal. Here are a few utility methods that immediately came to mind.

withLock -- This one I've seen an example of online a few times. It automatically release the lock when the block of code finishes executing.
public static void withLock(Lock lock, Runnable task) {
lock.lock();
try {
task.run();
} catch (Exception e) {
throw e;
} finally {
lock.unlock();
}
}
Example Usage:
final ReentrantLock lock = new ReentrantLock();
withLock(lock, #{
// call some important locked code
});
Now I'm not too fond of unchecked Exceptions, but rethrowing is still better then swallowing every exception that escapes the Runnable. Here is my second attempt.
private static interface ExceptionHandler {
public void uncaughtException(Runnable source, Throwable e);
}

public static void withLock(Lock lock, Runnable task, ExceptionHandler eHandel) {
lock.lock();
try {
task.run();
} catch (Exception e) {
eHandel.uncaughtException(task, e);
} finally {
lock.unlock();
}
}
Example Usage:
withLock(lock, #{
// do some code that needs to be locked.
// throw an exception to test the event handler.
throw new RuntimeException("year is even error");
}, #(Runnable source, Throwable e){
// inline implemented event handler.
e.printStackTrace();
}
);
Once side effect of this is now one might be able to write reusable exception handling code. There have been plenty of times where a method I'm executing throws an exception, but there is no real way for me to recover. All I can do is log the failure and continue on. I end up writing the same try catch block over and over. It would be nice to write something like this once and reuse it.
public class LogAndContinueExceptionHandler implements ExceptionHandler{
public void uncaughtException(Runnable source, final Throwable e) {
SwingUtilities.invokeLater(#{
Logger.getLogger("ErrorLogger").log(Level.SEVERE, e.getMessage(), e);
});
}
}
Example Usage:
withLock(lock, #{
// do some code that needs to be locked.
// throw an exception to test the event handler.
throw new RuntimeException("year is even error");

}, new LogAndContinueExceptionHandler());
I used this idea when exploring another area that might benefit from closures. The EDT thread scheduling methods.

invokeAndWait
public static void invokeAndWait(Runnable r, ExceptionHandler eHandel){
try {
SwingUtilities.invokeAndWait(r);
catch (InterruptedException e) {
eHandel.uncaughtException(e);
} catch (InvocationTargetException e) {
eHandel.uncaughtException(r, e.getCause());
}
}

public class AlertAndContinueExceptionHandler implements ExceptionHandler{
public void uncaughtException(Runnable source, final Throwable e) {
Runnable showMessageBox = #{
JOptionPane.showMessageDialog(null, e.getMessage());
};
if(SwingUtilities.isEventDispatchThread()){
showMessageBox.run();
}else{
SwingUtilities.invokeLater(showMessageBox);
}
}
}
Example Usage:
invokeAndWait(#{
JOptionPane.showMessageDialog(null, "Hello World");
}, new AlertAndContinueExceptionHandler());
simpleSwingWorker -- The simpleSwingWorker method is an attempt to apply closures to the simple case of, "do something off the EDT then do something ON the EDT".
public static void simpleWorker(final Runnable offEDT, final Runnable onEDT){
Thread bGround = new Thread(#{
offEDT.run();
SwingUtilities.invokeLater(onEDT);
});
bGround.start();
}
Example Usage:
simpleWorker(#{
System.out.println("sleep");
Thread.currentThread().sleep(1000);
System.out.println("start");
}, #{
JOptionPane.showMessageDialog(null, "Hello World");
});
I also wrote a blocking version based on invokeAndWait.
public static void simpleBlockingWorker(final Runnable offEDT, final Runnable onEDT){
Thread bGround = new Thread(#{
offEDT.run();
SwingUtilities.invokeAndWait(onEDT);
});
bGround.start();
}

Hay wait a second, invokeAndWait throws exceptions right? And yet the code as it stands compiles without issue. I think I may have found a bug in the FCM prototype.

Some may look at these examples and point out that this type of functionality may really fall into the realm of "control structures". There is some debate in the Java community as to weather the common man should be allowed to write their own control structures. Some prefer to leave this responsibility with the language designers. It is my opinion that once you make this type of code easy, then you already have allowed the common man to make their own control structures. In that case you might as well legitimize the pattern and provide as much support as it possible.

I look forward to the day when there is a Java Control Abstraction (JCA) prototype to play around with.

Wednesday, March 5, 2008

Experimenting with FCM

Stephen Colebourne has a prototype implementation of the FCM closures proposal. I took some time to download and play with the new syntax and functionality.

I tried to focus on some of the functionality FCM provides that other closure proposals do not. Namely method and field literals. I think FCM can help create flexible models for swing components. In the past I've done this using plain reflection but FCM makes things easier.

This is a screenshot of the demo application.

It displays three lists and one table all of which are backed by the same collection of SuperHero beans.

I found that I could apply FCM in one of the first few lines of my demo.
SwingUtilities.invokeLater(#startApp());
This calls my startApp() method on the event dispatch thread. I have to admit that while I'm not a fan of in-lining this was preferable to the traditional method of building a Runnable and passing that to invokeLater.

Here is a very basic ListModel that can expose any public field of an object.
   /**
* Wraps a list of elements and exposes one field to the list model
* interface
*
* @param <E>
*/
private class FCMFieldListModel<T> extends AbstractListModel {

private List<T> backingList;
private Field targetField;

public FCMFieldListModel(List<T> data, Field target) {
backingList = data;
targetField = target;
}

@Override
public Object getElementAt(int index) {
try {
return targetField.get(backingList.get(index));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}
In my case I'm building a list of superheroes and wish to expose the last name field.

FCMFieldListModel<SuperHero> lastListModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#lastName);

The last parameter is the new field literal syntax from FCM. It allows me a type safe way of specifying which field I want to expose.

To create more list models that expose other fields I just need to create another FCMFieldListModel and expose a different field.

FCMFieldListModel<SuperHero> listModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#firstName);

Now most of the time a bean will not expose a field. Instead getter/setter methods are used to expose this information. FCM has method literals as well as field literals. The code for a FCMMethodListModel is very much like FCMFieldListModel but it takes a Method reference instead of a field refrence.

/**
* Wraps a list of elements and exposes one method to the list model
* interface
*
* @param <E>
*/
private class FCMMethodListModel<E> extends AbstractListModel {

private List<E> backingList;
private Method targetMethod ;

public FCMMethodListModel(List<E> data, Method target) {
backingList = data;
targetMethod = target;
}

@Override
public Object getElementAt(int index) {
try {
Object item = backingList.get(index);
return targetMethod.invoke(item);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}
Basically this lets you tell the list model which method of your bean to call to represent your bean in the list.

Finally I used this same technique to build a table model.
FCMTableModel<SuperHero> superTableModel = new FCMTableModel<SuperHero>(heroes,
SuperHero#getFirstName(), SuperHero#getLastName(),
SuperHero#getHeroName(), SuperHero#getFirstAppearance());

The constructor takes a list of SuperHeroes and a variable list of methods to use as columns. This code is all it takes to populate the table seen in the center of the screenshot.

The first appearance column of the super hero table is a date without a day. I decided to use an anonymous inner method to implement a cellrendrer to format the date.
TableColumn dateColumn = superHeroTable.getColumn(SuperHero#getFirstAppearance().getName());

// in-line cell renderer for the date column of the superhero table
dateColumn.setCellRenderer(#(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
if(isSelected){
dateRenderer.setBackground(UIManager.getColor("Table.selectionBackground"));
}else{
dateRenderer.setBackground(UIManager.getColor("Table.background"));
}
dateRenderer.setText(sdfDateColumn.format((Date) value));
return dateRenderer;
});
Overall I have to say I like FCM. Even in it's incomplete state I feel it's still a step forward. The method and field literals were very convenient and useful. I can see myself creating generalized adapter classes around this functionality. As I said before I'm not a fan of in-lining code. I tend not to in-line inner classes either. But the anonymous inner method syntax seemed straight forward enough. Also I much prefer using the # syntax to pass method to invokeLater.

My examples involved a bean and it's associated methods. Yet there is no way currently to specify that a method used as a parameter come from any specific class. It certainly would be an error to pass a FCMMethodListModel System.out#println(Object). I think this is one of the items on the list of things to do for FCM but I'm not certain.

I've made the source code for this demo available on google docs. Just remember that you need the prototype FCM implementation to run it.

Finally I'd just like to thank
Stephen for all his hard work in creating this prototype. It's been fun to experiment with it.

Note:
This is demo level code. It was written to play around with FCM and a such the models are not as robust as they could be. Their job is to adapt an unchanging list of beans using FCMs method literals. I will probably revisit FCMTableModel at some point to show how it could be enhanced. As it stands now they have no support for events. Also I'm not sure a cell renderer was a good choice for an anonymous inner method example. If you read the javadoc for DefaultTableCellRenderer it talks about overriding some of the JLabel methods for performance reasons.

Thursday, August 2, 2007

API changes

The icon demo was a great experience, but, it did bring up some API issues.

First the getScaledInstance() call in the original code. I getScaledInstance() because it's one line and rather self documenting. It didn't get in the way by adding any complexity. The alternative would be to use a BufferedImage and a Graphics object. The best quality approach from Chris Campbell's article was a lot more code then I wanted to add. This demo is about Icons after all not Java2D. In the end I compromised on about 8 lines of code to do a simple bilinear downscaling. I think a more robust version of this faster method of resizing should be packaged up in a nice neat single call.

Something like this ..

public static BufferedImage BufferedImage.getScaledImage(BufferedImage src, width, height,
Object hint, boolean multipass);

I'm not sure if BufferedImage is the correct place for it or not.

Also while SwingWorker is very useful I really hate having to return null at the end of doInBackground(). I wish there was an "IntermediateSwingWroker" that just didn't return anything from doInBackground().

Other then that things went smoothly. I'm glad my changes had zero impact on Java Web Start.

Wednesday, August 1, 2007

I got published!

My first post on this blog was complaining about the current state of the icon demo app from the Java tutorial page. I even wrote some replacement code. It received a lot more attention then I ever thought was possible. I got some great comments, Mikael Grev (of MiG Layout fame), blogged about it on javalobby and finally I was contacted by Sharon Zakhour of Sun. She asked if they could include my code in the tutorial. I was very happy to say yes. I revised my code a little more, helped rewrite some of the page and submitted my code and documentation to Sharon. It went through an engineering review. There was some discussion about my usage of Image.getScaledInstance() and a tweak was added to use the resizing strategy put forth in The Perils of Image.getScaledInstance(). All in all it was an enjoyable experience. And now my code has actually been pushed to the web. It's now officially part of the How to Use Icons section of the Java tutorial.

Would I do it again? Yes, absolutely. Everyone at sun was great.

Wednesday, July 18, 2007

Reworking the reworking of the Icon demo

Java.net posted an article about the rewriting of some of the demo code in the java tutorial.

http://blogs.sun.com/thejavatutorials/entry/reworking_the_icondemo

I was not pleased with the overall quality of this "reworked" demo code. It turns out I'm not alone. Not to be one to criticize and not contribute I am posting my own revision. I'm sure someone can pick my code apart too, but I feel it's better then what sun has provided.

As far as I'm concerned demo code should do three things:
  1. Focus on the topic
  2. Be informative
  3. Exemplify best practices
To that effect I redesigned the demo a little bit. Instead of "Next" and "Previous" buttons I build a toolbar that has thumbnails of each image. This gives us the opportunity to make more Icons, which of course is the point. I had debated removing the background SwingWorker that loads the images. It just doesn't seem to be necessary to talk about that in the icon demo. In the end the "best practice" idea won out and I built a new SwingWorker that populates the buttons and creates the images and the thumbnails. Some of you more experienced Swing programmers may notice I call getScaledInstance() to create the thumbnail. I am aware that Chris Campbell has a blog entry called The Perils of Image.getScaledInstance(). In this demo though we are not resizing an image in a paint method that will be called lots of times, we do it one per image in a background thread. Performances wise I don't think it's an issue.

I have to admit I'm new to the JDK6 version of SwingWorker. I don't really like the use of Void in the parameters because I have to return null at the end of doInBackground(). The thing is all the work is done in the calls to process.

Also I've never done a webstart application so I'm not sure if I removed anything important to webstart.

All in all I think my demo more readable and concise. With spacing and javadoc comments it weighs in around 180 lines. The original was about 350 lines of code, and had almost no comments. So here is the code in all it's glory. I would gladly accept any feedback people have on how to make it even more clear for a beginner.



import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

/**
 * Reworking of the IconDemoApp from the java tutorial.
 *
 * IconDemoApp.java requires the following files: <br>
 * The following files are copyright 2006 spriggs.net and licenced under a
 * Creative Commons Licence (http://creativecommons.org/licenses/by-sa/3.0/)
 * <br>
 * images/sunw01.jpg <br>
 * images/sunw02.jpg <br>
 * images/sunw03.jpg <br>
 * images/sunw04.jpg <br>
 * images/sunw05.jpg <br>
 */
public class IconDemoApp extends JFrame {

    /**
     * Hashmap to store the icons used in this example. The goal is to only load
     * them from the disk once.
     */
    private HashMap<String, ImageIcon> iconCache;
    private HashMap<String, ImageIcon> thumbnailCache;

    private JLabel photographLabel;
    private JToolBar buttonBar = new JToolBar();

    private String imagedir = "images/";

    /**
     * List of all the descriptions of the image files. These correspond one to
     * one with the image file names
     */
    private String[] imageCaptions = { "Original SUNW Logo", "The Clocktower",
            "Clocktower from the West", "The Mansion", "Sun Auditorium" };

    /**
     * List of all the image files to load.
     */
    private String[] imageFileNames = { "sunw01.jpg", "sunw02.jpg",
            "sunw03.jpg", "sunw04.jpg", "sunw05.jpg" };

    /**
     * Main entry point to the demo. Loads the Swing elements on the "Event
     * Dispatch Thread".
     *
     * @param args
     */
    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                IconDemoApp app = new IconDemoApp();
                app.setVisible(true);
            }
        });
    }

    /**
     * Default constructor for the demo.
     */
    public IconDemoApp() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Icon Demo: Please Select an Image");

        // A label for displaying the pictures
        photographLabel = new JLabel();
        photographLabel.setVerticalTextPosition(JLabel.BOTTOM);
        photographLabel.setHorizontalTextPosition(JLabel.CENTER);
        photographLabel.setHorizontalAlignment(JLabel.CENTER);
        photographLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        // we add glue on two sides so that when we add stuff in between later
        // it will be centered
        buttonBar.add(Box.createGlue());
        buttonBar.add(Box.createGlue());

        add(buttonBar, BorderLayout.SOUTH);
        add(photographLabel, BorderLayout.CENTER);

        setSize(400, 300);
        // this centers the frame on the screen
        setLocationRelativeTo(null);

        loadimages.execute();
    }

    /**
     * SwingWorker class that loads the images a background thread and published
     * when a new one is ready to be displayed.
     *
     * We use Void as the first SwingWroker param as we do not need to return anything from do in background.
     */
    private SwingWorker<Void, String> loadimages = new SwingWorker<Void, String>() {

        /**
         * Creates full size and thumbnail versions of the target image files.
         */
        @Override
        protected Void doInBackground()
                throws Exception {

            iconCache = new HashMap<String, ImageIcon>();
            thumbnailCache = new HashMap<String, ImageIcon>();

            for (int i = 0; i < imageCaptions.length; i++) {
                ImageIcon icon;
                icon = new ImageIcon(IconDemoApp.class
                        .getResource((imagedir + imageFileNames[i])));
                iconCache.put(imageCaptions[i], icon);
                thumbnailCache.put(imageCaptions[i], new ImageIcon(icon
                        .getImage().getScaledInstance(32, 32,
                                Image.SCALE_AREA_AVERAGING)));
                publish(imageCaptions[i]);
            }
            // unfortunately we must return something, and only null is valid to return when the return type is void.
            return null;
        }

        /**
         * Process all loaded images.
         */
        @Override
        protected void process(List<String> chunks) {
            for (String caption : chunks) {
                JButton thumbButton = new JButton(thumbnailCache.get(caption));
                thumbButton.setToolTipText(caption);
                thumbButton.addActionListener(new ThumbnailActionListener(
                        caption));
                // add the new button BEFORE the last glue
                // this centers the buttons in the toolbar
                buttonBar.add(thumbButton, buttonBar.getComponentCount() - 1);
            }
        }
    };

    /**
     * changes the currently displayed image
     *
     * @param caption -
     *            the caption is also the key
     */
    private void setCurrentImage(String caption) {
        photographLabel.setIcon(iconCache.get(caption));
        photographLabel.setToolTipText(caption);
        setTitle("Icon Demo: " + caption);
    }

    /**
     * Action listener that shows the image specified in it's constructor. For
     * use on the thumbnail buttons.
     */
    private class ThumbnailActionListener implements ActionListener {
        private String imageCaption;

        public ThumbnailActionListener(String caption) {
            imageCaption = caption;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setCurrentImage(imageCaption);
        }
    };

}