net.nicoulaj.benchmark.mockwebapp.MockWebAppServlet.java Source code

Java tutorial

Introduction

Here is the source code for net.nicoulaj.benchmark.mockwebapp.MockWebAppServlet.java

Source

/*
 * Copyright (c) 2011 Julien Nicoulaud <julien.nicoulaud@gmail.com>
 *
 * 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.nicoulaj.benchmark.mockwebapp;

import net.nicoulaj.benchmark.mockwebapp.config.MockWebAppConfig;
import org.apache.commons.vfs.FileChangeEvent;
import org.apache.commons.vfs.FileListener;
import org.apache.commons.vfs.VFS;
import org.apache.commons.vfs.impl.DefaultFileMonitor;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;

/**
 * {@link HttpServlet} that defers requests handling to a {@link MockWebAppConfig}.
 *
 * @author Julien Nicoulaud <julien.nicoulaud@gmail.com>
 * @since 1.0.0
 */
public class MockWebAppServlet extends HttpServlet {

    /**
     * The name of property used to define the path to the configuration file to use.
     */
    public static final String MOCK_WEB_APP_CONF_PROPERTY = "mock-web-app-conf";

    /**
     * The {@link MockWebAppConfig} currently in use.
     */
    protected MockWebAppConfig mockWebAppConfig;

    /**
     * The file monitor used to detect changes in the configuration file.
     */
    protected DefaultFileMonitor fileMonitor;

    /**
     * Initialize the servlet.
     * <p/>
     * Loads the {@link #mockWebAppConfig} by looking up the {@link #MOCK_WEB_APP_CONF_PROPERTY} as a system property or init parameter,
     * and sets up a listener on the file changes.
     *
     * @param config the {@link ServletConfig}, optionally with a {@link #MOCK_WEB_APP_CONF_PROPERTY} parameter.
     * @throws ServletException if the {@link #MOCK_WEB_APP_CONF_PROPERTY} was neither defined as a system property nor an init parameter.
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // Locate the config file parameter.
        String configFilePath = System.getProperty(MOCK_WEB_APP_CONF_PROPERTY);
        if (configFilePath == null)
            configFilePath = config.getInitParameter(MOCK_WEB_APP_CONF_PROPERTY);
        if (configFilePath == null)
            throw new ServletException("No mock web app config file defined. Please define one using the '"
                    + MOCK_WEB_APP_CONF_PROPERTY + "' system property or servlet init parameter.");

        // Setup the config file changes listener.
        try {
            fileMonitor = new DefaultFileMonitor(new ConfigFileListener());
            fileMonitor.addFile(VFS.getManager().resolveFile(new File("."), configFilePath));
            fileMonitor.start();
        } catch (Exception e) {
            getServletContext().log(
                    "Failed setting up config file changes listener, config file changes will not be taken into account",
                    e);
        }

        // Load the config from the file.
        final File configFile = new File(configFilePath);
        try {
            mockWebAppConfig = MockWebAppConfig.Parser.parseConfig(configFile);
            getServletContext().log("Loaded config file " + configFilePath);
        } catch (Exception e) {
            getServletContext().log("Failed loading config, please replace it with a valid one", e);
        }
    }

    /**
     * Prepare the servlet for stopping service.
     * <p/>
     * Disposes the config file changes monitor.
     */
    @Override
    public void destroy() {
        if (fileMonitor != null)
            fileMonitor.stop();
        super.destroy();
    }

