Java tutorial
/******************************************************************************* * Copyright (c) 2014-2015 BSI Business Systems Integration AG. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * BSI Business Systems Integration AG - initial API and implementation ******************************************************************************/ package org.eclipse.scout.rt.ui.html.json; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.fileupload.util.Streams; import org.eclipse.scout.rt.platform.BEANS; import org.eclipse.scout.rt.platform.Order; import org.eclipse.scout.rt.platform.exception.DefaultExceptionTranslator; import org.eclipse.scout.rt.platform.resource.BinaryResource; import org.eclipse.scout.rt.platform.util.IOUtility; import org.eclipse.scout.rt.platform.util.StringUtility; import org.eclipse.scout.rt.platform.util.concurrent.IRunnable; import org.eclipse.scout.rt.ui.html.AbstractUiServletRequestHandler; import org.eclipse.scout.rt.ui.html.IUiSession; import org.eclipse.scout.rt.ui.html.UiRunContexts; import org.eclipse.scout.rt.ui.html.UiServlet; import org.eclipse.scout.rt.ui.html.res.IBinaryResourceConsumer; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This handler contributes to the {@link UiServlet} as the POST handler for /upload */ @Order(5030) public class UploadRequestHandler extends AbstractUiServletRequestHandler { private static final Logger LOG = LoggerFactory.getLogger(UploadRequestHandler.class); private static final Pattern PATTERN_UPLOAD_ADAPTER_RESOURCE_PATH = Pattern .compile("^/upload/([^/]*)/([^/]*)$"); private final JsonRequestHelper m_jsonRequestHelper = BEANS.get(JsonRequestHelper.class); @Override public boolean handlePost(final UiServlet servlet, final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { //serve only /upload String pathInfo = req.getPathInfo(); Matcher matcher = PATTERN_UPLOAD_ADAPTER_RESOURCE_PATH.matcher(pathInfo); if (!matcher.matches()) { return false; } final String uiSessionId = matcher.group(1); final String targetAdapterId = matcher.group(2); // Check if is really a file upload if (!ServletFileUpload.isMultipartContent(req)) { return false; } try { // Resolve session IUiSession uiSession = resolveUiSession(req, uiSessionId); // Associate subsequent processing with the uiSession. UiRunContexts.copyCurrent().withSession(uiSession).run(new IRunnable() { @Override public void run() throws Exception { handleUploadFileRequest(IUiSession.CURRENT.get(), req, resp, targetAdapterId); } }, DefaultExceptionTranslator.class); } catch (Exception e) { LOG.error("Unexpected error while handling multipart upload request", e); writeJsonResponse(resp, m_jsonRequestHelper.createUnrecoverableFailureResponse()); } return true; } /** * Method invoked to handle a file upload request from UI. */ protected void handleUploadFileRequest(IUiSession uiSession, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String targetAdapterId) throws IOException, FileUploadException { long start = System.nanoTime(); if (LOG.isDebugEnabled()) { LOG.debug("Fileupload started"); } IBinaryResourceConsumer binaryResourceConsumer = resolveJsonAdapter(uiSession, targetAdapterId); // Read uploaded data Map<String, String> uploadProperties = new HashMap<String, String>(); List<BinaryResource> uploadResources = new ArrayList<>(); readUploadData(httpServletRequest, binaryResourceConsumer.getMaximumBinaryResourceUploadSize(), uploadProperties, uploadResources); if (uploadProperties.containsKey("legacyFormTextPlainAnswer")) { httpServletResponse.setContentType("text/plain"); } // GUI requests for the same session must be processed consecutively uiSession.uiSessionLock().lock(); try { if (uiSession.isDisposed() || uiSession.currentJsonResponse() == null) { writeJsonResponse(httpServletResponse, m_jsonRequestHelper.createSessionTimeoutResponse()); return; } JSONObject jsonResp = uiSession.processFileUpload(httpServletRequest, httpServletResponse, binaryResourceConsumer, uploadResources, uploadProperties); if (jsonResp == null) { jsonResp = m_jsonRequestHelper.createEmptyResponse(); } writeJsonResponse(httpServletResponse, jsonResp); } finally { uiSession.uiSessionLock().unlock(); } if (LOG.isDebugEnabled()) { LOG.debug("completed in {} ms", StringUtility.formatNanos(System.nanoTime() - start)); } } protected void readUploadData(HttpServletRequest httpReq, long maxSize, Map<String, String> uploadProperties, List<BinaryResource> uploadResources) throws FileUploadException, IOException { ServletFileUpload upload = new ServletFileUpload(); upload.setHeaderEncoding(StandardCharsets.UTF_8.name()); upload.setSizeMax(maxSize); for (FileItemIterator it = upload.getItemIterator(httpReq); it.hasNext();) { FileItemStream item = it.next(); String name = item.getFieldName(); InputStream stream = item.openStream(); if (item.isFormField()) { // Handle non-file fields (interpreted as properties) uploadProperties.put(name, Streams.asString(stream, StandardCharsets.UTF_8.name())); } else { // Handle files String filename = item.getName(); if (StringUtility.hasText(filename)) { String[] parts = StringUtility.split(filename, "[/\\\\]"); filename = parts[parts.length - 1]; } String contentType = item.getContentType(); byte[] content = IOUtility.getContent(stream); // Info: we cannot set the charset property for uploaded files here, because we simply don't know it. // the only thing we could do is to guess the charset (encoding) by reading the byte contents of // uploaded text files (for binary file types the encoding is not relevant). However: currently we // do not set the charset at all. uploadResources.add(new BinaryResource(filename, contentType, content)); } } } protected IUiSession resolveUiSession(HttpServletRequest httpReq, String uiSessionId) { if (!StringUtility.hasText(uiSessionId)) { throw new IllegalArgumentException("Missing UI session ID."); } HttpSession httpSession = httpReq.getSession(); IUiSession uiSession = (IUiSession) httpSession .getAttribute(IUiSession.HTTP_SESSION_ATTRIBUTE_PREFIX + uiSessionId); if (uiSession == null) { throw new IllegalStateException("Could not resolve UI session with ID " + uiSessionId); } uiSession.touch(); return uiSession; } /** * Returns the {@link IBinaryResourceConsumer} that is registered to the specified session under the given adapter ID. * If the adapter could not be found, or the adapter is not a {@link IBinaryResourceConsumer}, a runtime exception is * thrown. */ protected IBinaryResourceConsumer resolveJsonAdapter(IUiSession uiSession, String targetAdapterId) { // Resolve adapter if (!StringUtility.hasText(targetAdapterId)) { throw new IllegalArgumentException("Missing target adapter ID"); } IJsonAdapter<?> jsonAdapter = uiSession.getJsonAdapter(targetAdapterId); if (!(jsonAdapter instanceof IBinaryResourceConsumer)) { throw new IllegalStateException("Invalid adapter for ID " + targetAdapterId + (jsonAdapter == null ? "" : " (unexpected type)")); } return (IBinaryResourceConsumer) jsonAdapter; } /** * Writes the given {@link JSONObject} into the given {@link ServletResponse}. */ protected void writeJsonResponse(ServletResponse servletResponse, JSONObject jsonObject) throws IOException { m_jsonRequestHelper.writeResponse(servletResponse, jsonObject); } }