001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * bstefanescu 011 */ 012package org.nuxeo.ecm.automation.jaxrs.io.operations; 013 014import java.io.File; 015import java.io.IOException; 016import java.io.InputStream; 017import java.lang.annotation.Annotation; 018import java.lang.reflect.Type; 019import java.util.List; 020 021import javax.mail.BodyPart; 022import javax.mail.MessagingException; 023import javax.mail.internet.MimeMultipart; 024import javax.servlet.http.HttpServletRequest; 025import javax.ws.rs.Consumes; 026import javax.ws.rs.WebApplicationException; 027import javax.ws.rs.core.Context; 028import javax.ws.rs.core.MediaType; 029import javax.ws.rs.core.MultivaluedMap; 030import javax.ws.rs.ext.MessageBodyReader; 031import javax.ws.rs.ext.Provider; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.codehaus.jackson.JsonFactory; 036import org.codehaus.jackson.JsonParser; 037import org.nuxeo.common.utils.FileUtils; 038import org.nuxeo.ecm.automation.core.util.BlobList; 039import org.nuxeo.ecm.automation.jaxrs.io.InputStreamDataSource; 040import org.nuxeo.ecm.automation.jaxrs.io.SharedFileInputStream; 041import org.nuxeo.ecm.core.api.Blob; 042import org.nuxeo.ecm.core.api.Blobs; 043import org.nuxeo.ecm.core.api.CoreSession; 044import org.nuxeo.ecm.webengine.WebException; 045import org.nuxeo.ecm.webengine.jaxrs.context.RequestCleanupHandler; 046import org.nuxeo.ecm.webengine.jaxrs.context.RequestContext; 047import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory; 048 049/** 050 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 051 */ 052@Provider 053@Consumes("multipart/form-data") 054public class MultiPartFormRequestReader implements MessageBodyReader<ExecutionRequest> { 055 056 private static final Log log = LogFactory.getLog(MultiPartFormRequestReader.class); 057 058 @Context 059 protected HttpServletRequest request; 060 061 @Context 062 JsonFactory factory; 063 064 public CoreSession getCoreSession() { 065 return SessionFactory.getSession(request); 066 } 067 068 @Override 069 public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) { 070 return ExecutionRequest.class.isAssignableFrom(arg0); // TODO check 071 // media type too 072 } 073 074 @Override 075 public ExecutionRequest readFrom(Class<ExecutionRequest> arg0, Type arg1, Annotation[] arg2, MediaType arg3, 076 MultivaluedMap<String, String> headers, InputStream in) throws IOException, WebApplicationException { 077 ExecutionRequest req = null; 078 try { 079 List<String> ctypes = headers.get("Content-Type"); 080 String ctype = ctypes.get(0); 081 // we need to copy first the stream into a file otherwise it may 082 // happen that 083 // javax.mail fail to receive some parts - I am not sure why - 084 // perhaps the stream is no more available when javax.mail need it? 085 File tmp = File.createTempFile("nx-automation-mp-upload-", ".tmp"); 086 FileUtils.copyToFile(in, tmp); 087 // get the input from the saved file 088 in = new SharedFileInputStream(tmp); 089 try { 090 MimeMultipart mp = new MimeMultipart(new InputStreamDataSource(in, ctype)); 091 BodyPart part = mp.getBodyPart(0); // use content ids 092 InputStream pin = part.getInputStream(); 093 JsonParser jp = factory.createJsonParser(pin); 094 req = JsonRequestReader.readRequest(jp, headers, getCoreSession()); 095 int cnt = mp.getCount(); 096 if (cnt == 2) { // a blob 097 req.setInput(readBlob(request, mp.getBodyPart(1))); 098 } else if (cnt > 2) { // a blob list 099 BlobList blobs = new BlobList(); 100 for (int i = 1; i < cnt; i++) { 101 blobs.add(readBlob(request, mp.getBodyPart(i))); 102 } 103 req.setInput(blobs); 104 } else { 105 log.error("Not all parts received."); 106 for (int i = 0; i < cnt; i++) { 107 log.error("Received parts: " + mp.getBodyPart(i).getHeader("Content-ID")[0] + " -> " 108 + mp.getBodyPart(i).getContentType()); 109 } 110 throw WebException.newException(new IllegalStateException("Received only " + cnt 111 + " part in a multipart request")); 112 } 113 } finally { 114 try { 115 in.close(); 116 } catch (IOException e) { 117 // do nothing 118 } 119 tmp.delete(); 120 } 121 } catch (MessagingException | IOException e) { 122 throw WebException.newException("Failed to parse multipart request", e); 123 } 124 return req; 125 } 126 127 public static Blob readBlob(HttpServletRequest request, BodyPart part) throws MessagingException, IOException { 128 String ctype = part.getContentType(); 129 String fname = part.getFileName(); 130 InputStream pin = part.getInputStream(); 131 final File tmp = File.createTempFile("nx-automation-upload-", ".tmp"); 132 FileUtils.copyToFile(pin, tmp); 133 Blob blob = Blobs.createBlob(tmp, ctype, null, fname); 134 RequestContext.getActiveContext(request).addRequestCleanupHandler(new RequestCleanupHandler() { 135 @Override 136 public void cleanup(HttpServletRequest req) { 137 tmp.delete(); 138 } 139 }); 140 return blob; 141 } 142 143}