io.vertigo.vega.plugins.webservice.handler.JsonConverterWebServiceHandlerPlugin.java Source code

Java tutorial

Introduction

Here is the source code for io.vertigo.vega.plugins.webservice.handler.JsonConverterWebServiceHandlerPlugin.java

Source

/**
 * vertigo - simple java starter
 *
 * Copyright (C) 2013-2017, KleeGroup, direction.technique@kleegroup.com (http://www.kleegroup.com)
 * KleeGroup, Centre d'affaire la Boursidiere - BP 159 - 92357 Le Plessis Robinson Cedex - France
 *
 * 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 io.vertigo.vega.plugins.webservice.handler;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.JsonSyntaxException;

import io.vertigo.app.Home;
import io.vertigo.core.component.ComponentSpace;
import io.vertigo.core.component.di.injector.DIInjector;
import io.vertigo.lang.Assertion;
import io.vertigo.vega.engines.webservice.json.JsonEngine;
import io.vertigo.vega.impl.webservice.WebServiceHandlerPlugin;
import io.vertigo.vega.plugins.webservice.handler.converter.DefaultJsonConverter;
import io.vertigo.vega.plugins.webservice.handler.converter.DefaultJsonSerializer;
import io.vertigo.vega.plugins.webservice.handler.converter.DtListDeltaJsonConverter;
import io.vertigo.vega.plugins.webservice.handler.converter.DtListJsonConverter;
import io.vertigo.vega.plugins.webservice.handler.converter.DtObjectJsonConverter;
import io.vertigo.vega.plugins.webservice.handler.converter.ImplicitJsonConverter;
import io.vertigo.vega.plugins.webservice.handler.converter.JsonConverter;
import io.vertigo.vega.plugins.webservice.handler.converter.JsonSerializer;
import io.vertigo.vega.plugins.webservice.handler.converter.PrimitiveJsonConverter;
import io.vertigo.vega.plugins.webservice.handler.converter.StringJsonSerializer;
import io.vertigo.vega.plugins.webservice.handler.converter.VFileJsonConverter;
import io.vertigo.vega.plugins.webservice.handler.reader.BodyJsonReader;
import io.vertigo.vega.plugins.webservice.handler.reader.HeaderJsonReader;
import io.vertigo.vega.plugins.webservice.handler.reader.InnerBodyJsonReader;
import io.vertigo.vega.plugins.webservice.handler.reader.JsonReader;
import io.vertigo.vega.plugins.webservice.handler.reader.PathJsonReader;
import io.vertigo.vega.plugins.webservice.handler.reader.QueryJsonReader;
import io.vertigo.vega.plugins.webservice.handler.reader.RequestJsonReader;
import io.vertigo.vega.webservice.exception.SessionException;
import io.vertigo.vega.webservice.metamodel.WebServiceDefinition;
import io.vertigo.vega.webservice.metamodel.WebServiceParam;
import io.vertigo.vega.webservice.metamodel.WebServiceParam.WebServiceParamType;
import spark.Request;
import spark.Response;

/**
 * Params handler.
 * It's an handler barrier : bellow this handler anything is object, over this handler it's json.
 * Extract and Json convert.
 * @author npiedeloup
 */
public final class JsonConverterWebServiceHandlerPlugin implements WebServiceHandlerPlugin {
    private static final Class<? extends JsonConverter>[] JSON_CONVERTER_CLASSES = new Class[] {
            ImplicitJsonConverter.class, PrimitiveJsonConverter.class, DtListJsonConverter.class,
            DtObjectJsonConverter.class, DtListDeltaJsonConverter.class, VFileJsonConverter.class,
            DefaultJsonConverter.class };
    private static final Class<? extends JsonReader<?>>[] JSON_READER_CLASSES = new Class[] { BodyJsonReader.class,
            InnerBodyJsonReader.class, HeaderJsonReader.class, PathJsonReader.class, QueryJsonReader.class,
            RequestJsonReader.class };

    private static final Class<? extends JsonSerializer>[] JSON_SERIALIZER_CLASSES = new Class[] {
            VFileJsonConverter.class, ImplicitJsonConverter.class, StringJsonSerializer.class,
            DefaultJsonSerializer.class };

    private final Map<Class, List<JsonConverter>> jsonConverters = new HashMap<>();
    private final EnumMap<WebServiceParamType, List<JsonReader<?>>> jsonReaders = new EnumMap<>(
            WebServiceParamType.class);
    private final List<JsonSerializer> jsonWriters = new ArrayList<>();

