com.admc.jcreole.CreoleToHtmlHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.admc.jcreole.CreoleToHtmlHandler.java

Source

/*
 * Copyright 2011 Axis Data Management Corp.
 *
 * 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 com.admc.jcreole;

import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.EnumSet;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileFilter;
import java.net.URL;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import com.admc.util.IOUtil;
import com.admc.util.Expander;
import com.admc.util.FileComparator;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.ServletContextAware;

/**
 * The supplied 'index.creole' file documents usage of this class.
 *
 * That file will be presented (in HTML format) as the home page if you
 * deploy the JCreole-provided war file.
 *
 * @author Blaine Simpson (blaine dot simpson at admc dot com)
 * @since 1.2.0
 */
public class CreoleToHtmlHandler implements InterWikiMapper, HttpRequestHandler, ServletContextAware {
    private static Pattern servletFilePattern = Pattern.compile("(.+)\\.html");

    private String creoleRoot = "WEB-INF/creole";
    private boolean isRootAbsolute;
    private boolean autoIndexing = true;

    private String contextPath;
    private ServletContext application;
    private Indexer indexer = new Indexer();
    private static SimpleDateFormat isoDateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
    private static SimpleDateFormat isoDateFormatter = new SimpleDateFormat("yyyy-MM-dd");
    private static Pattern sortParamPattern = Pattern.compile("([-+])(\\w+)");

    {
        indexer.setFilter(new FileFilter() {
            public boolean accept(File file) {
                String n = file.getName();
                if (n.length() < 1 || n.charAt(0) == '.')
                    return false;
                if (n.equalsIgnoreCase("web-inf"))
                    return false;
                if (n.equalsIgnoreCase("meta-inf"))
                    return false;
                if (file.isDirectory())
                    return true;
                if (!n.endsWith(".creole"))
                    return false;
                return !n.equals("index.creole");
            }
        });
        indexer.setNameTranslationMatchPat("(.+)\\Q.creole");
        indexer.setNameTranslationFormat("%1$s.html");
    }

    EnumSet<JCreolePrivilege> jcreolePrivs = EnumSet.complementOf(EnumSet.of(JCreolePrivilege.RAWHTML));

    public void setServletContext(ServletContext application) {
        this.application = application;
        String creoleRootParam = this.application.getInitParameter("creoleRoot");
        if (creoleRootParam != null)
            creoleRoot = creoleRootParam;
        if (creoleRoot == null || creoleRoot.length() < 1)
            throw new RuntimeException("Invalid 'creoleRoot': " + creoleRootParam);
        isRootAbsolute = creoleRoot.charAt(0) == '/' || creoleRoot.charAt(0) == '\\';
        String autoString = this.application.getInitParameter("autoIndexing");
        autoIndexing = autoString == null || Boolean.parseBoolean(autoString);
        //log("Using creoleRoot of '" + creoleRoot + "'");
    }

