Brain Flush

December 4, 2008

How To Gracefully Recover From File Upload Errors In Grails

Filed under: Software Development & Programming — Tags: , , — Matthias @ 4:45 pm

Problem statement

It is often desirable to let users upload files to your website, such as custom profile images. This is not a trivial task however, since it is prone to errors (e.g. file sizes exceeding maximum values, or certain file types not being allowed by the system).

Grails supports file uploads through its Spring layer, which in turn uses the Apache Commons FileUpload library, a Java based library that brings support for handling HTTP requests of the multipart/form-data MIME type (that’s the format of requests submitted from an HTML form). However, there is one major problem: Any exceptions that occur while uploading files (e.g. due to oversize files) are thrown in a Servlet specific to that library, and the request never reaches any of your Grails controllers. This means that if the user tries to upload a file that is too large, the backend will bail out with an internal exception and the container will display a 500 to the user.

That’s obviously not what we want. Consider for example a signup page where the user can upload a custom profile picture. If the maximum allowed size for that picture is, say, 1MB, we don’t want the user to face a 500, but instead gracefully handle that error and set an error flag on the signup data (e.g. using Spring’s Errors.reject()).

Solution

Grails manages a Spring bean for handling file uploads called ‘multipartResolver’, which is an instance of Spring’s CommonsMultipartResolver. We can set e.g. the maximum allowed size for uploaded files on that bean using the maxUploadSize property (you could do that e.g. in BootStrap.groovy), but that alone does not solve the problem mentioned above. What we want to do is subclass CommonsMultipartResolver, handle any exceptions we do not want to reach the user, and redirect to our own error handling logic. In the case for handling exceeding file sizes, our custom resolver could look like this:

public class CustomMultipartResolver extends CommonsMultipartResolver {

    static final String FILE_SIZE_EXCEEDED_ERROR = "fileSizeExceeded"

    public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) {

        try {
            return super.resolveMultipart(request)
        } catch (MaxUploadSizeExceededException e) {
            request.setAttribute(FILE_SIZE_EXCEEDED_ERROR, true)
            return new DefaultMultipartHttpServletRequest(request, [:], [:])
        }
    }
}

In the controller responsible for processing the request, we can then do as follows:


def handleRequest = {
    def user = new User(params)
    if (request.getAttribute(CustomMultipartResolver.FILE_SIZE_EXCEEDED_ERROR)) {
        user.errors.reject("user.picture.fileSizeTooLarge")
        return [user: user]
    } else {
        // OK, continue processing
    }
}

Of course, since we replaced the implementation of Grails’ multipartResolver, we have to tell Grails we’re using a custom class. We do that via Spring in resources.groovy or resources.xml:

<beans xmlns="...">
    <bean id="multipartResolver" class="com.example.CustomMultipartResolver">
        <!-- limit uploads to 1MB -->
<property name="maxUploadSize" value="1048576" />
    </bean>
</beans>

And that’s it. If the user now uploads an image which is larger than 1MB, the website will display a validation error not visually distinguishable from other validation errors which are actually produced by Spring.

References:
http://blog.bruary.net/2008/03/grails-ajax-file-upload-progressbar.html

Advertisements

July 31, 2008

Grails Quick Tip #2: Getting Access to SessionFactory and MessageSource

Filed under: Software Development & Programming — Tags: , — Matthias @ 9:52 am

Sometimes it is necessary to reach beyond the dynamics of Grails’ finder methods and other injected features, and instead make use of the underlying objects that implement this behavior directly. An example would be the need to access a Hibernate session directly, maybe because  you are writing a service object in plain Java, which means none of the features that rely on the dynamic nature of Groovy are available to you. These include:

  • the current Hibernate session
  • the Spring message source for accessing text in various translations
  • a logger object

All these objects are injected by Grails into your services automatically — that is, if you follow the conventions and are programming in Groovy. If you’re not, you’re pretty much on your own, because the Grails reference guide does not make any mention of these objects and how to access them.

However, I figured they’d be simply Spring beans as well (with the exception of log objects, see below), and due to the consistent conventions in Grails I soon discovered that they are called sessionFactory and messageSource respectively. So in order to access them directly from within a Groovy service object, just do this:

class MyService {
   def sessionFactory
   def messageSource

