Connecting to the GAE development server running on another machine

Google App Engine comes with a nice development server located in APP_ENGINE_HOME/bin/dev_appserver.sh

The syntax to run it is:  dev_appserver.sh PATH_OF_YOUR_GAE_EXPLODED_WAR

When you do that, your application is accessible from http://localhost:8080, however connecting to it from another machine using http://YOUR_IP:8080 will probably not work.

If this is your case, then it’s probably because it only listens on your loopback address (127.0.0.1)

[laurent@localhost ~]$ netstat -an | grep 8080
tcp 0 0 ::ffff:127.0.0.1:8080 :::* LISTE

To fix that, launch your dev appserver with “-a 0.0.0.0” and you should be good to go: dev_appserver.sh -a 0.0.0.0 PATH_OF_YOUR_GAE_EXPLODED_WAR

[laurent@localhost ~]$ netstat -an | grep 8080
tcp        0      0 :::8080                     :::*                        LISTEN

… and if it still doesn’t work, check your firewall settings: maybe the access to post 8080 is blocked.

Laurent KUBASKI

How Tomcat and Jetty generate the sessionId

Ever wondered how Tomcat and Jetty generate a unique sessionId ? (I’m talking about the one returned by HttpSession.getId()).

Here is how is works:

Tomcat 7.0.35

For Tomcat, the whole logic is in SessionIdGenerator.generateSessionId()


public class SessionIdGenerator {

/**
 * Generate and return a new session identifier.
 */
public String generateSessionId() {
byte random[] = new byte[16];
// Render the result as a String of hexadecimal digits
StringBuilder buffer = new StringBuilder();
int resultLenBytes = 0;

while (resultLenBytes < sessionIdLength) {
getRandomBytes(random);
for (int j = 0; j < random.length && resultLenBytes < sessionIdLength; j++) {
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
byte b2 = (byte) (random[j] & 0x0f);

if (b1 < 10) buffer.append((char) ('0' + b1));
else buffer.append((char) ('A' + (b1 - 10)));

if (b2 < 10) buffer.append((char) ('0' + b2));
else buffer.append((char) ('A' + (b2 - 10)));

resultLenBytes++;
 }
 }

if (jvmRoute != null && jvmRoute.length() > 0) {
 buffer.append('.').append(jvmRoute);
 }

return buffer.toString();
 }

/**
 *
 */
 private void getRandomBytes(byte bytes[]) {
SecureRandom random = randoms.poll();
 if (random == null) {
 random = createSecureRandom();
 }
 random.nextBytes(bytes);
 randoms.add(random);
 }

 /**
 * Create a new random number generator instance we should use for
 * generating session identifiers.
 */
 private SecureRandom createSecureRandom() {

SecureRandom result = null;

long t1 = System.currentTimeMillis();
 if (secureRandomClass != null) {
 try {
 // Construct and seed a new random number generator
 Class<?> clazz = Class.forName(secureRandomClass);
 result = (SecureRandom) clazz.newInstance();
 } catch (Exception e) {
 log.error(sm.getString("sessionIdGenerator.random",
 secureRandomClass), e);
 }
 }

if (result == null) {
 // No secureRandomClass or creation failed. Use SecureRandom.
 try {
 if (secureRandomProvider != null &&
 secureRandomProvider.length() > 0) {
 result = SecureRandom.getInstance(secureRandomAlgorithm,
 secureRandomProvider);
 } else if (secureRandomAlgorithm != null &&
 secureRandomAlgorithm.length() > 0) {
 result = SecureRandom.getInstance(secureRandomAlgorithm);
 }
 } catch (NoSuchAlgorithmException e) {
 log.error(sm.getString("sessionIdGenerator.randomAlgorithm",
 secureRandomAlgorithm), e);
 } catch (NoSuchProviderException e) {
 log.error(sm.getString("sessionIdGenerator.randomProvider",
 secureRandomProvider), e);
 }
 }

if (result == null) {
 // Invalid provider / algorithm
 try {
 result = SecureRandom.getInstance("SHA1PRNG");
 } catch (NoSuchAlgorithmException e) {
 log.error(sm.getString("sessionIdGenerator.randomAlgorithm",
 secureRandomAlgorithm), e);
 }
 }

if (result == null) {
 // Nothing works - use platform default
 result = new SecureRandom();
 }

// Force seeding to take place
 result.nextInt();

long t2 = System.currentTimeMillis();
 if ((t2 - t1) > 100)
 log.info(sm.getString("sessionIdGenerator.createRandom",
 result.getAlgorithm(), Long.valueOf(t2 - t1)));
 return result;
 }

}

