Java Servlet Example

Caution

For server security, refer to the guide below when implementing file upload and document import handling.

Software Security Weakness Diagnosis Guide

1. Servlet Configuration

Note

In Servlet 3.0 and above, you can use the @WebServlet annotation instead.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         id="WebApp_ID" version="3.1">
  <display-name>synapeditor</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>ImportServlet</servlet-name>
    <servlet-class>com.synap.synapeditor.ImportServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ImportServlet</servlet-name>
    <url-pattern>/importDoc</url-pattern>
  </servlet-mapping>
  <servlet>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>com.synap.synapeditor.UploadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/uploadFile</url-pattern>
  </servlet-mapping>
</web-app>

2. Image and Video File Upload

Caution

The file-upload portion of the sample code below is intentionally minimal and lacks proper security handling.

For the file-upload portion, use what is already in place inside your project, and refer to the code below for the integration portion only.

import com.google.gson.GsonBuilder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import java.io.*;
import java.util.*;

public class UploadServlet extends HttpServlet {
    private static final long serialVersionUID    = 1L;
    private static final String UPLOAD_DIR_REL_PATH = "uploads";

    private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3;
    private static final int MAX_FILE_SIZE    = 1024 * 1024 * 40;
    private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (!ServletFileUpload.isMultipartContent(request)) return;

        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(MEMORY_THRESHOLD);
        factory.setRepository(new File(System.getProperty("java.io.tmpdir")));

        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setHeaderEncoding("UTF-8");
        upload.setFileSizeMax(MAX_FILE_SIZE);
        upload.setSizeMax(MAX_REQUEST_SIZE);

        String ROOT_ABS_PATH       = request.getSession().getServletContext().getRealPath("");
        String UPLOAD_DIR_ABS_PATH = ROOT_ABS_PATH + File.separator + UPLOAD_DIR_REL_PATH;
        makeDirectory(UPLOAD_DIR_ABS_PATH);

        String storeFileName = "";
        try {
            List<FileItem> items = upload.parseRequest(request);
            if (items != null) {
                for (FileItem item : items) {
                    if (item.isFormField()) continue;
                    String ext = item.getName().substring(item.getName().lastIndexOf('.'));
                    storeFileName = UUID.randomUUID().toString() + ext;
                    item.write(new File(UPLOAD_DIR_ABS_PATH + File.separator + storeFileName));
                }
            }
        } catch (Exception ex) { ex.printStackTrace(); }

        Map<String, Object> map = new HashMap<>();
        map.put("uploadPath", "uploads/" + storeFileName);

        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.print(new GsonBuilder().create().toJson(map));
        out.flush();
    }

    private static void makeDirectory(String dirPath) {
        File dir = new File(dirPath);
        if (!dir.exists()) dir.mkdir();
    }
}

3. HWP / Word / Excel Document Import

Caution

The file-upload portion of the sample code below is intentionally minimal and lacks proper security handling.

For the file-upload portion, use what is already in place inside your project, and refer to the code below for the integration portion only.

import com.google.gson.GsonBuilder;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import java.io.*;
import java.util.*;
import java.util.zip.InflaterInputStream;

public class ImportServlet extends HttpServlet {
    private static final long serialVersionUID    = 1L;
    private static final String UPLOAD_DIR_REL_PATH = "import";

    private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3;
    private static final int MAX_FILE_SIZE    = 1024 * 1024 * 40;
    private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (!ServletFileUpload.isMultipartContent(request)) return;

        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(MEMORY_THRESHOLD);
        factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setHeaderEncoding("UTF-8");
        upload.setFileSizeMax(MAX_FILE_SIZE);
        upload.setSizeMax(MAX_REQUEST_SIZE);

        String ROOT_ABS_PATH       = request.getSession().getServletContext().getRealPath("");
        String UPLOAD_DIR_ABS_PATH = ROOT_ABS_PATH + File.separator + UPLOAD_DIR_REL_PATH;
        makeDirectory(UPLOAD_DIR_ABS_PATH);

