com.mockey.ui.JsonSchemaValidateServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.mockey.ui.JsonSchemaValidateServlet.java

Source

/*
 * Copyright (c) 2013, Francis Galiegue <fgaliegue@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Lesser GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Lesser GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.mockey.ui;

import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.fge.jsonschema.JsonValidators;
import com.github.fge.jsonschema.constants.ParseError;
import com.github.fge.jsonschema.constants.ValidateRequest;
import com.github.fge.jsonschema.constants.ValidateResponse;
import com.github.fge.jsonschema.main.JsonValidator;
import com.github.fge.jsonschema.report.ProcessingReport;
import com.github.fge.jsonschema.util.AsJson;
import com.github.fge.jsonschema.util.JsonLoader;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;
import com.google.common.io.Closeables;
import com.google.common.net.MediaType;
import com.mockey.model.Scenario;
import com.mockey.model.Service;
import com.mockey.storage.IMockeyStorage;
import com.mockey.storage.StorageRegistry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.Set;

/**
 * Servlet responsible of validating a schema/data pair
 * 
 * <p>
 * It returns a JSON Object as a result with the appropriate media type (thanks
 * Guava for providing {@link MediaType#JSON_UTF_8}!).
 * </p>
 * 
 * <p>
 * This object has the following members:
 * </p>
 * 
 * <ul>
 * <li>{@code invalidSchema}: boolean indicating whether the provided schema was
 * valid JSON;</li>
 * <li>{@code invalidData}: same, but for the data;</li>
 * <li>{@code valid} (only if the schema and data are valid): whether the
 * validation has succeeded;</li>
 * <li>{@code results} (only if the schema and data are valid): the result of
 * {@link ProcessingReport#getMessages()}.</li>
 * </ul>
 */
public final class JsonSchemaValidateServlet extends HttpServlet {
    /**
     * 
     */
    private static final long serialVersionUID = 2625630469996134777L;

    private static final Logger logger = LoggerFactory.getLogger(JsonSchemaValidateServlet.class);

    private static IMockeyStorage store = StorageRegistry.MockeyStorage;

    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        try {
            Long serviceId = new Long(req.getParameter("serviceId"));
            Long scenarioId = null;
            scenarioId = new Long(req.getParameter("scenarioId"));
            Service service = store.getServiceById(serviceId);
            Scenario scenario = service.getScenario(scenarioId);
            req.setAttribute("service", service);
            req.setAttribute("scenario", scenario);
        } catch (Exception e) {
            logger.debug("Unable to retrieve a Service of ID: " + req.getParameter("serviceId"));
        }

        // Get the service.
        RequestDispatcher dispatch = req.getRequestDispatcher("/jsonschemavalidate.jsp");
        dispatch.forward(req, resp);
    }

    @Override
    public void doPost(final HttpServletRequest req, final HttpServletResponse resp)
            throws ServletException, IOException {
        final Set<String> params = Sets.newHashSet();
        final Enumeration<String> enumeration = req.getParameterNames();

        // FIXME: no duplicates, it seems, but I cannot find the spec which
        // guarantees that
        while (enumeration.hasMoreElements())
            params.add(enumeration.nextElement());

        // We have required parameters
        if (!params.containsAll(ValidateRequest.REQUIRED_PARAMS)) {
            logger.warn("Missing parameters! Someone using me as a web service?");
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing parameters");
            return;
        }

        // We don't want extraneous parameters
        params.removeAll(ValidateRequest.VALID_PARAMS);

        if (!params.isEmpty()) {
            logger.warn("Invalid parameters! Someone using me as a web service?");
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid parameters");
            return;
        }

        final String rawSchema = req.getParameter(ValidateRequest.SCHEMA);
        final String data = req.getParameter(ValidateRequest.DATA);

        // Set correct content type
        resp.setContentType(MediaType.JSON_UTF_8.toString());

        final boolean useV3 = Boolean.parseBoolean(req.getParameter(ValidateRequest.USE_V3));
        final boolean useId = Boolean.parseBoolean(req.getParameter(ValidateRequest.USE_ID));

        final JsonNode ret = JsonSchemaUtil.buildResult(rawSchema, data, useV3, useId);

        final OutputStream out = resp.getOutputStream();

        try {
            out.write(ret.toString().getBytes(Charset.forName("UTF-8")));
            out.flush();
        } finally {
            Closeables.closeQuietly(out);
        }
    }

    //   /*
    //    * Build the response. When we arrive here, we are guaranteed that we have
    //    * the needed elements.
    //    */
    //   @VisibleForTesting
    //   static JsonNode buildResult(final String rawSchema, final String rawData,
    //         final boolean useV3, final boolean useId) throws IOException {
    //      final ObjectNode ret = JsonNodeFactory.instance.objectNode();
    //
    //      final boolean invalidSchema = fillWithData(ret,
    //            ValidateResponse.SCHEMA, ValidateResponse.INVALID_SCHEMA,
    //            rawSchema);
    //      final boolean invalidData = fillWithData(ret, ValidateResponse.DATA,
    //            ValidateResponse.INVALID_DATA, rawData);
    //
    //      final JsonNode schemaNode = ret.remove(ValidateResponse.SCHEMA);
    //      final JsonNode data = ret.remove(ValidateResponse.DATA);
    //
    //      if (invalidSchema || invalidData)
    //         return ret;
    //
    //      final JsonValidator validator = JsonValidators
    //            .withOptions(useV3, useId);
    //      final ProcessingReport report = validator.validateUnchecked(schemaNode,
    //            data);
    //
    //      final boolean success = report.isSuccess();
    //      ret.put(ValidateResponse.VALID, success);
    //      ret.put(ValidateResponse.RESULTS, ((AsJson) report).asJson());
    //      return ret;
    //   }
    //
    //   /*
    //    * We have to use that since Java is not smart enough to detect that
    //    * sometimes, a variable is initialized in all paths.
    //    * 
    //    * This returns true if the data is invalid.
    //    */
    //   private static boolean fillWithData(final ObjectNode node,
    //         final String onSuccess, final String onFailure, final String raw)
    //         throws IOException {
    //      try {
    //         node.put(onSuccess, JsonLoader.fromString(raw));
    //         return false;
    //      } catch (JsonProcessingException e) {
    //         node.put(onFailure, buildParsingError(e, raw.contains("\r\n")));
    //         return true;
    //      }
    //   }
    //
    //   private static JsonNode buildParsingError(final JsonProcessingException e,
    //         final boolean crlf) {
    //      final JsonLocation location = e.getLocation();
    //      final ObjectNode ret = JsonNodeFactory.instance.objectNode();
    //
    //      /*
    //       * Unfortunately, for some reason, Jackson botches the column number in
    //       * its JsonPosition -- I cannot figure out why exactly. However, it does
    //       * have a correct offset into the buffer.
    //       * 
    //       * The problem is that if the input has CR/LF line terminators, its
    //       * offset will be "off" by the number of lines minus 1 with regards to
    //       * what JavaScript sees as positions in text areas. Make the necessary
    //       * adjustments so that the caret jumps at the correct position in this
    //       * case.
    //       */
    //      final int lineNr = location.getLineNr();
    //      int offset = (int) location.getCharOffset();
    //      if (crlf)
    //         offset = offset - lineNr + 1;
    //      ret.put(ParseError.LINE, lineNr);
    //      ret.put(ParseError.OFFSET, offset);
    //
    //      // Finally, put the message
    //      ret.put(ParseError.MESSAGE, e.getOriginalMessage());
    //      return ret;
    //   }
}