    public void handleRequest(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        File css;
        URL url;
        StringBuilder readmeSb = null;
        File fsDirFile = null;
        List<String> cssHrefs = new ArrayList<String>();
        File servletPathFile = new File(req.getServletPath());
        if (contextPath == null) {
            contextPath = application.getContextPath();
            iwUrls.put("home", contextPath);
            String appName = application.getServletContextName();
            iwLabels.put("home", ((appName == null) ? "Site" : appName) + " Home Page");
        }
        InputStream bpStream = null;
        Matcher matcher = servletFilePattern.matcher(servletPathFile.getName());
        if (!matcher.matches())
            throw new ServletException("Servlet " + getClass().getName()
                    + " only supports servlet paths ending with '.html':  " + servletPathFile.getAbsolutePath());
        File crRootedDir = servletPathFile.getParentFile();
        // crRootedDir is the parent dir of the requested path.
        String pageBaseName = matcher.group(1);
        String absUrlDirPath = contextPath + crRootedDir.getAbsolutePath();
        String absUrlBasePath = absUrlDirPath + '/' + pageBaseName;
        File creoleFile = new File((isRootAbsolute ? "" : "/") + creoleRoot + crRootedDir.getAbsolutePath(),
                pageBaseName + ".creole");
        // creoleFile is a /-path either absolute or CR-rooted
        InputStream creoleStream = null;
        creoleStream = isRootAbsolute ? (creoleFile.isFile() ? new FileInputStream(creoleFile) : null)
                : application.getResourceAsStream(creoleFile.getAbsolutePath());
        if (indexer != null) {
            if (isRootAbsolute) {
                fsDirFile = creoleFile.getParentFile();
                if (!fsDirFile.isDirectory())
                    fsDirFile = null;
            } else {
                fsDirFile = new File(application.getRealPath(creoleFile.getParentFile().getAbsolutePath()));
            }
            if (fsDirFile != null && !fsDirFile.isDirectory())
                throw new ServletException(
                        "fsDirFile unexpectedly not a directory: " + fsDirFile.getAbsolutePath());
        }
        if (pageBaseName.equals("index")) {
            File readmeFile = new File(creoleFile.getParentFile(), "readme.creole");
            InputStream readmeStream = isRootAbsolute
                    ? (readmeFile.isFile() ? new FileInputStream(readmeFile) : null)
                    : application.getResourceAsStream(readmeFile.getAbsolutePath());
            readmeSb = new StringBuilder("----\n");
            if (readmeStream == null) {
                readmeSb.append("{{{\n");
                readmeStream = application
                        .getResourceAsStream(new File(crRootedDir, "readme.txt").getAbsolutePath());
                if (readmeStream != null) {
                    readmeSb.append(IOUtil.toStringBuilder(readmeStream));
                    readmeSb.append("\n}}}\n");
                }
            } else {
                readmeSb.append(IOUtil.toStringBuilder(readmeStream));
            }
            if (readmeStream == null)
                readmeSb = null;
        }

        boolean inAncestorDir = false;
        File tmpDir;
        tmpDir = crRootedDir;
        while (tmpDir != null) {
            // Search from crRootedDir to creoleRoot for auxilliary files
            File curDir = new File((isRootAbsolute ? "" : "/") + creoleRoot + tmpDir.getAbsolutePath());
            File bpFile = new File(curDir, "boilerplate.html");
            if (bpStream == null)
                bpStream = isRootAbsolute ? (bpFile.isFile() ? new FileInputStream(bpFile) : null)
                        : application.getResourceAsStream(bpFile.getAbsolutePath());
            url = application.getResource(new File(tmpDir, "site.css").getAbsolutePath());
            if (url != null)
                cssHrefs.add(0, new File(contextPath + tmpDir, "site.css").getAbsolutePath());
            if (creoleStream == null && inAncestorDir && pageBaseName.equals("index") && autoIndexing) {
                File indexFile = new File(curDir, "index.creole");
                creoleStream = isRootAbsolute ? (indexFile.isFile() ? new FileInputStream(indexFile) : null)
                        : application.getResourceAsStream(indexFile.getAbsolutePath());
            }
            tmpDir = tmpDir.getParentFile();
            inAncestorDir = true;
        }
        if (creoleStream == null)
            throw new ServletException("Failed to access:  " + creoleFile.getAbsolutePath());
        if (bpStream == null)
            throw new ServletException("Failed to access 'boilerplate.html' " + "from creole dir or ancestor dir");
        tmpDir = crRootedDir;
        while (tmpDir != null) {
            url = application.getResource(new File(tmpDir, "jcreole.css").getAbsolutePath());
            if (url != null)
                cssHrefs.add(0, new File(contextPath + tmpDir, "jcreole.css").getAbsolutePath());
            tmpDir = tmpDir.getParentFile();
        }

        JCreole jCreole = new JCreole(IOUtil.toString(bpStream));
        Expander htmlExpander = jCreole.getHtmlExpander();
        Date now = new Date();
        htmlExpander.put("isoDateTime", isoDateTimeFormatter.format(now), false);
        htmlExpander.put("isoDate", isoDateFormatter.format(now), false);
        htmlExpander.put("contextPath", contextPath, false);
        htmlExpander.put("pageBaseName", pageBaseName, false);
        htmlExpander.put("pageDirPath", absUrlDirPath, false);
        htmlExpander.put("pageTitle", absUrlBasePath, false);
        if (readmeSb == null) {
            htmlExpander.put("readmeContent", "");
        } else {
            JCreole readmeJCreole = new JCreole();
            readmeJCreole.setHtmlExpander(htmlExpander);
            readmeJCreole.setInterWikiMapper(this);
            readmeJCreole.setPrivileges(jcreolePrivs);
            htmlExpander.put("readmeContent", readmeJCreole.postProcess(readmeJCreole.parseCreole(readmeSb), "\n"),
                    false);
        }
        if (fsDirFile != null) {
            FileComparator.SortBy sortBy = FileComparator.SortBy.NAME;
            boolean ascending = true;
            String sortStr = req.getParameter("sort");
            if (sortStr != null) {
                Matcher m = sortParamPattern.matcher(sortStr);
                if (!m.matches())
                    throw new ServletException("Malformatted sort value: " + sortStr);
                ascending = m.group(1).equals("+");
                try {
                    sortBy = Enum.valueOf(FileComparator.SortBy.class, m.group(2));
                } catch (Exception e) {
                    throw new ServletException("Malformatted sort string: " + sortStr);
                }
            }
            htmlExpander.put("index",
                    "\n" + indexer.generateTable(fsDirFile, absUrlDirPath, true, sortBy, ascending), false);
            // An alternative for using the Tomcat-like Indexer in a
            // htmlExpander would be to write a Creole table to a
            // creoleExpander.
        }

        /* Set up Creole macros like this:
        Expander creoleExpander =
            new Expander(Expander.PairedDelims.RECTANGULAR);
        creoleExpander.put("testMacro", "\n\n<<prettyPrint>>\n{{{\n"
            + "!/bin/bash -p\n\ncp /etc/inittab /tmp\n}}}\n");
        jCreole.setCreoleExpander(creoleExpander);
        */

        if (cssHrefs.size() > 0)
            jCreole.addCssHrefs(cssHrefs);
        jCreole.setInterWikiMapper(this);
        jCreole.setPrivileges(jcreolePrivs);
        String html = jCreole.postProcess(jCreole.parseCreole(IOUtil.toStringBuilder(creoleStream)), "\n");
        resp.setBufferSize(1024);
        resp.setContentType("text/html");
        resp.getWriter().print(html);
    }

    // InterWikiMapper implementation follows
    protected Map<String, String> iwUrls = new HashMap<String, String>();
    protected Map<String, String> iwLabels = new HashMap<String, String>();

    // TODO:  Add translations for all of the popular public Wikis
    public String toPath(String wikiName, String wikiPage) {
        if (wikiPage == null)
            throw new RuntimeException("wiki page name not given to InterWikiMapper");
        if (wikiName == null)
            return iwUrls.get(wikiPage);
        if (wikiName.equals("wikipedia"))
            return "http://en.wikipedia.org/wiki/" + wikiPage;
        return null;
    }

    public String toLabel(String wikiName, String wikiPage) {
        if (wikiPage == null)
            throw new RuntimeException("wiki page name not given to InterWikiMapper");
        if (wikiName == null)
            return iwLabels.get(wikiPage);
        if (wikiName.equals("wikipedia"))
            return wikiPage + " @ Wikipedia";
        return null;
    }
}