nl.armatiek.xslweb.serializer.RequestSerializer.java Source code

Java tutorial

Introduction

Here is the source code for nl.armatiek.xslweb.serializer.RequestSerializer.java

Source

package nl.armatiek.xslweb.serializer;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.File;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.bind.DatatypeConverter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.helpers.XMLReaderFactory;

import com.sun.xml.ws.util.xml.ContentHandlerToXMLStreamWriter;

import javanet.staxutils.IndentingXMLStreamWriter;
import nl.armatiek.xslweb.configuration.Attribute;
import nl.armatiek.xslweb.configuration.Context;
import nl.armatiek.xslweb.configuration.Definitions;
import nl.armatiek.xslweb.configuration.WebApp;
import nl.armatiek.xslweb.error.XSLWebException;
import nl.armatiek.xslweb.xml.BodyFilter;

public class RequestSerializer {

    private static final String URI = Definitions.NAMESPACEURI_XSLWEB_REQUEST;

    private HttpServletRequest req;
    private WebApp webApp;
    private boolean developmentMode;
    private XMLStreamWriter xsw;
    private XMLReader xmlReader;
    private File reposDir;

    public RequestSerializer(HttpServletRequest req, WebApp webApp) {
        this.req = req;
        this.webApp = webApp;
        this.developmentMode = webApp.getDevelopmentMode();
    }

    public String serializeToXML() throws Exception {
        StringWriter sw = new StringWriter();

        List<FileItem> fileItems = getMultipartContentItems();

        XMLOutputFactory output = XMLOutputFactory.newInstance();
        this.xsw = output.createXMLStreamWriter(sw);
        if (developmentMode) {
            this.xsw = new IndentingXMLStreamWriter(this.xsw);
        }

        xsw.writeStartDocument();
        xsw.setPrefix("req", URI);
        xsw.writeStartElement(URI, "request");
        xsw.writeNamespace("req", URI);

        serializeProperties();
        serializeHeaders();
        serializeParameters(fileItems);
        serializeBody(fileItems);
        serializeAttributes();
        serializeFileUploads(fileItems);
        serializeSession();
        serializeCookies();

        xsw.writeEndElement();
        xsw.writeEndDocument();

        return sw.toString();
    }

    public void close() throws IOException {
        if (reposDir != null && reposDir.exists()) {
            FileUtils.deleteDirectory(reposDir);
        }
    }

    private List<FileItem> getMultipartContentItems() throws IOException, FileUploadException {
        List<FileItem> items = null;
        boolean isMultipart = ServletFileUpload.isMultipartContent(req);
        if (isMultipart) {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            factory.setSizeThreshold(0);
            reposDir = new File(FileUtils.getTempDirectory(), File.separatorChar + UUID.randomUUID().toString());
            if (!reposDir.mkdirs()) {
                throw new XSLWebException(
                        String.format("Could not create DiskFileItemFactory repository directory (%s)",
                                reposDir.getAbsolutePath()));
            }
            factory.setRepository(reposDir);
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setSizeMax(1024 * 1024 * webApp.getMaxUploadSize());
            items = upload.parseRequest(req);
        }
        return items;
    }

    private boolean hasItems(List<FileItem> fileItems, boolean formField) {
        boolean result = false;
        if (fileItems == null) {
            return result;
        }
        Iterator<FileItem> iter = fileItems.iterator();
        while (iter.hasNext()) {
            FileItem item = iter.next();
            if (item.isFormField() && formField) {
                return true;
            } else if (!item.isFormField() && !formField) {
                return true;
            }
        }
        return result;
    }

    private void serializeProperties() throws Exception {
        dataElement(xsw, URI, "auth-type", req.getAuthType());
        dataElement(xsw, URI, "character-encoding", req.getCharacterEncoding());
        dataElement(xsw, URI, "content-length", Integer.toString(req.getContentLength()));
        dataElement(xsw, URI, "context-path", req.getContextPath());
        dataElement(xsw, URI, "content-type", req.getContentType());
        dataElement(xsw, URI, "local-addr", req.getLocalAddr());
        // locale
        dataElement(xsw, URI, "local-name", req.getLocalName());
        dataElement(xsw, URI, "local-port", Integer.toString(req.getLocalPort()));
        dataElement(xsw, URI, "method", req.getMethod());
        String path = StringUtils.substringAfter(safeString(req.getServletPath()) + safeString(req.getPathInfo()),
                webApp.getPath());
        if (StringUtils.isBlank(path)) {
            path = "/";
        }
        dataElement(xsw, URI, "path", path);
        dataElement(xsw, URI, "path-info", req.getPathInfo());
        dataElement(xsw, URI, "path-translated", req.getPathTranslated());
        dataElement(xsw, URI, "protocol", req.getProtocol());
        dataElement(xsw, URI, "query-string", req.getQueryString());
        dataElement(xsw, URI, "remote-addr", req.getRemoteAddr());
        dataElement(xsw, URI, "remote-host", req.getRemoteHost());
        dataElement(xsw, URI, "remote-port", Integer.toString(req.getRemotePort()));
        dataElement(xsw, URI, "remote-user", req.getRemoteUser());
        dataElement(xsw, URI, "requested-session-id", req.getRequestedSessionId());
        dataElement(xsw, URI, "request-URI", req.getRequestURI());
        dataElement(xsw, URI, "request-url", req.getRequestURL().toString());
        dataElement(xsw, URI, "scheme", req.getScheme());
        dataElement(xsw, URI, "server-name", req.getServerName());
        dataElement(xsw, URI, "server-port", Integer.toString(req.getServerPort()));
        dataElement(xsw, URI, "servlet-path", req.getServletPath());
        dataElement(xsw, URI, "webapp-path", webApp.getPath());
        // userPrincipal
        dataElement(xsw, URI, "is-secure", Boolean.toString(req.isSecure()));
        dataElement(xsw, URI, "is-requested-session-id-from-cookie",
                Boolean.toString(req.isRequestedSessionIdFromCookie()));
        dataElement(xsw, URI, "is-requested-session-id-from-url",
                Boolean.toString(req.isRequestedSessionIdFromURL()));
        dataElement(xsw, URI, "is-requested-session-id-valid", Boolean.toString(req.isRequestedSessionIdValid()));
        // isUserInRole
        // login
        // logout
    }