Jetty 8.1.9

For Jetty, the logic is in  AbstractSessionIdManager.newSessionId()

public abstract class AbstractSessionIdManager extends AbstractLifeCycle implements SessionIdManager {
/**
 * Set up a random number generator for the sessionids.
 * <p/>
 * By preference, use a SecureRandom but allow to be injected.
 */
 public void initRandom() {
 if (_random == null) {
 try {
 _random = new SecureRandom();
 } catch (Exception e) {
 LOG.warn("Could not generate SecureRandom for session-id randomness", e);
 _random = new Random();
 _weakRandom = true;
 }
 } else
 _random.setSeed(_random.nextLong() ^ System.currentTimeMillis() ^ hashCode() ^ Runtime.getRuntime().freeMemory());
 }

/**
 * Create a new session id if necessary.
 *
 * @see org.eclipse.jetty.server.SessionIdManager#newSessionId(javax.servlet.http.HttpServletRequest, long)
 */
 public String newSessionId(HttpServletRequest request, long created) {
 synchronized (this) {
 if (request != null) {
 // A requested session ID can only be used if it is in use already.
 String requested_id = request.getRequestedSessionId();
 if (requested_id != null) {
 String cluster_id = getClusterId(requested_id);
 if (idInUse(cluster_id))
 return cluster_id;
 }

// Else reuse any new session ID already defined for this request.
 String new_id = (String) request.getAttribute(__NEW_SESSION_ID);
 if (new_id != null && idInUse(new_id))
 return new_id;
 }

// pick a new unique ID!
 String id = null;
 while (id == null || id.length() == 0 || idInUse(id)) {
 long r0 = _weakRandom
 ? (hashCode() ^ Runtime.getRuntime().freeMemory() ^ _random.nextInt() ^ (((long) request.hashCode()) << 32))
 : _random.nextLong();
 if (r0 < 0)
 r0 = -r0;
 long r1 = _weakRandom
 ? (hashCode() ^ Runtime.getRuntime().freeMemory() ^ _random.nextInt() ^ (((long) request.hashCode()) << 32))
 : _random.nextLong();
 if (r1 < 0)
 r1 = -r1;
 id = Long.toString(r0, 36) + Long.toString(r1, 36);

//add in the id of the node to ensure unique id across cluster
 //NOTE this is different to the node suffix which denotes which node the request was received on
 if (_workerName != null)
 id = _workerName + id;
 }

request.setAttribute(__NEW_SESSION_ID, id);
 return id;
 }
 }

}

Laurent KUBASKI

Rotating photos from mobile devices uploaded to Google App Engine

I’m currently working on a Google App Engine application that allows users to upload photos from their mobile device and then view these photos in a slideshow.

So far, so good, until I realized that some of the uploaded images where sometimes rotated.

What the… ?

This is where I learnt about the concept of EXIF metadata. Long story short: each photo on your mobile device is stored as a jpeg file which contains the photo itself, but also a bunch of extra metadata, like the photo orientation.

This photo orientation depends on your mobile device orientation when the photo is taken. Using the iphone as an example, you basically have 4 possible positions:

  • If the iphone “home” button points downwards when the photo is taken, the photo is rotated 90° counter clockwise (“turned to the left” if you prefer)
  • If the iphone “home” button points upwards when the photo is taken, the photo is rotated 90° clockwise (“turned to the right” if you prefer)
  • If the iphone “home” button points to the left when the photo is taken,  the photo is rotated 180°.
  • If the iphone “home” button points to the right when the photo is taken,  the photo is not rotated (I guess this is how the iphone is supposed to be held when taking pictures).

What I ended up doing is:

  1. User uploads a photo
  2. GAE application determines what the photo orientation is and rotates it accordingly
  3. GAE application stores the rotated photo in the datastore

How to determine the photo orientation

As previously explained, you need to access the photo EXIF metadata and get the value of the “orientation” property.

Luckily, there is a great open-source project that can help us extract this value: it’s called metadata-extractor.

Here is how I used this library:


