thinwire.render.web.WebServlet.java Source code

Java tutorial

Introduction

Here is the source code for thinwire.render.web.WebServlet.java

Source

/*
ThinWire(R) Ajax RIA Framework
Copyright (C) 2003-2008 Custom Credit Systems
    
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 2.1 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
package thinwire.render.web;

import java.io.*;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;

import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;

import thinwire.ui.FileChooser;

import javax.servlet.*;
import javax.servlet.http.*;

/**
 * @author Joshua J. Gertzen
 */
public class WebServlet extends HttpServlet {
    private static final Level LEVEL = Level.FINER;
    private static final Logger log = Logger.getLogger(WebServlet.class.getName());

    private static enum InitParam {
        MAIN_CLASS, EXTRA_ARGUMENTS, STYLE_SHEET, RELOAD_ON_REFRESH, INITIAL_FRAME_TITLE;

        private String mixedCaseName;

        private InitParam() {
            StringBuilder sb = new StringBuilder();
            String[] parts = name().split("_");
            sb.append(parts[0].toLowerCase());

            for (int i = 1, cnt = parts.length; i < cnt; i++) {
                sb.append(parts[i].charAt(0)).append(parts[i].toLowerCase().substring(1));
            }

            mixedCaseName = sb.toString();
        }

        public String mixedCaseName() {
            return mixedCaseName;
        }

        public static InitParam valueOfMixedCase(String mixedCaseName) {
            for (InitParam ip : values()) {
                if (ip.mixedCaseName().equals(mixedCaseName))
                    return ip;
            }

            return valueOf(mixedCaseName);
        }
    }

    private static class ApplicationHolder implements HttpSessionBindingListener, Serializable {
        private static final long serialVersionUID = 2454889032868933806L;
        transient WebApplication app;

        public void valueBound(HttpSessionBindingEvent event) {

        }

        public void valueUnbound(HttpSessionBindingEvent event) {
            if (log.isLoggable(LEVEL))
                log.log(LEVEL, "Unbinding application instance " + event.getSession().getId());
            if (app != null)
                app.shutdown();
        }
    }

    public WebServlet() {
        if (Thread.currentThread() instanceof EventProcessor) {
            throw new IllegalStateException("This class '" + this.getClass().getName()
                    + "' is managed by the servlet engine and cannot be constructed from an EventProcessor UI thread");
        }
    }

    public void service(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        String method = request.getMethod();

        if (method.equals("GET")) {
            String resource = request.getParameter("_twr_");

            if (resource == null) {
                handleStart(request, response);
            } else {
                handleResource(request, response, resource);
            }
        } else if (method.equals("POST")) {
            String action = request.getParameter("_twa_");

            if (action == null) {
                handlePostEvent(request, response);
            } else if (action.equals("upload")) {
                handleUserUpload(request, response);
            }
        } else {
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }
    }

    private Set<String> getStartArguments(HttpServletRequest request) {
        Set<String> args = new TreeSet<String>();
        StringBuilder sb = new StringBuilder();

        for (Map.Entry<String, String[]> e : ((Map<String, String[]>) request.getParameterMap()).entrySet()) {
            String key = e.getKey();
            String[] values = e.getValue();

            if (values.length > 1) {
                for (int i = 0; i < values.length; i++) {
                    sb.append(key).append(i).append('=').append(values[i]);
                }
            } else {
                sb.append(key).append('=').append(values[0]);
            }

            args.add(sb.toString());
            sb.setLength(0);
        }

        String extraArguments = getInitParameter(InitParam.EXTRA_ARGUMENTS.mixedCaseName());
        if (extraArguments == null)
            extraArguments = "";
        extraArguments = "," + extraArguments + ",";

        if (extraArguments.indexOf(",contextParam,") >= 0) {
            ServletContext sc = getServletContext();

            for (Enumeration<String> ipn = sc.getInitParameterNames(); ipn.hasMoreElements();) {
                String name = ipn.nextElement();
                sb.append("CONTEXT_PARAM_").append(name).append('=').append(sc.getInitParameter(name));
                args.add(sb.toString());
                sb.setLength(0);
            }
        }

        if (extraArguments.indexOf(",initParam,") >= 0) {
            InitParam[] initParams = InitParam.values();

            ipn_loop: for (Enumeration<String> ipn = getInitParameterNames(); ipn.hasMoreElements();) {
                String name = ipn.nextElement();

                for (InitParam ip : initParams) {
                    if (ip.mixedCaseName().equals(name))
                        continue ipn_loop;
                }

                sb.append("INIT_PARAM_").append(name).append('=').append(getInitParameter(name));
                args.add(sb.toString());
                sb.setLength(0);
            }
        }

        if (extraArguments.indexOf(",header,") >= 0) {
            for (Enumeration<String> hn = request.getHeaderNames(); hn.hasMoreElements();) {
                String name = hn.nextElement();
                sb.append("HEADER_").append(name.toUpperCase()).append('=').append(request.getHeader(name));
                args.add(sb.toString());
                sb.setLength(0);
            }
        }

        if (extraArguments.indexOf(",clientInfo,") >= 0) {
            sb.append("CLIENT_INFO_USER").append('=').append(request.getRemoteUser());
            args.add(sb.toString());
            sb.setLength(0);
            sb.append("CLIENT_INFO_HOST").append('=').append(request.getRemoteHost());
            args.add(sb.toString());
            sb.setLength(0);
            sb.append("CLIENT_INFO_ADDRESS").append('=').append(request.getRemoteAddr());
            args.add(sb.toString());
            sb.setLength(0);
        }

        return args;
    }