   def serviceMethod = {
      def session = sessionFactory.getCurrentSession()
      ...
   }
}

That doesn’t work with Java services of course. In that case, go to resources.groovy and add a bean declaration:

 myService(com.example.services.MyService) {
    sessionFactory = ref("sessionFactory")
    messageSource = ref("messageSource")
 }

Note that log objects have to be created manually, because they are not handled by the Spring container. You could for instance create a Log4J object, as shown below. Do not forget to add the setters for the Spring beans, so Grails can set them for you automatically:

import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.springframework.context.MessageSource;

public class MyService {
    // instantiates a Log4J logger object
    private Logger log = Logger.getLogger(getClass().getName());

    // a Hibernate SessionFactory
    private SessionFactory sessionFactory;

    // a Spring MessageSource
    private MessageSource messageSource;

    [...]

    // used by the Spring IoC container to inject the session factory bean
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    // used by the Spring IoC container to inject the message source bean
    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }
}

It may be a good idea to use a class like this as a base class for all your plain Java services, so they can benefit from these objects, too.

May 28, 2008

Grails + Eclipse Quick Tip #1

Filed under: Software Development & Programming — Tags: , — Matthias @ 9:07 am

More Automated Builds

here is a little hint on how to make building your Grails apps from within Eclipse a little less explicit. The goal is to avoid being asked to manually issue a “grails package” after each re-build. Plus, if you followed my hints on how to let Grails and Eclipse compile to the same directory structure, you won’t need to issue “grails clean” anymore. Simply running Project –> Clean… and then running the Grails launcher will suffice for successful compilation and deployment if you follow these instructions.

  1. Go to you project properties and select the Builders entry. You should see two builders: Groovy builder and Java builder.
  2. If you haven’t yet configured an external tools launcher for a “grails package”, click New…, otherwise import that builder
  3. If you have to create the builder, set the following fields:
    • set Location to the folder where the Grails executables reside on your system
    • set Working Directory to ${workspace_loc:/your_project_name}
    • set Arguments to “package”
    • In the Build Options tab, check the fields After a “Clean” and During manual builds
  4. move the new builder to the bottom

I would also advice to create a keyboard shortcut to issue a manual build. For myself, I reassigned Ctrl+B to “Build project” instead of “Build all”.

When you now “Clean” your project and run the “run-app” launcher (I assume you have one!), Eclipse will first build your project and package it for deployment. The packaging is conditional though: if the sources are up-to-date, the new builder will be excluded when launching the app.

May 3, 2008

Grails and Eclipse: Not So Groovy

Filed under: Software Development & Programming — Tags: , , , — Matthias @ 7:16 pm

Grails is a Web application framework for rapid prototyping based on the Groovy scripting language, a Java dialect that compiles to Java byte code. Grails strongest advantage over similar frameworks (e.g. AppFuse, to name a more popular one) is its consequent use of the Convention Over Configuration paradigm, making it almost a no-brainer to set up a full featured Web app using Grails. Grails also relies heavily on the dynamic nature of Groovy to provide useful utility functionality or inject commonly used features such as logging objects and CRUD accessors for domain objects at runtime.

While Grails is an excellent piece of software, it is completely beyond me why apparently almost zero effort has been undergone to make it work flawlessly with one of the most (if not THE) widely used IDEs out there: the Eclipse IDE.

From day one, I had nothing but trouble running Grails applications in Eclipse. There is a document over at grails.org which has instructions for Grails + Eclipse, but it is erroneous and contradictory. While I still suggest to read that document, I will offer solutions to most of the problems you will probably still encounter, even after following that guide.

All instructions below worked for Grails 1.0.2 and Eclipse 3.3 on Ubuntu Linux 8.04.

The Groovy Eclipse Plugin

I assume that the Eclipse Groovy plugin has been installed.

By default, the output directory setting for Groovy compilations is left empty. That means your Groovy files in Eclipse will be compiled to your Grails project root. That is bad, as it confuses Grails. Set it to a different folder, e.g. bin-groovy. In any case, regardless what the Eclipse guide over at grails.org says, leave the “Disable Groovy Compiler Generating Class Files” box unchecked, but check “Disable Check Package Matches Source Directory”. Two reasons: If you check the first one, you won’t be able to debug your Groovy sources, but of course you want that. If you leave the second unchecked, you will get errors related to Groovy’s Spring DSL config in resources.groovy. This error is safe to ignore however.

