blog image

How to handle file upload in AEM?

Blog - Technology

  • icons15 March, 2019
  • iconsParth Mathia

In this article, we are going to talk about how to handle file upload in Adobe AEM. We will also talk about any potential issues and solutions you could be facing during file upload.

When we started implementation of forms which can handle file upload and save it in the server file system, we decided to use an Apache Commons FileUpload API to deal with form upload. We chose this API because AEM has this API pre-installed

FileUploadHandle service:

boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
    FileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    try {
        List items = upload.parseRequest(request);
        Iterator iterator = items.iterator();
        while (iterator.hasNext()) {
            FileItem item = (FileItem) iterator.next();
            if (!item.isFormField()) {
                String fileName = item.getName();
                String root = "submission/uploads";
                if (!path.exists()) {
                    boolean status = path.mkdirs();
                }
                File uploadedFile = new File(path + "/" + fileName);
                item.write(uploadedFile);
            }
        }
    } catch (FileUploadException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

After building and deploying this code to AEM, we tested file upload and got following error:

java.lang.IllegalStateException: Request Data has already been read

There were no errors in the above code. In fact, if we write same code for pure J2EE application, it will work correctly. However, in AEM world, sling automatically reads request data when POST request happens, so when above code attempts to parse file data using ServletFileUpload, then that is consider as second attempt, and that’s throwing “`Request Data has already been read“` exception.

So the question arises, how do we read file data from the request? Here’s a solution, Sling already read data when user submitted a request. So, now we will use Sling API to retrieve the file data. Sling makes the uploaded files and all parameters available from the SlingHttpServletRequest.getRequestParameterMap method, which returns a RequestParamterMap. Simply iterate over the parameters to retrieve file, and any parameters passed into request. 

if (ServletFileUpload.isMultipartContent(request)) {
   Map<String, RequestParameter[]> requestParameters = request.getRequestParameterMap();
   for (final Map.Entry<String, RequestParameter[]> entry : params.entrySet()) {
    String formField = entry.getKey();
    RequestParameter[] pArr = entry.getValue();
    RequestParameter param = pArr[0];
    InputStream stream = param.getInputStream();
    if (param.isFormField()) {
        LOG.info("Form field {} with value {} detected", formField, Streams.asString(stream));
    }else{
        LOG.info("File field {} with file name {} detected", formField, param.getFileName());
    }
}