private int getEXIFOrientation(byte[] bytes) {
int orientation = -1; // default = unknown
 ByteArrayInputStream bis = null;
 try {
 bis = new ByteArrayInputStream(bytes);
 Metadata metadata = ImageMetadataReader.readMetadata(new BufferedInputStream(bis), false);
 ExifIFD0Directory exifDir = metadata.getDirectory(ExifIFD0Directory.class);
 if (exifDir != null) {
 orientation = exifDir.getInt(274); // 274 is the EXIF orientation standard code
 }
 } catch (Exception e) {
 log.warning("Couldn't extract EXIF orientation from image");
 } finally {
 if (bis != null) try {
 bis.close();
 } catch (IOException e) {
 // nothing
 }
 }
 return orientation;
}

How do I know that 274 is the internal code for the orientation EXIF tag ? Because of this link.

The orientation property can have 8 different values, but only 4 of them (in bold) are used:

  • 1: image is Normal-> that’s the orientation value you get when the iphone home button is on the right
  • 2: image is flipped horizontally
  • 3: image is rotated 180° -> that’s the orientation value you get when the iphone home button is on the left
  • 4: image is flipped vertically
  • 5: image is rotated 90° CCW and flipped vertically
  • 6: image is rotated 90° CCW -> that’s the orientation value you get when the iphone home button is upwards
  • 7: image is rotated 90° CW and flipped vertically
  • 8: image is rotated 90° CW -> that’s the orientation value you get when the iphone home button is downwards

How to rotate the image

That’s the easy part: we just use the GAE Image service, more precisely: ImagesServiceFactory.makeRotate().

  • orientation = 1 -> don’t rotate
  • orientation = 3 -> rotate 180° clockwise
  • orientation = 6 -> rotate 90° clockwise
  • orientation = 8 -> rotate -90° clockwise (or 90° counter clockwise if you prefer).

So we end up with:


private byte[] rotateImage(byte[] bytes) {
byte[] result = bytes;
int orientation = getEXIFOrientation(bytes);
int degrees = -1;
if (orientation == 3) degrees = 180;
else if (orientation == 6) degrees = 90;
else if (orientation == 8) degrees = -90;
if (degrees != -1) {
Image img = ImagesServiceFactory.makeImage(bytes);
Transform rotation = ImagesServiceFactory.makeRotate(degrees);
// GAE changes output format from JPEG to PNG while rotating the image if the expected output format is not given:
OutputSettings settings = new OutputSettings(ImagesService.OutputEncoding.JPEG);
settings.setQuality(1);
img = ImagesServiceFactory.getImagesService().applyTransform(rotation, img, settings);
result = img.getImageData();
}
return result;
}

Laurent KUBASKI

Serving dynamic images in Google App Engine

Serving a static image in Google App Engine is as easy as:


<img src="/images/01.jpg">

But what if the image is stored in the datastore as a BLOB ?

There is an official “Serving Dynamic Images with Google App Engine” article in the Google App Engine knowledge base, but it doesn’t explain all the needed steps to accomplish this… and that’s exactly what I’m going to do.

The thing is: the “src” attribute of the HTML “img” tag doesn’t need to be the path of an image on the server filesystem. It can also be the url of a Servlet that will return an image.

So, assuming that you know the id of your image in the datastore, you can have this:


<img src="/serveImage?id=<%=key.getId()%>">

/serveImage is the URI of my ServeImageServlet, as configured in web.xml:


<servlet>
<servlet-name>ServeImageServlet</servlet-name>
<servlet-class>fr.lk.servlet.ServeImageServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>ServeImageServlet</servlet-name>
<url-pattern>/serveImage</url-pattern>
</servlet-mapping>

Now let’s see ServeImageServlet.java:

public class ServeImageServlet extends HttpServlet {

@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String id = req.getParameter("id");
byte[] bytes = new DAO().getImage(Long.parseLong(id));
resp.setContentType("image/jpeg");
resp.getOutputStream().write(bytes);
}
}

As you can see, the “id” request parameter is used to retrieve the image from the datastore (as a raw byte array), and we just directly write it to the response output stream.

Laurent KUBASKI

Apache Commons Javadoc in CHM format

My latest project: the Javadoc for all Apache Commons component in CHM format.

Imagine getting instant access to any class/method Javadoc of any Apache Commons component… well, there you are !

commons.javadoc

 

Grab your copy from here !

Laurent KUBASKI

Java SE Application Design With MVC (with images)

