net.contextfw.web.application.internal.WebResponder.java Source code

Java tutorial

Introduction

Here is the source code for net.contextfw.web.application.internal.WebResponder.java

Source

/**
 * Copyright 2010 Marko Lavikainen
 *
 * Licensed 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.
 */

package net.contextfw.web.application.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import net.contextfw.org.dom4j.io.XMLWriter;
import net.contextfw.web.application.DocumentProcessor;
import net.contextfw.web.application.WebApplicationException;
import net.contextfw.web.application.configuration.Configuration;
import net.contextfw.web.application.development.XMLResponseLogger;
import net.contextfw.web.application.internal.configuration.KeyValue;
import net.contextfw.web.application.internal.util.ResourceEntry;
import net.contextfw.web.application.internal.util.ResourceScanner;
import net.contextfw.web.application.internal.util.Utils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.HTMLWriter;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

@Singleton
public class WebResponder {

    private static final Pattern XSL_ACCEPTOR = Pattern.compile(".*\\.xsl", Pattern.CASE_INSENSITIVE);

    private Logger logger = LoggerFactory.getLogger(WebResponder.class);

    private List<String> rootResourcePaths = new ArrayList<String>();
    private final List<String> resourcePaths = new ArrayList<String>();
    private final List<KeyValue<String, String>> namespaces = new ArrayList<KeyValue<String, String>>();

    private final Transformers transformers;

    private final XMLResponseLogger responseLogger;
    private final DocumentProcessor xslPostProcessor;

    private final OutputFormat htmlFormat;

    public enum Mode {

        INIT("text/html;charset=UTF-8"), UPDATE("text/xml;charset=UTF-8"), XML("text/xml;charset=UTF-8");

        private final String contentType;

        private Mode(String contentType) {
            this.contentType = contentType;
        }

        public String getContentType() {
            return contentType;
        }
    }

    @SuppressWarnings("unchecked")
    @Inject
    public WebResponder(Configuration configuration, Injector injector) {
        rootResourcePaths.add("net.contextfw.web.application");
        transformers = new Transformers();
        resourcePaths.addAll(configuration.get(Configuration.RESOURCE_PATH));
        namespaces.addAll(configuration.get(Configuration.NAMESPACE));

        htmlFormat = OutputFormat.createCompactFormat();
        htmlFormat.setXHTML(true);
        htmlFormat.setTrimText(false);
        htmlFormat.setPadText(true);
        htmlFormat.setNewlines(false);
        htmlFormat.setExpandEmptyElements(true);

        if (configuration.get(Configuration.XSL_POST_PROCESSOR) != null) {
            xslPostProcessor = Utils.toInstance(configuration.get(Configuration.XSL_POST_PROCESSOR), injector);
        } else {
            xslPostProcessor = null;
        }
        if (configuration.get(Configuration.LOG_XML)) {
            Object obj = configuration.get(Configuration.XML_RESPONSE_LOGGER);
            if (obj instanceof XMLResponseLogger) {
                responseLogger = (XMLResponseLogger) obj;
            } else if (obj instanceof Class && XMLResponseLogger.class.isAssignableFrom((Class<?>) obj)) {
                responseLogger = injector.getInstance((Class<XMLResponseLogger>) obj);
            } else {
                responseLogger = null;
            }
        } else {
            responseLogger = null;
        }
    }

    public void logXML(Document d) {
        try {
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter writer;

            StringWriter xml = new StringWriter();
            writer = new XMLWriter(xml, format);
            writer.write(d);

            responseLogger.logXML(xml.toString());

        } catch (Exception e) {
            throw new WebApplicationException(e);
        }
    }

    protected Document getXSLDocument() {

        List<ResourceEntry> rootResources = ResourceScanner.findResources(rootResourcePaths, XSL_ACCEPTOR);

        ResourceEntry root = null;

        Iterator<ResourceEntry> iter = rootResources.iterator();
        if (iter != null) {
            while (iter.hasNext()) {
                ResourceEntry next = iter.next();
                if (next.getPath().endsWith("root.xsl")) {
                    iter.remove();
                    root = next;
                    break;
                }
            }
        }

        if (root == null) {
            throw new InternalWebApplicationException("root.xsl was not found");
        }

        List<ResourceEntry> resources = ResourceScanner.findResources(resourcePaths, XSL_ACCEPTOR);

        InputStream stream;
        SAXReader reader = new SAXReader();
        try {
            stream = root.getInputStream();
            Document document = reader.read(stream);
            stream.close();
            for (KeyValue<String, String> entry : namespaces) {
                document.getRootElement().addNamespace(entry.getKey(), entry.getValue());
            }

            Element stylesheet = (Element) document.selectSingleNode("//stylesheet");

            // Adding other stylesheets

            for (ResourceEntry file : resources) {
                if (file.getPath().endsWith(".xsl")) {
                    reader = new SAXReader();
                    stream = file.getInputStream();

                    try {
                        Document child = reader.read(stream);
                        for (Object el : child.getRootElement().elements()) {
                            if (el instanceof Node) {
                                stylesheet.add(((Node) el).detach());
                            }
                        }
                    } catch (DocumentException de) {
                        transformers.invalidate();
                        throw new WebApplicationException("Xsl-file " + file.getPath() + " contains errors", de);
                    } finally {
                        stream.close();
                    }

                }
            }

            if (xslPostProcessor != null) {
                xslPostProcessor.process(document);
            }
            return document;
        } catch (DocumentException e) {
            throw new WebApplicationException(e);
        } catch (UnsupportedEncodingException e) {
            throw new WebApplicationException(e);
        } catch (IOException e) {
            throw new WebApplicationException(e);
        }
    }

    public void sendResponse(Document document, HttpServletResponse resp, Mode mode)
            throws ServletException, IOException {
        if (responseLogger != null) {
            logXML(document);
        }
        if (mode != Mode.XML) {
            sendHTMLResponse(document, resp, mode);
        } else {
            sendXMLResponse(document, resp);
        }
    }

    private void sendXMLResponse(Document document, HttpServletResponse resp) throws IOException {
        resp.setContentType(Mode.XML.getContentType());
        resp.setHeader("Expires", "-1");
        resp.setHeader("Pragma", "no-cache");
        resp.setHeader("Cache-Control", "no-cache, no-store");
        OutputFormat format = OutputFormat.createPrettyPrint();
        new XMLWriter(resp.getWriter(), format).write(document);
    }

    public void sendHTMLResponse(Document document, HttpServletResponse resp, Mode mode)
            throws ServletException, IOException {

        resp.setContentType(mode.getContentType());
        resp.setHeader("Expires", "-1");
        resp.setHeader("Pragma", "no-cache");
        resp.setHeader("Cache-Control", "no-cache, no-store");

        if (!transformers.isInitialized()) {
            synchronized (transformers) {
                if (!transformers.isInitialized()) {
                    transformers.initialize(getXSLDocument());
                }
            }
        }

        Document rDocument = transformers.transform(document);

        if (mode == Mode.INIT) {
            rDocument.addDocType("html", "-//W3C//DTD XHTML 1.0 Transitional//EN",
                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
        }

        new HTMLWriter(resp.getWriter(), htmlFormat).write(rDocument);
    }

    public void clean() {
        logger.debug("Reloading resources");
        transformers.invalidate();
    }
}