Make sure to follow the instructions for debugging Groovy applications in Eclipse, too.

Fixing The Class-File Hell: 1st Try

Grails will generate an Eclipse .project file for you after issueing ‘grails create-app’. However, there are several issues with that file. First of all, Grails always compiles your Groovy and Java sources to the directory ~/.grails/<ver>/projects/<proj>/classes, but the generated project file sets the default output folder for Java class files to web-app/WEB-INF/classes. Furthermore, the Groovy plugin may compile to yet another directory, say bin-groovy. In other words, by default an imported Grails app is doomed to make you trouble, because the ‘grails’ command will always compile to a different folder than Eclipse does, and you will end up in a class-file mess where Eclipse will not recognize any changes made by Grails and vice versa.

The solution obviously is to make both Grails, the Eclipse Java compiler and the Groovy Eclipse plugin all compile to the same output directory. However, this is not as easy as it sounds. The best solution would be to tell Grails to compile to a different directory, but I haven’t found a way to do so.

The next best solution would be to create two symbolic links in your project root: bin and bin-groovy, both pointing to the Grails output directory (see above, it’s in your home directory under .grails/) and then tell the Eclipse Java compiler to compile to bin/ (via Project -> Properties -> Java Build Path -> Default Output Folder) and the Groovy plugin to compile to bin-groovy (via Project -> Properties -> Groovy Project Properties -> Groovy compiler output location).

While this solves the class-file hell, it leads to a weird problem: At least for me, I wasn’t able to run my Grails app from its Eclipse launcher anymore without the launch failing with a cryptic error message:

Failed to compile configuration file <proj_path>/grails-app/conf/Config.groovy: No signature of method: groovy.util.ConfigSlurper.parse() is applicable for argument types: (Config)

As of now, no one on the grails-user mailing list was able to say what is causing this, but of course it’s a show stopper, because you won’t be able to debug your application anymore (please note that this only affects Eclipse, your app would still start from the command line using ‘grails run-app’).

The third solution is somewhat ugly, but it works.

Fixing The Class-File Hell: 2nd Try

This approach is as follows: Instead of symlinking from bin and bin-groovy to the Grails output folder, we do it vice versa:

  1. leave the Java output folder to its default value: web-app/WEB-INF/classes
  2. the Groovy class files must also go there, so set a bin-groovy symlink to the same directory
  3. add bin-groovy to the build path: Project -> Properties -> Java Build Path -> Libraries -> Add Class Folder
  4. go to ~/.grails/<ver>/projects/<proj>, remove the classes/ folder and create a symlink “classes” to the full path of the web-app/WEB-INF/classes directory (e.g. ~/workspace/<proj>/web-app/WEB-INF/classes)

What we have done now is to turn around the sym-linkage: Grails will now compile to web-app/WEB-INF/classes. You may ask: What is the difference to the first approach?! Actually, there shouldn’t be any difference, but now you will notice that the ConfigSlurper error is gone, and you can run your app again from within Eclipse. THAT is why we do it (in lack of a better explanation…).

Unfortunately we’re still not 100% done. The reason is: As soon as you issue a ‘grails clean’, the symlink will become invalid and any “creational” follow-up commands like ‘grails compile’ will fail. The problem here is that ‘grails clean’ does not merely empty the ‘classes’ directory, but removes it alltogether. So we need to tell Grails not to remove the directory upon clean, but only its contents. A little background: Whenever you issue a command like this, you are effectively executing a Gant script (that’s the Groovy DSL for Apache Ant). These scripts reside in your Grails installation directory, in the scripts/ subfolder. Find the Clean.groovy script and perform the following changes:

  1. Find the target cleanCompiledSources
  2. Change the first call to Ant.delete to this code:
    Ant.delete(includeEmptyDirs:true) {
       fileset(dir:"${webInf}/classes", includes:"**/*")
    }
  3. Remove/comment the line Ant.delete(dir:classesDirPath)

save the file and exit. When you now run ‘grails clean’, only the content of classes/ will be removed, not the directory itself.

And that’s it!

Grails and Eclipse should now love each other. Ain’t that a happy ending?

Create a free website or blog at WordPress.com.