This post is not from me, but since the original one from Oracle’s website (which was written 5 years ago) doesn’t display the images any more, I decided to replicate the post here… including all images.

Original post is from Robert Eckstein, March 2007

What Is Model-View-Controller (MVC)?

If you’ve programmed with graphical user interface (GUI) libraries in the past 10 years or so, you have likely come across the model-view-controller (MVC) design. MVC was first introduced by Trygve Reenskaug, a Smalltalk developer at the Xerox Palo Alto Research Center in 1979, and helps to decouple data access and business logic from the manner in which it is displayed to the user. More precisely, MVC can be broken down into three elements:

  • Model – The model represents data and the rules that govern access to and updates of this data. In enterprise software, a model often serves as a software approximation of a real-world process.
  • View – The view renders the contents of a model. It specifies exactly how the model data should be presented. If the model data changes, the view must update its presentation as needed. This can be achieved by using a push model, in which the view registers itself with the model for change notifications, or a pull model, in which the view is responsible for calling the model when it needs to retrieve the most current data.
  • Controller – The controller translates the user’s interactions with the view into actions that the model will perform. In a stand-alone GUI client, user interactions could be button clicks or menu selections, whereas in an enterprise web application, they appear as GET and POST HTTP requests. Depending on the context, a controller may also select a new view — for example, a web page of results — to present back to the user.

MVC1

Figure1. A Common MVC Implementation

Interaction Between MVC Components

This section will take a closer look at one way to implement Figure 1 in the context of an application in the Java Platform, Standard Edition 6 (Java SE 6). Once the model, view, and controller objects are instantiated, the following occurs:

  1. The view registers as a listener on the model. Any changes to the underlying data of the model immediately result in a broadcast change notification, which the view receives. This is an example of the push model described earlier. Note that the model is not aware of the view or the controller — it simply broadcasts change notifications to all interested listeners.
  2. The controller is bound to the view. This typically means that any user actions that are performed on the view will invoke a registered listener method in the controller class.
  3. The controller is given a reference to the underlying model.

Once a user interacts with the view, the following actions occur:

  1. The view recognizes that a GUI action — for example, pushing a button or dragging a scroll bar — has occurred, using a listener method that is registered to be called when such an action occurs.
  2. The view calls the appropriate method on the controller.
  3. The controller accesses the model, possibly updating it in a way appropriate to the user’s action.
  4. If the model has been altered, it notifies interested listeners, such as the view, of the change. In some architectures, the controller may also be responsible for updating the view. This is common in Java technology-based enterprise applications.

Figure 2 shows this interaction in more detail.

MVC2

Figure 2. A Java SE Application Using MVC

As this article mentioned earlier, the model does not carry a reference to the view but instead uses an event-notification model to notify interested parties of a change. One of the consequences of this powerful design is that the many views can have the same underlying model. When a change in the data model occurs, each view is notified by a property change event and can update itself accordingly. For example, Figure 3 shows two views that use the same data model.

MVC3

Figure 3. Multiple Views Using the Same Model

Modifying the MVC Design

 A more recent implementation of the MVC design places the controller between the model and the view. This design, which is common in the Apple Cocoa framework, is shown in Figure 4.

MVC4

Figure 4. An MVC Design Placing the Controller Between the Model and the View

The primary difference between this design and the more traditional version of MVC is that the notifications of state changes in model objects are communicated to the view through the controller. Hence, the controller mediates the flow of data between model and view objects in both directions. View objects, as always, use the controller to translate user actions into property updates on the model. In addition, changes in model state are communicated to view objects through an application’s controller objects.

Thus, when all three components are instantiated, the view and the model will both register with the controller. Once a user interacts with the view, the events are nearly identical:

  1. The view recognizes that a GUI action — for example, pushing a button or dragging a scroll bar — has occurred, using a listener method that is registered to be called when such an action occurs.
  2. The view calls the appropriate method on the controller.
  3. The controller accesses the model, possibly updating it in a way appropriate to the user’s action.
  4. If the model has been altered, it notifies interested listeners of the change. However, in this case, the change is sent to the controller.

Why adopt this design? Using this modified MVC helps to more completely decouple the model from the view. In this case, the controller can dictate the model properties that it expects to find in one or more models registered with the controller. In addition, it can also provide the methods that effect the model’s property changes for one or more views that are registered with it.

