Jul 05

Subversion: Compile Subversion 1.8 on Mac OS 10.8 or 10.9

To compile Subversion 1.8 on Mac OS 10.8 (Mountain Lion) only requires the compilation of one dependency. Prior to 1.8 Subversion used neon for HTTP requests. It now uses Serf. If you access any repositories via HTTP you must first download and compile Serf.

If you compile Subversion without Serf being present and then try to access a repository via HTTP you get an error that looks something like this:

svn: Unrecognized URL scheme for http://www.example.com/svn/some_respository

Compiling Serf

First you need to download Serf which can be downloaded from http://code.google.com/p/serf/downloads/list. I used version 1.2.1 which was the most recent at the time I compiled it.

Generally compiling something is as easy as ./configure && make && sudo make install; however, for some reason Serf tries to use the wrong compiler by default. I am sure a C programmer could explain why; however, I am not one so I won’t attempt to explain. I will just tell you how to fix it. If you try to run “./configure” you will get the error message:

checking for gcc… /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.8.xctoolchain/usr/bin/cc
checking whether the C compiler works… no
configure: error: in `/Users/mjparme/temp/serf-1.2.1′:
configure: error: C compiler cannot create executables
See `config.log’ for more details

To fix this you need to create a symbolic link to point it at the correct compiler, so execute this command:

sudo ln -s /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.8.xctoolchain

For Mavericks (10.9) this symbolic link should be

sudo ln -s /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.9.xctoolchain

Now you can run ./configure with no errors.

  1. Donwload Serf http://code.google.com/p/serf/downloads/list
  2. Unzip the downloaded file: unzip serf-1.2.1.zip (or “tar xvfz serf-1.2.1.tar.bz2″ if you downloaded the bzip one)
  3. cd serf-1.2.1
  4. Execute: ./configure && make -j 5 && sudo make install

Note that the value you pass for the -j parameter should be number of cores + 1 (this is the general consensus and my totally unscientific benchmarking supports the consensus). So if you have a dual-core machine, pass 3, quad-core pass 5, etc.

Also note that newer versions of the tar command can unzip files compressed with bzip2 as well as gzip with the “z” option.

Compile Subversion 1.8

Now since the Serf stuff is taken care of you can compile Subversion 1.8 that includes HTTP support like you would most any other app written in C.

  1. Download the source here: http://subversion.apache.org/download/
  2. Unzip the downloaded file: unzip subversion-1.8.0.zip (or “tar xvfz subversion-1.8.0.tar.gz” or “tar xvfz subversion-1.8.0.tar.bz2″ depending on which one you downloaded)
  3. cd subversion-1.8.0
  4. ./configure –with-serf=/usr/local/serf && make -j 5 && sudo make install

By default Subversion is installed in /usr/local/bin. Note that Mac OS 10.8 comes with subversion 1.6.18 installed in /usr/bin. To insure your compiled version is the one executed make sure /usr/local/bin appears in your PATH before /usr/bin.

So if you are using bash as your shell, add this to .bashrc in your home directory:

PATH=/usr/local/bin:$PATH
export PATH

Jul 03

Weblogic: Grails index.gsp not found

If you try to deploy a Grails application to Weblogic and try to go to “/” in the app you will get the message:

“/index.gsp” not found.

This definitely affects Weblogic 9. and 10.x. I am unsure if it is a problem with later versions. The fix is a simple addition to the UrlMappings.groovy file. Add the line:

"/index.gsp"(view:"/index")

So that it looks like this:

class UrlMappings {
	static mappings = {
		"/$controller/$action?/$id?"{
			constraints {
				// apply constraints here
			}
		}

		"/"(view:"/index")
		"500"(view:'/error')
        "/index.gsp"(view:"/index")
	}
}

See: 

http://jira.grails.org/browse/GRAILS-8767

Jul 03

Grails: Deploy Grails 2.x or newer application to Weblogic 9

If you try to deploy a Grails application built with Grails 2.0 or greater to Weblogic 9.0 it will fail. There are two things you need to do to get a Grails 2.0 application to deploy to Weblogic 9. These occur because of Weblogic 9′s use of Java 1.5.

