<commit_before>package org.qfox.jestful.async;

import org.qfox.jestful.async.annotation.Async;
import org.qfox.jestful.core.*;
import org.qfox.jestful.core.exception.BeanConfigException;
import org.qfox.jestful.core.exception.JestfulRuntimeException;
import org.qfox.jestful.core.formatting.ResponseSerializer;
import org.qfox.jestful.server.renderer.Renderer;
import org.qfox.jestful.server.renderer.ResultRenderer;

import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by yangchangpei on 17/5/3.
 */
public class CallableRenderer extends ResultRenderer implements Renderer, Initialable, Destroyable {
    private ExecutorService executor;

    @Override
    public boolean supports(Action action, Object value) {
        if (value instanceof Callable) {
            Mapping mapping = action.getMapping();
            Resource resource = action.getResource();
            Async async = mapping.isAnnotationPresent(Async.class)
                    ? mapping.getAnnotation(Async.class)
                    : resource.isAnnotationPresent(Async.class)
                    ? resource.getAnnotation(Async.class)
                    : null;
            return async == null || async.value();
        } else {
            return false;
        }
    }

    @Override
    public void render(Action action, Object value, Request request, Response response) throws Exception {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        AsyncContext asyncContext = req.startAsync(req, resp);
        executor.execute(new AsyncRunnable(asyncContext, (Callable<?>) value, action));
    }

    @Override
    public void config(Map<String, String> arguments) throws BeanConfigException {

    }

    public void initialize(BeanContainer beanContainer) {
        Collection<ResponseSerializer> serializers = beanContainer.find(ResponseSerializer.class).values();
        for (ResponseSerializer serializer : serializers) {
            String contentType = serializer.getContentType();
            MediaType mediaType = MediaType.valueOf(contentType);
            this.serializers.put(mediaType, serializer);
        }

        this.renderers.addAll(beanContainer.find(Renderer.class).values());
        this.executor = Executors.newCachedThreadPool();
    }

    @Override
    public void destroy() {
        if (executor != null) executor.shutdown();
    }

    private class AsyncRunnable implements Runnable, Actor {
        private final AsyncContext asyncContext;
        private final Callable<?> callable;
        private final Action action;
        private Object value;

        public AsyncRunnable(AsyncContext asyncContext, Callable<?> callable, Action action) {
            this.asyncContext = asyncContext;
            this.callable = callable;
            this.action = action;
        }

        @Override
        public void run() {
            try {
                value = callable.call();
                action.intrude(this);
                action.getResult().setRendered(false);
                CallableRenderer.this.react(action);
            } catch (Exception e) {
                throw new JestfulRuntimeException(e);
            } finally {<commit_msg>Server Async Supported<commit_after>package org.qfox.jestful.async;

import org.qfox.jestful.async.annotation.Async;
import org.qfox.jestful.core.*;
import org.qfox.jestful.core.exception.JestfulRuntimeException;
import org.qfox.jestful.server.renderer.Renderer;

import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by yangchangpei on 17/5/3.
 */
public class CallableRenderer implements Renderer, Initialable, Destroyable {
    private ExecutorService executor;
    private Actor renderer;

    @Override
    public boolean supports(Action action, Object value) {
        if (value instanceof Callable) {
            Mapping mapping = action.getMapping();
            Resource resource = action.getResource();
            Async async = mapping.isAnnotationPresent(Async.class)
                    ? mapping.getAnnotation(Async.class)
                    : resource.isAnnotationPresent(Async.class)
                    ? resource.getAnnotation(Async.class)
                    : null;
            return async == null || async.value();
        } else {
            return false;
        }
    }

    @Override
    public void render(Action action, Object value, Request request, Response response) throws Exception {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        AsyncContext asyncContext = req.startAsync(req, resp);
        executor.execute(new AsyncRunnable(asyncContext, (Callable<?>) value, action));
    }

    public void initialize(BeanContainer beanContainer) {
        this.executor = Executors.newCachedThreadPool();
        this.renderer = (Actor) beanContainer.get("renderer");
    }

    @Override
    public void destroy() {
        if (executor != null) executor.shutdown();
    }

    private class AsyncRunnable implements Runnable, Actor {
        private final AsyncContext asyncContext;
        private final Callable<?> callable;
        private final Action action;
        private Object value;

        public AsyncRunnable(AsyncContext asyncContext, Callable<?> callable, Action action) {
            this.asyncContext = asyncContext;
            this.callable = callable;
            this.action = action;
        }

        @Override
        public void run() {
            try {
                value = callable.call();
                action.intrude(this);
                action.getResult().setRendered(false);
                renderer.react(action);
            } catch (Exception e) {
                throw new JestfulRuntimeException(e);
            } finally {
{'fraction_non_alphanumeric': 0.08967046894803549, 'fraction_numerical': 0.0012674271229404308, 'mean_word_length': 2.6810495626822157, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5219044', 'n_tokens_mistral': 1620, 'n_tokens_neox': 1564, 'n_words': 370}