Using the Modified MVC

 This section of the article shows you how to put this design into practice, starting with the model. Suppose that you want to paint some text using a simple display model with five properties. Code Sample 1 shows a simple component that you can use to create such a model.

Code Sample 1

public class TextElementModel extends AbstractModel
{

    private String text;
    private Font font;
    private Integer x;
    private Integer y;
    private Integer opacity;
    private Integer rotation;

    /**
     * Provides the means to set or reset the model to
     * a default state
     */
    public void initDefault() {

        setOpacity(89);
        setRotation(0);
        setText("Sample Text");
        setFont(new Font("Arial", Font.BOLD, 24));
        setX(50);
        setY(50);

    }

    //  Accessors

    public String getText() {
        return text;
    }

    public void setText(String text) {

        String oldText = this.text;
        this.text = text;

        firePropertyChange(
            DefaultController.ELEMENT_TEXT_PROPERTY,
            oldText, text);
    }

    public Font getFont() {
        return font;
    }

    public void setFont(Font font) {

        Font oldFont = this.font;
        this.font = font;

        firePropertyChange(
            DefaultController.ELEMENT_FONT_PROPERTY,
            oldFont, font);
    }

    //  The remaining accessors for properties are omitted.

}

Note that the rest of the accessors follow the standard JavaBeans model, although they are omitted in Code Sample 1. For reference, Code Sample 2 shows the underlying AbstractModel class, which simply uses the javax.beans.PropertyChangeSupport class to register, deregister, and notify interested listeners of changes to the model.

Code Sample 2

public abstract class AbstractModel
{

    protected PropertyChangeSupport propertyChangeSupport;

    public AbstractModel()
    {
        propertyChangeSupport = new PropertyChangeSupport(this);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
        propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

}

The Controller

Between the model and view lies the controller. First, take a look at the code for the abstract controller superclass, as shown in Code Sample 3.

Code Sample 3


public abstract class AbstractController implements PropertyChangeListener {

    private ArrayList<abstractviewpanel> registeredViews;
    private ArrayList<abstractmodel> registeredModels;

    public AbstractController() {
        registeredViews = new ArrayList<abstractviewpanel>();
        registeredModels = new ArrayList<abstractmodel>();
    }

    public void addModel(AbstractModel model) {
        registeredModels.add(model);
        model.addPropertyChangeListener(this);
    }

    public void removeModel(AbstractModel model) {
        registeredModels.remove(model);
        model.removePropertyChangeListener(this);
    }

    public void addView(AbstractViewPanel view) {
        registeredViews.add(view);
    }

    public void removeView(AbstractViewPanel view) {
        registeredViews.remove(view);
    }

    //  Use this to observe property changes from registered models
    //  and propagate them on to all the views.

    public void propertyChange(PropertyChangeEvent evt) {

        for (AbstractViewPanel view: registeredViews) {
            view.modelPropertyChange(evt);
        }
    }

    /**
     * This is a convenience method that subclasses can call upon
     * to fire property changes back to the models. This method
     * uses reflection to inspect each of the model classes
     * to determine whether it is the owner of the property
     * in question. If it isn't, a NoSuchMethodException is thrown,
     * which the method ignores.
     *
     * @param propertyName = The name of the property.
     * @param newValue = An object that represents the new value
     * of the property.
     */
    protected void setModelProperty(String propertyName, Object newValue) {

        for (AbstractModel model: registeredModels) {
            try {

                Method method = model.getClass().
                    getMethod("set"+propertyName, new Class[] {
                                                      newValue.getClass()
                                                  }

                             );
                method.invoke(model, newValue);

            } catch (Exception ex) {
                //  Handle exception.
            }
        }
    }

}

The AbstractController class contains two ArrayList objects, which are used to keep track of the models and views that are registered. Note that whenever a model is registered, the controller also registers itself as a property change listener on the model. This way, whenever a model changes its state, the propertyChange() method is called and the controller will pass this event on to the appropriate views.

The final method, setModelProperty(), employs some magic to get its work done. In order to keep the models completely decoupled from the controller, the code samples in this article have employed the Java Reflection API. In this case, when this method is called with the desired property name, you hunt through the registered models to determine which one contains the appropriate method. Once you find it, you invoke the method using the new value. If the method is not called, thegetMethod() will throw a NoSuchMethodException, which the exception handler ignores, allowing the for- loop to continue.

Code Sample 4 shows the source code for the default controller class. This class consists of only property constants and methods called by the GUI event listeners of the view.

Code Sample 4

public class DefaultController extends AbstractController
{