As an overview the 2 things you need to do are:

  1. Change the XML schema declaration in the generated web.xml file to use Servlet specification 2.4 rather than 2.5
  2. Put the JAXB jars in the lib folder of the project

Change XML schema declaration of web.xml

Starting with Grails 2.0 the XML Schema declaration in web.xml is for Servlet spec 2.5:

<web-app version=”2.5″  metadata-complete=”true” xmlns=”http://java.sun.com/xml/ns/javaee” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd”>

Your app will not deploy to Weblogic 9 with this declaration in your web.xml. You will get an exception that looks like this:

[HTTP:101064][WebAppModule(ivrtester:ivrtester.war)] Error parsing descriptor in Web appplication weblogic.application.ModuleException: Unmarshaller failed at weblogic.servlet.internal.WebAppModule.loadDescriptor(WebAppModule.java:781) at weblogic.servlet.internal.WebAppModule.prepare(WebAppModule.java:272) at weblogic.application.internal.flow.ScopedModuleDriver.prepare(ScopedModuleDriver.java:176) at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:93) at weblogic.application.internal.flow.DeploymentCallbackFlow$1.next(DeploymentCallbackFlow.java:360) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:56) at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:46) at weblogic.application.internal.BaseDeployment$1.next(BaseDeployment.java:615) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26) at weblogic.application.internal.BaseDeployment.prepare(BaseDeployment.java:191) at weblogic.application.internal.DeploymentStateChecker.prepare(DeploymentStateChecker.java:147) at weblogic.deploy.internal.targetserver.AppContainerInvoker.prepare(AppContainerInvoker.java:61) at weblogic.deploy.internal.targetserver.operations.RedeployOperation.createAndPrepareContainer(RedeployOperation.java:98) at weblogic.deploy.internal.targetserver.operations.RedeployOperation.doPrepare(RedeployOperation.java:118) at weblogic.deploy.internal.targetserver.operations.AbstractOperation.prepare(AbstractOperation.java:217) at weblogic.deploy.internal.targetserver.DeploymentManager.handleDeploymentPrepare(DeploymentManager.java:718) at weblogic.deploy.internal.targetserver.DeploymentManager.prepareDeploymentList(DeploymentManager.java:1185) at weblogic.deploy.internal.targetserver.DeploymentManager.handlePrepare(DeploymentManager.java:247) at weblogic.deploy.internal.targetserver.DeploymentServiceDispatcher.prepare(DeploymentServiceDispatcher.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentReceiverCallbackDeliverer.java:157) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer.java:12) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer$1.run(DeploymentReceiverCallbackDeliverer.java:45) at weblogic.work.ServerWorkManagerImpl$WorkAdapterImpl.run(ServerWorkManagerImpl.java:518) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209) at weblogic.work.ExecuteThread.run(ExecuteThread.java:181) Caused by: com.bea.xml.XmlException: failed to load java type corresponding to e=web-app@http://java.sun.com/xml/ns/javaee at com.bea.staxb.runtime.internal.UnmarshalResult.getPojoBindingType(UnmarshalResult.java:325) at com.bea.staxb.runtime.internal.UnmarshalResult.determineTypeForGlobalElement(UnmarshalResult.java:292) at

To fix this the declaration needs to be changed to a Servlet spec 2.4 declaration. However, by default you can’t see the web.xml that Grails packages into the war file. This web.xml file is included in the templates, so to get it execute:

grails install-templates

This will put the templates under the src/ directory. The web.xm file is found at src/templates/war/web.xml edit web.xml and change the opening web-app tag to:

<web-app xmlns=”http://java.sun.com/xml/ns/j2ee” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd” version=”2.4″>

When you do a grails war this web.xml will be used and this fixes the first deployment problem.

Put JAXB in the lib/ directory

The next problem is that Weblogic 9 requires Java 1.5 which does not include JAXB which wasn’t included in the JDK until Java 1.6 (in Update 3 if I recall correctly). Starting with Grails 2.0 JAXB appears to now be a required dependency (or it always was but Grails just stopped including it with Grails since it is included in Java 1.6 now).

If you do not include JAXB in lib/ you will get an exception that looks like this:

weblogic.application.ModuleException:
at weblogic.servlet.internal.WebAppModule.startContexts(WebAppModule.java:891)
at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:333)
at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:204)
at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26)
at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:60)
Truncated. see log file for complete stacktrace
java.lang.InternalError: erroneous handlers
at org.hibernate.validator.xml.ValidationXmlParser.parseValidationXml(ValidationXmlParser.java:60)
at org.hibernate.validator.engine.ConfigurationImpl.parseValidationXml(ConfigurationImpl.java:252)
at org.hibernate.validator.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:143)
at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:111)
at org.hibernate.cfg.beanvalidation.TypeSafeActivator.getValidatorFactory(TypeSafeActivator.java:380)
Truncated. see log file for complete stacktrace

This one is actually quite easy to fix. Just download JAXB from https://jaxb.java.net, unzip it and copy jaxb-api.jar, jaxb-impl.jar, jaxb-xjc.jar, and jaxb1-impl.jar to the lib/ directory in your project. Any jars in the lib/ directory automatically get added to WEB-INF/lib in the generated war file.

You could alternatively try to get JAXB from IVY. For some reason I remember having issues with this working. However, I can’t recall the exact problem I had right now. So you can try adding this to Build.config in the dependencies closure. You should of course change the version numbers to the one you want.

runtime ‘com.sun.xml.bind:jaxb-impl:2.1.12′,
‘com.sun.xml.bind:jaxb-xjc:2.1.12′,
‘com.sun.xml.bind:jaxb1-impl:2.0.3′

You only need to do one or the other. Either put the jars directory in lib/ or try using IVY.

This should fix the final problem with getting a Grails 2.x app to deploy to Weblogic. I have used this to deploy a Grails 2.0.1 and Grails 2.2 application to Weblogic 9.

Aug 30

Swing: Composition (Has-A) vs Inheritance (Is-A)

Introduction

Even a beginning object orientated developer probably knows that when possible you should favor Composition over Inheritance. Some people may also know this as the difference between Has-A (Composition) and Is-A (Inheritance). Annoyingly, for whatever reason, developers don’t seem to apply this principle when writing Java Swing code. Before we cover that let’s have a little composition vs. inheritance primer or recap whatever the case may be for your level of experience.

Composition vs. Inheritance Primer/Recap

It is generally better not to sub-class and instead have a class that has other classes as properties and offers methods to control the behavior of those owned classes. That is probably a poor description so to illustrate the concept let’s consider an example. Let’s say you need to implement a caching class for some data that is expensive performance-wise to retrieve. There are two ways to accomplish this. You could extend a collection like HashMap and then your cache is a HashMap with some custom methods to manipulate the cache. The other way would be to create a class that has a instance of HashMap as a property and then offers methods to manipulate that HashMap. From the description it may sound like these are very similar. However, the implementation and consequences are vastly different. I will let the following examples illustrate.

Example of Composition (Has-A)

public class Cache {
    private Map<String, String> cache;

    public Cache() {
        this.cache = new HashMap<String, String>();
    }

    //Methods to manipulate cache here
}

Example of Inheritance (Is-A)

public class Cache extends HashMap<String, String> {
    public Cache() {
    }

    //Methods to manipulate cache here
}

I don’t think you will find many people that could argue with a straight face that implementing this with inheritance is the preferred way. In this example using composition is clearly the better design.

Apply Composition Over Inheritance to Java Swing Code

There is no reason to not apply the same preference for composition to Swing code. Yet, in my experience it is much more common (practically universal) for Swing code to be implemented with inheritance. I believe this is because all of the Swing example code in the Swing Tutorial shows inheritance rather than composition. However, tutorial code is meant to be a quick example of the demonstrated component and not production quality code. Here is an example of what you most certainly will see if you develop with Swing:

public class ButtonPanel extends JPanel {
    public ButtonPanel() {
        this.add(new JButton("Button1"));
        this.add(new JButton("Button2"));
        this.add(new JButton("Button3"));
    }
}

If you are doing it this way you are doing it wrong. There is no flexibility here. Someone that wants to reuse your ButtonPanel is stuck using it the way you lay it out. What if another developer wants all the functionality of the ButtonPanel but they want the buttons to be stacked vertically but your layout lays them out horizontally? It would make much more sense for ButtonPanel to not be a JPanel and instead have a JPanel with getters for the JPanel and the JButtons. This would let someone reuse ButtonPanel much more easily.

