#312 ✓resolved
Niko Schmuck

Add documentation on proper Blob usage in Play 1.1

Reported by Niko Schmuck | October 20th, 2010 @ 05:05 PM

It would be great if the Play 1.1 documentation (which is a very good reference in general) could elaborate on how to setup a proper blob field in your model class, how it is handled on create, update, and delete cycle (referring to a file). And how to configure the storage mechanism underneath.

In addition it would be nice for Play 1.0 users, on how to best migrate their existing FileAttachment fields to the new Blob way and ensuring the existent files are still referred in the proper way after the migration.

Comments and changes to this ticket

  • Erwan Loisant

    Erwan Loisant October 21st, 2010 @ 12:20 PM

    • Tag changed from binary, blob, documentation to blob, documentation
  • Nicolas Leroux

    Nicolas Leroux December 5th, 2010 @ 08:39 PM

    • State changed from “new” to “confirmed”
    • Assigned user set to “Peter Hilton”
  • Peter Hilton

    Peter Hilton February 6th, 2011 @ 11:54 AM

    I haven’t used Blob fields yet, but file uploads are in the next iteration for my current project, so I should be able to resolve this then.

  • Art McBain

    Art McBain February 10th, 2011 @ 04:44 AM

    The last message in the following Play! Google group thread may be of some use for documenting a proper way to handle deletion of files associated with Blobs. (Only the last message is important, the rest of it is me embarrassing myself for the reason mentioned in the top of that message :P)

    http://groups.google.com/group/play-framework/browse_thread/thread/...

    Hopefully it'll provide an okay solution or starting point. I will certainly be much happier when there's more documentation on handling Blobs. Thank you :)

  • Peter Hilton
  • Peter Hilton

    Peter Hilton April 21st, 2011 @ 05:41 PM

    • State changed from “confirmed” to “inprogress”

    I wasn’t expecting this: it turns out that play.db.jpa.Blob data is stored in a file outside the database, and does not use the java.sql.Blob type with a BLOB in the database.

  • Peter Hilton

    Peter Hilton April 26th, 2011 @ 04:10 PM

    Niko, I've done some experimentation and written up the result: http://www.lunatech-research.com/playframework-file-upload-blob - any suggestions for which parts of this should be in the Play documentation?

  • Niko Schmuck

    Niko Schmuck April 27th, 2011 @ 11:20 AM

    Thanks, Peter for putting together a tutorial about the proper blob usage.

    Here are some comments and suggestions:

    • when showing the code for the addUser action, explain on what is happening in the background (file is copied, named with UUID and put in the attachment directory)
    • the id attribute on the input element seems not necessary
    • add input element for the User.name property
    • show how to specify a different path for attachments (set attachments.path in application.conf)
    • in userPhoto action have a guard if user is not in the DB: notFoundIfNull(user)
    • when explaining the deletion of the photos which do not any longer exist, you could make use of convenient JPA interceptors: annotate a method with @PreUpdate (on update) @PreRemove (when deleting a user entity) and therein delete the old file
    • in the action downloadUserPhoto you could simplify the code by using a variant of renderBinary(java.io.File file, String filename) and therefore avoiding to set the header manually

    For the Play documentation, I would like to suggest to shrink your example down to the necessary part of uploading from the template and the controller to save / deliver the binary back to the client (you might also spend some words on the configuration aspects resp. conventions). A nice goodie would be on howto implement a different attachment save strategy, for example having a directory nesting instead of storing all files flat in the same directory.

  • Peter Hilton

    Peter Hilton April 27th, 2011 @ 04:18 PM

    Niko, thanks for the many good suggestions. I'll update my text and examples next.

  • Peter Hilton

    Peter Hilton April 28th, 2011 @ 07:07 PM

    Niko, I’ve updated the article with your suggestions, and credited you at the bottom.

    I just had a go at changing the save strategy. Unfortunately, play.db.jpa.Blob is not designed for extension (e.g. private instead of protected fields), so I did it on a copy of play.db.jpa.Blob, which is a bit of a hack.

    Anyway, I made a DateBlob class that saves files in a year/month/day/ sub-directory as follows.

    1. Make a copy of play.db.jpa.Blob.
    2. Rename the UUID field to path, because it’s going to store a relative path including the UUID.
    3. Replace the set method with this:
    public void set(InputStream is, String type) {
       final String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
       final File dateDirectory = new File(getStore(), datePath);
       dateDirectory.mkdirs(); // create today’s directory, if needed
       this.path = datePath + Codec.UUID();
       this.type = type;
       IO.write(is, getFile());
    }
    
  • Art McBain

    Art McBain May 1st, 2011 @ 09:33 PM

    As to the handling of orphans, I think an inverted approach to the one you suggested (scanning the directory in a Job) might scale better. It does require an extra database table, but I believe would work like this on update or deletion:

    1) Pre-update or delete code stores the name of the current Blob attachment in a tracking table.
    2) An asynchronous Job then gets the tracking table contents and deletes the files with those names.

    I think this should be safe assuming all updates to the tracking table are done in the same transaction as the actual update or deletion.

  • Play Duck
  • Peter Hilton

    Peter Hilton May 28th, 2011 @ 01:17 PM

    • State changed from “inprogress” to “resolved”

    I’ve just committed and pushed to the master branch: a new ‘Storing uploaded files with play.db.jpa.Blob’ section on the JPA manual page, and new ‘Return binary content’ and ‘Download a file as an attachment’ sub-sections on the controllers page.

  • Play Duck

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2>Play framework</h2>

Play makes it easier to build Web applications with Java. It is a clean alternative to bloated Enterprise Java stacks. It focuses on developer productivity and targets RESTful architectures. Learn more on the <a href="http://www.playframework.org">http://www.playframework.org</a> website.<br><br>

<h2>Source code is hosted on github</h2>Check out our repository at <a href="http://github.com/playframework/play">http://github.com/playframework/play</a><br><br>

<h2>Contributing, creating a patch</h2> Please read the <a href="http://play.lighthouseapp.com/projects/57987/contributor-guide">contributor guide</a><br><br>

<h2>Reporting Security Vulnerabilities</h2> Since all bug reports are public, please report any security vulnerability directly to <em>guillaume dot bort at gmail dot com</em>.<br><br>

<h2>Creating a bug report</h2> Bug reports are incredibly helpful, so take time to report bugs and request features in our ticket tracker. We’re always grateful for patches to Play’s code. Indeed, bug reports with attached patches will get fixed far quickly than those without any.<br><br>

Please include as much relevant information as possible including the exact framework version you're using and a code snippet that reproduces the problem.<br><br>

Don't have too much expectations. Unless the bug is really a serious "everything is broken" thing, you're creating a ticket to start a discussion. Having a patch (or a branch on Github we can pull from) is better, but then again we'll only pull high quality branches that make sense to be in the core of Play.

Referenced by

Pages