    public static final String ELEMENT_TEXT_PROPERTY = "Text";
    public static final String ELEMENT_FONT_PROPERTY = "Font";
    public static final String ELEMENT_X_PROPERTY = "X";
    public static final String ELEMENT_Y_PROPERTY = "Y";
    public static final String ELEMENT_OPACITY_PROPERTY = "Opacity";
    public static final String ELEMENT_ROTATION_PROPERTY = "Rotation";

    //  Code omitted

    public void changeElementText(String newText) {
        setModelProperty(ELEMENT_TEXT_PROPERTY, newText);
    }

    public void changeElementFont(Font newFont) {
        setModelProperty(ELEMENT_FONT_PROPERTY, newFont);
    }

    public void changeElementXPosition(int newX) {
        setModelProperty(ELEMENT_X_PROPERTY, newX);
    }

    public void changeElementYPosition(int newY) {
        setModelProperty(ELEMENT_Y_PROPERTY, newY);
    }

    public void changeElementOpacity(int newOpacity) {
        setModelProperty(ELEMENT_OPACITY_PROPERTY, newOpacity);
    }

    public void changeElementRotation(int newRotation) {
        setModelProperty(ELEMENT_ROTATION_PROPERTY, newRotation);
    }

}

The View

This example will have two views displaying the data from the model: a property-editor view and a graphical page view. Both of these are implementations of a JPanel, inserted into either a JDialogor JFrame. The dialog box allows the user to update the values of the model, and the frame panel simply reflects the changes as the final textual display. The author of this article built this example using the NetBeans Swing GUI Builder, formerly referred to as Project Matisse, to design the GUI forms.

Code Sample 5 shows the source code for the property-editor view, the more interesting of the two. The first section is simply devoted to initialization of the components, which for the most part was automatically generated by the NetBeans integrated development environment (IDE) in theinitComponents() method. All of this section is omitted but is present in the downloadable code. Any other initialization that you need to perform — in this case, creating custom models for JSpinnerand JSlider objects or adding DocumentListeners to the JTextField components — is handled in the localInitialization() method.

Code Sample 5

public PropertiesViewPanel(DefaultController controller) {

this.controller = controller;

initComponents();
localInitialization();

}

// ‹editor-fold defaultstate="collapsed" desc=" Local Initialization "›

/**
* Used to provide local initialization of Swing components
* outside of the NetBeans automatic code generator
*/
public void localInitialization() {

opacitySpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
opacitySlider.setModel(new DefaultBoundedRangeModel(100, 0, 0, 100));

rotationSpinner.setModel(new SpinnerNumberModel(0, -180, 180, 1));
rotationSlider.setModel(new DefaultBoundedRangeModel(0, 0, -180, 180));

text.getDocument().addDocumentListener(new DocumentListener() {

public void insertUpdate(DocumentEvent e) {
textDocumentChanged(e);
}

public void removeUpdate(DocumentEvent e) {
textDocumentChanged(e);
}

public void changedUpdate(DocumentEvent e) {
textDocumentChanged(e);
}

});

}

// ‹/editor-fold›

Note that the automatically generated NetBeans IDE code folds in the source code so that the developer can collapse each of these sections when it is not needed:


// ‹editor-fold defaultstate="collapsed" desc=" Local Initialization "›
// ‹/editor-fold›

If you’re using the NetBeans IDE, this practice is highly recommended.

The second section of the PropertiesViewPanel class deals exclusively with the model. In Code Sample 6, a modelPropertyChange() method is called by the controller whenever the model reports a state change.

Code Sample 6


// ‹editor-fold defaultstate="collapsed" desc=" Model Event Handling Code "›