    private void handleStart(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        HttpSession httpSession = request.getSession();
        String id = httpSession.getId();

        ApplicationHolder holder = (ApplicationHolder) httpSession.getAttribute("instance");
        response.setContentType("text/html");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache, no-store");
        response.setHeader("Expires", "-1");

        String initialFrameTitle = getInitParameter(InitParam.INITIAL_FRAME_TITLE.mixedCaseName());
        if (initialFrameTitle == null || initialFrameTitle.trim().length() == 0)
            initialFrameTitle = "Loading ThinWire Application...";
        response.getOutputStream().write(
                WebApplication.MAIN_PAGE.replaceAll("[$][{]initialFrameTitle[}]", initialFrameTitle).getBytes());

        String reload = getInitParameter(InitParam.RELOAD_ON_REFRESH.mixedCaseName());

        if (holder != null && holder.app != null && (reload == null || reload.toLowerCase().equals("false"))) {
            if (log.isLoggable(LEVEL))
                log.log(LEVEL, "repainting frame for application id=" + id);
            holder.app.repaint();
            return;
        } else {
            if (log.isLoggable(LEVEL))
                log.log(LEVEL, "starting new application with id=" + id);

            if (holder != null) {
                if (log.isLoggable(LEVEL))
                    log.log(LEVEL, "removing existing application instance with id=" + id);
                httpSession.removeAttribute("instance");
            }
        }

        Set<String> args = getStartArguments(request);
        holder = new ApplicationHolder();
        String className = getInitParameter(InitParam.MAIN_CLASS.mixedCaseName());
        Class mainClass;

        if (className == null || className.trim().length() == 0) {
            if (WebServlet.class != this.getClass()) {
                mainClass = this.getClass();
            } else {
                throw new IllegalArgumentException(
                        "The init-param 'mainClass' is required or the servlet you specify must subclass WebServlet and contain a static 'main' method");
            }
        } else {
            try {
                mainClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

        holder.app = new WebApplication(this.getServletContext().getRealPath(""), mainClass,
                getInitParameter(InitParam.STYLE_SHEET.mixedCaseName()), args.toArray(new String[args.size()]),
                initialFrameTitle);
        httpSession.setAttribute("instance", holder);
    }

    private void handleResource(HttpServletRequest request, HttpServletResponse response, String resourceName)
            throws IOException, ServletException {
        ApplicationHolder holder = (ApplicationHolder) request.getSession().getAttribute("instance");

        if (holder == null || holder.app == null) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                    "no application instance exists from which to retreive resources");
            return;
        }

        if (log.isLoggable(LEVEL))
            log.log(LEVEL, "getting resource: " + resourceName);
        byte[] data = holder.app.remoteFileMap.load(resourceName);

        if (data == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        } else {
            try {
                String mimeType;

                //Necessary because the XMLHttpRequest object in certain browsers, such as Opera
                //do not properly handle text/javascript as the content type.  
                if (resourceName.endsWith(".js")) {
                    mimeType = "text/plain";
                } else {
                    mimeType = getServletContext().getMimeType(resourceName.toLowerCase());
                    if (mimeType != null && mimeType.startsWith("image/"))
                        response.setHeader("Cache-Control", "max-age=43200");
                }

                response.setContentType(mimeType);

                if (data[0] == 31 && data[1] == -117) {
                    String encoding = request.getHeader("Accept-Encoding");

                    if (encoding == null || encoding.toLowerCase().indexOf("gzip") == -1) {
                        if (log.isLoggable(Level.WARNING))
                            log.log(Level.WARNING, "User-Agent(" + request.getHeader("User-Agent")
                                    + ") does not accept gzip encoding, decompressing resource: " + resourceName);
                        WebApplication.writeInputToStream(new GZIPInputStream(new ByteArrayInputStream(data)),
                                response.getOutputStream());
                    } else {
                        response.setHeader("Content-Encoding", "gzip");
                        response.getOutputStream().write(data);
                    }
                } else {
                    response.getOutputStream().write(data);
                }
            } catch (Exception e) {
                if (log.isLoggable(Level.WARNING))
                    log.log(Level.WARNING, "resource not found: " + resourceName, e);
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
            }
        }
    }

    private void handlePostEvent(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        HttpSession httpSession = request.getSession();
        ApplicationHolder holder = (ApplicationHolder) httpSession.getAttribute("instance");
        response.setContentType("text/plain; charset=utf-8");
        response.setHeader("Cache-Control", "no-store");
        if (holder == null || holder.app == null)
            return;
        holder.app.processActionEvents(request.getReader(), response.getWriter());

        if (holder.app.state == WebApplication.State.TERMINATED) {
            holder.app = null;
            httpSession.invalidate();
        }
    }

    private void handleUserUpload(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        HttpSession httpSession = request.getSession();
        ApplicationHolder holder = (ApplicationHolder) httpSession.getAttribute("instance");

        if (holder.app != null) {
            try {
                DiskFileUpload upload = new DiskFileUpload();
                upload.setSizeThreshold(1000000);
                upload.setSizeMax(-1);
                upload.setRepositoryPath("C:\\");
                List<FileItem> items = upload.parseRequest(request);

                if (items.size() > 0) {
                    FileChooser.FileInfo f = null;

                    synchronized (holder.app.fileList) {
                        for (FileItem fi : items) {
                            if (!fi.isFormField()) {
                                f = new FileChooser.FileInfo(fi.getName(), fi.getInputStream());
                                holder.app.fileList[0] = f;
                            }
                        }

                        holder.app.fileList.notify();
                    }
                }
            } catch (FileUploadException e) {
                log.log(Level.SEVERE, null, e);
            }
        }

        response.sendRedirect("?_twr_=FileUploadPage.html");
    }
}