    /**
     * Handle a GET request.
     * <p/>
     * Defers the request to {@link #mockWebAppConfig} when possible.
     *
     * @param req  the client request.
     * @param resp the servlet response.
     * @throws IOException      if an input or output error occured while handling the request.
     * @throws ServletException if the request could not be handled.
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (mockWebAppConfig != null)
            mockWebAppConfig.process(req, resp);
        else
            super.doDelete(req, resp);
    }

    /**
     * Handle a HEAD request.
     * <p/>
     * Defers the request to {@link #mockWebAppConfig} when possible.
     *
     * @param req  the client request.
     * @param resp the servlet response.
     * @throws IOException      if an input or output error occured while handling the request.
     * @throws ServletException if the request could not be handled.
     */
    @Override
    protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (mockWebAppConfig != null)
            mockWebAppConfig.process(req, resp);
        else
            super.doDelete(req, resp);
    }

    /**
     * Handle a POST request.
     * <p/>
     * Defers the request to {@link #mockWebAppConfig} when possible.
     *
     * @param req  the client request.
     * @param resp the servlet response.
     * @throws IOException      if an input or output error occured while handling the request.
     * @throws ServletException if the request could not be handled.
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (mockWebAppConfig != null)
            mockWebAppConfig.process(req, resp);
        else
            super.doDelete(req, resp);
    }

    /**
     * Handle a PUT request.
     * <p/>
     * Defers the request to {@link #mockWebAppConfig} when possible.
     *
     * @param req  the client request.
     * @param resp the servlet response.
     * @throws IOException      if an input or output error occured while handling the request.
     * @throws ServletException if the request could not be handled.
     */
    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (mockWebAppConfig != null)
            mockWebAppConfig.process(req, resp);
        else
            super.doDelete(req, resp);
    }

    /**
     * Handle a DELETE request.
     * <p/>
     * Defers the request to {@link #mockWebAppConfig} when possible.
     *
     * @param req  the client request.
     * @param resp the servlet response.
     * @throws IOException      if an input or output error occured while handling the request.
     * @throws ServletException if the request could not be handled.
     */
    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (mockWebAppConfig != null)
            mockWebAppConfig.process(req, resp);
        else
            super.doDelete(req, resp);
    }

    /**
     * Handle a OPTIONS request.
     * <p/>
     * Defers the request to {@link #mockWebAppConfig} when possible.
     *
     * @param req  the client request.
     * @param resp the servlet response.
     * @throws IOException      if an input or output error occured while handling the request.
     * @throws ServletException if the request could not be handled.
     */
    @Override
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        if (mockWebAppConfig != null)
            mockWebAppConfig.process(req, resp);
        else
            super.doDelete(req, resp);
    }

    /**
     * Handle a TRACE request.
     * <p/>
     * Defers the request to {@link #mockWebAppConfig} when possible.
     *
     * @param req  the client request.
     * @param resp the servlet response.
     * @throws IOException      if an input or output error occured while handling the request.
     * @throws ServletException if the request could not be handled.
     */
    @Override
    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (mockWebAppConfig != null)
            mockWebAppConfig.process(req, resp);
        else
            super.doDelete(req, resp);
    }

    /**
     * {@link FileListener} handling the mock webapp config file changes.
     *
     * @author Julien Nicoulaud <julien.nicoulaud@gmail.com>
     * @see MockWebAppServlet#init(javax.servlet.ServletConfig)
     * @see MockWebAppServlet#fileMonitor
     * @since 1.0.0
     */
    protected class ConfigFileListener implements FileListener {

        /**
         * Handle a file creation event.
         * <p/>
         * Defers the event to {@link #fileChanged(org.apache.commons.vfs.FileChangeEvent)}.
         *
         * @param fileChangeEvent the event to handle.
         */
        public void fileCreated(FileChangeEvent fileChangeEvent) {
            fileChanged(fileChangeEvent);
        }

        /**
         * Handle a file deletion event.
         * <p/>
         * Unsets {@link MockWebAppServlet#mockWebAppConfig}.
         *
         * @param fileChangeEvent the event to handle.
         */
        public void fileDeleted(FileChangeEvent fileChangeEvent) {
            getServletContext().log("Config file deleted");
            mockWebAppConfig = null;
        }

        /**
         * Handle a file change event.
         * <p/>
         * Updates {@link MockWebAppServlet#mockWebAppConfig}.
         *
         * @param fileChangeEvent the event to handle.
         */
        public void fileChanged(FileChangeEvent fileChangeEvent) {
            try {
                final File configFile = new File(fileChangeEvent.getFile().getURL().getFile());
                mockWebAppConfig = MockWebAppConfig.Parser.parseConfig(configFile);
                getServletContext().log("Updated config from " + configFile.getPath());
            } catch (Exception e) {
                getServletContext().log("Failed updating config", e);
            }
        }
    }
}