In this article, we are going to talk about how to handle file upload in Adobe Experience Manager. We will also talk about any potential issues and solutions you could be facing during file upload.
When we started the implementation of forms that 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 Adobe Experience Manager 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 Adobe Experience Manager, 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 the Adobe Experience Manager 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());
}
}