Monday, September 19, 2011

Wicket Form Submission in IE

No matter how much developers hate it, Internet Explorer is here to stay. And one of its fun little idiosyncrasies is how it handles form submission when a user presses [enter] with a text box selected. In most browsers, doing that would cause the form to be submitted as if it had been submitted by pressing the form's first submit, with the submit's name and value in the request. However, IE does not do that. This problem is universal in web development but the result in Wicket is that the Form's onSubmit() method gets called but none of the Button's onSubmit() methods do. If the Button's onSubmit() method is the one that deals with the data that was submitted, the user isn't going to get the result they expect and it's entirely possible that the information they entered may be lost.

In looking for a way to solve this, I ran across Wicket's setDefaultButton() method. However, that really just changes the rendered HTML in a best-effort attempt to override which button is used by browsers that do submit one by default. But since IE doesn't do that to begin with, setDefaultButton() won't have any effect.

Thankfully, IE's form submission problem can be addressed reliably in Java. The approach I took was to override a Form's delegateSubmit() method. Unless you have default form processing turned off, delegateSubmit() is called after validation passes and the models have been updated, but before any of the onSubmit methods are called. The IFormSubmittingComponent (typically a Button of some sort) that submitted the form is passed in as a parameter and this is the perfect opportunity to set one if there isn't one!

public class DefaultingForm extends Form {
    // Constructors go here...

    protected void delegateSubmit(IFormSubmittingComponent submittingComponent) {
        if(submittingComponent==null) {
            submittingComponent = getDefaultButton();
        }
        super.delegateSubmit(submittingComponent);
    }
}

You could set submittingComponent to any value you want but be warned - since that only happens when no submit is sent by the browser, any conditional logic you put in the if-block may only be seen by IE users. That kind of browser-specific behavior could be considered just as bad as the behavior we are trying to remedy! Instead, using the value of getDefaultButton() helps ensure that all browsers will get the same result. Browsers that choose a default button will benefit from the markup changes setDefaultButton() causes. And IE will benefit by having the same button chosen for it. I'm not sure why an approach like this wouldn't be used by Wicket itself. Thoughts?

Thursday, September 8, 2011

Configuring an OpenCV 2 project in Eclipse

I recently picked up a book on OpenCV 2 but all the setup instructions are mostly geared toward developing in either Visual Studio or Qt. Since I mostly do Java development, I would prefer to use Eclipse and I happen to use a Mac at home. And I haven't done much C++ development in Eclipse so I wasn't sure how to get things setup. Setup is actually pretty easy once you know the right values. I've seen some incorrect (maybe just outdated?) info about this on the internet so hopefully this updated info will be useful for people like myself who are new to OpenCV, as well as the C++/Eclipse/Mac combo.

Once you have CDT installed, download the OpenCV source from their site, opencv.willowgarage.com. OpenCV uses a tool called CMake to generate make scripts for the build tool of your choice. Since I'm not very familiar with Xcode, I followed the Linux instructions, where you generate files for make. Using the default build configuration in CMake has worked well for me so far. In a Terminal, navigate to the directory where the Makefile was generated and run "make". Then run "sudo make install" to copy the headers and dylibs where they belong, in /usr/local/include/ and /usr/local/lib/ respectively.

Once those are built and installed, you can creata a C++ project in Eclipse. Then, the trick to getting an OpenCV project to compile and run is to go to the Project Properties and select Settings, under C/C++ Build. On the Tool Settings tab, under MacOS X C++ Linker, select Libraries. Add /usr/local/lib as a library search path. Then add the following as libraries:

  • opencv_calib3d
  • opencv_contrib
  • opencv_core
  • opencv_features2d
  • opencv_flann
  • opencv_gpu
  • opencv_highgui
  • opencv_imgproc
  • opencv_legacy
  • opencv_ml
  • opencv_objdetect
  • opencv_ts
  • opencv_video

Those values correspond to files in the library search path but with the "lib" prefix and ".dylib" extension stripped off. So if your build relies on libfoo.dylib, you would simply add "foo" as a library.

You may also notice that the OpenCV build process creates quite a few files in the library directory. Most of those are aliases/links that allow you to be as specific (or not) as you want about which version to use. A library like opencv_core should point to the most recent version. But the most recent version tomorrow might have a totally different API than it did yesterday, so watch out. The opencv_core.2.3 library points to the most recent 2.3.x release. And for me, as of right now, opencv_core.2.3.1 is that most recent version.

Sunday, March 13, 2011

Configuring Jetty 7 programatically using Wicket and Spring

UPDATE: I don't know why I couldn't get this running before (maybe the example in the documentation was updated?) but I got a Wicket servlet filter application working in an embedded Jetty 7 server that was configured using the existing web.xml. This is all you need prior to calling start().