    @SuppressWarnings("rawtypes")
    private void serializeHeaders() throws Exception {
        Enumeration headerNames = req.getHeaderNames();
        if (headerNames.hasMoreElements()) {
            xsw.writeStartElement(URI, "headers");
            while (headerNames.hasMoreElements()) {
                String headerName = (String) headerNames.nextElement();
                xsw.writeStartElement(URI, "header");
                xsw.writeAttribute("name", headerName);
                xsw.writeCharacters(req.getHeader(headerName));
                xsw.writeEndElement();
            }
            xsw.writeEndElement();
        }
    }

    @SuppressWarnings("rawtypes")
    private void serializeParameters(List<FileItem> fileItems) throws Exception {
        if (fileItems != null) {
            if (hasItems(fileItems, true)) {
                Iterator<FileItem> iter = fileItems.iterator();
                if (iter.hasNext()) {
                    xsw.writeStartElement(URI, "parameters");
                    while (iter.hasNext()) {
                        FileItem item = iter.next();
                        if (item.isFormField()) {
                            String paramName = item.getFieldName();
                            String value = item.getString();
                            xsw.writeStartElement(URI, "parameter");
                            xsw.writeAttribute("name", paramName);
                            dataElement(xsw, URI, "value", value);
                            xsw.writeEndElement();
                        }
                    }
                    xsw.writeEndElement();
                }
            }
        } else {
            Enumeration paramNames = req.getParameterNames();
            if (paramNames.hasMoreElements()) {
                xsw.writeStartElement(URI, "parameters");
                while (paramNames.hasMoreElements()) {
                    String paramName = (String) paramNames.nextElement();
                    xsw.writeStartElement(URI, "parameter");
                    xsw.writeAttribute("name", paramName);
                    String[] values = req.getParameterValues(paramName);
                    for (String value : values) {
                        dataElement(xsw, URI, "value", value);
                    }
                    xsw.writeEndElement();
                }
                xsw.writeEndElement();
            }
        }
    }

    private void serializeBody(List<FileItem> fileItems) throws Exception {
        if (!req.getMethod().equals("POST") || fileItems != null) {
            return;
        }
        PushbackReader pushbackReader = new PushbackReader(req.getReader());
        int b = pushbackReader.read();
        if (b == -1) {
            return;
        }
        pushbackReader.unread(b);
        xsw.writeStartElement(URI, "body");
        String contentType = req.getContentType();
        if (contentType != null && contentType.contains(";")) {
            contentType = contentType.split(";")[0].trim();
        }
        if ((contentType != null) && (contentType.startsWith("text/xml")
                || contentType.startsWith("application/xml") || contentType.endsWith("+xml"))) {
            getFilteredXMLReader().parse(new InputSource(pushbackReader));
        } else if ((contentType != null) && contentType.startsWith("text/plain")) {
            xsw.writeCharacters(IOUtils.toString(pushbackReader));
        } else {
            xsw.writeCData(Base64.encodeBase64String(IOUtils.toByteArray(pushbackReader, "UTF-8")));
        }
        xsw.writeEndElement();
    }