    /**
    * @param jsonReaderEngine jsonReaderEngine
    */
    @Inject
    public JsonConverterWebServiceHandlerPlugin(final JsonEngine jsonReaderEngine) {
        Assertion.checkNotNull(jsonReaderEngine);
        //-----
        final ComponentSpace componentSpace = Home.getApp().getComponentSpace();
        for (final Class<? extends JsonConverter> jsonConverterClass : JSON_CONVERTER_CLASSES) {
            final JsonConverter jsonConverter = DIInjector.newInstance(jsonConverterClass, componentSpace);
            for (final Class inputType : jsonConverter.getSupportedInputs()) {
                jsonConverters.computeIfAbsent(inputType, k -> new ArrayList<>()).add(jsonConverter);
            }
        }

        for (final Class<? extends JsonReader<?>> jsonReaderClass : JSON_READER_CLASSES) {
            final JsonReader<?> jsonReader = DIInjector.newInstance(jsonReaderClass, componentSpace);
            for (final WebServiceParamType restParamType : jsonReader.getSupportedInput()) {
                List<JsonReader<?>> jsonReaderByRestParamType = jsonReaders.get(restParamType);
                if (jsonReaderByRestParamType == null) {
                    jsonReaderByRestParamType = new ArrayList<>();
                    jsonReaders.put(restParamType, jsonReaderByRestParamType);
                }
                jsonReaderByRestParamType.add(jsonReader);
            }
        }
        for (final Class<? extends JsonSerializer> jsonSerializerClass : JSON_SERIALIZER_CLASSES) {
            final JsonSerializer jsonSerializer = DIInjector.newInstance(jsonSerializerClass, componentSpace);
            jsonWriters.add(jsonSerializer);
        }

    }

    /** {@inheritDoc} */
    @Override
    public boolean accept(final WebServiceDefinition webServiceDefinition) {
        return true;
    }

    /** {@inheritDoc}  */
    @Override
    public Object handle(final Request request, final Response response, final WebServiceCallContext routeContext,
            final HandlerChain chain) throws SessionException {
        //we can't read body at first : because if it's a multipart request call body() disabled getParts() access.
        for (final WebServiceParam webServiceParam : routeContext.getWebServiceDefinition().getWebServiceParams()) {
            readParameterValue(request, routeContext, webServiceParam);
        }
        final Object result = chain.handle(request, response, routeContext);
        return convertResultToJson(result, response, routeContext);
    }

    private void readParameterValue(final Request request, final WebServiceCallContext routeContext,
            final WebServiceParam webServiceParam) {
        try {
            boolean found = false;
            JsonReader jsonReaderToApply = null;
            JsonConverter jsonConverterToApply = null;
            for (final JsonReader jsonReader : jsonReaders.get(webServiceParam.getParamType())) {
                jsonReaderToApply = jsonReader;

                for (final JsonConverter jsonConverter : jsonConverters.get(jsonReader.getSupportedOutput())) {

                    if (jsonConverter.canHandle(webServiceParam.getType())) {
                        jsonConverterToApply = jsonConverter;
                        found = true;
                        break;
                    }
                }
                if (found) {
                    break;
                }
            }
            //-----
            Assertion.checkNotNull(jsonReaderToApply,
                    "Can't parse param {0} of service {1} {2} no compatible JsonReader found for {3}",
                    webServiceParam.getFullName(), routeContext.getWebServiceDefinition().getVerb(),
                    routeContext.getWebServiceDefinition().getPath(), webServiceParam.getParamType());
            Assertion.checkNotNull(jsonConverterToApply,
                    "Can't parse param {0} of service {1} {2} no compatible JsonConverter found for {3} {4}",
                    webServiceParam.getFullName(), routeContext.getWebServiceDefinition().getVerb(),
                    routeContext.getWebServiceDefinition().getPath(), webServiceParam.getParamType(),
                    webServiceParam.getType());
            //-----
            final Object converterSource = jsonReaderToApply.extractData(request, webServiceParam, routeContext);
            if (converterSource != null) { //On ne convertit pas les null
                jsonConverterToApply.populateWebServiceCallContext(converterSource, webServiceParam, routeContext);
            } else if (webServiceParam.isOptional()) {
                routeContext.setParamValue(webServiceParam, null /*converterSource*/);
            }
            Assertion.checkNotNull(routeContext.getParamValue(webServiceParam), "RestParam not found : {0}",
                    webServiceParam);
        } catch (final JsonSyntaxException e) {
            throw new JsonSyntaxException("Error parsing param " + webServiceParam.getFullName() + " on service "
                    + routeContext.getWebServiceDefinition().getVerb() + " "
                    + routeContext.getWebServiceDefinition().getPath(), e);
        }
    }

    private String convertResultToJson(final Object result, final Response response,
            final WebServiceCallContext routeContext) {
        //optimize most common case
        if (result == null) {
            //if status was not set, or set to OK we set it to NO_CONTENT
            if (response.raw().getStatus() == HttpServletResponse.SC_OK || response.raw().getStatus() == 0) {
                response.status(HttpServletResponse.SC_NO_CONTENT);
            }
            return ""; //jetty understand null as 404 not found
        }

        JsonSerializer jsonWriterToApply = null;
        for (final JsonSerializer jsonWriter : jsonWriters) {
            if (jsonWriter.canHandle(result.getClass())) {
                jsonWriterToApply = jsonWriter;
                break;
            }
        }
        //-----
        Assertion.checkNotNull(jsonWriterToApply,
                "Can't send result of service {0} {1} no compatible JsonConverter found for {2}",
                routeContext.getWebServiceDefinition().getVerb(), routeContext.getWebServiceDefinition().getPath(),
                result.getClass().getName());
        final String json = jsonWriterToApply.toJson(result, response, routeContext.getWebServiceDefinition());
        Assertion.checkNotNull(json, "Can't convert result to json");
        return json;
    }
}