    public void modelPropertyChange(final PropertyChangeEvent evt) {

        if (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_X_PROPERTY)) {
            String newStringValue = evt.getNewValue().toString();
            xPositionTextField.setText(newStringValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_Y_PROPERTY)) {
            String newStringValue = evt.getNewValue().toString();
            yPositionTextField.setText(newStringValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_OPACITY_PROPERTY)) {
            int newIntegerValue = (Integer)evt.getNewValue();
            opacitySpinner.setValue(newIntegerValue);
            opacitySlider.setValue(newIntegerValue);
        } else if
            (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_ROTATION_PROPERTY)) {
            int newIntegerValue = (Integer)evt.getNewValue();
            rotationSpinner.setValue(newIntegerValue);
            rotationSlider.setValue(newIntegerValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_TEXT_PROPERTY)) {
            String newStringValue = evt.getNewValue().toString();
            text.setText(newStringValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_FONT_PROPERTY)) {
            Font f = (Font)evt.getNewValue();
            String fontString = f.getFontName() + " " + f.getSize();
            font.setText(fontString);
            currentFont = f;
        }

        //  Remainder of the code omitted

    }

    // ‹/editor-fold›

Again, this code sample omits portions of the code that are similar to the sections shown.

The final portion consists of the GUI event listeners. Code Sample 7 contains listeners that are called whenever GUI events occur, such as pushing the Change Font button or the Opacityspinner buttons, or resetting the text in any of the text fields. These are largely event listeners that most Swing developers are already familiar with. If you’re using the NetBeans IDE, you’ll see that the IDE can automatically generate many of these using the GUI developer.

Code Sample 7

// ‹editor-fold defaultstate="collapsed" desc=" GUI Event Handling Code "›

    //  Code omitted

    private void yPositionTextFieldFocusLost(java.awt.event.FocusEvent evt) {
        try {
            controller.changeElementYPosition(
                Integer.parseInt(yPositionTextField.getText()));
        } catch (Exception e) {
            //  Handle exception.
        }
    }

    private void yPositionTextFieldActionPerformed(java.awt.event.ActionEvent evt) {
        try {
            controller.changeElementYPosition(
                Integer.parseInt(yPositionTextField.getText()));
        } catch (Exception e) {
            //  Handle exception.
        }
    }

    //  Code omitted -- code for xPosition
    //  is nearly the same as for yPosition.

    private void changeFontButtonActionPerformed(java.awt.event.ActionEvent evt) {

        JFontChooserDialog fontChooser = new
            JFontChooserDialog((Dialog)this.getTopLevelAncestor());
        fontChooser.setSelectedFont(currentFont);
        fontChooser.setVisible(true);

        Font returnedFont = fontChooser.getSelectedFont();
        if (returnedFont != null) {
            controller.changeElementFont(returnedFont);
        }
    }

    private void opacitySliderStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementOpacity((int)opacitySlider.getValue());
    }

    private void rotationSliderStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementRotation((int)rotationSlider.getValue());
    }

    private void opacitySpinnerStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementOpacity((Integer)opacitySpinner.getValue());
    }

    private void rotationSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementRotation((Integer)rotationSpinner.getValue());
    }

    private void textDocumentChanged(DocumentEvent evt) {

        Document document = evt.getDocument();
        try {
            controller.changeElementText(document.getText(0,
            document.getLength()));
        } catch (BadLocationException ex) {
            //  Handle exception.
        }
    }

    // ‹/editor-fold›

Issues With Application Design
Once the application is up and running, you immediately run into a problem. Consider the following chain of events:

  1. One of the Swing components in the view receives a change, presumably from the user action.
  2. The appropriate controller method is called.
  3. The model is updated. It notifies the controller of its property change.
  4. The view receives a change event from the controller and attempts to reset the value of the appropriate Swing components.
  5. The appropriate controller method is called, and the model is updated again.

At this point, any of three different scenarios can occur, depending on what Swing component you use and how robust your model is.

  • The Swing component that prompted the initial change refuses to update itself the second time, noting that its property state cannot be updated again while it is in the process of notifying listeners of the initial state change. This primarily occurs when you use Swing text components.
  • The model notes that the value of the second update matches that of the first, its current value, and refuses to send a change notification. This is always a safe programming practice, and it automatically occurs if you use the PropertyChangeSupport class provided in the java.beans package. However, it does not keep the model from receiving a redundant update.
  • No safeguards are in place on either the model or the Swing component, and the program enters an infinite loop.

This issue occurs because the Swing components are autonomous. For example, what happens if the user presses the up arrow of the JSpinner component in PropertiesViewPanel, incrementing the spinner’s value by one? After the value is updated, a GUI event listener method that is listening for value changes is called, opacitySpinnerStateChanged(), which in turn calls the controller and then updates the appropriate property in the model.