        String storeFileAbsPath = "";
        try {
            List<FileItem> items = upload.parseRequest(request);
            for (FileItem item : items) {
                if (item.isFormField()) continue;
                String fileName    = item.getName();
                String contentType = item.getContentType();
                String ext = "";
                if (contentType != null) ext = "." + contentType.substring(contentType.lastIndexOf('/') + 1);
                else if (fileName.lastIndexOf('.') > 0) ext = fileName.substring(fileName.lastIndexOf('.'));
                if (ext.contains(".jpeg")) ext = ".jpg";

                String storeFileName = UUID.randomUUID().toString() + ext;
                storeFileAbsPath     = UPLOAD_DIR_ABS_PATH + File.separator + storeFileName;
                item.write(new File(storeFileAbsPath));
            }
        } catch (Exception ex) { ex.printStackTrace(); }

        Calendar cal     = Calendar.getInstance();
        String yearMonth = String.format("%04d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1);
        String uuid             = UUID.randomUUID().toString();
        String outputDirAbsPath = UPLOAD_DIR_ABS_PATH + File.separator + yearMonth + File.separator + uuid;
        makeDirectory(outputDirAbsPath);

        executeConverter(storeFileAbsPath, outputDirAbsPath);
        deleteFile(storeFileAbsPath);

        String pbAbsPath = outputDirAbsPath + File.separator + "document.pb";
        Integer[] serializedData = serializePbData(pbAbsPath);
        deleteFile(pbAbsPath);

        Map<String, Object> map = new HashMap<>();
        map.put("serializedData", serializedData);
        map.put("importPath", UPLOAD_DIR_REL_PATH + "/" + yearMonth + "/" + uuid);

        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.print(new GsonBuilder().create().toJson(map));
        out.flush();
    }

    protected static int executeConverter(String inputFilePath, String outputPath) {
        String SEDOC_CONVERTER_DIR_ABS_PATH = "absolute/path/to/converter/dir";
        String FONT_DIR_ABS_PATH            = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "fonts";
        String TEMP_DIR_ABS_PATH            = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "temp";
        String SEDOC_CONVERTER_ABS_PATH     = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "sedocConverter_exe";
        // Windows: "sedocConverter.exe"

        makeDirectory(TEMP_DIR_ABS_PATH);
        makeDirectory(FONT_DIR_ABS_PATH);
        String[] cmd = { SEDOC_CONVERTER_ABS_PATH, "-f", FONT_DIR_ABS_PATH, inputFilePath, outputPath, TEMP_DIR_ABS_PATH };
        try {
            Timer t = new Timer();
            ProcessBuilder pb = new ProcessBuilder(cmd);
            pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
            pb.redirectError(ProcessBuilder.Redirect.INHERIT);
            Process proc = pb.start();
            TimerTask killer = new TimeoutProcessKiller(proc);
            t.schedule(killer, 20000);
            int exitValue = proc.waitFor();
            killer.cancel();
            return exitValue;
        } catch (Exception e) { e.printStackTrace(); return -1; }
    }

    protected static Integer[] serializePbData(String pbFilePath) throws IOException {
        List<Integer> serialized = new ArrayList<>();
        try (FileInputStream fis = new FileInputStream(pbFilePath)) {
            fis.skip(16);
            try (InflaterInputStream ifis = new InflaterInputStream(fis)) {
                byte[] buffer = new byte[1024];
                int n;
                while ((n = ifis.read(buffer)) != -1) {
                    for (int i = 0; i < n; i++) serialized.add(buffer[i] & 0xFF);
                }
            }
        }
        return serialized.toArray(new Integer[0]);
    }

    private static void deleteFile(String path) {
        File f = new File(path);
        if (f.exists()) f.delete();
    }
    private static void makeDirectory(String dirPath) {
        File dir = new File(dirPath);
        if (!dir.exists()) dir.mkdir();
    }
    private static class TimeoutProcessKiller extends TimerTask {
        private final Process p;
        public TimeoutProcessKiller(Process p) { this.p = p; }
        @Override public void run() { p.destroy(); }
    }
}