I have a full example here. This example consists of two classes and is a fully functioning Swing application. Note, that I do not inherit JPanel or JFrame instead I have classes that have JPanels and JFrames. The advantage here is that UrlEntryPanel can easily be reused. It offers a default layout method which returns a panel. However, anyone using this class is free to ignore that method and instead use the getters for the buttons and put them in a container of their choice however they need them laid out. Yet they still get all of the functionality of the UrlEntryPanel.

public class UrlDemo {
    private JFrame topLevelFrame;

    public UrlDemo() {
        //Do any non-GUI initialization here
    }

    public void createGui() {
        //GUI initialization goes here
        this.topLevelFrame = new JFrame("Super Duper URL Application");

        UrlEntryPanel panel = new UrlEntryPanel();
        this.topLevelFrame.add(panel.getDefaultLayout(), BorderLayout.CENTER);
        this.topLevelFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent ev) {
                System.exit(0);
            }
        });

        this.topLevelFrame.pack();
        this.topLevelFrame.setVisible(true);
    }

    public static void main(String[] args) {
        final UrlDemo demo = new UrlDemo();

        Runnable runnable = new Runnable() {
            public void run() {
                demo.createGui();
            }
        };

        EventQueue.invokeLater(runnable);
    }
}
public class UrlEntryPanel {
    private JTextField textField;
    private JButton button;
    private JButton exitButton;

    public UrlEntryPanel() {
        this.textField = new JTextField(20);
        this.textField.setText("http://www.lp.org");
        this.button = new JButton(new OpenUrlAction());
        this.exitButton = new JButton(new ExitAction());
    }

    public JButton getButton() {
        return button;
    }

    public JButton getExitButton() {
        return exitButton;
    }

    public JTextField getTextField() {
        return textField;
    }

     public JPanel getDefaultLayout() {
        JPanel panel = new JPanel();
        panel.add(this.textField);
        panel.add(this.button);
        panel.add(this.exitButton);

        return panel;
    }

    private class OpenUrlAction extends AbstractAction {
        public OpenUrlAction() {
            super("Open URL");
        }

