com.github.jknack.handlebars.server.HbsServer.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jknack.handlebars.server.HbsServer.java

Source

/**
 * Copyright (c) 2012-2013 Edgar Espina
 *
 * This file is part of Handlebars.java.
 *
 * 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.github.jknack.handlebars.server;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.net.MalformedURLException;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.HelperRegistry;
import com.github.jknack.handlebars.HumanizeHelper;
import com.github.jknack.handlebars.Jackson2Helper;
import com.github.jknack.handlebars.MarkdownHelper;
import com.github.jknack.handlebars.helper.StringHelpers;
import com.github.jknack.handlebars.io.FileTemplateLoader;
import com.github.jknack.handlebars.io.TemplateLoader;
import com.github.jknack.handlebars.io.URLTemplateLoader;

/**
 * A handlebars web server.
 *
 * @author edgar.espina
 */
public class HbsServer {

    /**
     * The logging system.
     */
    public static final Logger logger = LoggerFactory.getLogger(HbsServer.class);

    public static final String CONTEXT = "/";

    public static final String CONTENT_TYPE = "text/html";

    public static final int PORT = 6780;

    public static String version;

    static {
        InputStream in = null;
        try {
            in = HbsServer.class.getResourceAsStream("/hbs.properties");
            Properties properties = new Properties();
            properties.load(in);
            version = properties.getProperty("version");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(in);
        }

    }

    public static class Options {
        @Option(name = "-dir", aliases = "-d", required = true, usage = "set the template directory", metaVar = " ")
        public File dir;

        @Option(name = "-suffix", aliases = "-sx", usage = "set the template's suffix, default is: "
                + TemplateLoader.DEFAULT_SUFFIX, metaVar = " ")
        public String suffix = TemplateLoader.DEFAULT_SUFFIX;

        @Option(name = "-prefix", aliases = "-px", usage = "set the template's prefix, default is: "
                + TemplateLoader.DEFAULT_PREFIX, metaVar = " ")
        public String prefix = TemplateLoader.DEFAULT_PREFIX;

        @Option(name = "-context", aliases = "-c", usage = "set the web context's path, default is: "
                + CONTEXT, metaVar = " ")
        public String contextPath = CONTEXT;

        @Option(name = "-port", aliases = "-p", usage = "set the port's number, default is: " + PORT, metaVar = " ")
        public int port = PORT;

        @Option(name = "-contentType", aliases = "-ct", usage = "set the content's type header, default is: "
                + CONTENT_TYPE, metaVar = " ")
        public String contentType = CONTENT_TYPE;

        @Option(name = "-encoding", aliases = "-e", usage = "set the charset used it while rendering, default is: UTF-8", metaVar = " ")
        public String encoding = "UTF-8";
    }

    public static void main(final String[] args) throws Exception {
        Options arguments = new Options();
        CmdLineParser parser = new CmdLineParser(arguments);
        try {
            parser.parseArgument(args);
            run(arguments);
        } catch (CmdLineException e) {
            System.err.println(e.getMessage());
            String os = System.getProperty("os.name").toLowerCase();
            System.err.println("Usage:");
            String program = "java -jar handlebars-proto-${version}.jar";
            if (os.contains("win")) {
                program = "handlebars";
            }
            System.err.println("  " + program + " [-option value]");
            System.err.println("Options:");
            parser.printUsage(System.err);
        }
    }

    /**
     * Start a Handlebars server.
     *
     * @param args The command line arguments.
     * @throws Exception If something goes wrong.
     */
    public static void run(final Options args) throws Exception {
        if (!args.dir.exists()) {
            System.out.println("File not found: " + args.dir);
        }
        logger.info("Welcome to the Handlebars.java server v" + version);

        URLTemplateLoader loader = new FileTemplateLoader(args.dir);
        loader.setPrefix(new File(args.dir, args.prefix).getAbsolutePath());
        loader.setSuffix(args.suffix);
        Handlebars handlebars = new Handlebars(loader);

        /**
         * Helper wont work in the stand-alone version, so we add a default helper
         * that render the plain text.
         */
        handlebars.registerHelper(HelperRegistry.HELPER_MISSING, new Helper<Object>() {
            @Override
            public CharSequence apply(final Object context, final com.github.jknack.handlebars.Options options)
                    throws IOException {
                return new Handlebars.SafeString(options.fn.text());
            }
        });
        handlebars.registerHelper("json", Jackson2Helper.INSTANCE);
        handlebars.registerHelper("md", new MarkdownHelper());
        // String helpers
        StringHelpers.register(handlebars);
        // Humanize helpers
        HumanizeHelper.register(handlebars);

        final Server server = new Server(args.port);
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                logger.info("Hope you enjoy it! bye!");
                try {
                    server.stop();
                } catch (Exception ex) {
                    logger.info("Cann't stop the server", ex);
                }
            }
        }));

        server.addLifeCycleListener(new AbstractLifeCycleListener() {
            @Override
            public void lifeCycleStarted(final LifeCycle event) {
                logger.info("Open a browser and type:");
                logger.info("  http://localhost:{}{}/[page]{}", new Object[] { args.port,
                        args.contextPath.equals(CONTEXT) ? "" : args.contextPath, args.suffix });
            }
        });

        WebAppContext root = new WebAppContext();
        ErrorHandler errorHandler = new ErrorHandler() {
            @Override
            protected void writeErrorPageHead(final HttpServletRequest request, final Writer writer, final int code,
                    final String message) throws IOException {
                writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>\n");
                writer.write("<title>{{");
                writer.write(Integer.toString(code));
                writer.write("}}");
                writer.write("</title>\n");
                writer.write("<style>body{font-family: monospace;}</style>");
            }

            @Override
            protected void writeErrorPageMessage(final HttpServletRequest request, final Writer writer,
                    final int code, final String message, final String uri) throws IOException {
                writer.write("<div align=\"center\">");
                writer.write(
                        "<p><span style=\"font-size: 48px;\">{{</span><span style=\"font-size: 36px; color:#999;\">");
                writer.write(Integer.toString(code));
                writer.write("</span><span style=\"font-size: 48px;\">}}</span></p>");
                writer.write("</h2>\n<p>Problem accessing ");
                write(writer, uri);
                writer.write(". Reason:\n<pre>    ");
                write(writer, message);
                writer.write("</pre></p>");
                writer.write("</div>");
                writer.write("<hr />");
            }

            @Override
            protected void writeErrorPageBody(final HttpServletRequest request, final Writer writer, final int code,
                    final String message, final boolean showStacks) throws IOException {
                String uri = request.getRequestURI();

                writeErrorPageMessage(request, writer, code, message, uri);
            }
        };
        root.setErrorHandler(errorHandler);
        root.setContextPath(args.contextPath);
        root.setResourceBase(args.dir.getAbsolutePath());
        root.addServlet(new ServletHolder(new HbsServlet(handlebars, args)), "*" + args.suffix);

        root.setParentLoaderPriority(true);

        // prevent jetty from loading the webapp web.xml
        root.setConfigurations(new Configuration[] { new WebXmlConfiguration() {
            @Override
            protected Resource findWebXml(final WebAppContext context) throws IOException, MalformedURLException {
                return null;
            }
        } });

        server.setHandler(root);

        server.start();
        server.join();
    }

}