com.github.woonsan.katharsis.invoker.KatharsisInvoker.java Source code

Java tutorial

Introduction

Here is the source code for com.github.woonsan.katharsis.invoker.KatharsisInvoker.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.woonsan.katharsis.invoker;

import io.katharsis.dispatcher.RequestDispatcher;
import io.katharsis.errorhandling.exception.KatharsisMappableException;
import io.katharsis.errorhandling.exception.KatharsisMatchingException;
import io.katharsis.errorhandling.mapper.KatharsisExceptionMapper;
import io.katharsis.queryParams.RequestParams;
import io.katharsis.queryParams.RequestParamsBuilder;
import io.katharsis.request.dto.RequestBody;
import io.katharsis.request.path.JsonPath;
import io.katharsis.request.path.PathBuilder;
import io.katharsis.resource.registry.ResourceRegistry;
import io.katharsis.response.BaseResponse;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.Scanner;

import javax.servlet.http.HttpServletResponse;

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

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.woonsan.katharsis.invoker.util.QueryStringUtils;
import com.google.common.net.MediaType;

/**
 * Katharsis dispatcher invoker.
 */
public class KatharsisInvoker {

    private static Logger log = LoggerFactory.getLogger(KatharsisInvoker.class);

    private static int BUFFER_SIZE = 4096;

    private ObjectMapper objectMapper;
    private ResourceRegistry resourceRegistry;
    private RequestDispatcher requestDispatcher;

    public KatharsisInvoker(ObjectMapper objectMapper, ResourceRegistry resourceRegistry,
            RequestDispatcher requestDispatcher) {
        this.objectMapper = objectMapper;
        this.resourceRegistry = resourceRegistry;
        this.requestDispatcher = requestDispatcher;
    }

    public void invoke(KatharsisInvokerContext invokerContext) throws KatharsisInvokerException {
        if (isAcceptableMediaType(invokerContext)) {
            try {
                dispatchRequest(invokerContext);
            } catch (Exception e) {
                throw new KatharsisInvokerException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
            }
        } else {
            throw new KatharsisInvokerException(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE,
                    "Unsupported Media Type");
        }
    }

    private void dispatchRequest(KatharsisInvokerContext invokerContext) throws Exception {
        BaseResponse<?> katharsisResponse = null;

        boolean passToMethodMatcher = false;

        InputStream in = null;

        try {
            JsonPath jsonPath = new PathBuilder(resourceRegistry).buildPath(invokerContext.getRequestPath());

            RequestParams requestParams = createRequestParams(invokerContext);

            in = invokerContext.getRequestEntityStream();
            RequestBody requestBody = inputStreamToBody(in);

            String method = invokerContext.getRequestMethod();
            katharsisResponse = requestDispatcher.dispatchRequest(jsonPath, method, requestParams, requestBody);
        } catch (KatharsisMappableException e) {
            if (log.isDebugEnabled()) {
                log.warn("Error occurred while dispatching katharsis request. " + e, e);
            } else {
                log.warn("Error occurred while dispatching katharsis request. " + e);
            }
            katharsisResponse = new KatharsisExceptionMapper().toErrorResponse(e);
        } catch (KatharsisMatchingException e) {
            passToMethodMatcher = true;
        } finally {
            closeQuietly(in);

            if (katharsisResponse != null) {
                invokerContext.setResponseStatus(katharsisResponse.getHttpStatus());
                invokerContext.setResponseContentType(JsonApiMediaType.APPLICATION_JSON_API);

                ByteArrayOutputStream baos = null;
                OutputStream out = null;

                try {
                    // first write to a buffer first because objectMapper may fail while writing.
                    baos = new ByteArrayOutputStream(BUFFER_SIZE);
                    objectMapper.writeValue(baos, katharsisResponse);

                    out = invokerContext.getResponseOutputStream();
                    out.write(baos.toByteArray());
                    out.flush();
                } finally {
                    closeQuietly(baos);
                    closeQuietly(out);
                }
            } else {
                invokerContext.setResponseStatus(HttpServletResponse.SC_NO_CONTENT);
            }
        }
    }

    private boolean isAcceptableMediaType(KatharsisInvokerContext invokerContext) {
        String acceptHeader = invokerContext.getRequestHeader("Accept");

        if (acceptHeader != null) {
            String[] accepts = acceptHeader.split(",");
            MediaType acceptableType;

            for (String mediaTypeItem : accepts) {
                acceptableType = MediaType.parse(mediaTypeItem.trim());

                if (JsonApiMediaType.isCompatibleMediaType(acceptableType)) {
                    return true;
                }
            }
        }

        return false;
    }

    private RequestParams createRequestParams(KatharsisInvokerContext invokerContext) {
        RequestParamsBuilder requestParamsBuilder = new RequestParamsBuilder(objectMapper);
        Map<String, String> queryParameters = QueryStringUtils.parseQueryStringAsSingleValueMap(invokerContext);
        return requestParamsBuilder.buildRequestParams(queryParameters);
    }

    private RequestBody inputStreamToBody(InputStream is) throws IOException {
        if (is == null) {
            return null;
        }

        Scanner s = new Scanner(is).useDelimiter("\\A");
        String requestBody = s.hasNext() ? s.next() : "";

        if (requestBody == null || requestBody.isEmpty()) {
            return null;
        }

        return objectMapper.readValue(requestBody, RequestBody.class);
    }

    private void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException ignore) {
            }
        }
    }
}