Server server = new Server();
server.setStopAtShutdown(true);
server.setGracefulShutdown(ALLOWED_SHUTDOWN_TIME);

SocketConnector connector = new SocketConnector();
connector.setPort(8080);
server.addConnector(connector);

WebAppContext context = new WebAppContext();
context.setDescriptor("config/web.xml");
context.setResourceBase("build");
context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);

Anyway, here's the rest of my original post:


I recently spent some time beating my head against a rock, trying to get my Wicket- and Spring-based web application running in an embedded Jetty 7 server. Running an embedded server through the debugger is a convenient way to debug a web application. And if you configure it to run the application from the project's build directory, it also has the added benefit of picking up changes on the fly.

Anyway, although I haven't seen any announcements about it, it seems that Jetty was adopted by (or is at lease now in cahoots with) Eclipse, as of version 7. The problem is that the API has changed a fair amount and updated examples are hard to come by. I've even had trouble with some of the examples on the Jetty site.

However, with a bit of tinkering, I came up with the code below. It adheres to the recommended practice of using the Wicket servlet filter instead of the Wicket servlet. And in this case, I am using the SpringWebApplicationFactory to configure my application through Spring.

public class JettyServer {
 private static int DEFAULT_MAXIMUM_IDLE_TIME = 1000*60*60;
 private static int ALLOWED_SHUTDOWN_TIME = 1000*5;

 public static void main(String[] args) {
  Server server = new Server();
  server.setStopAtShutdown(true);
  server.setGracefulShutdown(ALLOWED_SHUTDOWN_TIME);
  
  SocketConnector connector = new SocketConnector();
  connector.setPort(8080);
  // Settings from the Wicket quickstart archetype...
  connector.setMaxIdleTime(DEFAULT_MAXIMUM_IDLE_TIME);
  connector.setSoLingerTime(-1);
  server.addConnector(connector);

  ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
  servletContextHandler.addServlet(DefaultServlet.class, "/");
  servletContextHandler.setAttribute("contextConfigLocation","classpath:spring/spring-config.xml");
  server.setHandler(servletContextHandler);

  FilterHolder filterHolder = new FilterHolder(new WicketFilter());
  filterHolder.setInitParameter("applicationFactoryClassName", "org.apache.wicket.spring.SpringWebApplicationFactory");
  servletContextHandler.addFilter(filterHolder, "/*", FilterMapping.REQUEST);

  servletContextHandler.getInitParams().put("contextConfigLocation", "classpath:spring/spring-config.xml");
  servletContextHandler.addEventListener(new ContextLoaderListener());

  try {
   server.start();
   System.out.println("Started Jetty.  Press [return] to shutdown.");
   System.in.read();
   System.out.println("Stopping Jetty..."); 
   server.stop();
   server.join();
  } catch (Exception e) {
   e.printStackTrace();
   System.exit(100);
  }
 }
}

Tuesday, February 1, 2011

Using Sass in an Ant build

I recently started using Sass in a side project I've been working on.  It allows me to do two neat things:

  1. Declare my site's colors as variables and re-use them everywhere.
  2. Use only meaningful classes in my markup and style those classes appropriately without copying and pasting a lot of CSS.  For example, if I want an invoice to be displayed in a groupbox, I can put the invoice data inside of a div and assign "invoice" as its class.  Then I can use the Sass mixin feature to say that the invoice class should be styled like a groupbox, whose style I define only once.

However, Sass is a Ruby tool and I'm working in Java.  The project uses Ant for its builds and I wanted a way of compiling my Sass code into CSS in an automated way.  What I ended up doing was using Ant's <apply> task to find all the .sass and .scss files in my project and run them through the Sass processor.  This is what the task ended up looking like:

<target name="sass-compile" depends="properties">
    <apply executable="sass" dest="${project.src.dir}" verbose="true" force="true" failonerror="true">
        <srcfile />
        <targetfile />

        <fileset dir="${project.src.dir}" includes="**/*.scss,**/*.sass" excludes="**/_*" />
        <firstmatchmapper>
            <globmapper from="*.sass" to="*.css" />
            <globmapper from="*.scss" to="*.css" />
        </firstmatchmapper>
    </apply>
</target>

Everything is pretty straight forward with one possible exception.  By convention, partials (shared files that are only intended to be imported by other Sass files) begin with an underscore.  I excluded them from the fileset since they aren't intended to be used directly and my build automatically rolls CSS files into the .war file.

But there's one more import-related caveat.  When used with a mapper, the <apply> task only runs the executable on input files that have been modified more recently than the corresponding destination file.  That's a problem because a Sass file might not have changed but one of its imports could have, in which case it should be re-compiled.  To make sure the build happens every time, I used force="true".