        public void actionPerformed(ActionEvent actionEvent) {
            String osName = System.getProperty("os.name");
            String url = textField.getText();
            if (osName.toLowerCase().startsWith("windows")) {
                try {
                    Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            } else if (osName.startsWith("Mac OS")) {
                try {
                    Class fileMgr = Class.forName("com.apple.eio.FileManager");
                    Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[]{String.class});
                    openURL.invoke(null, url);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class ExitAction extends AbstractAction {
        public ExitAction() {
            super("Exit");
        }

        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    }
}

When is it OK to sub-class a Swing Component?

Does this mean you should never extend a Swing component? Nope. You simply need to know when it is appropriate to extend a Swing component. My rule-of-thumb is if you need to override the paintComponent() method of a Component then you need to use inheritance. Otherwise, use composition and make a class that has your needed components. If you aren’t over-riding paintComponent() then you really don’t have a new type of a component and inheritance isn’t appropriate.

Jul 26

Grails: Update One-to-Many Collection

One of the things you frequently have to do is update the many side of a one-to-many relationship. Since Grails of course uses Hibernate the many side is a collection (a Set unless you change it) so when this relationship is updated you need to add new elements to the collection and then remove any element that should no longer be in the collection. Here I am going to show you an easy way to accomplish this. Note, that I will be showing this with Grails domain objects but the same thing will work just fine if you are using Hibernate directly.

In our example we will use an imaginary use case where we want to keep track of clubs and members of the clubs. So we will have the domain objects Club, ClubMember, and Person. There is a one-to-many relationship between Club and ClubMember and a one-to-one relationship between ClubMember and a Person.

I have included the three domain objects below. Notice that I have also included a equals() and hashcode() method. The equals() method is very important to what we are trying to accomplish. Note, that I wrote the equals() method with bad style to save space, I wouldn’t recommend that someone writes code like that.

Club

class Club {
    String name

    static hasMany = [clubMembers: ClubMember]

    static constraints = {
    }

    boolean equals(o) {
        if (this.is(o)) return true
        if (getClass() != o.class) return false
        Club group = (Club) o
        if (name != group.name) return false
        return true
    }

    int hashCode() {
        return name.hashCode()
    }
}

ClubMember

class ClubMember {
    Club club
    Person person

    static belongsTo = [Club]

    static constraints = {
    }

    boolean equals(o) {
        if (this.is(o)) return true
        if (getClass() != o.class) return false
        ClubMember that = (ClubMember) o
        if (person.fullName != that.person.fullName) return false
        return true
    }

    int hashCode() {
        return person.hashCode()
    }
}

Person

class Person {
    class Person {
    String fullName

    static constraints = {
    }

    boolean equals(o) {
        if (this.is(o)) return true
        if (getClass() != o.class) return false
        Person person = (Person) o
        if (fullName != person.fullName) return false
        return true
    }

    int hashCode() {
        return fullName.hashCode()
    }
}

Let’s just assume a user is editing the members of a currently existing Club and that user has submitted a form that contains a multiple select box that contains a list of all the names of people that should now be in the Club. Some of the names might already be in the Club, some names might have been removed, and some of the names might be new members. What is the easiest way to handle this situation? The answer is to take advantage of Collection bulk operations and let the JDK handle it for you. Once you have the right objects in the collection Hibernate will take care of the rest. By default hibernate uses Sets to map collections which are well suited to this; however, these methods can be used on Lists as well (they are part of the Collection interface, not the Set interface). My example is shown as if it was a method in a Service and the id and submitted names have already been pulled from the form parameters by the controller and passed to this method:

Club update(int id, Set<String> fullNames) {
        def club = Club.findById(id)

        def clubMembers = [] as Set
        //Construct ClubMembers by assigning them to the Club we are editing and 
        //looking up an existing person from the DB
        fullNames.each {
            //Assumes the Person being added to the Club already exists in the DB
            def person = Person.findByFullName(it)
            clubMembers << new ClubMember(club: club, person: person)
        }

        //Now we let the collection bulk operations from the JDK and Hibernate 
        //take over. Add all the clubMembers to the Set. This will make this 
        //set contain all previous members of the club and new 
        //members. Right now the Set includes members that might need to be 
        //removed
        club.clubMembers.addAll(clubMembers)

        //Remember that clubMembers contains only the names of people that 
        //should be in the Club now. So retain just those members. Equality 
        //of a ClubMember is determined by the Person's fullName
        club.clubMembers.retainAll(clubMembers)
        club.save()

        return club
}

If you had logSql set to true for the datasource in the Grails Datasource.groovy config file you would see that Hibernate does inserts for any new Person in the club and does deletes for any Person no longer in the Club. Remember that this functionality depends on having a proper implementation of equals() for all the domain objects (something that is a Hibernate best practice anyway).

May 18

Groovy HTML Builder Encoding Issue

I ran into a situation recently, while using a Groovy HTML builder, that took me a while to figure out that it wasn’t my badness causing the issue. The Groovy HTML Builder is actually an XML builder so it will encode ampersands (&) as &amp. This is a problem when building links with parameters. This Groovy code and test case demonstrates the problem.

Code:

class HtmlBuilderBug {
    String buildHtml() {
        def writer = new StringWriter()
        def builder = new groovy.xml.MarkupBuilder(writer)
        builder.a(href: "http://www.example.com?foo=1&bar=2")

        println writer.toString()
        return writer.toString()
    }

    public static void main(String[] args) {
        new HtmlBuilderBug().buildHtml()
    }
}

The output of this code is

<a href="http://www.example.com?foo=1&amp;bar=2">

You will notice that the ampersand parameter separator has been encoded as “&amp” (I can’t put the semi-colon here or WordPress will write it as &). Now this is probably what you want to happen when building XML, but not for HTML.

Testcase that demonstrates the problem:

class HtmlBuilderBugTest extends GroovyTestCase {
    void testBuildHtml() {
        def htmlBuilderBug = new HtmlBuilderBug()
        String output = htmlBuilderBug.buildHtml()
        assertEquals("<a href="http://www.example.com?foo=1&bar=2">", output)
 }
}

Output of the testcase is:

Testcase Output

Now you may be wondering why this is a problem because a browser (at least Safari) was able to correctly follow the link when it was clicked on. In my circumstance I was using the enter key to follow a link from a drop down div (search drop down with arrow navigation and selection by enter key). Once I had the link that the enter key was pressed on I set window.href.location to go to the page, that is what choked on having the & encoded as &amp.

I have a bug report (http://jira.codehaus.org/browse/GROOVY-5460) open to the Groovy project, so we will see if the developers think it is legitimate or if I am just an idiot.

Apr 23

Swing Layout and Sizing

“I set the preferred size of that component why the hell isn’t it sizing it at that size, WTF???”. If you have worked with Swing you have surely heard yourself ask this question. Swing layout and sizing is something that even experienced Java programmers suck at. I used to suck at it, until one day, years ago, I decided to figure out what the hell was going on. It turned out to be quite simple. There are just a few pieces of information you need to know to understand layout and sizing with Swing.

All layout and sizing of components are controlled by the layout managers and each layout manager will accept some hints on how to size components. Some of the layout managers readily accept the hints and try to honor them. Other layout managers seem to take some of your hints under advisement and then ignore others, still other layout managers look at your hints, laugh in your face, and lay out the components randomly (j/k) according to its predefined rules.

The hints you can pass to the layout manager come from three method calls you can call on each component you add to your container. These methods are from the JComponent class and are setPreferredSize(), setMinimumSize(), and setMaximumSize(). The key piece of information to know is that it is up to each layout manager which of these methods it will honor.

I am going to tell you which layout managers honor which hint but first it is probably important to know what layout managers are available. As of Java 1.6 there are 7 layout managers that come with the JDK, they are:

  • BorderLayout (default layout manager of top-level containers, JFrame, JDialog, JApplet, and the kind-of top-level container JInternalFrame. A perfect choice for all top-level containers, don’t change it unless you have some weird one-off use case)
  • GridBagLayout (avoid like the plague, if you don’t take my advice and try to make a go of it you will find this humorous: http://madbean.com/anim/totallygridbag/ )
  • FlowLayout (a nearly worthless layout manager that is the default layout manager of JPanels, do yourself a favor and change the layout manager of your JPanel immediately to something more useful like BoxLayout)
  • CardLayout
  • BoxLayout (IMHO, the most useful layout manager available for all non top-level containers)
  • GridLayout
  • GroupLayout (added in Java 1.6, primarily intended to be used by GUI builders)

Without further ado here is the information you really need to know.

Layout Manager Honors setPreferredSize()? Honors setMinimumSize()? Honors setMaximumSize()?
BorderLayout Partly (see BorderLayout extra notes) No No
GridBagLayout Yes Yes No
FlowLayout Yes No No
CardLayout Sort of (see Card and GridLayout extra notes) No No
BoxLayout X_AXIS–honors preferred width
Y_AXIS–honors preferred height
Yes Yes
GridLayout Sort of (see Card and GridLayout extra notes) No No
GroupLayout Sequential Groups–Yes
Parallel Groups–Sort of (see GroupLayout extra notes)
Sequential Groups–Yes
Parallel Groups–No
Sequential Groups–Yes
Parallel Groups–No

BorderLayout Extra Notes

  • NORTH and SOUTH components — respects component’s preferred height if possible, width is set to full available width of the container
  • EAST and WEST components –  respects component’s preferred width if possible, height is set to full available height of the container
  • CENTER component — gets whatever space is left over, if any

CardLayout and GridLayout Extra Notes

Both CardLayout and GridLayout sizes all of the components in a container it is controlling to be the same size. It searches for the component with the largest preferred width and the component with the largest preferred height and sets all components to that preferred width and height. It should be noted that the maximum preferred height and width DO NOT have to come from the same component.

GroupLayout Extra Notes

Note that GroupLayout is really designed to be used by GUI builders. It can be hand coded but that wasn’t really what it was designed for. Anyway, parallel groups have some odd sizing rules and it is best to read about them straight from Oracle, (from:http://docs.oracle.com/javase/tutorial/uiswing/layout/group.html )

The underlying mechanism works as follows:

1. The size of the parallel group is set to the preferred size of the largest element; so to the preferred size of c4 in our example.
2. Resizable elements are stretched to the size of the group. In our example, only c3 is effectively stretched, the size of c4 already corresponds to the size of the group.

Conclusion

Knowing this information should keep you from beating your head on your keyboard wondering why the hell the components aren’t appearing like you think they should.

As a helpful hint to Swing newbies you can almost always achieve the layout you want by using BorderLayout for your top-level container (the default) and then using nested JPanels with BoxLayout. I rarely use anything other than BoxLayout for my JPanels.

Apr 11

JavaScript Array Iteration Madness

A few days ago I ran across a situation that was making me pull my hair out for half an afternoon. I was simply trying to iterate a JavaScript array to display some validation error messages that came back from the server as JSON. Easy, I thought, should be able to knock that out in about 2.2 seconds. Of course we know that isn’t true or I would have to change the name of the blog to The Good Programmer.

Take a look at this simple JavaScript:

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
    <script type="text/javascript">
        function showErrors() {
            var errors = ["foo", "bar", "somethingElse"];

            var line = ""
            for (error in errors) {
                line = line + error + ' ';
            }

            alert(line);
        }
    </script>
</head>
<body onload="showErrors();">

</body>
</html>

The output of this code should be the browser displaying an alert box with “foo bar something” in it right? Well that is what I thought, but no, the alert box has “0 1 2″ on it. Don’t believe me? Try it for yourself.

Obviously, what is being shown is the array index and not the value at the index. Running this code through the Safari’s excellent Web Inspector and its script debugger clearly shows errors is an Array JavaScript Debugger Screenshot
and not some other data structure I would have to reference further to get to my values.

The solution is to of course use a standard indexed for loop, like so:

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
    <script type="text/javascript">
        function showErrors() {
            var errors = ["foo", "bar", "somethingElse"];

            var line = ""
            for (var i = 0; i < errors.length; i++) {
                line = line + errors[i] + ' ';
            }

            alert(line);
        }
    </script>
</head>
<body onload="showErrors();">

</body>
</html>

Then the output is what you expect.

So the obvious question is why does the for-in loop show the array indices and not the values? If you were expecting an answer then you obviously didn’t read the title of this blog. I don’t have a fscking clue.

Feel free to tell me how bad I am in the comments and to tell me why JavaScript does this.

Apr 03

Java MD5 Hash

How do you get a MD5 hash in Java? Well I am glad you asked! I have somehow managed to create some Java code that does exactly that. Here it is for your cut and pasting pleasure! I have seen some code out there that won’t work correctly if the hashed value starts with zeros (generally because they are using a BigInteger). This version will properly display leading zeroes.

public class Hasher {
    /**
     * Gets the md5 hash of the passed in bytes
     *
     * @param bytes The bytes to determine the md5 hash of
     * @return a String containing the md5 hash string
     */
    public String getMd5Hash(byte[] bytes) {
        Formatter fm = new Formatter();
        MessageDigest digest = null;
        try {
            digest = MessageDigest.getInstance("MD5");
            digest.update(bytes);
            bytes = digest.digest();
            for (byte b : bytes) {
                fm.format("%02x", b);
            }
        } catch (NoSuchAlgorithmException e) {
            System.out.println("Exception: " + e);
        }

        return fm.out().toString();
    }

    public static void main(String[] args) {
        Hasher hasher = new Hasher();
        String hash = hasher.getMd5Hash("what is the md5 hash of this?".getBytes());
        System.out.println("hash = " + hash);
    }
}

If you run this code the output will be:

hash = 49a9884c3121800a49d64a5389691d1a

Comparing this to obtaining the md5 hash from the command-line shows that I actually managed to put together some code that works. This is on Mac OS, although every unix flavor probably has a md5 command-line utility:

bad:~:7> md5 -s "what is the md5 hash of this?"
MD5 ("what is the md5 hash of this?") = 49a9884c3121800a49d64a5389691d1a

This code actually demonstrates another issue I sometimes have with Java. That being that the JDK itself doesn’t always get the checked vs. unchecked exception nonsense correct. Being a bad programmer might mean that I don’t have a clue what I am talking about, but NoSuchAlgorithmException should not be a checked exception! I can’t reasonably be expected to recover from that exception so it should be unchecked. If a unknown algorithm is being passed to getInstance() then that is a programming error, so again, that should be an unchecked exception.