com.jsmartframework.web.manager.WebContext.java Source code

Java tutorial

Introduction

Here is the source code for com.jsmartframework.web.manager.WebContext.java

Source

/*
 * JSmart Framework - Java Web Development Framework
 * Copyright (c) 2015, Jeferson Albino da Silva, All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

package com.jsmartframework.web.manager;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.jsmartframework.web.util.WebAlert;
import com.jsmartframework.web.util.WebUtils;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringReader;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.el.ExpressionFactory;
import javax.servlet.AsyncContext;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.PageContext;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * This class represents the context of the request being currently processed and it allows beans
 * to get an instance of {@link ServletContext}, {@link HttpSession}, {@link HttpServletRequest} or 
 * {@link HttpServletResponse}.
 * <br>
 * This class also include methods to add message to client side, check if request is Ajax request or 
 * retrieve attributes from the request, session or application among other utilities.
 */
public final class WebContext implements Serializable {

    private static final long serialVersionUID = -3910553204750683737L;

    private static final String ERROR_CODE = "error";

    private static final JspFactory JSP_FACTORY = JspFactory.getDefaultFactory();

    private static final Map<Thread, WebContext> THREADS = new ConcurrentHashMap<>();

    private static final Gson GSON = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, new JsonConverter.LocalDateTimeTypeConverter())
            .registerTypeAdapter(DateTime.class, new JsonConverter.DateTimeTypeConverter())
            .registerTypeAdapter(Date.class, new JsonConverter.DateTypeConverter()).create();

    private static Servlet smartServlet;

    private static JspApplicationContext jspContext;

    private HttpServletRequest request;

    private String bodyContent;

    private HttpServletResponse response;

    private boolean responseWritten;

    private String redirectTo;

    private boolean redirectToWindow;

    private boolean invalidate;

    private PageContext pageContext;

    private Map<String, List<WebAlert>> alerts = new LinkedHashMap<>();

    private Map<String, Object> mappedValues = new ConcurrentHashMap<>();

    private Map<String, String> queryParams;

    private WebContext(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    static final void setServlet(Servlet servlet) {
        smartServlet = servlet;
        jspContext = JSP_FACTORY.getJspApplicationContext(servlet.getServletConfig().getServletContext());
    }

    private static final WebContext getCurrentInstance() {
        return THREADS.get(Thread.currentThread());
    }

    static final void initCurrentInstance(HttpServletRequest request, HttpServletResponse response) {
        THREADS.put(Thread.currentThread(), new WebContext(request, response));
    }

    static final void closeCurrentInstance() {
        THREADS.remove(Thread.currentThread()).close();
    }

    private void close() {
        if (invalidate) {
            request.getSession().invalidate();
        }
        invalidate = false;
        request = null;
        bodyContent = null;
        response = null;
        responseWritten = false;
        redirectTo = null;
        alerts.clear();
        alerts = null;
        mappedValues.clear();
        mappedValues = null;
        JSP_FACTORY.releasePageContext(pageContext);
        pageContext = null;
    }

    static PageContext getPageContext() {
        WebContext context = getCurrentInstance();
        return context != null ? context.getPage() : null;
    }

    private PageContext getPage() {
        if (pageContext == null) {
            pageContext = JSP_FACTORY.getPageContext(smartServlet, request, response, null, true, 8192, true);
        }
        return pageContext;
    }

    static ExpressionFactory getExpressionFactory() {
        return jspContext.getExpressionFactory();
    }

    private static void setResponseAsError(String errorCode) {
        // Case response error is called we need to call onError on client side
        HttpServletResponse response = getResponse();
        if (response != null) {
            response.setHeader("Error-Ajax", StringUtils.isNotBlank(errorCode) ? errorCode : ERROR_CODE);
        }
    }

    /**
     * Returns the current {@link ServletContext} instance associated to the request
     * being processed.
     *
     * @return a instance of {@link ServletContext}.
     */
    public static ServletContext getApplication() {
        return smartServlet.getServletConfig().getServletContext();
    }

    /**
     * Returns the current {@link HttpSession} instance associated to the request being
     * processed.
     *
     * @return a instance of {@link HttpSession}.
     */
    public static HttpSession getSession() {
        WebContext context = getCurrentInstance();
        return context != null ? context.request.getSession() : null;
    }

    /**
     * Returns the current {@link HttpServletRequest} instance associated to the request being
     * processed.
     *
     * @return a instance of {@link HttpServletRequest}.
     */
    public static HttpServletRequest getRequest() {
        WebContext context = getCurrentInstance();
        return context != null ? context.request : null;
    }

    /**
     * Returns the current query parameters associated to the request being processed.
     *
     * @return Map containing name and values of URL query parameters
     */
    public static Map<String, String> getQueryParams() {
        WebContext context = getCurrentInstance();
        if (context == null) {
            return null;
        }
        if (context.queryParams == null) {
            context.queryParams = new ConcurrentHashMap<String, String>();

            String queryParam = context.request.getQueryString();
            if (StringUtils.isBlank(queryParam)) {
                return context.queryParams;
            }

            for (String param : context.request.getParameterMap().keySet()) {
                if (queryParam.contains(param + "=")) {
                    context.queryParams.put(param, context.request.getParameter(param));
                }
            }
        }
        return context.queryParams;
    }

    /**
     * Returns the current {@link HttpServletResponse} instance associated to the request
     * being processed.
     *
     * @return a instance of {@link HttpServletResponse}
     */
    public static HttpServletResponse getResponse() {
        WebContext context = getCurrentInstance();
        return context != null ? context.response : null;
    }

    static String getRedirectTo() {
        WebContext context = getCurrentInstance();
        return context != null ? context.redirectTo : null;
    }

    static boolean isRedirectToWindow() {
        WebContext context = getCurrentInstance();
        return context != null ? context.redirectToWindow : false;
    }

    /**
     * Redirect the request to the specified link path after the current request is processed.
     * <br>
     * Case this method is called on {@link PostConstruct} annotated method, the redirect is done
     * after method execution.
     *
     * @param path mapped on configuration file {@code webConfig.xml} or general valid URL link.
     */
    public static void redirectTo(String path) {
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.redirectTo = WebUtils.decodePath(path);
        }
    }

    /**
     * Redirect the request to the specified link path after the current request is processed on a
     * new window on client browser.
     * <br>
     * Case this method is called on {@link PostConstruct} annotated method, the redirect is done
     * after method execution.
     *
     * @param path mapped on configuration file {@code webConfig.xml} or general valid URL link.
     */
    public static void redirectToWindow(String path) {
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.redirectTo = WebUtils.decodePath(path);
            context.redirectToWindow = true;
        }
    }

    /**
     * Calling this method will cause the current {@link HttpSession} to be invalidated after the request
     * processing is done. It means that the session will be invalidated after request is completed.
     * <br>
     * Case there is a need to invalidate the session at the moment of the execution, use {@link HttpSession}
     * invalidate method instead.
     */
    public static void invalidate() {
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.invalidate = true;
        }
    }

    /**
     * Returns the {@link Locale} of the client associated to the request being processed.
     *
     * @return {@link Locale} instance.
     */
    public static Locale getLocale() {
        HttpServletRequest request = getRequest();
        return request != null ? request.getLocale() : null;
    }

    /**
     * Returns true if the request being process was triggered by Ajax on client side,
     * false otherwise.
     *
     * @return boolean value indicating if request was done using Ajax.
     */
    public static boolean isAjaxRequest() {
        HttpServletRequest request = getRequest();
        return request != null ? "XMLHttpRequest".equals(request.getHeader("X-Requested-With")) : false;
    }

    static List<WebAlert> getAlerts(String id) {
        WebContext context = getCurrentInstance();
        return context != null ? context.alerts.get(id) : null;
    }

    /**
     * Add info alert to be presented on client side after the response is returned.
     * <br>
     * This method only take effect if the alert tag is mapped with specified id on JSP page.
     * <br>
     * The message is placed on the same position where the {@code alert} is mapped.
     *
     * @param id of the alert to receive the message.
     * @param alert object containing alert details such as title, message, header and icon.
     */
    public static void addAlert(String id, WebAlert alert) {
        WebContext context = getCurrentInstance();
        if (context != null && id != null && alert != null) {

            List<WebAlert> alerts = context.alerts.get(id);
            if (alerts == null) {
                context.alerts.put(id, alerts = new ArrayList<>());
            }
            alerts.add(alert);
        }
    }

    /**
     * Add info alert to be presented on client side after the response is returned.
     * <br>
     * This method only take effect if the alert tag is mapped with specified id on JSP page.
     * <br>
     * The message is placed on the same position where the {@code alert} tag is mapped.
     *
     * @param id of the alert to receive the message.
     * @param message to be presented on the client side.
     */
    public static void addInfo(String id, String message) {
        WebAlert alert = new WebAlert(WebAlert.AlertType.INFO);
        alert.setMessage(message);
        addAlert(id, alert);
    }

    /**
     * Add warning alert to be presented on client side after the response is returned.
     * <br>
     * This method only take effect if the alert tag is mapped with specified id on JSP page.
     * <br>
     * The message is placed on the same position where the {@code alert} tag is mapped.
     *
     * @param id of the alert to receive the message.
     * @param message to be presented on the client side.
     */
    public static void addWarning(String id, String message) {
        WebAlert alert = new WebAlert(WebAlert.AlertType.WARNING);
        alert.setMessage(message);
        addAlert(id, alert);
    }

    /**
     * Add success alert to be presented on client side after the response is returned.
     * <br>
     * This method only take effect if the alert tag is mapped with specified id on JSP page.
     * <br>
     * The message is placed on the same position where the {@code alert} tag is mapped.
     *
     * @param id of the alert to receive the message.
     * @param message to be presented on the client side.
     */
    public static void addSuccess(String id, String message) {
        WebAlert alert = new WebAlert(WebAlert.AlertType.SUCCESS);
        alert.setMessage(message);
        addAlert(id, alert);
    }

    /**
     *
     * @param errorCode
     */
    public static void addError(String errorCode) {
        // Case addError is called we need to call onError on client side
        setResponseAsError(errorCode);
    }

    /**
     * Add error alert to be presented on client side after the response is returned.
     * <br>
     * This method only take effect if the alert tag is mapped with specified id on JSP page.
     * <br>
     * The message is placed on the same position where the {@code alert} message tag is mapped.
     *
     * @param id of the alert to receive the message.
     * @param message to be presented on the client side.
     */
    public static void addError(String id, String message) {
        addError(id, message, ERROR_CODE);
    }

    /**
     *
     * @param id
     * @param message
     * @param errorCode
     */
    public static void addError(String id, String message, String errorCode) {
        WebAlert alert = new WebAlert(WebAlert.AlertType.DANGER);
        alert.setMessage(message);
        addAlert(id, alert);
        // Case addError is called we need to call onError on client side
        setResponseAsError(errorCode);
    }

    static Object getMappedValue(String name) {
        WebContext context = getCurrentInstance();
        if (context != null) {
            return context.mappedValues.get(name);
        }
        return null;
    }

    static Object removeMappedValue(String name) {
        WebContext context = getCurrentInstance();
        if (context != null) {
            return context.mappedValues.remove(name);
        }
        return null;
    }

    static void addMappedValue(String name, Object value) {
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.mappedValues.put(name, value);
        }
    }

    /**
     * Returns the attribute carried on {@link HttpServletRequest}, {@link HttpSession} or {@link ServletContext}
     * instances associated with current request being processed.
     *
     * @param name name of the attribute.
     * @return the {@link Object} mapped by attribute name on the current request.
     */
    public static Object getAttribute(String name) {
        if (name != null) {
            HttpServletRequest request = getRequest();
            if (request != null && request.getAttribute(name) != null) {
                return request.getAttribute(name);
            }

            HttpSession session = getSession();
            if (session != null) {
                synchronized (session) {
                    if (session.getAttribute(name) != null) {
                        return session.getAttribute(name);
                    }
                }
            }

            ServletContext application = getApplication();
            if (application.getAttribute(name) != null) {
                return application.getAttribute(name);
            }
        }
        return null;
    }

    /**
     * Check if attribute is carried on {@link HttpServletRequest}, {@link HttpSession} or {@link ServletContext}
     * instances associated with current request being processed.
     *
     * @param name name of the attribute.
     * @return true if the attribute is contained in one of the instances {@link HttpServletRequest},
     * {@link HttpSession} or {@link ServletContext}, false otherwise.
     */
    public static boolean containsAttribute(String name) {
        if (name != null) {
            HttpServletRequest request = getRequest();
            if (request != null && request.getAttribute(name) != null) {
                return true;
            }

            HttpSession session = getSession();
            if (session != null) {
                synchronized (session) {
                    if (session.getAttribute(name) != null) {
                        return true;
                    }
                }
            }

            return getApplication().getAttribute(name) != null;
        }
        return false;
    }

    /**
     * Given that the current request has ReCaptcha content to be verified use this method
     * to check if the ReCaptcha input is valid on server side.
     *
     * @param secretKey for ReCaptcha based on your domain registered
     *
     * @return true if the ReCaptcha input is valid, false otherwise
     */
    public static boolean checkReCaptcha(String secretKey) {
        String responseField = (String) getMappedValue(ReCaptchaHandler.RESPONSE_V1_FIELD_NAME);
        if (responseField != null) {
            return ReCaptchaHandler.checkReCaptchaV1(secretKey, responseField);
        }

        responseField = (String) getMappedValue(ReCaptchaHandler.RESPONSE_V2_FIELD_NAME);
        if (responseField != null) {
            return ReCaptchaHandler.checkReCaptchaV2(secretKey, responseField);
        }
        throw new RuntimeException(
                "ReCaptcha not found on this submit. Plase make sure the recaptcha tag is included on submitted form");
    }

    /**
     * Returns the request content as String
     *
     * @return request content as String
     * @throws IOException
     */
    public static String getContentAsString() throws IOException {
        WebContext context = getCurrentInstance();
        if (context == null) {
            return null;
        }
        if (context.bodyContent == null) {
            String line = null;
            StringBuffer buffer = new StringBuffer();

            BufferedReader reader = context.request.getReader();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            context.bodyContent = buffer.toString();
        }
        return context.bodyContent;
    }

    /**
     * Get request content from JSON and convert it to class mapping the content.
     *
     * @param clazz - Class mapping the request content.
     * @param <T> - type of class to convert JSON into class.
     *
     * @return content from JSON to object
     * @throws IOException
     */
    public static <T> T getContentFromJson(Class<T> clazz) throws IOException {
        return getContentFromJson(clazz, GSON);
    }

    /**
     * Get request content from JSON and convert it to class mapping the content.
     *
     * @param clazz - Class mapping the request content.
     * @param gson - Gson converter to convert JSON request into object.
     * @param <T> - type of class to convert JSON into class.
     *
     * @return content from JSON to object
     * @throws IOException
     */
    public static <T> T getContentFromJson(Class<T> clazz, Gson gson) throws IOException {
        return gson.fromJson(getContentAsString(), clazz);
    }

    /**
     * Get request content from XML and convert it to class mapping the content.
     *
     * @param clazz - Class mapping the request content.
     * @param <T> - type of class to convert XML into class.
     *
     * @return content from XML to object
     * @throws IOException
     */
    public static <T> T getContentFromXml(Class<T> clazz) throws IOException, JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
        return getContentFromXml(jaxbContext.createUnmarshaller());
    }

    /**
     * Get request content from XML and convert it to class mapping the content.
     *
     * @param unmarshaller - JAXBContext unmarshaller to convert the request content into object.
     * @param <T> - type of class to convert XML into class.
     *
     * @return content from XML to object
     * @throws IOException
     */
    public static <T> T getContentFromXml(Unmarshaller unmarshaller) throws IOException, JAXBException {
        StringReader reader = new StringReader(getContentAsString());
        return (T) unmarshaller.unmarshal(reader);
    }

    static boolean isResponseWritten() {
        WebContext context = getCurrentInstance();
        return context != null ? context.responseWritten : false;
    }

    /**
     *
     * @throws IOException
     */
    public static void writeResponseError() throws IOException {
        writeResponseError(ERROR_CODE);
    }

    /**
     *
     * @param errorCode
     * @throws IOException
     */
    public static void writeResponseError(int errorCode) throws IOException {
        writeResponseError(String.valueOf(errorCode));
    }

    /**
     *
     * @param errorCode
     * @throws IOException
     */
    public static void writeResponseError(String errorCode) throws IOException {
        setResponseAsError(errorCode);
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.responseWritten = true;
        }
    }

    /**
     *
     * @param response
     * @throws IOException
     */
    public static void writeResponseErrorAsString(String response) throws IOException {
        writeResponseErrorAsString(ERROR_CODE, response);
    }

    /**
     *
     * @param errorCode
     * @param response
     * @throws IOException
     */
    public static void writeResponseErrorAsString(String errorCode, String response) throws IOException {
        setResponseAsError(errorCode);
        writeResponseAsString(response);
    }

    /**
     * Write response directly as String. Note that by using this method the response
     * as HTML will not be generated and the response will be what you have defined.
     *
     * @param response String to write in the response.
     * @throws IOException
     */
    public static void writeResponseAsString(String response) throws IOException {
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.responseWritten = true;
            PrintWriter writer = context.response.getWriter();
            writer.write(response);
            writer.flush();
        }
    }

    /**
     *
     * @param object
     * @throws IOException
     */
    public static void writeResponseErrorAsJson(Object object) throws IOException {
        writeResponseErrorAsJson(ERROR_CODE, object);
    }

    /**
     *
     * @param errorCode
     * @param object
     * @throws IOException
     */
    public static void writeResponseErrorAsJson(String errorCode, Object object) throws IOException {
        writeResponseErrorAsJson(errorCode, object, GSON);
    }

    /**
     *
     * @param errorCode
     * @param object
     * @param gson
     * @throws IOException
     */
    public static void writeResponseErrorAsJson(String errorCode, Object object, Gson gson) throws IOException {
        setResponseAsError(errorCode);
        writeResponseAsJson(object, gson);
    }

    /**
     * Write response directly as JSON from Object. Note that by using this method the response
     * as HTML will not be generated and the response will be what you have defined.
     *
     * @param object Object to convert into JSON to write in the response.
     * @throws IOException
     */
    public static void writeResponseAsJson(Object object) throws IOException {
        writeResponseAsJson(object, GSON);
    }

    /**
     * Write response directly as JSON from Object. Note that by using this method the response
     * as HTML will not be generated and the response will be what you have defined.
     *
     * @param object Object to convert into JSON to write in the response.
     * @param gson Gson instance to be used to convert object into JSON.
     * @throws IOException
     */
    public static void writeResponseAsJson(Object object, Gson gson) throws IOException {
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.responseWritten = true;
            context.response.setContentType("application/json");
            PrintWriter writer = context.response.getWriter();
            writer.write(gson.toJson(object));
            writer.flush();
        }
    }

    /**
     *
     * @param object
     * @throws IOException
     * @throws JAXBException
     */
    public static void writeResponseErrorAsXml(Object object) throws IOException, JAXBException {
        writeResponseErrorAsXml(ERROR_CODE, object);
    }

    /**
     *
     * @param errorCode
     * @param object
     * @throws IOException
     * @throws JAXBException
     */
    public static void writeResponseErrorAsXml(String errorCode, Object object) throws IOException, JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
        writeResponseErrorAsXml(errorCode, object, jaxbContext.createMarshaller());
    }

    /**
     *
     * @param errorCode
     * @param object
     * @param marshaller
     * @throws IOException
     * @throws JAXBException
     */
    public static void writeResponseErrorAsXml(String errorCode, Object object, Marshaller marshaller)
            throws IOException, JAXBException {
        setResponseAsError(errorCode);
        writeResponseAsXml(object, marshaller);
    }

    /**
     * Write response directly as XML from Object. Note that by using this method the response
     * as HTML will not be generated and the response will be what you have defined.
     *
     * @param object Object to convert into XML to write in the response.
     * @throws IOException
     */
    public static void writeResponseAsXml(Object object) throws IOException, JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
        writeResponseAsXml(object, jaxbContext.createMarshaller());
    }

    /**
     * Write response directly as XML from Object. Note that by using this method the response
     * as HTML will not be generated and the response will be what you have defined.
     *
     * @param object Object to convert into XML to write in the response.
     */
    public static void writeResponseAsXmlQuietly(Object object) {
        try {
            writeResponseAsXml(object);
        } catch (Exception e) {
        }
    }

    /**
     * Write response directly as XML from Object. Note that by using this method the response
     * as HTML will not be generated and the response will be what you have defined.
     *
     * @param object Object to convert into XML to write in the response.
     * @param marshaller JAXBContext marshaller to write object as XML.
     * @throws IOException
     */
    public static void writeResponseAsXml(Object object, Marshaller marshaller) throws IOException, JAXBException {
        WebContext context = getCurrentInstance();
        if (context != null) {
            context.responseWritten = true;
            context.response.setContentType("application/xml");
            PrintWriter writer = context.response.getWriter();
            marshaller.marshal(object, writer);
            writer.flush();
        }
    }

    /**
     * Write response directly as Event-Stream for Server Sent Events.
     *
     * @param asyncContext - Asynchronous Context.
     * @param event - Name of event to be written on response.
     * @param data - Content of event ot be written on response.
     * @throws IOException
     */
    public static void writeResponseAsEventStream(AsyncContext asyncContext, String event, Object data)
            throws IOException {
        writeResponseAsEventStream(asyncContext, event, data, null);
    }

    /**
     * Write response directly as Event-Stream for Server Sent Events.
     *
     * @param asyncContext - Asynchronous Context.
     * @param event - Name of event to be written on response.
     * @param data - Content of event ot be written on response.
     * @param retry - Time in (milliseconds) for client retry opening connection.
     *              after asynchronous context is closed.
     * @throws IOException
     */
    public static void writeResponseAsEventStream(AsyncContext asyncContext, String event, Object data, Long retry)
            throws IOException {
        if (asyncContext != null && event != null && data != null) {
            HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
            response.setContentType("text/event-stream");
            PrintWriter printWriter = response.getWriter();

            if (retry != null) {
                printWriter.write("retry:" + retry + "\n");
            }
            printWriter.write("event:" + event + "\n");
            printWriter.write("data:" + data + "\n\n");
            printWriter.flush();
        }
    }

    /**
     * Write response as file stream when you want to provide download functionality.
     * Note that by using this method the response as HTML will not be generated and
     * the response will be what you have defined.
     *
     * @param file - File to be written on response.
     * @param bufferSize - Buffer size to write the response. Example 2048 bytes.
     * @throws IOException
     */
    public static void writeResponseAsFileStream(File file, int bufferSize) throws IOException {
        WebContext context = getCurrentInstance();
        if (context != null && file != null && bufferSize > 0) {
            context.responseWritten = true;
            context.response.setHeader("Content-Disposition", "attachment;filename=\"" + file.getName() + "\"");
            context.response.addHeader("Content-Length", Long.toString(file.length()));
            context.response.setContentLength((int) file.length());

            String mimetype = getApplication().getMimeType(file.getName());
            context.response.setContentType((mimetype != null) ? mimetype : "application/octet-stream");

            FileInputStream fileInputStream = new FileInputStream(file);
            ServletOutputStream outputStream = context.response.getOutputStream();

            try {
                int i;
                byte[] buffer = new byte[bufferSize];
                while ((i = fileInputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, i);
                }
            } finally {
                outputStream.flush();
                fileInputStream.close();
            }
        }
    }
}