    @SuppressWarnings("rawtypes")
    private void serializeAttributes() throws Exception {
        Enumeration attrNames = req.getAttributeNames();
        if (attrNames.hasMoreElements()) {
            xsw.writeStartElement(URI, "attributes");
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                xsw.writeStartElement(URI, "atribute");
                xsw.writeAttribute("name", attrName);
                xsw.writeCharacters(req.getAttribute(attrName).toString());
                xsw.writeEndElement();
            }
            xsw.writeEndElement();
        }
    }

    private void serializeFileUploads(List<FileItem> fileItems) throws Exception {
        if (!hasItems(fileItems, false)) {
            return;
        }
        Iterator<FileItem> iter = fileItems.iterator();
        if (iter.hasNext()) {
            xsw.writeStartElement(URI, "file-uploads");
            while (iter.hasNext()) {
                FileItem item = iter.next();
                if (!item.isFormField() && StringUtils.isNotBlank(item.getName())) {
                    String fileName = item.getName();
                    File file = new File(reposDir, fileName);
                    xsw.writeStartElement(URI, "file-upload");
                    dataElement(xsw, URI, "file-path", file.getAbsolutePath());
                    dataElement(xsw, URI, "field-name", item.getFieldName());
                    dataElement(xsw, URI, "file-name", item.getName());
                    dataElement(xsw, URI, "content-type", item.getContentType());
                    dataElement(xsw, URI, "size", Long.toString(item.getSize()));
                    xsw.writeEndElement();
                    item.write(file);
                }
            }
            xsw.writeEndElement();
        }
    }

    @SuppressWarnings("rawtypes")
    private void serializeSession() throws Exception {
        HttpSession session = req.getSession();
        if (session == null) {
            return;
        }
        xsw.writeStartElement(URI, "session");
        dataElement(xsw, URI, "creation-time", getXsDateTimeString(new Date(session.getCreationTime())));
        dataElement(xsw, URI, "id", session.getId());
        dataElement(xsw, URI, "last-accessed-time", getXsDateTimeString(new Date(session.getLastAccessedTime())));
        dataElement(xsw, URI, "max-inactive-interval", Integer.toString(session.getMaxInactiveInterval()));
        dataElement(xsw, URI, "is-new", Boolean.toString(session.isNew()));
        Enumeration attrNames = session.getAttributeNames();
        if (attrNames.hasMoreElements()) {
            xsw.writeStartElement(URI, "attributes");
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                xsw.writeStartElement(URI, "attribute");
                xsw.writeAttribute("name", attrName);
                Object attr = session.getAttribute(attrName);
                if (attr instanceof Collection) {
                    @SuppressWarnings("unchecked")
                    Collection<Attribute> attrs = (Collection<Attribute>) attr;
                    for (Attribute a : attrs) {
                        xsw.writeStartElement(URI, "item");
                        if (a.isSerialized()) {
                            xsw.writeAttribute("type", a.getType());
                            getFilteredXMLReader().parse(new InputSource(new StringReader(a.getSerializedValue())));
                        } else {
                            xsw.writeAttribute("type", a.getType());
                            xsw.writeCharacters(a.getValue().toString());
                        }
                        xsw.writeEndElement();
                    }
                } else {
                    xsw.writeCharacters(attr.toString());
                }
                xsw.writeEndElement();
            }
            xsw.writeEndElement();
        }
        xsw.writeEndElement();
    }

    private void serializeCookies() throws Exception {
        Cookie[] cookies = req.getCookies();
        if (cookies != null && cookies.length > 0) {
            xsw.writeStartElement(URI, "cookies");
            for (Cookie cookie : cookies) {
                xsw.writeStartElement(URI, "cookie");
                dataElement(xsw, URI, "comment", cookie.getComment());
                dataElement(xsw, URI, "domain", cookie.getDomain());
                dataElement(xsw, URI, "max-age", Integer.toString(cookie.getMaxAge()));
                dataElement(xsw, URI, "name", cookie.getName());
                dataElement(xsw, URI, "path", cookie.getPath());
                dataElement(xsw, URI, "is-secure", Boolean.toString(cookie.getSecure()));
                dataElement(xsw, URI, "value", cookie.getValue());
                dataElement(xsw, URI, "version", Integer.toString(cookie.getVersion()));
                xsw.writeEndElement();
            }
            xsw.writeEndElement();
        }
    }

    private void dataElement(XMLStreamWriter xsw, String uri, String localName, String text)
            throws XMLStreamException {
        if (text == null) {
            return;
        }
        if (text.equals("")) {
            xsw.writeEmptyElement(uri, localName);
        } else {
            xsw.writeStartElement(uri, localName);
            xsw.writeCharacters(text);
            xsw.writeEndElement();
        }
    }

    private XMLReader getFilteredXMLReader() throws SAXException {
        if (this.xmlReader == null) {
            XMLFilterImpl filter = new BodyFilter();
            filter.setContentHandler(new ContentHandlerToXMLStreamWriter(xsw));
            this.xmlReader = XMLReaderFactory.createXMLReader();
            this.xmlReader.setFeature("http://xml.org/sax/features/validation", false);
            this.xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
            this.xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
            if (Context.getInstance().getParserHardening()) {
                this.xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
                this.xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
                this.xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
                this.xmlReader.setEntityResolver(new EntityResolver() {
                    @Override
                    public InputSource resolveEntity(String publicId, String systemId)
                            throws SAXException, IOException {
                        return null;
                    }
                });
                this.xmlReader.setProperty("http://apache.org/xml/properties/security-manager",
                        "org.apache.xerces.util.SecurityManager");
            }
            this.xmlReader.setContentHandler(filter);
        }
        return this.xmlReader;
    }

    private String safeString(String str) {
        return (str == null) ? "" : str;
    }

    private String getXsDateTimeString(Date date) {
        Calendar cal = Calendar.getInstance();
        if (date != null) {
            cal.setTime(date);
        }
        return DatatypeConverter.printDateTime(cal);
    }

}