users@jersey.java.net

Re: [Jersey] Problem saving binary data using Jersey multipart

From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
Date: Sat, 31 Jan 2009 08:18:10 -0800

Geoff Sallee wrote:
> Unfortunately that did not work. I also attempted actually changing
> the value of the threshold variable in the source code for
> MultiPartConfig and recompiled the whole library (thinking that maybe
> the properties file was not being picked up by my app for some reason)
> but there was still no change.
Hmm ... the mystery deepens.

Unfortunately, I'm going to be in the air (and out of communication for
a while) flying from Europe back to the US, but I will be able to take a
look at this in detail early next week.

Craig
>
> On Fri, Jan 30, 2009 at 3:20 AM, Craig McClanahan
> <Craig.McClanahan_at_sun.com <mailto:Craig.McClanahan_at_sun.com>> wrote:
>
> Geoff Sallee wrote:
>
> Hello,
>
> I just integrated the jersey-multipart-1.0.1 library into my
> Jersey project in order to more easily handle file uploads.
> The problem is that when I attempt to save the file using the
> InputStream retrieved from multiPart.getBodyParts().get(0)
> (there is only one part in my test form) it only saves part of
> the file to disk. For example, if I attempt to upload a 92KB
> JPEG image it only gets saved as an 8KB JPEG, which only
> contains the top portion of the image. Here is the code I am
> using:
>
> public Response addUserAsset(
> @PathParam("userName") String userName,
> MultiPart multiPart) {
> String relativePath = null;
> String mimeType = null;
> String fileName = null;
> try {
> InputStream inputStream = null;
> for(BodyPart bodyPart : multiPart.getBodyParts()) {
> mimeType =
> bodyPart.getHeaders().getFirst("Content-Type");
> if(!StringUtils.isEmpty(mimeType) &&
> mimeType.startsWith("image")) { String
> metaData = bodyPart.getHeaders().getFirst("Content-Disposition");
> Matcher m = fileNamePattern.matcher(metaData);
> if(m.matches()) {
> fileName = m.group(1);
> }
> BodyPartEntity bpe = (BodyPartEntity)
> bodyPart.getEntity();
> inputStream = bpe.getInputStream();
> break;
> }
> }
> if(inputStream != null) {
> String baseDirPath =
> servletContext.getInitParameter("USER_DIGITAL_ASSET_DIR_PATH");
> DigitalAssetAccess access = new
> DigitalAssetAccessImpl(baseDirPath);
> relativePath = access.store(userName, fileName,
> mimeType, inputStream); //THIS METHOD ACTUALLY STORES THE
> FILE TO DISK
> }
> else {
> result.setSuccess(false);
> result.addMessage(INVALID_VALUE);
> return
> ResponseUtil.buildResponse(Status.BAD_REQUEST, result);
> }
> }
> catch(IOException ioe) {
> result.setSuccess(false);
> result.addMessage(INTERNAL_SERVER_ERROR);
> return
> ResponseUtil.buildResponse(Status.INTERNAL_SERVER_ERROR, result);
> }
> catch(Exception e) {
> result.setSuccess(false);
> result.addMessage(INTERNAL_SERVER_ERROR);
> return
> ResponseUtil.buildResponse(Status.INTERNAL_SERVER_ERROR, result);
> }
> }
>
> My store method uses the InputStream as follows:
>
> public String store(String userLoginId, String fileName,
> String mimeType, InputStream inputStream) throws
> IOException {
> File parentDir = new File(baseDirPath + "/" +
> userLoginId);
> if (!parentDir.exists()) {
> parentDir.mkdirs();
> }
>
> String assetFileName = getUniqueName(fileName, mimeType);
>
> File assetFile = new File(parentDir, assetFileName);
> if (assetFile.exists()) {
> throw new IllegalStateException(
> "File already exists with the name:" +
> assetFileName);
> } else {
> assetFile.createNewFile();
> }
>
> OutputStream outputStream = new BufferedOutputStream(
> new FileOutputStream(assetFile), BUFFER_SIZE);
> // BUFFER_SIZE is 1024 * 1024 * 2 (2MB)
>
> int b;
> while ((b = inputStream.read()) != EOF) { // EOF is -1
> outputStream.write(b);
> }
> inputStream.close();
> outputStream.flush();
> outputStream.close();
>
> return userLoginId + "/" + assetFileName;
> }
>
> I have also tested storing the file using the javax.ImageIO
> package with the same results, so I can't imagine it's due to
> the way the file is being stored. Am I missing something
> important? I did notice the mention of calling
> multipart.cleanup() but that had no effect in my case. Right
> now it looks like the files that are being stored are exactly
> 8KB so I'm thinking it has something to do with the threshold
> value, but I'm not sure what I can do to fix it. Any help is
> appreciated.
>
> That is definitely a red flag that points to a threshold value
> issue (although the default buffer size is 4k, so it's definitely
> odd). Could you do me the favor of one experiment to nail this
> down farther? I'd like you to try setting the threshold value to
> something larger than the size of the file (to ensure that it
> stays buffered in memory and not to the local disk file that would
> otherwise be used). If the app works in this configuration, then
> we know for sure that something in the jersey-multipart buffering
> logic is loopy. If it still doesn't work, we'll need to keep digging.
>
> To set this configuration, create a
> "jersey-multipart-config.properties" file (in WEB-INF/classes if
> this is a webapp, or on the classpath otherwise), with an entry
> like this:
>
> bufferThreshold = 128000
>
> This will set the buffer size to ~128k, which should be big enough
> to avoid the disk buffering for a 92kb image file.
>
> Regards,
> Geoff
>
>
> Craig
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> <mailto:users-unsubscribe_at_jersey.dev.java.net>
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
> <mailto:users-help_at_jersey.dev.java.net>
>
>