With a traditional MVC design, the view would still contain the previous value, and the change in the model would update the view to the current value. However, there is no need to update the Swing component because it has already reset itself to the correct value — it did so before it even passed an event to the controller.

How do you get around this? One way is to write a mechanism that tells the model or the controller not to propagate a change notification under these circumstances, but this is not a good idea. Remember that more than one view may be listening for changes on the model. If you shut down the change notification for the model, no other listeners, including other views, will be notified of the change. In addition, other components in the same view may rely on the property change notification, with a slider and spinner combination, for example.

Ideally, each Swing component would be aware of its current value and the value that the view is trying to set it to. If they match, no change notifications will be sent. However, some Swing components include this logic, and others do not. One possible solution is to check the incoming changed value of the model against the current value stored in the Swing component. If they are identical, there is no need to reset the value of the Swing component.

Code Sample 8 shows an update of the modelPropertyChange() method to demonstrate this approach.

Code Sample 8

public void modelPropertyChange(final PropertyChangeEvent evt) {

        if (evt.getPropertyName().equals(DefaultController.ELEMENT_X_PROPERTY)) {

            String newStringValue = evt.getNewValue().toString();
            if (!xPositionTextField.getText().equals(newStringValue))
                xPositionTextField.setText(newStringValue);

        }

        //  Remaining code omitted

    }

The final example, which uses two delegate views, is shown in Figure 5. The second delegate makes use of the Java 2D libraries to display the text, which is beyond the scope of this article. However, the source code is relatively easy to follow and is included in the downloadable source code.

Conclusion

MVC is one of the staples of any GUI programmer’s toolkit. This article has shown how to implement a variation of the MVC design using Java SE and the Swing libraries. In addition, it has demonstrated some common issues that programmers may face when using MVC, as well as listed common Swing component events that any Java platform programmer can use when creating a view.

For More Information

Laurent KUBASKI  (originally from Robert Eckstein)

Solving the Dropbox diet challenge

There are some nice programming challenges on the Dropbox website, and today I would like to give a possible solution for the “Dropbox diet challenge”.

The most obvious solution is to compute all possible calories permutations and find the one where the sum of all calories is zero.

The problem with this approach is that you will end up computing useless permutations like [802, 421, 143] (free-lunch + mixed-nuts + orange-juice). This specific example will led you nowhere since all values are positives, which means that the sum cannot possibly be equals to 0.

In the solution I’m describing today, I will split the items in two groups: one with all the items with negative calory values and one with all the items with positive calory values. Using the example on the Dropbox site, we will end up with 2 lists:

  • [-195, -466, -302, -42, -295, -137, -611]: rock-band, coding-six-hours, heavy-ddr-session, …
  • [143, 802, 421, 316, 150]: orange-juice, free-lunch, mixed-nuts…

Then, we are going to compute all the “negative elements permutations”.

  • first the 1-element permutations: [-195], [-466], [-302]…
  • then the 2-elements permutations: [-195, -466], [-195, -302],…
  • then…
  • finally the only existing 7-elements permutation: [-195, -466, -302, -42, -295, -137, -611]

Finally, for each “negative elements permutation”, we are going to compute all the “positive elements permutations” and we are going to compare the current “negative value permutation” with each one of the “positive value permutations” that we have computed: if the sum of the elements in the 2 lists is 0, we are done.

For example, assuming that the current “negative value permutation” is [-466] (coding-6-hours), then we are going to compare this to:

  • [143] : -466+143 is not 0 so we continue
  • [802] : -466+802 is not 0 so we continue
  • [143, 802] : -466+143+802 is not 0 so we continue
  • [143, 421] : -466+143+421 is not 0 so we continue
  • [316, 150] : -466+316+150 is equals to 0 so we have a match !

Now for the super-duper enhancement: assuming that the current “negative permutation” is [-42, -195] which adds to -237. We don’t need to compare this permutation to ALL the possible positive element permutations. Why ? because we already know that a positive element that is greater than 237 will not be part of the final solution. In our example, we will only need to compare [-42, -195] with all possible permutations of [143, 150] (802, 421 and 316 have been discarded).

The only remaining thing that we need to do is to find an algorithm that will compute the permutations we need. I found this great MSDN article by James McCaffrey that offers an easy to understand non-recursive implementation.

Here is the source code for the solution: dropboxDiet (why not a zip file ? because wordpress doesn’t allow uploading zip files! )

Laurent KUBASKI